From f911ba985aa7fe0096c386c5be385ac5825ea527 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Sat, 16 Jul 2005 00:30:23 +0000 Subject: Initial revision From-SVN: r102074 --- libjava/classpath/java/applet/Applet.java | 524 ++ libjava/classpath/java/applet/AppletContext.java | 154 + libjava/classpath/java/applet/AppletStub.java | 103 + libjava/classpath/java/applet/AudioClip.java | 68 + libjava/classpath/java/applet/package.html | 47 + libjava/classpath/java/awt/AWTError.java | 64 + libjava/classpath/java/awt/AWTEvent.java | 278 + .../classpath/java/awt/AWTEventMulticaster.java | 1209 ++++ libjava/classpath/java/awt/AWTException.java | 64 + libjava/classpath/java/awt/AWTKeyStroke.java | 660 +++ libjava/classpath/java/awt/AWTPermission.java | 121 + libjava/classpath/java/awt/ActiveEvent.java | 61 + libjava/classpath/java/awt/Adjustable.java | 171 + libjava/classpath/java/awt/AlphaComposite.java | 167 + libjava/classpath/java/awt/AttributeValue.java | 98 + libjava/classpath/java/awt/BasicStroke.java | 248 + libjava/classpath/java/awt/BorderLayout.java | 731 +++ libjava/classpath/java/awt/BufferCapabilities.java | 253 + libjava/classpath/java/awt/Button.java | 466 ++ libjava/classpath/java/awt/Canvas.java | 354 ++ libjava/classpath/java/awt/CardLayout.java | 483 ++ libjava/classpath/java/awt/Checkbox.java | 649 +++ libjava/classpath/java/awt/CheckboxGroup.java | 173 + libjava/classpath/java/awt/CheckboxMenuItem.java | 355 ++ libjava/classpath/java/awt/Choice.java | 638 +++ libjava/classpath/java/awt/Color.java | 1008 ++++ libjava/classpath/java/awt/ColorPaintContext.java | 195 + libjava/classpath/java/awt/Component.java | 6017 ++++++++++++++++++++ .../classpath/java/awt/ComponentOrientation.java | 215 + libjava/classpath/java/awt/Composite.java | 73 + libjava/classpath/java/awt/CompositeContext.java | 71 + libjava/classpath/java/awt/Container.java | 2026 +++++++ .../awt/ContainerOrderFocusTraversalPolicy.java | 413 ++ libjava/classpath/java/awt/Cursor.java | 224 + .../java/awt/DefaultFocusTraversalPolicy.java | 109 + .../java/awt/DefaultKeyboardFocusManager.java | 536 ++ libjava/classpath/java/awt/Dialog.java | 553 ++ libjava/classpath/java/awt/Dimension.java | 234 + libjava/classpath/java/awt/DisplayMode.java | 164 + libjava/classpath/java/awt/Event.java | 185 + .../classpath/java/awt/EventDispatchThread.java | 94 + libjava/classpath/java/awt/EventQueue.java | 552 ++ libjava/classpath/java/awt/FileDialog.java | 318 ++ libjava/classpath/java/awt/FlowLayout.java | 364 ++ .../classpath/java/awt/FocusTraversalPolicy.java | 103 + libjava/classpath/java/awt/Font.java | 1336 +++++ .../classpath/java/awt/FontFormatException.java | 65 + libjava/classpath/java/awt/FontMetrics.java | 425 ++ libjava/classpath/java/awt/Frame.java | 649 +++ libjava/classpath/java/awt/GradientPaint.java | 229 + libjava/classpath/java/awt/Graphics.java | 767 +++ libjava/classpath/java/awt/Graphics2D.java | 158 + .../classpath/java/awt/GraphicsConfigTemplate.java | 106 + .../classpath/java/awt/GraphicsConfiguration.java | 218 + libjava/classpath/java/awt/GraphicsDevice.java | 292 + .../classpath/java/awt/GraphicsEnvironment.java | 244 + libjava/classpath/java/awt/GridBagConstraints.java | 195 + libjava/classpath/java/awt/GridBagLayout.java | 1069 ++++ libjava/classpath/java/awt/GridBagLayoutInfo.java | 70 + libjava/classpath/java/awt/GridLayout.java | 360 ++ libjava/classpath/java/awt/HeadlessException.java | 72 + .../java/awt/IllegalComponentStateException.java | 71 + libjava/classpath/java/awt/Image.java | 203 + libjava/classpath/java/awt/ImageCapabilities.java | 107 + libjava/classpath/java/awt/Insets.java | 158 + libjava/classpath/java/awt/ItemSelectable.java | 75 + libjava/classpath/java/awt/JobAttributes.java | 500 ++ libjava/classpath/java/awt/KeyEventDispatcher.java | 82 + .../classpath/java/awt/KeyEventPostProcessor.java | 81 + .../classpath/java/awt/KeyboardFocusManager.java | 1478 +++++ libjava/classpath/java/awt/Label.java | 314 + libjava/classpath/java/awt/LayoutManager.java | 92 + libjava/classpath/java/awt/LayoutManager2.java | 100 + libjava/classpath/java/awt/List.java | 1263 ++++ libjava/classpath/java/awt/MediaTracker.java | 697 +++ libjava/classpath/java/awt/Menu.java | 468 ++ libjava/classpath/java/awt/MenuBar.java | 423 ++ libjava/classpath/java/awt/MenuComponent.java | 1324 +++++ libjava/classpath/java/awt/MenuContainer.java | 71 + libjava/classpath/java/awt/MenuItem.java | 603 ++ libjava/classpath/java/awt/MenuShortcut.java | 207 + libjava/classpath/java/awt/PageAttributes.java | 482 ++ libjava/classpath/java/awt/Paint.java | 79 + libjava/classpath/java/awt/PaintContext.java | 76 + libjava/classpath/java/awt/Panel.java | 173 + libjava/classpath/java/awt/Point.java | 245 + libjava/classpath/java/awt/Polygon.java | 613 ++ libjava/classpath/java/awt/PopupMenu.java | 169 + libjava/classpath/java/awt/PrintGraphics.java | 57 + libjava/classpath/java/awt/PrintJob.java | 104 + libjava/classpath/java/awt/Rectangle.java | 749 +++ libjava/classpath/java/awt/RenderingHints.java | 803 +++ libjava/classpath/java/awt/Robot.java | 423 ++ libjava/classpath/java/awt/ScrollPane.java | 615 ++ .../classpath/java/awt/ScrollPaneAdjustable.java | 200 + libjava/classpath/java/awt/Scrollbar.java | 825 +++ libjava/classpath/java/awt/Shape.java | 203 + libjava/classpath/java/awt/Stroke.java | 65 + libjava/classpath/java/awt/SystemColor.java | 462 ++ libjava/classpath/java/awt/TextArea.java | 629 ++ libjava/classpath/java/awt/TextComponent.java | 739 +++ libjava/classpath/java/awt/TextField.java | 541 ++ libjava/classpath/java/awt/TexturePaint.java | 75 + libjava/classpath/java/awt/Toolkit.java | 995 ++++ libjava/classpath/java/awt/Transparency.java | 67 + libjava/classpath/java/awt/Window.java | 1125 ++++ libjava/classpath/java/awt/color/CMMException.java | 63 + libjava/classpath/java/awt/color/ColorSpace.java | 183 + .../classpath/java/awt/color/ICC_ColorSpace.java | 314 + libjava/classpath/java/awt/color/ICC_Profile.java | 1244 ++++ .../classpath/java/awt/color/ICC_ProfileGray.java | 133 + .../classpath/java/awt/color/ICC_ProfileRGB.java | 227 + .../java/awt/color/ProfileDataException.java | 64 + libjava/classpath/java/awt/color/package.html | 46 + .../classpath/java/awt/datatransfer/Clipboard.java | 114 + .../java/awt/datatransfer/ClipboardOwner.java | 57 + .../java/awt/datatransfer/DataFlavor.java | 1034 ++++ .../classpath/java/awt/datatransfer/FlavorMap.java | 75 + .../java/awt/datatransfer/FlavorTable.java | 73 + .../awt/datatransfer/MimeTypeParseException.java | 70 + .../java/awt/datatransfer/StringSelection.java | 158 + .../java/awt/datatransfer/SystemFlavorMap.java | 169 + .../java/awt/datatransfer/Transferable.java | 83 + .../datatransfer/UnsupportedFlavorException.java | 65 + .../classpath/java/awt/datatransfer/package.html | 47 + libjava/classpath/java/awt/dnd/Autoscroll.java | 70 + libjava/classpath/java/awt/dnd/DnDConstants.java | 77 + .../java/awt/dnd/DnDEventMulticaster.java | 74 + .../classpath/java/awt/dnd/DragGestureEvent.java | 156 + .../java/awt/dnd/DragGestureListener.java | 63 + .../java/awt/dnd/DragGestureRecognizer.java | 179 + libjava/classpath/java/awt/dnd/DragSource.java | 257 + .../classpath/java/awt/dnd/DragSourceAdapter.java | 126 + .../classpath/java/awt/dnd/DragSourceContext.java | 200 + .../java/awt/dnd/DragSourceDragEvent.java | 102 + .../java/awt/dnd/DragSourceDropEvent.java | 89 + .../classpath/java/awt/dnd/DragSourceEvent.java | 93 + .../classpath/java/awt/dnd/DragSourceListener.java | 97 + .../java/awt/dnd/DragSourceMotionListener.java | 64 + libjava/classpath/java/awt/dnd/DropTarget.java | 293 + .../classpath/java/awt/dnd/DropTargetAdapter.java | 100 + .../classpath/java/awt/dnd/DropTargetContext.java | 188 + .../java/awt/dnd/DropTargetDragEvent.java | 140 + .../java/awt/dnd/DropTargetDropEvent.java | 170 + .../classpath/java/awt/dnd/DropTargetEvent.java | 56 + .../classpath/java/awt/dnd/DropTargetListener.java | 89 + .../java/awt/dnd/InvalidDnDOperationException.java | 73 + .../java/awt/dnd/MouseDragGestureRecognizer.java | 131 + libjava/classpath/java/awt/dnd/package.html | 46 + .../java/awt/dnd/peer/DragSourceContextPeer.java | 57 + .../java/awt/dnd/peer/DropTargetContextPeer.java | 68 + .../java/awt/dnd/peer/DropTargetPeer.java | 48 + libjava/classpath/java/awt/dnd/peer/package.html | 46 + .../classpath/java/awt/event/AWTEventListener.java | 65 + .../java/awt/event/AWTEventListenerProxy.java | 155 + libjava/classpath/java/awt/event/ActionEvent.java | 226 + .../classpath/java/awt/event/ActionListener.java | 59 + .../classpath/java/awt/event/AdjustmentEvent.java | 222 + .../java/awt/event/AdjustmentListener.java | 58 + .../classpath/java/awt/event/ComponentAdapter.java | 97 + .../classpath/java/awt/event/ComponentEvent.java | 137 + .../java/awt/event/ComponentListener.java | 84 + .../classpath/java/awt/event/ContainerAdapter.java | 79 + .../classpath/java/awt/event/ContainerEvent.java | 135 + .../java/awt/event/ContainerListener.java | 70 + libjava/classpath/java/awt/event/FocusAdapter.java | 79 + libjava/classpath/java/awt/event/FocusEvent.java | 181 + .../classpath/java/awt/event/FocusListener.java | 69 + .../java/awt/event/HierarchyBoundsAdapter.java | 78 + .../java/awt/event/HierarchyBoundsListener.java | 70 + .../classpath/java/awt/event/HierarchyEvent.java | 253 + .../java/awt/event/HierarchyListener.java | 62 + libjava/classpath/java/awt/event/InputEvent.java | 381 ++ .../classpath/java/awt/event/InputMethodEvent.java | 303 + .../java/awt/event/InputMethodListener.java | 70 + .../classpath/java/awt/event/InvocationEvent.java | 237 + libjava/classpath/java/awt/event/ItemEvent.java | 155 + libjava/classpath/java/awt/event/ItemListener.java | 62 + libjava/classpath/java/awt/event/KeyAdapter.java | 88 + libjava/classpath/java/awt/event/KeyEvent.java | 1740 ++++++ libjava/classpath/java/awt/event/KeyListener.java | 77 + libjava/classpath/java/awt/event/MouseAdapter.java | 106 + libjava/classpath/java/awt/event/MouseEvent.java | 432 ++ .../classpath/java/awt/event/MouseListener.java | 94 + .../java/awt/event/MouseMotionAdapter.java | 79 + .../java/awt/event/MouseMotionListener.java | 72 + .../classpath/java/awt/event/MouseWheelEvent.java | 232 + .../java/awt/event/MouseWheelListener.java | 60 + libjava/classpath/java/awt/event/PaintEvent.java | 127 + libjava/classpath/java/awt/event/TextEvent.java | 93 + libjava/classpath/java/awt/event/TextListener.java | 60 + .../classpath/java/awt/event/WindowAdapter.java | 156 + libjava/classpath/java/awt/event/WindowEvent.java | 312 + .../java/awt/event/WindowFocusListener.java | 68 + .../classpath/java/awt/event/WindowListener.java | 109 + .../java/awt/event/WindowStateListener.java | 62 + libjava/classpath/java/awt/event/package.html | 46 + .../classpath/java/awt/font/FontRenderContext.java | 126 + .../java/awt/font/GlyphJustificationInfo.java | 77 + libjava/classpath/java/awt/font/GlyphMetrics.java | 134 + libjava/classpath/java/awt/font/GlyphVector.java | 145 + .../classpath/java/awt/font/GraphicAttribute.java | 84 + .../java/awt/font/ImageGraphicAttribute.java | 109 + .../classpath/java/awt/font/LineBreakMeasurer.java | 113 + libjava/classpath/java/awt/font/LineMetrics.java | 67 + .../classpath/java/awt/font/MultipleMaster.java | 61 + libjava/classpath/java/awt/font/NumericShaper.java | 137 + libjava/classpath/java/awt/font/OpenType.java | 111 + .../java/awt/font/ShapeGraphicAttribute.java | 105 + libjava/classpath/java/awt/font/TextAttribute.java | 309 + libjava/classpath/java/awt/font/TextHitInfo.java | 125 + libjava/classpath/java/awt/font/TextLayout.java | 332 ++ libjava/classpath/java/awt/font/TextMeasurer.java | 97 + .../java/awt/font/TransformAttribute.java | 100 + libjava/classpath/java/awt/font/package.html | 46 + .../classpath/java/awt/geom/AffineTransform.java | 1487 +++++ libjava/classpath/java/awt/geom/Arc2D.java | 1399 +++++ libjava/classpath/java/awt/geom/Area.java | 3312 +++++++++++ libjava/classpath/java/awt/geom/CubicCurve2D.java | 1724 ++++++ libjava/classpath/java/awt/geom/Dimension2D.java | 118 + libjava/classpath/java/awt/geom/Ellipse2D.java | 413 ++ .../java/awt/geom/FlatteningPathIterator.java | 579 ++ libjava/classpath/java/awt/geom/GeneralPath.java | 958 ++++ .../java/awt/geom/IllegalPathStateException.java | 71 + libjava/classpath/java/awt/geom/Line2D.java | 1182 ++++ .../awt/geom/NoninvertibleTransformException.java | 65 + libjava/classpath/java/awt/geom/PathIterator.java | 189 + libjava/classpath/java/awt/geom/Point2D.java | 396 ++ libjava/classpath/java/awt/geom/QuadCurve2D.java | 1467 +++++ libjava/classpath/java/awt/geom/Rectangle2D.java | 992 ++++ .../classpath/java/awt/geom/RectangularShape.java | 385 ++ .../classpath/java/awt/geom/RoundRectangle2D.java | 533 ++ .../classpath/java/awt/geom/doc-files/Area-1.png | Bin 0 -> 21447 bytes .../java/awt/geom/doc-files/CubicCurve2D-1.png | Bin 0 -> 6280 bytes .../java/awt/geom/doc-files/CubicCurve2D-2.png | Bin 0 -> 5791 bytes .../java/awt/geom/doc-files/CubicCurve2D-3.png | Bin 0 -> 13168 bytes .../java/awt/geom/doc-files/CubicCurve2D-4.png | Bin 0 -> 7839 bytes .../java/awt/geom/doc-files/CubicCurve2D-5.png | Bin 0 -> 5112 bytes .../java/awt/geom/doc-files/Ellipse-1.png | Bin 0 -> 19426 bytes .../geom/doc-files/FlatteningPathIterator-1.html | 481 ++ .../java/awt/geom/doc-files/GeneralPath-1.png | Bin 0 -> 13111 bytes .../java/awt/geom/doc-files/QuadCurve2D-1.png | Bin 0 -> 6363 bytes .../java/awt/geom/doc-files/QuadCurve2D-2.png | Bin 0 -> 5872 bytes .../java/awt/geom/doc-files/QuadCurve2D-3.png | Bin 0 -> 12334 bytes .../java/awt/geom/doc-files/QuadCurve2D-4.png | Bin 0 -> 7797 bytes .../java/awt/geom/doc-files/QuadCurve2D-5.png | Bin 0 -> 4757 bytes libjava/classpath/java/awt/geom/package.html | 46 + libjava/classpath/java/awt/im/InputContext.java | 434 ++ .../java/awt/im/InputMethodHighlight.java | 185 + .../classpath/java/awt/im/InputMethodRequests.java | 153 + libjava/classpath/java/awt/im/InputSubset.java | 129 + libjava/classpath/java/awt/im/package.html | 46 + libjava/classpath/java/awt/im/spi/InputMethod.java | 240 + .../java/awt/im/spi/InputMethodContext.java | 123 + .../java/awt/im/spi/InputMethodDescriptor.java | 113 + libjava/classpath/java/awt/im/spi/package.html | 46 + .../java/awt/image/AffineTransformOp.java | 375 ++ .../java/awt/image/AreaAveragingScaleFilter.java | 127 + .../classpath/java/awt/image/BandCombineOp.java | 168 + .../java/awt/image/BandedSampleModel.java | 548 ++ .../classpath/java/awt/image/BufferStrategy.java | 124 + .../classpath/java/awt/image/BufferedImage.java | 693 +++ .../java/awt/image/BufferedImageFilter.java | 110 + .../classpath/java/awt/image/BufferedImageOp.java | 55 + .../classpath/java/awt/image/ByteLookupTable.java | 166 + .../classpath/java/awt/image/ColorConvertOp.java | 319 ++ libjava/classpath/java/awt/image/ColorModel.java | 758 +++ .../java/awt/image/ComponentColorModel.java | 391 ++ .../java/awt/image/ComponentSampleModel.java | 544 ++ libjava/classpath/java/awt/image/ConvolveOp.java | 337 ++ .../classpath/java/awt/image/CropImageFilter.java | 180 + libjava/classpath/java/awt/image/DataBuffer.java | 436 ++ .../classpath/java/awt/image/DataBufferByte.java | 245 + .../classpath/java/awt/image/DataBufferDouble.java | 288 + .../classpath/java/awt/image/DataBufferFloat.java | 286 + .../classpath/java/awt/image/DataBufferInt.java | 244 + .../classpath/java/awt/image/DataBufferShort.java | 245 + .../classpath/java/awt/image/DataBufferUShort.java | 246 + .../classpath/java/awt/image/DirectColorModel.java | 420 ++ .../java/awt/image/FilteredImageSource.java | 125 + .../classpath/java/awt/image/ImageConsumer.java | 216 + libjava/classpath/java/awt/image/ImageFilter.java | 221 + .../classpath/java/awt/image/ImageObserver.java | 129 + .../classpath/java/awt/image/ImageProducer.java | 85 + .../java/awt/image/ImagingOpException.java | 66 + .../classpath/java/awt/image/IndexColorModel.java | 697 +++ libjava/classpath/java/awt/image/Kernel.java | 143 + libjava/classpath/java/awt/image/LookupOp.java | 252 + libjava/classpath/java/awt/image/LookupTable.java | 109 + .../java/awt/image/MemoryImageSource.java | 373 ++ .../awt/image/MultiPixelPackedSampleModel.java | 388 ++ .../classpath/java/awt/image/PackedColorModel.java | 192 + libjava/classpath/java/awt/image/PixelGrabber.java | 618 ++ .../awt/image/PixelInterleavedSampleModel.java | 98 + .../classpath/java/awt/image/RGBImageFilter.java | 267 + libjava/classpath/java/awt/image/Raster.java | 546 ++ .../java/awt/image/RasterFormatException.java | 65 + libjava/classpath/java/awt/image/RasterOp.java | 57 + .../classpath/java/awt/image/RenderedImage.java | 70 + .../java/awt/image/ReplicateScaleFilter.java | 244 + libjava/classpath/java/awt/image/RescaleOp.java | 218 + libjava/classpath/java/awt/image/SampleModel.java | 477 ++ .../classpath/java/awt/image/ShortLookupTable.java | 162 + .../awt/image/SinglePixelPackedSampleModel.java | 449 ++ libjava/classpath/java/awt/image/TileObserver.java | 47 + .../classpath/java/awt/image/VolatileImage.java | 253 + .../classpath/java/awt/image/WritableRaster.java | 265 + .../java/awt/image/WritableRenderedImage.java | 56 + libjava/classpath/java/awt/image/package.html | 46 + .../renderable/ContextualRenderedImageFactory.java | 56 + .../java/awt/image/renderable/ParameterBlock.java | 308 + .../java/awt/image/renderable/RenderContext.java | 141 + .../java/awt/image/renderable/RenderableImage.java | 62 + .../awt/image/renderable/RenderableImageOp.java | 157 + .../image/renderable/RenderableImageProducer.java | 79 + .../awt/image/renderable/RenderedImageFactory.java | 47 + .../java/awt/image/renderable/package.html | 46 + libjava/classpath/java/awt/package.html | 46 + libjava/classpath/java/awt/peer/ButtonPeer.java | 46 + libjava/classpath/java/awt/peer/CanvasPeer.java | 45 + .../java/awt/peer/CheckboxMenuItemPeer.java | 46 + libjava/classpath/java/awt/peer/CheckboxPeer.java | 52 + libjava/classpath/java/awt/peer/ChoicePeer.java | 54 + libjava/classpath/java/awt/peer/ComponentPeer.java | 187 + libjava/classpath/java/awt/peer/ContainerPeer.java | 59 + libjava/classpath/java/awt/peer/DialogPeer.java | 48 + .../classpath/java/awt/peer/FileDialogPeer.java | 52 + libjava/classpath/java/awt/peer/FontPeer.java | 45 + libjava/classpath/java/awt/peer/FramePeer.java | 55 + libjava/classpath/java/awt/peer/LabelPeer.java | 46 + .../classpath/java/awt/peer/LightweightPeer.java | 45 + libjava/classpath/java/awt/peer/ListPeer.java | 61 + libjava/classpath/java/awt/peer/MenuBarPeer.java | 48 + .../classpath/java/awt/peer/MenuComponentPeer.java | 45 + libjava/classpath/java/awt/peer/MenuItemPeer.java | 48 + libjava/classpath/java/awt/peer/MenuPeer.java | 48 + libjava/classpath/java/awt/peer/PanelPeer.java | 45 + libjava/classpath/java/awt/peer/PopupMenuPeer.java | 53 + libjava/classpath/java/awt/peer/RobotPeer.java | 54 + .../classpath/java/awt/peer/ScrollPanePeer.java | 52 + libjava/classpath/java/awt/peer/ScrollbarPeer.java | 47 + libjava/classpath/java/awt/peer/TextAreaPeer.java | 53 + .../classpath/java/awt/peer/TextComponentPeer.java | 57 + libjava/classpath/java/awt/peer/TextFieldPeer.java | 52 + libjava/classpath/java/awt/peer/WindowPeer.java | 46 + libjava/classpath/java/awt/peer/package.html | 46 + libjava/classpath/java/awt/print/Book.java | 159 + libjava/classpath/java/awt/print/PageFormat.java | 292 + libjava/classpath/java/awt/print/Pageable.java | 113 + libjava/classpath/java/awt/print/Paper.java | 236 + libjava/classpath/java/awt/print/Printable.java | 80 + .../java/awt/print/PrinterAbortException.java | 71 + .../classpath/java/awt/print/PrinterException.java | 71 + .../classpath/java/awt/print/PrinterGraphics.java | 61 + .../java/awt/print/PrinterIOException.java | 98 + libjava/classpath/java/awt/print/PrinterJob.java | 299 + libjava/classpath/java/awt/print/package.html | 46 + .../classpath/java/beans/AppletInitializer.java | 61 + libjava/classpath/java/beans/BeanDescriptor.java | 89 + libjava/classpath/java/beans/BeanInfo.java | 181 + libjava/classpath/java/beans/Beans.java | 368 ++ libjava/classpath/java/beans/Customizer.java | 86 + libjava/classpath/java/beans/DesignMode.java | 93 + libjava/classpath/java/beans/EventHandler.java | 606 ++ .../classpath/java/beans/EventSetDescriptor.java | 442 ++ .../classpath/java/beans/ExceptionListener.java | 57 + libjava/classpath/java/beans/Expression.java | 133 + .../classpath/java/beans/FeatureDescriptor.java | 232 + .../java/beans/IndexedPropertyDescriptor.java | 307 + .../java/beans/IntrospectionException.java | 67 + libjava/classpath/java/beans/Introspector.java | 608 ++ libjava/classpath/java/beans/MethodDescriptor.java | 88 + .../classpath/java/beans/ParameterDescriptor.java | 52 + .../classpath/java/beans/PropertyChangeEvent.java | 189 + .../java/beans/PropertyChangeListener.java | 61 + .../java/beans/PropertyChangeListenerProxy.java | 102 + .../java/beans/PropertyChangeSupport.java | 488 ++ .../classpath/java/beans/PropertyDescriptor.java | 583 ++ libjava/classpath/java/beans/PropertyEditor.java | 209 + .../java/beans/PropertyEditorManager.java | 215 + .../java/beans/PropertyEditorSupport.java | 265 + .../java/beans/PropertyVetoException.java | 85 + libjava/classpath/java/beans/SimpleBeanInfo.java | 139 + libjava/classpath/java/beans/Statement.java | 326 ++ libjava/classpath/java/beans/TODO | 4 + .../java/beans/VetoableChangeListener.java | 73 + .../java/beans/VetoableChangeListenerProxy.java | 102 + .../java/beans/VetoableChangeSupport.java | 530 ++ libjava/classpath/java/beans/Visibility.java | 85 + libjava/classpath/java/beans/XMLDecoder.java | 307 + .../java/beans/beancontext/BeanContext.java | 272 + .../java/beans/beancontext/BeanContextChild.java | 174 + .../BeanContextChildComponentProxy.java | 60 + .../beans/beancontext/BeanContextChildSupport.java | 381 ++ .../beancontext/BeanContextContainerProxy.java | 63 + .../java/beans/beancontext/BeanContextEvent.java | 110 + .../beancontext/BeanContextMembershipEvent.java | 112 + .../beancontext/BeanContextMembershipListener.java | 70 + .../java/beans/beancontext/BeanContextProxy.java | 65 + .../BeanContextServiceAvailableEvent.java | 95 + .../beancontext/BeanContextServiceProvider.java | 138 + .../BeanContextServiceProviderBeanInfo.java | 60 + .../BeanContextServiceRevokedEvent.java | 110 + .../BeanContextServiceRevokedListener.java | 62 + .../beans/beancontext/BeanContextServices.java | 216 + .../beancontext/BeanContextServicesListener.java | 56 + .../beancontext/BeanContextServicesSupport.java | 300 + .../java/beans/beancontext/BeanContextSupport.java | 460 ++ .../classpath/java/beans/beancontext/package.html | 46 + libjava/classpath/java/beans/package.html | 46 + libjava/classpath/java/io/BufferedInputStream.java | 379 ++ .../classpath/java/io/BufferedOutputStream.java | 192 + libjava/classpath/java/io/BufferedReader.java | 581 ++ libjava/classpath/java/io/BufferedWriter.java | 262 + .../classpath/java/io/ByteArrayInputStream.java | 251 + .../classpath/java/io/ByteArrayOutputStream.java | 283 + libjava/classpath/java/io/CharArrayReader.java | 305 + libjava/classpath/java/io/CharArrayWriter.java | 274 + .../classpath/java/io/CharConversionException.java | 73 + libjava/classpath/java/io/Closeable.java | 63 + libjava/classpath/java/io/DataInput.java | 456 ++ libjava/classpath/java/io/DataInputStream.java | 739 +++ libjava/classpath/java/io/DataOutput.java | 326 ++ libjava/classpath/java/io/DataOutputStream.java | 455 ++ libjava/classpath/java/io/DeleteFileHelper.java | 109 + libjava/classpath/java/io/EOFException.java | 76 + libjava/classpath/java/io/Externalizable.java | 107 + libjava/classpath/java/io/File.java | 1357 +++++ libjava/classpath/java/io/FileDescriptor.java | 139 + libjava/classpath/java/io/FileFilter.java | 65 + libjava/classpath/java/io/FileInputStream.java | 309 + .../classpath/java/io/FileNotFoundException.java | 73 + libjava/classpath/java/io/FileOutputStream.java | 296 + libjava/classpath/java/io/FilePermission.java | 292 + libjava/classpath/java/io/FileReader.java | 92 + libjava/classpath/java/io/FileWriter.java | 137 + libjava/classpath/java/io/FilenameFilter.java | 76 + libjava/classpath/java/io/FilterInputStream.java | 203 + libjava/classpath/java/io/FilterOutputStream.java | 150 + libjava/classpath/java/io/FilterReader.java | 185 + libjava/classpath/java/io/FilterWriter.java | 147 + libjava/classpath/java/io/Flushable.java | 62 + libjava/classpath/java/io/IOException.java | 74 + libjava/classpath/java/io/InputStream.java | 272 + libjava/classpath/java/io/InputStreamReader.java | 438 ++ .../classpath/java/io/InterruptedIOException.java | 94 + .../classpath/java/io/InvalidClassException.java | 111 + .../classpath/java/io/InvalidObjectException.java | 66 + .../classpath/java/io/LineNumberInputStream.java | 315 + libjava/classpath/java/io/LineNumberReader.java | 417 ++ libjava/classpath/java/io/NotActiveException.java | 72 + .../java/io/NotSerializableException.java | 74 + libjava/classpath/java/io/ObjectInput.java | 140 + libjava/classpath/java/io/ObjectInputStream.java | 1956 +++++++ .../classpath/java/io/ObjectInputValidation.java | 67 + libjava/classpath/java/io/ObjectOutput.java | 111 + libjava/classpath/java/io/ObjectOutputStream.java | 1578 +++++ libjava/classpath/java/io/ObjectStreamClass.java | 976 ++++ .../classpath/java/io/ObjectStreamConstants.java | 89 + .../classpath/java/io/ObjectStreamException.java | 74 + libjava/classpath/java/io/ObjectStreamField.java | 412 ++ .../classpath/java/io/OptionalDataException.java | 91 + libjava/classpath/java/io/OutputStream.java | 140 + libjava/classpath/java/io/OutputStreamWriter.java | 356 ++ libjava/classpath/java/io/PipedInputStream.java | 374 ++ libjava/classpath/java/io/PipedOutputStream.java | 181 + libjava/classpath/java/io/PipedReader.java | 361 ++ libjava/classpath/java/io/PipedWriter.java | 182 + libjava/classpath/java/io/PrintStream.java | 553 ++ libjava/classpath/java/io/PrintWriter.java | 571 ++ libjava/classpath/java/io/PushbackInputStream.java | 328 ++ libjava/classpath/java/io/PushbackReader.java | 384 ++ libjava/classpath/java/io/RandomAccessFile.java | 991 ++++ libjava/classpath/java/io/Reader.java | 271 + libjava/classpath/java/io/SequenceInputStream.java | 221 + libjava/classpath/java/io/Serializable.java | 54 + .../classpath/java/io/SerializablePermission.java | 113 + .../java/io/StreamCorruptedException.java | 73 + libjava/classpath/java/io/StreamTokenizer.java | 708 +++ .../classpath/java/io/StringBufferInputStream.java | 187 + libjava/classpath/java/io/StringReader.java | 209 + libjava/classpath/java/io/StringWriter.java | 191 + libjava/classpath/java/io/SyncFailedException.java | 66 + .../classpath/java/io/UTFDataFormatException.java | 74 + .../java/io/UnsupportedEncodingException.java | 73 + .../classpath/java/io/WriteAbortedException.java | 109 + libjava/classpath/java/io/Writer.java | 192 + libjava/classpath/java/io/class-dependencies.conf | 100 + libjava/classpath/java/io/package.html | 46 + .../classpath/java/lang/AbstractMethodError.java | 75 + libjava/classpath/java/lang/Appendable.java | 122 + .../classpath/java/lang/ArithmeticException.java | 77 + .../java/lang/ArrayIndexOutOfBoundsException.java | 87 + .../classpath/java/lang/ArrayStoreException.java | 77 + libjava/classpath/java/lang/AssertionError.java | 148 + libjava/classpath/java/lang/Boolean.java | 224 + libjava/classpath/java/lang/Byte.java | 357 ++ libjava/classpath/java/lang/CharSequence.java | 99 + libjava/classpath/java/lang/Character.java | 2253 ++++++++ libjava/classpath/java/lang/Class.java | 1324 +++++ .../classpath/java/lang/ClassCastException.java | 76 + .../classpath/java/lang/ClassCircularityError.java | 73 + libjava/classpath/java/lang/ClassFormatError.java | 72 + libjava/classpath/java/lang/ClassLoader.java | 1116 ++++ .../java/lang/ClassNotFoundException.java | 125 + .../java/lang/CloneNotSupportedException.java | 92 + libjava/classpath/java/lang/Cloneable.java | 78 + libjava/classpath/java/lang/Comparable.java | 98 + libjava/classpath/java/lang/Compiler.java | 127 + libjava/classpath/java/lang/Double.java | 521 ++ libjava/classpath/java/lang/Error.java | 107 + libjava/classpath/java/lang/Exception.java | 104 + .../java/lang/ExceptionInInitializerError.java | 123 + libjava/classpath/java/lang/Float.java | 527 ++ .../classpath/java/lang/IllegalAccessError.java | 76 + .../java/lang/IllegalAccessException.java | 99 + .../java/lang/IllegalArgumentException.java | 75 + .../java/lang/IllegalMonitorStateException.java | 78 + .../classpath/java/lang/IllegalStateException.java | 80 + .../java/lang/IllegalThreadStateException.java | 75 + .../java/lang/IncompatibleClassChangeError.java | 73 + .../java/lang/IndexOutOfBoundsException.java | 75 + .../java/lang/InheritableThreadLocal.java | 116 + .../classpath/java/lang/InstantiationError.java | 75 + .../java/lang/InstantiationException.java | 74 + libjava/classpath/java/lang/Integer.java | 772 +++ libjava/classpath/java/lang/InternalError.java | 72 + .../classpath/java/lang/InterruptedException.java | 80 + libjava/classpath/java/lang/LinkageError.java | 74 + libjava/classpath/java/lang/Long.java | 614 ++ libjava/classpath/java/lang/Math.java | 650 +++ .../java/lang/NegativeArraySizeException.java | 77 + .../classpath/java/lang/NoClassDefFoundError.java | 76 + libjava/classpath/java/lang/NoSuchFieldError.java | 74 + .../classpath/java/lang/NoSuchFieldException.java | 73 + libjava/classpath/java/lang/NoSuchMethodError.java | 74 + .../classpath/java/lang/NoSuchMethodException.java | 72 + .../classpath/java/lang/NullPointerException.java | 82 + libjava/classpath/java/lang/Number.java | 131 + .../classpath/java/lang/NumberFormatException.java | 73 + libjava/classpath/java/lang/Object.java | 530 ++ libjava/classpath/java/lang/OutOfMemoryError.java | 73 + libjava/classpath/java/lang/Package.java | 318 ++ libjava/classpath/java/lang/Process.java | 129 + libjava/classpath/java/lang/Readable.java | 71 + libjava/classpath/java/lang/Runnable.java | 62 + libjava/classpath/java/lang/Runtime.java | 796 +++ libjava/classpath/java/lang/RuntimeException.java | 102 + libjava/classpath/java/lang/RuntimePermission.java | 208 + libjava/classpath/java/lang/SecurityException.java | 74 + libjava/classpath/java/lang/SecurityManager.java | 1062 ++++ libjava/classpath/java/lang/Short.java | 353 ++ .../classpath/java/lang/StackOverflowError.java | 72 + libjava/classpath/java/lang/StackTraceElement.java | 259 + libjava/classpath/java/lang/StrictMath.java | 1844 ++++++ libjava/classpath/java/lang/String.java | 1750 ++++++ libjava/classpath/java/lang/StringBuffer.java | 931 +++ libjava/classpath/java/lang/StringBuilder.java | 944 +++ .../java/lang/StringIndexOutOfBoundsException.java | 85 + libjava/classpath/java/lang/System.java | 528 ++ libjava/classpath/java/lang/Thread.java | 999 ++++ libjava/classpath/java/lang/ThreadDeath.java | 68 + libjava/classpath/java/lang/ThreadGroup.java | 749 +++ libjava/classpath/java/lang/ThreadLocal.java | 171 + libjava/classpath/java/lang/Throwable.java | 563 ++ .../java/lang/TypeNotPresentException.java | 97 + libjava/classpath/java/lang/UnknownError.java | 72 + .../classpath/java/lang/UnsatisfiedLinkError.java | 74 + .../java/lang/UnsupportedClassVersionError.java | 74 + .../java/lang/UnsupportedOperationException.java | 73 + libjava/classpath/java/lang/VerifyError.java | 72 + .../classpath/java/lang/VirtualMachineError.java | 73 + libjava/classpath/java/lang/Void.java | 68 + .../lang/annotation/AnnotationFormatError.java | 104 + .../AnnotationTypeMismatchException.java | 116 + .../classpath/java/lang/annotation/package.html | 46 + .../classpath/java/lang/class-dependencies.conf | 58 + libjava/classpath/java/lang/package.html | 48 + .../classpath/java/lang/ref/PhantomReference.java | 73 + libjava/classpath/java/lang/ref/Reference.java | 177 + .../classpath/java/lang/ref/ReferenceQueue.java | 145 + libjava/classpath/java/lang/ref/SoftReference.java | 84 + libjava/classpath/java/lang/ref/WeakReference.java | 79 + libjava/classpath/java/lang/ref/package.html | 46 + .../java/lang/reflect/AccessibleObject.java | 159 + libjava/classpath/java/lang/reflect/Array.java | 675 +++ .../java/lang/reflect/GenericArrayType.java | 61 + .../lang/reflect/GenericSignatureFormatError.java | 62 + .../java/lang/reflect/InvocationHandler.java | 137 + .../lang/reflect/InvocationTargetException.java | 123 + libjava/classpath/java/lang/reflect/Member.java | 100 + libjava/classpath/java/lang/reflect/Modifier.java | 332 ++ .../java/lang/reflect/ParameterizedType.java | 122 + libjava/classpath/java/lang/reflect/Proxy.java | 1615 ++++++ libjava/classpath/java/lang/reflect/README | 4 + .../java/lang/reflect/ReflectPermission.java | 102 + libjava/classpath/java/lang/reflect/TODO | 4 + libjava/classpath/java/lang/reflect/Type.java | 55 + .../lang/reflect/UndeclaredThrowableException.java | 128 + .../classpath/java/lang/reflect/WildcardType.java | 115 + libjava/classpath/java/lang/reflect/package.html | 47 + libjava/classpath/java/math/BigDecimal.java | 517 ++ libjava/classpath/java/math/BigInteger.java | 2230 ++++++++ .../classpath/java/math/class-dependencies.conf | 58 + libjava/classpath/java/math/package.html | 46 + libjava/classpath/java/net/Authenticator.java | 313 + libjava/classpath/java/net/BindException.java | 74 + libjava/classpath/java/net/ConnectException.java | 75 + libjava/classpath/java/net/ContentHandler.java | 126 + .../classpath/java/net/ContentHandlerFactory.java | 65 + libjava/classpath/java/net/DatagramPacket.java | 391 ++ libjava/classpath/java/net/DatagramSocket.java | 933 +++ libjava/classpath/java/net/DatagramSocketImpl.java | 296 + .../java/net/DatagramSocketImplFactory.java | 60 + libjava/classpath/java/net/FileNameMap.java | 65 + libjava/classpath/java/net/HttpURLConnection.java | 589 ++ libjava/classpath/java/net/Inet4Address.java | 233 + libjava/classpath/java/net/Inet6Address.java | 261 + libjava/classpath/java/net/InetAddress.java | 813 +++ libjava/classpath/java/net/InetSocketAddress.java | 221 + libjava/classpath/java/net/JarURLConnection.java | 228 + .../classpath/java/net/MalformedURLException.java | 74 + libjava/classpath/java/net/MimeTypeMapper.java | 213 + libjava/classpath/java/net/MulticastSocket.java | 486 ++ libjava/classpath/java/net/NetPermission.java | 90 + libjava/classpath/java/net/NetworkInterface.java | 259 + .../classpath/java/net/NoRouteToHostException.java | 74 + .../classpath/java/net/PasswordAuthentication.java | 92 + .../java/net/PortUnreachableException.java | 72 + libjava/classpath/java/net/ProtocolException.java | 75 + libjava/classpath/java/net/STATUS | 48 + libjava/classpath/java/net/ServerSocket.java | 599 ++ libjava/classpath/java/net/Socket.java | 1284 +++++ libjava/classpath/java/net/SocketAddress.java | 63 + libjava/classpath/java/net/SocketException.java | 75 + libjava/classpath/java/net/SocketImpl.java | 321 ++ libjava/classpath/java/net/SocketImplFactory.java | 59 + libjava/classpath/java/net/SocketOptions.java | 166 + libjava/classpath/java/net/SocketPermission.java | 408 ++ .../classpath/java/net/SocketTimeoutException.java | 73 + libjava/classpath/java/net/TODO | 24 + libjava/classpath/java/net/URI.java | 1438 +++++ libjava/classpath/java/net/URISyntaxException.java | 144 + libjava/classpath/java/net/URL.java | 956 ++++ libjava/classpath/java/net/URLClassLoader.java | 1171 ++++ libjava/classpath/java/net/URLConnection.java | 1021 ++++ libjava/classpath/java/net/URLDecoder.java | 180 + libjava/classpath/java/net/URLEncoder.java | 184 + libjava/classpath/java/net/URLStreamHandler.java | 532 ++ .../java/net/URLStreamHandlerFactory.java | 65 + .../classpath/java/net/UnknownHostException.java | 77 + .../java/net/UnknownServiceException.java | 76 + libjava/classpath/java/net/class-dependencies.conf | 122 + libjava/classpath/java/net/package.html | 46 + libjava/classpath/java/nio/Buffer.java | 361 ++ .../java/nio/BufferOverflowException.java | 51 + .../java/nio/BufferUnderflowException.java | 51 + libjava/classpath/java/nio/ByteBuffer.java | 651 +++ libjava/classpath/java/nio/ByteBufferHelper.java | 344 ++ libjava/classpath/java/nio/ByteBufferImpl.java | 379 ++ libjava/classpath/java/nio/ByteOrder.java | 82 + libjava/classpath/java/nio/CharBuffer.java | 508 ++ libjava/classpath/java/nio/CharBufferImpl.java | 219 + libjava/classpath/java/nio/CharViewBufferImpl.java | 187 + .../classpath/java/nio/DirectByteBufferImpl.java | 419 ++ libjava/classpath/java/nio/DoubleBuffer.java | 383 ++ libjava/classpath/java/nio/DoubleBufferImpl.java | 172 + .../classpath/java/nio/DoubleViewBufferImpl.java | 172 + libjava/classpath/java/nio/FloatBuffer.java | 383 ++ libjava/classpath/java/nio/FloatBufferImpl.java | 172 + .../classpath/java/nio/FloatViewBufferImpl.java | 173 + libjava/classpath/java/nio/IntBuffer.java | 383 ++ libjava/classpath/java/nio/IntBufferImpl.java | 172 + libjava/classpath/java/nio/IntViewBufferImpl.java | 173 + .../classpath/java/nio/InvalidMarkException.java | 52 + libjava/classpath/java/nio/LongBuffer.java | 383 ++ libjava/classpath/java/nio/LongBufferImpl.java | 172 + libjava/classpath/java/nio/LongViewBufferImpl.java | 173 + libjava/classpath/java/nio/MappedByteBuffer.java | 93 + .../classpath/java/nio/MappedByteBufferImpl.java | 360 ++ .../java/nio/ReadOnlyBufferException.java | 52 + libjava/classpath/java/nio/ShortBuffer.java | 383 ++ libjava/classpath/java/nio/ShortBufferImpl.java | 172 + .../classpath/java/nio/ShortViewBufferImpl.java | 173 + .../nio/channels/AlreadyConnectedException.java | 48 + .../nio/channels/AsynchronousCloseException.java | 53 + .../classpath/java/nio/channels/ByteChannel.java | 43 + .../java/nio/channels/CancelledKeyException.java | 53 + libjava/classpath/java/nio/channels/Channel.java | 59 + libjava/classpath/java/nio/channels/Channels.java | 143 + .../nio/channels/ClosedByInterruptException.java | 53 + .../java/nio/channels/ClosedChannelException.java | 55 + .../java/nio/channels/ClosedSelectorException.java | 53 + .../nio/channels/ConnectionPendingException.java | 53 + .../java/nio/channels/DatagramChannel.java | 210 + .../classpath/java/nio/channels/FileChannel.java | 367 ++ libjava/classpath/java/nio/channels/FileLock.java | 150 + .../channels/FileLockInterruptionException.java | 55 + .../java/nio/channels/GatheringByteChannel.java | 79 + .../nio/channels/IllegalBlockingModeException.java | 57 + .../nio/channels/IllegalSelectorException.java | 53 + .../java/nio/channels/InterruptibleChannel.java | 51 + .../nio/channels/NoConnectionPendingException.java | 53 + .../nio/channels/NonReadableChannelException.java | 53 + .../nio/channels/NonWritableChannelException.java | 53 + .../java/nio/channels/NotYetBoundException.java | 53 + .../nio/channels/NotYetConnectedException.java | 53 + .../nio/channels/OverlappingFileLockException.java | 53 + libjava/classpath/java/nio/channels/Pipe.java | 121 + .../java/nio/channels/ReadableByteChannel.java | 64 + .../java/nio/channels/ScatteringByteChannel.java | 79 + .../java/nio/channels/SelectableChannel.java | 140 + .../classpath/java/nio/channels/SelectionKey.java | 164 + libjava/classpath/java/nio/channels/Selector.java | 134 + .../java/nio/channels/ServerSocketChannel.java | 98 + .../classpath/java/nio/channels/SocketChannel.java | 248 + .../nio/channels/UnresolvedAddressException.java | 53 + .../channels/UnsupportedAddressTypeException.java | 53 + .../java/nio/channels/WritableByteChannel.java | 60 + libjava/classpath/java/nio/channels/package.html | 47 + .../channels/spi/AbstractInterruptibleChannel.java | 119 + .../channels/spi/AbstractSelectableChannel.java | 256 + .../nio/channels/spi/AbstractSelectionKey.java | 78 + .../java/nio/channels/spi/AbstractSelector.java | 167 + .../java/nio/channels/spi/SelectorProvider.java | 151 + .../classpath/java/nio/channels/spi/package.html | 46 + .../java/nio/charset/CharacterCodingException.java | 53 + libjava/classpath/java/nio/charset/Charset.java | 406 ++ .../classpath/java/nio/charset/CharsetDecoder.java | 317 ++ .../classpath/java/nio/charset/CharsetEncoder.java | 369 ++ .../java/nio/charset/CoderMalfunctionError.java | 52 + .../classpath/java/nio/charset/CoderResult.java | 189 + .../java/nio/charset/CodingErrorAction.java | 66 + .../nio/charset/IllegalCharsetNameException.java | 73 + .../java/nio/charset/MalformedInputException.java | 77 + .../nio/charset/UnmappableCharacterException.java | 71 + .../nio/charset/UnsupportedCharsetException.java | 69 + libjava/classpath/java/nio/charset/package.html | 47 + .../java/nio/charset/spi/CharsetProvider.java | 91 + .../classpath/java/nio/charset/spi/package.html | 46 + libjava/classpath/java/nio/class-dependencies.conf | 58 + libjava/classpath/java/nio/package.html | 46 + libjava/classpath/java/rmi/AccessException.java | 76 + .../classpath/java/rmi/AlreadyBoundException.java | 73 + libjava/classpath/java/rmi/ConnectException.java | 74 + libjava/classpath/java/rmi/ConnectIOException.java | 74 + libjava/classpath/java/rmi/MarshalException.java | 76 + libjava/classpath/java/rmi/MarshalledObject.java | 113 + libjava/classpath/java/rmi/Naming.java | 220 + .../classpath/java/rmi/NoSuchObjectException.java | 68 + libjava/classpath/java/rmi/NotBoundException.java | 75 + .../classpath/java/rmi/RMISecurityException.java | 77 + libjava/classpath/java/rmi/RMISecurityManager.java | 48 + libjava/classpath/java/rmi/Remote.java | 41 + libjava/classpath/java/rmi/RemoteException.java | 127 + libjava/classpath/java/rmi/ServerError.java | 64 + libjava/classpath/java/rmi/ServerException.java | 74 + .../classpath/java/rmi/ServerRuntimeException.java | 67 + .../classpath/java/rmi/StubNotFoundException.java | 77 + .../classpath/java/rmi/UnexpectedException.java | 75 + .../classpath/java/rmi/UnknownHostException.java | 75 + libjava/classpath/java/rmi/UnmarshalException.java | 88 + .../classpath/java/rmi/activation/Activatable.java | 105 + .../rmi/activation/ActivateFailedException.java | 76 + .../java/rmi/activation/ActivationDesc.java | 113 + .../java/rmi/activation/ActivationException.java | 122 + .../java/rmi/activation/ActivationGroup.java | 85 + .../java/rmi/activation/ActivationGroupDesc.java | 134 + .../java/rmi/activation/ActivationGroupID.java | 70 + .../java/rmi/activation/ActivationID.java | 72 + .../rmi/activation/ActivationInstantiator.java | 50 + .../java/rmi/activation/ActivationMonitor.java | 55 + .../java/rmi/activation/ActivationSystem.java | 78 + .../classpath/java/rmi/activation/Activator.java | 50 + .../java/rmi/activation/UnknownGroupException.java | 69 + .../rmi/activation/UnknownObjectException.java | 69 + libjava/classpath/java/rmi/activation/package.html | 46 + libjava/classpath/java/rmi/dgc/DGC.java | 51 + libjava/classpath/java/rmi/dgc/Lease.java | 67 + libjava/classpath/java/rmi/dgc/VMID.java | 138 + libjava/classpath/java/rmi/dgc/package.html | 46 + libjava/classpath/java/rmi/package.html | 46 + .../java/rmi/registry/LocateRegistry.java | 87 + libjava/classpath/java/rmi/registry/Registry.java | 65 + .../java/rmi/registry/RegistryHandler.java | 58 + libjava/classpath/java/rmi/registry/package.html | 46 + .../classpath/java/rmi/server/ExportException.java | 78 + .../classpath/java/rmi/server/LoaderHandler.java | 66 + libjava/classpath/java/rmi/server/LogStream.java | 146 + libjava/classpath/java/rmi/server/ObjID.java | 103 + libjava/classpath/java/rmi/server/Operation.java | 70 + .../classpath/java/rmi/server/RMIClassLoader.java | 339 ++ .../java/rmi/server/RMIClassLoaderSpi.java | 64 + .../java/rmi/server/RMIClientSocketFactory.java | 47 + .../java/rmi/server/RMIFailureHandler.java | 46 + .../java/rmi/server/RMIServerSocketFactory.java | 47 + .../java/rmi/server/RMISocketFactory.java | 108 + libjava/classpath/java/rmi/server/RemoteCall.java | 86 + .../classpath/java/rmi/server/RemoteObject.java | 160 + libjava/classpath/java/rmi/server/RemoteRef.java | 79 + .../classpath/java/rmi/server/RemoteServer.java | 76 + libjava/classpath/java/rmi/server/RemoteStub.java | 61 + .../java/rmi/server/ServerCloneException.java | 117 + .../java/rmi/server/ServerNotActiveException.java | 72 + libjava/classpath/java/rmi/server/ServerRef.java | 51 + libjava/classpath/java/rmi/server/Skeleton.java | 57 + .../java/rmi/server/SkeletonMismatchException.java | 68 + .../java/rmi/server/SkeletonNotFoundException.java | 79 + .../java/rmi/server/SocketSecurityException.java | 75 + libjava/classpath/java/rmi/server/UID.java | 127 + .../java/rmi/server/UnicastRemoteObject.java | 133 + .../classpath/java/rmi/server/Unreferenced.java | 43 + libjava/classpath/java/rmi/server/package.html | 46 + .../java/security/AccessControlContext.java | 176 + .../java/security/AccessControlException.java | 97 + .../classpath/java/security/AccessController.java | 221 + .../java/security/AlgorithmParameterGenerator.java | 302 + .../security/AlgorithmParameterGeneratorSpi.java | 94 + .../java/security/AlgorithmParameters.java | 340 ++ .../java/security/AlgorithmParametersSpi.java | 149 + libjava/classpath/java/security/AllPermission.java | 198 + .../classpath/java/security/BasicPermission.java | 308 + libjava/classpath/java/security/Certificate.java | 125 + libjava/classpath/java/security/CodeSource.java | 354 ++ .../classpath/java/security/DigestException.java | 70 + .../classpath/java/security/DigestInputStream.java | 167 + .../java/security/DigestOutputStream.java | 158 + .../classpath/java/security/DomainCombiner.java | 67 + .../java/security/DummyKeyPairGenerator.java | 75 + .../java/security/DummyMessageDigest.java | 90 + .../classpath/java/security/DummySignature.java | 102 + .../java/security/GeneralSecurityException.java | 75 + libjava/classpath/java/security/Guard.java | 60 + libjava/classpath/java/security/GuardedObject.java | 121 + libjava/classpath/java/security/Identity.java | 407 ++ libjava/classpath/java/security/IdentityScope.java | 226 + .../java/security/IntersectingDomainCombiner.java | 82 + .../InvalidAlgorithmParameterException.java | 73 + .../java/security/InvalidKeyException.java | 69 + .../java/security/InvalidParameterException.java | 70 + libjava/classpath/java/security/Key.java | 94 + libjava/classpath/java/security/KeyException.java | 72 + libjava/classpath/java/security/KeyFactory.java | 297 + libjava/classpath/java/security/KeyFactorySpi.java | 133 + .../java/security/KeyManagementException.java | 71 + libjava/classpath/java/security/KeyPair.java | 87 + .../classpath/java/security/KeyPairGenerator.java | 401 ++ .../java/security/KeyPairGeneratorSpi.java | 102 + libjava/classpath/java/security/KeyStore.java | 507 ++ .../classpath/java/security/KeyStoreException.java | 70 + libjava/classpath/java/security/KeyStoreSpi.java | 275 + libjava/classpath/java/security/MessageDigest.java | 413 ++ .../classpath/java/security/MessageDigestSpi.java | 155 + .../java/security/NoSuchAlgorithmException.java | 70 + .../java/security/NoSuchProviderException.java | 70 + libjava/classpath/java/security/Permission.java | 187 + .../java/security/PermissionCollection.java | 167 + libjava/classpath/java/security/Permissions.java | 254 + libjava/classpath/java/security/Policy.java | 310 + libjava/classpath/java/security/Principal.java | 85 + libjava/classpath/java/security/PrivateKey.java | 62 + .../classpath/java/security/PrivilegedAction.java | 64 + .../java/security/PrivilegedActionException.java | 109 + .../java/security/PrivilegedExceptionAction.java | 65 + .../classpath/java/security/ProtectionDomain.java | 269 + libjava/classpath/java/security/Provider.java | 202 + .../classpath/java/security/ProviderException.java | 70 + libjava/classpath/java/security/PublicKey.java | 60 + .../classpath/java/security/SecureClassLoader.java | 128 + libjava/classpath/java/security/SecureRandom.java | 380 ++ .../classpath/java/security/SecureRandomSpi.java | 85 + libjava/classpath/java/security/Security.java | 740 +++ .../java/security/SecurityPermission.java | 178 + libjava/classpath/java/security/Signature.java | 636 +++ .../java/security/SignatureException.java | 70 + libjava/classpath/java/security/SignatureSpi.java | 302 + libjava/classpath/java/security/SignedObject.java | 240 + libjava/classpath/java/security/Signer.java | 164 + .../java/security/UnrecoverableKeyException.java | 71 + .../java/security/UnresolvedPermission.java | 304 + libjava/classpath/java/security/acl/Acl.java | 153 + libjava/classpath/java/security/acl/AclEntry.java | 143 + .../java/security/acl/AclNotFoundException.java | 60 + libjava/classpath/java/security/acl/Group.java | 90 + .../java/security/acl/LastOwnerException.java | 62 + .../java/security/acl/NotOwnerException.java | 62 + libjava/classpath/java/security/acl/Owner.java | 95 + .../classpath/java/security/acl/Permission.java | 67 + libjava/classpath/java/security/acl/package.html | 46 + libjava/classpath/java/security/cert/CRL.java | 98 + .../classpath/java/security/cert/CRLException.java | 73 + .../classpath/java/security/cert/CRLSelector.java | 69 + libjava/classpath/java/security/cert/CertPath.java | 252 + .../java/security/cert/CertPathBuilder.java | 238 + .../security/cert/CertPathBuilderException.java | 159 + .../java/security/cert/CertPathBuilderResult.java | 63 + .../java/security/cert/CertPathBuilderSpi.java | 74 + .../java/security/cert/CertPathParameters.java | 58 + .../java/security/cert/CertPathValidator.java | 249 + .../security/cert/CertPathValidatorException.java | 226 + .../security/cert/CertPathValidatorResult.java | 63 + .../java/security/cert/CertPathValidatorSpi.java | 79 + .../classpath/java/security/cert/CertSelector.java | 58 + .../classpath/java/security/cert/CertStore.java | 294 + .../java/security/cert/CertStoreException.java | 159 + .../java/security/cert/CertStoreParameters.java | 60 + .../classpath/java/security/cert/CertStoreSpi.java | 102 + .../classpath/java/security/cert/Certificate.java | 306 + .../cert/CertificateEncodingException.java | 71 + .../java/security/cert/CertificateException.java | 74 + .../security/cert/CertificateExpiredException.java | 71 + .../java/security/cert/CertificateFactory.java | 358 ++ .../java/security/cert/CertificateFactorySpi.java | 225 + .../cert/CertificateNotYetValidException.java | 71 + .../security/cert/CertificateParsingException.java | 71 + .../cert/CollectionCertStoreParameters.java | 121 + .../security/cert/LDAPCertStoreParameters.java | 140 + .../java/security/cert/PKIXBuilderParameters.java | 145 + .../security/cert/PKIXCertPathBuilderResult.java | 102 + .../java/security/cert/PKIXCertPathChecker.java | 133 + .../security/cert/PKIXCertPathValidatorResult.java | 142 + .../java/security/cert/PKIXParameters.java | 546 ++ .../classpath/java/security/cert/PolicyNode.java | 102 + .../java/security/cert/PolicyQualifierInfo.java | 168 + .../classpath/java/security/cert/TrustAnchor.java | 185 + libjava/classpath/java/security/cert/X509CRL.java | 397 ++ .../classpath/java/security/cert/X509CRLEntry.java | 169 + .../java/security/cert/X509CRLSelector.java | 440 ++ .../java/security/cert/X509CertSelector.java | 1106 ++++ .../java/security/cert/X509Certificate.java | 588 ++ .../java/security/cert/X509Extension.java | 113 + libjava/classpath/java/security/cert/package.html | 46 + .../classpath/java/security/interfaces/DSAKey.java | 56 + .../security/interfaces/DSAKeyPairGenerator.java | 85 + .../java/security/interfaces/DSAParams.java | 72 + .../java/security/interfaces/DSAPrivateKey.java | 61 + .../java/security/interfaces/DSAPublicKey.java | 61 + .../classpath/java/security/interfaces/RSAKey.java | 57 + .../interfaces/RSAMultiPrimePrivateCrtKey.java | 111 + .../java/security/interfaces/RSAPrivateCrtKey.java | 95 + .../java/security/interfaces/RSAPrivateKey.java | 60 + .../java/security/interfaces/RSAPublicKey.java | 60 + .../java/security/interfaces/package.html | 46 + libjava/classpath/java/security/package.html | 46 + .../java/security/spec/AlgorithmParameterSpec.java | 52 + .../java/security/spec/DSAParameterSpec.java | 101 + .../java/security/spec/DSAPrivateKeySpec.java | 113 + .../java/security/spec/DSAPublicKeySpec.java | 113 + .../java/security/spec/EncodedKeySpec.java | 85 + .../security/spec/InvalidKeySpecException.java | 74 + .../spec/InvalidParameterSpecException.java | 76 + libjava/classpath/java/security/spec/KeySpec.java | 52 + .../java/security/spec/PKCS8EncodedKeySpec.java | 81 + .../java/security/spec/PSSParameterSpec.java | 90 + .../java/security/spec/RSAKeyGenParameterSpec.java | 97 + .../spec/RSAMultiPrimePrivateCrtKeySpec.java | 217 + .../java/security/spec/RSAOtherPrimeInfo.java | 133 + .../java/security/spec/RSAPrivateCrtKeySpec.java | 151 + .../java/security/spec/RSAPrivateKeySpec.java | 88 + .../java/security/spec/RSAPublicKeySpec.java | 88 + .../java/security/spec/X509EncodedKeySpec.java | 82 + libjava/classpath/java/security/spec/package.html | 46 + libjava/classpath/java/sql/Array.java | 185 + .../classpath/java/sql/BatchUpdateException.java | 141 + libjava/classpath/java/sql/Blob.java | 131 + libjava/classpath/java/sql/CallableStatement.java | 651 +++ libjava/classpath/java/sql/Clob.java | 152 + libjava/classpath/java/sql/Connection.java | 420 ++ libjava/classpath/java/sql/DataTruncation.java | 157 + libjava/classpath/java/sql/DatabaseMetaData.java | 2214 +++++++ libjava/classpath/java/sql/Date.java | 188 + libjava/classpath/java/sql/Driver.java | 123 + libjava/classpath/java/sql/DriverManager.java | 346 ++ libjava/classpath/java/sql/DriverPropertyInfo.java | 88 + libjava/classpath/java/sql/ParameterMetaData.java | 103 + libjava/classpath/java/sql/PreparedStatement.java | 438 ++ libjava/classpath/java/sql/Ref.java | 75 + libjava/classpath/java/sql/ResultSet.java | 1530 +++++ libjava/classpath/java/sql/ResultSetMetaData.java | 281 + libjava/classpath/java/sql/SQLData.java | 72 + libjava/classpath/java/sql/SQLException.java | 167 + libjava/classpath/java/sql/SQLInput.java | 259 + libjava/classpath/java/sql/SQLOutput.java | 257 + libjava/classpath/java/sql/SQLPermission.java | 57 + libjava/classpath/java/sql/SQLWarning.java | 120 + libjava/classpath/java/sql/Savepoint.java | 55 + libjava/classpath/java/sql/Statement.java | 366 ++ libjava/classpath/java/sql/Struct.java | 77 + libjava/classpath/java/sql/Time.java | 205 + libjava/classpath/java/sql/Timestamp.java | 315 + libjava/classpath/java/sql/Types.java | 85 + libjava/classpath/java/sql/package.html | 47 + libjava/classpath/java/text/Annotation.java | 113 + .../java/text/AttributedCharacterIterator.java | 268 + libjava/classpath/java/text/AttributedString.java | 425 ++ .../java/text/AttributedStringIterator.java | 348 ++ libjava/classpath/java/text/BreakIterator.java | 374 ++ libjava/classpath/java/text/CharacterIterator.java | 144 + libjava/classpath/java/text/ChoiceFormat.java | 503 ++ .../java/text/CollationElementIterator.java | 467 ++ libjava/classpath/java/text/CollationKey.java | 199 + libjava/classpath/java/text/Collator.java | 400 ++ libjava/classpath/java/text/DateFormat.java | 892 +++ libjava/classpath/java/text/DateFormatSymbols.java | 525 ++ libjava/classpath/java/text/DecimalFormat.java | 1435 +++++ .../classpath/java/text/DecimalFormatSymbols.java | 688 +++ libjava/classpath/java/text/FieldPosition.java | 232 + libjava/classpath/java/text/Format.java | 181 + libjava/classpath/java/text/MessageFormat.java | 832 +++ libjava/classpath/java/text/NumberFormat.java | 808 +++ libjava/classpath/java/text/ParseException.java | 86 + libjava/classpath/java/text/ParsePosition.java | 151 + libjava/classpath/java/text/RuleBasedCollator.java | 1017 ++++ libjava/classpath/java/text/SimpleDateFormat.java | 1257 ++++ .../java/text/StringCharacterIterator.java | 356 ++ .../classpath/java/text/class-dependencies.conf | 220 + libjava/classpath/java/text/package.html | 47 + libjava/classpath/java/util/.cvsignore | 1 + .../classpath/java/util/AbstractCollection.java | 470 ++ libjava/classpath/java/util/AbstractList.java | 1225 ++++ libjava/classpath/java/util/AbstractMap.java | 749 +++ .../java/util/AbstractSequentialList.java | 235 + libjava/classpath/java/util/AbstractSet.java | 139 + libjava/classpath/java/util/ArrayList.java | 591 ++ libjava/classpath/java/util/Arrays.java | 2510 ++++++++ libjava/classpath/java/util/BitSet.java | 744 +++ libjava/classpath/java/util/Calendar.java | 1277 +++++ libjava/classpath/java/util/Collection.java | 288 + libjava/classpath/java/util/Collections.java | 5493 ++++++++++++++++++ libjava/classpath/java/util/Comparator.java | 119 + .../java/util/ConcurrentModificationException.java | 92 + libjava/classpath/java/util/Currency.java | 437 ++ libjava/classpath/java/util/Date.java | 1263 ++++ libjava/classpath/java/util/Dictionary.java | 136 + .../classpath/java/util/EmptyStackException.java | 69 + libjava/classpath/java/util/Enumeration.java | 81 + libjava/classpath/java/util/EventListener.java | 54 + .../classpath/java/util/EventListenerProxy.java | 75 + libjava/classpath/java/util/EventObject.java | 101 + libjava/classpath/java/util/GregorianCalendar.java | 1343 +++++ libjava/classpath/java/util/HashMap.java | 906 +++ libjava/classpath/java/util/HashSet.java | 293 + libjava/classpath/java/util/Hashtable.java | 1151 ++++ libjava/classpath/java/util/IdentityHashMap.java | 935 +++ libjava/classpath/java/util/Iterator.java | 87 + libjava/classpath/java/util/LinkedHashMap.java | 501 ++ libjava/classpath/java/util/LinkedHashSet.java | 160 + libjava/classpath/java/util/LinkedList.java | 958 ++++ libjava/classpath/java/util/List.java | 451 ++ libjava/classpath/java/util/ListIterator.java | 170 + .../classpath/java/util/ListResourceBundle.java | 140 + libjava/classpath/java/util/Locale.java | 952 ++++ libjava/classpath/java/util/Map.java | 338 ++ .../java/util/MissingResourceException.java | 105 + .../java/util/NoSuchElementException.java | 88 + libjava/classpath/java/util/Observable.java | 180 + libjava/classpath/java/util/Observer.java | 60 + libjava/classpath/java/util/Properties.java | 574 ++ .../classpath/java/util/PropertyPermission.java | 271 + .../java/util/PropertyPermissionCollection.java | 166 + .../java/util/PropertyResourceBundle.java | 152 + libjava/classpath/java/util/Random.java | 429 ++ libjava/classpath/java/util/RandomAccess.java | 64 + libjava/classpath/java/util/ResourceBundle.java | 580 ++ libjava/classpath/java/util/Set.java | 264 + libjava/classpath/java/util/SimpleTimeZone.java | 1077 ++++ libjava/classpath/java/util/SortedMap.java | 173 + libjava/classpath/java/util/SortedSet.java | 176 + libjava/classpath/java/util/Stack.java | 158 + libjava/classpath/java/util/StringTokenizer.java | 268 + libjava/classpath/java/util/TimeZone.java | 1523 +++++ libjava/classpath/java/util/Timer.java | 615 ++ libjava/classpath/java/util/TimerTask.java | 145 + .../java/util/TooManyListenersException.java | 78 + libjava/classpath/java/util/TreeMap.java | 1781 ++++++ libjava/classpath/java/util/TreeSet.java | 416 ++ libjava/classpath/java/util/Vector.java | 931 +++ libjava/classpath/java/util/WeakHashMap.java | 881 +++ .../classpath/java/util/class-dependencies.conf | 78 + libjava/classpath/java/util/jar/Attributes.java | 630 ++ libjava/classpath/java/util/jar/JarEntry.java | 165 + libjava/classpath/java/util/jar/JarException.java | 77 + libjava/classpath/java/util/jar/JarFile.java | 1059 ++++ .../classpath/java/util/jar/JarInputStream.java | 200 + .../classpath/java/util/jar/JarOutputStream.java | 113 + libjava/classpath/java/util/jar/Manifest.java | 472 ++ libjava/classpath/java/util/jar/package.html | 47 + .../java/util/logging/ConsoleHandler.java | 125 + .../classpath/java/util/logging/ErrorManager.java | 194 + .../classpath/java/util/logging/FileHandler.java | 646 +++ libjava/classpath/java/util/logging/Filter.java | 64 + libjava/classpath/java/util/logging/Formatter.java | 171 + libjava/classpath/java/util/logging/Handler.java | 386 ++ libjava/classpath/java/util/logging/Level.java | 414 ++ .../classpath/java/util/logging/LogManager.java | 829 +++ libjava/classpath/java/util/logging/LogRecord.java | 672 +++ libjava/classpath/java/util/logging/Logger.java | 1199 ++++ .../java/util/logging/LoggingPermission.java | 73 + .../classpath/java/util/logging/MemoryHandler.java | 345 ++ .../java/util/logging/SimpleFormatter.java | 119 + .../classpath/java/util/logging/SocketHandler.java | 221 + .../classpath/java/util/logging/StreamHandler.java | 521 ++ .../classpath/java/util/logging/XMLFormatter.java | 387 ++ libjava/classpath/java/util/logging/package.html | 46 + libjava/classpath/java/util/package.html | 48 + .../java/util/prefs/AbstractPreferences.java | 1272 +++++ .../java/util/prefs/BackingStoreException.java | 104 + .../prefs/InvalidPreferencesFormatException.java | 116 + .../classpath/java/util/prefs/NodeChangeEvent.java | 91 + .../java/util/prefs/NodeChangeListener.java | 64 + .../java/util/prefs/PreferenceChangeEvent.java | 105 + .../java/util/prefs/PreferenceChangeListener.java | 60 + libjava/classpath/java/util/prefs/Preferences.java | 668 +++ .../java/util/prefs/PreferencesFactory.java | 65 + libjava/classpath/java/util/prefs/package.html | 46 + libjava/classpath/java/util/regex/Matcher.java | 301 + libjava/classpath/java/util/regex/Pattern.java | 254 + .../java/util/regex/PatternSyntaxException.java | 132 + libjava/classpath/java/util/regex/package.html | 46 + libjava/classpath/java/util/zip/Adler32.java | 205 + libjava/classpath/java/util/zip/CRC32.java | 132 + .../java/util/zip/CheckedInputStream.java | 135 + .../java/util/zip/CheckedOutputStream.java | 100 + libjava/classpath/java/util/zip/Checksum.java | 86 + .../java/util/zip/DataFormatException.java | 71 + libjava/classpath/java/util/zip/Deflater.java | 520 ++ .../classpath/java/util/zip/DeflaterConstants.java | 78 + .../classpath/java/util/zip/DeflaterEngine.java | 696 +++ .../classpath/java/util/zip/DeflaterHuffman.java | 776 +++ .../java/util/zip/DeflaterOutputStream.java | 198 + .../classpath/java/util/zip/DeflaterPending.java | 54 + .../classpath/java/util/zip/GZIPInputStream.java | 355 ++ .../classpath/java/util/zip/GZIPOutputStream.java | 151 + libjava/classpath/java/util/zip/Inflater.java | 715 +++ .../classpath/java/util/zip/InflaterDynHeader.java | 203 + .../java/util/zip/InflaterHuffmanTree.java | 217 + .../java/util/zip/InflaterInputStream.java | 261 + libjava/classpath/java/util/zip/OutputWindow.java | 178 + libjava/classpath/java/util/zip/PendingBuffer.java | 200 + .../classpath/java/util/zip/StreamManipulator.java | 216 + libjava/classpath/java/util/zip/ZipConstants.java | 97 + libjava/classpath/java/util/zip/ZipEntry.java | 432 ++ libjava/classpath/java/util/zip/ZipException.java | 72 + libjava/classpath/java/util/zip/ZipFile.java | 595 ++ .../classpath/java/util/zip/ZipInputStream.java | 371 ++ .../classpath/java/util/zip/ZipOutputStream.java | 399 ++ libjava/classpath/java/util/zip/package.html | 47 + 1147 files changed, 301154 insertions(+) create mode 100644 libjava/classpath/java/applet/Applet.java create mode 100644 libjava/classpath/java/applet/AppletContext.java create mode 100644 libjava/classpath/java/applet/AppletStub.java create mode 100644 libjava/classpath/java/applet/AudioClip.java create mode 100644 libjava/classpath/java/applet/package.html create mode 100644 libjava/classpath/java/awt/AWTError.java create mode 100644 libjava/classpath/java/awt/AWTEvent.java create mode 100644 libjava/classpath/java/awt/AWTEventMulticaster.java create mode 100644 libjava/classpath/java/awt/AWTException.java create mode 100644 libjava/classpath/java/awt/AWTKeyStroke.java create mode 100644 libjava/classpath/java/awt/AWTPermission.java create mode 100644 libjava/classpath/java/awt/ActiveEvent.java create mode 100644 libjava/classpath/java/awt/Adjustable.java create mode 100644 libjava/classpath/java/awt/AlphaComposite.java create mode 100644 libjava/classpath/java/awt/AttributeValue.java create mode 100644 libjava/classpath/java/awt/BasicStroke.java create mode 100644 libjava/classpath/java/awt/BorderLayout.java create mode 100644 libjava/classpath/java/awt/BufferCapabilities.java create mode 100644 libjava/classpath/java/awt/Button.java create mode 100644 libjava/classpath/java/awt/Canvas.java create mode 100644 libjava/classpath/java/awt/CardLayout.java create mode 100644 libjava/classpath/java/awt/Checkbox.java create mode 100644 libjava/classpath/java/awt/CheckboxGroup.java create mode 100644 libjava/classpath/java/awt/CheckboxMenuItem.java create mode 100644 libjava/classpath/java/awt/Choice.java create mode 100644 libjava/classpath/java/awt/Color.java create mode 100644 libjava/classpath/java/awt/ColorPaintContext.java create mode 100644 libjava/classpath/java/awt/Component.java create mode 100644 libjava/classpath/java/awt/ComponentOrientation.java create mode 100644 libjava/classpath/java/awt/Composite.java create mode 100644 libjava/classpath/java/awt/CompositeContext.java create mode 100644 libjava/classpath/java/awt/Container.java create mode 100644 libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java create mode 100644 libjava/classpath/java/awt/Cursor.java create mode 100644 libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java create mode 100644 libjava/classpath/java/awt/DefaultKeyboardFocusManager.java create mode 100644 libjava/classpath/java/awt/Dialog.java create mode 100644 libjava/classpath/java/awt/Dimension.java create mode 100644 libjava/classpath/java/awt/DisplayMode.java create mode 100644 libjava/classpath/java/awt/Event.java create mode 100644 libjava/classpath/java/awt/EventDispatchThread.java create mode 100644 libjava/classpath/java/awt/EventQueue.java create mode 100644 libjava/classpath/java/awt/FileDialog.java create mode 100644 libjava/classpath/java/awt/FlowLayout.java create mode 100644 libjava/classpath/java/awt/FocusTraversalPolicy.java create mode 100644 libjava/classpath/java/awt/Font.java create mode 100644 libjava/classpath/java/awt/FontFormatException.java create mode 100644 libjava/classpath/java/awt/FontMetrics.java create mode 100644 libjava/classpath/java/awt/Frame.java create mode 100644 libjava/classpath/java/awt/GradientPaint.java create mode 100644 libjava/classpath/java/awt/Graphics.java create mode 100644 libjava/classpath/java/awt/Graphics2D.java create mode 100644 libjava/classpath/java/awt/GraphicsConfigTemplate.java create mode 100644 libjava/classpath/java/awt/GraphicsConfiguration.java create mode 100644 libjava/classpath/java/awt/GraphicsDevice.java create mode 100644 libjava/classpath/java/awt/GraphicsEnvironment.java create mode 100644 libjava/classpath/java/awt/GridBagConstraints.java create mode 100644 libjava/classpath/java/awt/GridBagLayout.java create mode 100644 libjava/classpath/java/awt/GridBagLayoutInfo.java create mode 100644 libjava/classpath/java/awt/GridLayout.java create mode 100644 libjava/classpath/java/awt/HeadlessException.java create mode 100644 libjava/classpath/java/awt/IllegalComponentStateException.java create mode 100644 libjava/classpath/java/awt/Image.java create mode 100644 libjava/classpath/java/awt/ImageCapabilities.java create mode 100644 libjava/classpath/java/awt/Insets.java create mode 100644 libjava/classpath/java/awt/ItemSelectable.java create mode 100644 libjava/classpath/java/awt/JobAttributes.java create mode 100644 libjava/classpath/java/awt/KeyEventDispatcher.java create mode 100644 libjava/classpath/java/awt/KeyEventPostProcessor.java create mode 100644 libjava/classpath/java/awt/KeyboardFocusManager.java create mode 100644 libjava/classpath/java/awt/Label.java create mode 100644 libjava/classpath/java/awt/LayoutManager.java create mode 100644 libjava/classpath/java/awt/LayoutManager2.java create mode 100644 libjava/classpath/java/awt/List.java create mode 100644 libjava/classpath/java/awt/MediaTracker.java create mode 100644 libjava/classpath/java/awt/Menu.java create mode 100644 libjava/classpath/java/awt/MenuBar.java create mode 100644 libjava/classpath/java/awt/MenuComponent.java create mode 100644 libjava/classpath/java/awt/MenuContainer.java create mode 100644 libjava/classpath/java/awt/MenuItem.java create mode 100644 libjava/classpath/java/awt/MenuShortcut.java create mode 100644 libjava/classpath/java/awt/PageAttributes.java create mode 100644 libjava/classpath/java/awt/Paint.java create mode 100644 libjava/classpath/java/awt/PaintContext.java create mode 100644 libjava/classpath/java/awt/Panel.java create mode 100644 libjava/classpath/java/awt/Point.java create mode 100644 libjava/classpath/java/awt/Polygon.java create mode 100644 libjava/classpath/java/awt/PopupMenu.java create mode 100644 libjava/classpath/java/awt/PrintGraphics.java create mode 100644 libjava/classpath/java/awt/PrintJob.java create mode 100644 libjava/classpath/java/awt/Rectangle.java create mode 100644 libjava/classpath/java/awt/RenderingHints.java create mode 100644 libjava/classpath/java/awt/Robot.java create mode 100644 libjava/classpath/java/awt/ScrollPane.java create mode 100644 libjava/classpath/java/awt/ScrollPaneAdjustable.java create mode 100644 libjava/classpath/java/awt/Scrollbar.java create mode 100644 libjava/classpath/java/awt/Shape.java create mode 100644 libjava/classpath/java/awt/Stroke.java create mode 100644 libjava/classpath/java/awt/SystemColor.java create mode 100644 libjava/classpath/java/awt/TextArea.java create mode 100644 libjava/classpath/java/awt/TextComponent.java create mode 100644 libjava/classpath/java/awt/TextField.java create mode 100644 libjava/classpath/java/awt/TexturePaint.java create mode 100644 libjava/classpath/java/awt/Toolkit.java create mode 100644 libjava/classpath/java/awt/Transparency.java create mode 100644 libjava/classpath/java/awt/Window.java create mode 100644 libjava/classpath/java/awt/color/CMMException.java create mode 100644 libjava/classpath/java/awt/color/ColorSpace.java create mode 100644 libjava/classpath/java/awt/color/ICC_ColorSpace.java create mode 100644 libjava/classpath/java/awt/color/ICC_Profile.java create mode 100644 libjava/classpath/java/awt/color/ICC_ProfileGray.java create mode 100644 libjava/classpath/java/awt/color/ICC_ProfileRGB.java create mode 100644 libjava/classpath/java/awt/color/ProfileDataException.java create mode 100644 libjava/classpath/java/awt/color/package.html create mode 100644 libjava/classpath/java/awt/datatransfer/Clipboard.java create mode 100644 libjava/classpath/java/awt/datatransfer/ClipboardOwner.java create mode 100644 libjava/classpath/java/awt/datatransfer/DataFlavor.java create mode 100644 libjava/classpath/java/awt/datatransfer/FlavorMap.java create mode 100644 libjava/classpath/java/awt/datatransfer/FlavorTable.java create mode 100644 libjava/classpath/java/awt/datatransfer/MimeTypeParseException.java create mode 100644 libjava/classpath/java/awt/datatransfer/StringSelection.java create mode 100644 libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java create mode 100644 libjava/classpath/java/awt/datatransfer/Transferable.java create mode 100644 libjava/classpath/java/awt/datatransfer/UnsupportedFlavorException.java create mode 100644 libjava/classpath/java/awt/datatransfer/package.html create mode 100644 libjava/classpath/java/awt/dnd/Autoscroll.java create mode 100644 libjava/classpath/java/awt/dnd/DnDConstants.java create mode 100644 libjava/classpath/java/awt/dnd/DnDEventMulticaster.java create mode 100644 libjava/classpath/java/awt/dnd/DragGestureEvent.java create mode 100644 libjava/classpath/java/awt/dnd/DragGestureListener.java create mode 100644 libjava/classpath/java/awt/dnd/DragGestureRecognizer.java create mode 100644 libjava/classpath/java/awt/dnd/DragSource.java create mode 100644 libjava/classpath/java/awt/dnd/DragSourceAdapter.java create mode 100644 libjava/classpath/java/awt/dnd/DragSourceContext.java create mode 100644 libjava/classpath/java/awt/dnd/DragSourceDragEvent.java create mode 100644 libjava/classpath/java/awt/dnd/DragSourceDropEvent.java create mode 100644 libjava/classpath/java/awt/dnd/DragSourceEvent.java create mode 100644 libjava/classpath/java/awt/dnd/DragSourceListener.java create mode 100644 libjava/classpath/java/awt/dnd/DragSourceMotionListener.java create mode 100644 libjava/classpath/java/awt/dnd/DropTarget.java create mode 100644 libjava/classpath/java/awt/dnd/DropTargetAdapter.java create mode 100644 libjava/classpath/java/awt/dnd/DropTargetContext.java create mode 100644 libjava/classpath/java/awt/dnd/DropTargetDragEvent.java create mode 100644 libjava/classpath/java/awt/dnd/DropTargetDropEvent.java create mode 100644 libjava/classpath/java/awt/dnd/DropTargetEvent.java create mode 100644 libjava/classpath/java/awt/dnd/DropTargetListener.java create mode 100644 libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java create mode 100644 libjava/classpath/java/awt/dnd/MouseDragGestureRecognizer.java create mode 100644 libjava/classpath/java/awt/dnd/package.html create mode 100644 libjava/classpath/java/awt/dnd/peer/DragSourceContextPeer.java create mode 100644 libjava/classpath/java/awt/dnd/peer/DropTargetContextPeer.java create mode 100644 libjava/classpath/java/awt/dnd/peer/DropTargetPeer.java create mode 100644 libjava/classpath/java/awt/dnd/peer/package.html create mode 100644 libjava/classpath/java/awt/event/AWTEventListener.java create mode 100644 libjava/classpath/java/awt/event/AWTEventListenerProxy.java create mode 100644 libjava/classpath/java/awt/event/ActionEvent.java create mode 100644 libjava/classpath/java/awt/event/ActionListener.java create mode 100644 libjava/classpath/java/awt/event/AdjustmentEvent.java create mode 100644 libjava/classpath/java/awt/event/AdjustmentListener.java create mode 100644 libjava/classpath/java/awt/event/ComponentAdapter.java create mode 100644 libjava/classpath/java/awt/event/ComponentEvent.java create mode 100644 libjava/classpath/java/awt/event/ComponentListener.java create mode 100644 libjava/classpath/java/awt/event/ContainerAdapter.java create mode 100644 libjava/classpath/java/awt/event/ContainerEvent.java create mode 100644 libjava/classpath/java/awt/event/ContainerListener.java create mode 100644 libjava/classpath/java/awt/event/FocusAdapter.java create mode 100644 libjava/classpath/java/awt/event/FocusEvent.java create mode 100644 libjava/classpath/java/awt/event/FocusListener.java create mode 100644 libjava/classpath/java/awt/event/HierarchyBoundsAdapter.java create mode 100644 libjava/classpath/java/awt/event/HierarchyBoundsListener.java create mode 100644 libjava/classpath/java/awt/event/HierarchyEvent.java create mode 100644 libjava/classpath/java/awt/event/HierarchyListener.java create mode 100644 libjava/classpath/java/awt/event/InputEvent.java create mode 100644 libjava/classpath/java/awt/event/InputMethodEvent.java create mode 100644 libjava/classpath/java/awt/event/InputMethodListener.java create mode 100644 libjava/classpath/java/awt/event/InvocationEvent.java create mode 100644 libjava/classpath/java/awt/event/ItemEvent.java create mode 100644 libjava/classpath/java/awt/event/ItemListener.java create mode 100644 libjava/classpath/java/awt/event/KeyAdapter.java create mode 100644 libjava/classpath/java/awt/event/KeyEvent.java create mode 100644 libjava/classpath/java/awt/event/KeyListener.java create mode 100644 libjava/classpath/java/awt/event/MouseAdapter.java create mode 100644 libjava/classpath/java/awt/event/MouseEvent.java create mode 100644 libjava/classpath/java/awt/event/MouseListener.java create mode 100644 libjava/classpath/java/awt/event/MouseMotionAdapter.java create mode 100644 libjava/classpath/java/awt/event/MouseMotionListener.java create mode 100644 libjava/classpath/java/awt/event/MouseWheelEvent.java create mode 100644 libjava/classpath/java/awt/event/MouseWheelListener.java create mode 100644 libjava/classpath/java/awt/event/PaintEvent.java create mode 100644 libjava/classpath/java/awt/event/TextEvent.java create mode 100644 libjava/classpath/java/awt/event/TextListener.java create mode 100644 libjava/classpath/java/awt/event/WindowAdapter.java create mode 100644 libjava/classpath/java/awt/event/WindowEvent.java create mode 100644 libjava/classpath/java/awt/event/WindowFocusListener.java create mode 100644 libjava/classpath/java/awt/event/WindowListener.java create mode 100644 libjava/classpath/java/awt/event/WindowStateListener.java create mode 100644 libjava/classpath/java/awt/event/package.html create mode 100644 libjava/classpath/java/awt/font/FontRenderContext.java create mode 100644 libjava/classpath/java/awt/font/GlyphJustificationInfo.java create mode 100644 libjava/classpath/java/awt/font/GlyphMetrics.java create mode 100644 libjava/classpath/java/awt/font/GlyphVector.java create mode 100644 libjava/classpath/java/awt/font/GraphicAttribute.java create mode 100644 libjava/classpath/java/awt/font/ImageGraphicAttribute.java create mode 100644 libjava/classpath/java/awt/font/LineBreakMeasurer.java create mode 100644 libjava/classpath/java/awt/font/LineMetrics.java create mode 100644 libjava/classpath/java/awt/font/MultipleMaster.java create mode 100644 libjava/classpath/java/awt/font/NumericShaper.java create mode 100644 libjava/classpath/java/awt/font/OpenType.java create mode 100644 libjava/classpath/java/awt/font/ShapeGraphicAttribute.java create mode 100644 libjava/classpath/java/awt/font/TextAttribute.java create mode 100644 libjava/classpath/java/awt/font/TextHitInfo.java create mode 100644 libjava/classpath/java/awt/font/TextLayout.java create mode 100644 libjava/classpath/java/awt/font/TextMeasurer.java create mode 100644 libjava/classpath/java/awt/font/TransformAttribute.java create mode 100644 libjava/classpath/java/awt/font/package.html create mode 100644 libjava/classpath/java/awt/geom/AffineTransform.java create mode 100644 libjava/classpath/java/awt/geom/Arc2D.java create mode 100644 libjava/classpath/java/awt/geom/Area.java create mode 100644 libjava/classpath/java/awt/geom/CubicCurve2D.java create mode 100644 libjava/classpath/java/awt/geom/Dimension2D.java create mode 100644 libjava/classpath/java/awt/geom/Ellipse2D.java create mode 100644 libjava/classpath/java/awt/geom/FlatteningPathIterator.java create mode 100644 libjava/classpath/java/awt/geom/GeneralPath.java create mode 100644 libjava/classpath/java/awt/geom/IllegalPathStateException.java create mode 100644 libjava/classpath/java/awt/geom/Line2D.java create mode 100644 libjava/classpath/java/awt/geom/NoninvertibleTransformException.java create mode 100644 libjava/classpath/java/awt/geom/PathIterator.java create mode 100644 libjava/classpath/java/awt/geom/Point2D.java create mode 100644 libjava/classpath/java/awt/geom/QuadCurve2D.java create mode 100644 libjava/classpath/java/awt/geom/Rectangle2D.java create mode 100644 libjava/classpath/java/awt/geom/RectangularShape.java create mode 100644 libjava/classpath/java/awt/geom/RoundRectangle2D.java create mode 100644 libjava/classpath/java/awt/geom/doc-files/Area-1.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-1.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-2.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-3.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-4.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-5.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/Ellipse-1.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/FlatteningPathIterator-1.html create mode 100644 libjava/classpath/java/awt/geom/doc-files/GeneralPath-1.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-1.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-2.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-3.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-4.png create mode 100644 libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-5.png create mode 100644 libjava/classpath/java/awt/geom/package.html create mode 100644 libjava/classpath/java/awt/im/InputContext.java create mode 100644 libjava/classpath/java/awt/im/InputMethodHighlight.java create mode 100644 libjava/classpath/java/awt/im/InputMethodRequests.java create mode 100644 libjava/classpath/java/awt/im/InputSubset.java create mode 100644 libjava/classpath/java/awt/im/package.html create mode 100644 libjava/classpath/java/awt/im/spi/InputMethod.java create mode 100644 libjava/classpath/java/awt/im/spi/InputMethodContext.java create mode 100644 libjava/classpath/java/awt/im/spi/InputMethodDescriptor.java create mode 100644 libjava/classpath/java/awt/im/spi/package.html create mode 100644 libjava/classpath/java/awt/image/AffineTransformOp.java create mode 100644 libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java create mode 100644 libjava/classpath/java/awt/image/BandCombineOp.java create mode 100644 libjava/classpath/java/awt/image/BandedSampleModel.java create mode 100644 libjava/classpath/java/awt/image/BufferStrategy.java create mode 100644 libjava/classpath/java/awt/image/BufferedImage.java create mode 100644 libjava/classpath/java/awt/image/BufferedImageFilter.java create mode 100644 libjava/classpath/java/awt/image/BufferedImageOp.java create mode 100644 libjava/classpath/java/awt/image/ByteLookupTable.java create mode 100644 libjava/classpath/java/awt/image/ColorConvertOp.java create mode 100644 libjava/classpath/java/awt/image/ColorModel.java create mode 100644 libjava/classpath/java/awt/image/ComponentColorModel.java create mode 100644 libjava/classpath/java/awt/image/ComponentSampleModel.java create mode 100644 libjava/classpath/java/awt/image/ConvolveOp.java create mode 100644 libjava/classpath/java/awt/image/CropImageFilter.java create mode 100644 libjava/classpath/java/awt/image/DataBuffer.java create mode 100644 libjava/classpath/java/awt/image/DataBufferByte.java create mode 100644 libjava/classpath/java/awt/image/DataBufferDouble.java create mode 100644 libjava/classpath/java/awt/image/DataBufferFloat.java create mode 100644 libjava/classpath/java/awt/image/DataBufferInt.java create mode 100644 libjava/classpath/java/awt/image/DataBufferShort.java create mode 100644 libjava/classpath/java/awt/image/DataBufferUShort.java create mode 100644 libjava/classpath/java/awt/image/DirectColorModel.java create mode 100644 libjava/classpath/java/awt/image/FilteredImageSource.java create mode 100644 libjava/classpath/java/awt/image/ImageConsumer.java create mode 100644 libjava/classpath/java/awt/image/ImageFilter.java create mode 100644 libjava/classpath/java/awt/image/ImageObserver.java create mode 100644 libjava/classpath/java/awt/image/ImageProducer.java create mode 100644 libjava/classpath/java/awt/image/ImagingOpException.java create mode 100644 libjava/classpath/java/awt/image/IndexColorModel.java create mode 100644 libjava/classpath/java/awt/image/Kernel.java create mode 100644 libjava/classpath/java/awt/image/LookupOp.java create mode 100644 libjava/classpath/java/awt/image/LookupTable.java create mode 100644 libjava/classpath/java/awt/image/MemoryImageSource.java create mode 100644 libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java create mode 100644 libjava/classpath/java/awt/image/PackedColorModel.java create mode 100644 libjava/classpath/java/awt/image/PixelGrabber.java create mode 100644 libjava/classpath/java/awt/image/PixelInterleavedSampleModel.java create mode 100644 libjava/classpath/java/awt/image/RGBImageFilter.java create mode 100644 libjava/classpath/java/awt/image/Raster.java create mode 100644 libjava/classpath/java/awt/image/RasterFormatException.java create mode 100644 libjava/classpath/java/awt/image/RasterOp.java create mode 100644 libjava/classpath/java/awt/image/RenderedImage.java create mode 100644 libjava/classpath/java/awt/image/ReplicateScaleFilter.java create mode 100644 libjava/classpath/java/awt/image/RescaleOp.java create mode 100644 libjava/classpath/java/awt/image/SampleModel.java create mode 100644 libjava/classpath/java/awt/image/ShortLookupTable.java create mode 100644 libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java create mode 100644 libjava/classpath/java/awt/image/TileObserver.java create mode 100644 libjava/classpath/java/awt/image/VolatileImage.java create mode 100644 libjava/classpath/java/awt/image/WritableRaster.java create mode 100644 libjava/classpath/java/awt/image/WritableRenderedImage.java create mode 100644 libjava/classpath/java/awt/image/package.html create mode 100644 libjava/classpath/java/awt/image/renderable/ContextualRenderedImageFactory.java create mode 100644 libjava/classpath/java/awt/image/renderable/ParameterBlock.java create mode 100644 libjava/classpath/java/awt/image/renderable/RenderContext.java create mode 100644 libjava/classpath/java/awt/image/renderable/RenderableImage.java create mode 100644 libjava/classpath/java/awt/image/renderable/RenderableImageOp.java create mode 100644 libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java create mode 100644 libjava/classpath/java/awt/image/renderable/RenderedImageFactory.java create mode 100644 libjava/classpath/java/awt/image/renderable/package.html create mode 100644 libjava/classpath/java/awt/package.html create mode 100644 libjava/classpath/java/awt/peer/ButtonPeer.java create mode 100644 libjava/classpath/java/awt/peer/CanvasPeer.java create mode 100644 libjava/classpath/java/awt/peer/CheckboxMenuItemPeer.java create mode 100644 libjava/classpath/java/awt/peer/CheckboxPeer.java create mode 100644 libjava/classpath/java/awt/peer/ChoicePeer.java create mode 100644 libjava/classpath/java/awt/peer/ComponentPeer.java create mode 100644 libjava/classpath/java/awt/peer/ContainerPeer.java create mode 100644 libjava/classpath/java/awt/peer/DialogPeer.java create mode 100644 libjava/classpath/java/awt/peer/FileDialogPeer.java create mode 100644 libjava/classpath/java/awt/peer/FontPeer.java create mode 100644 libjava/classpath/java/awt/peer/FramePeer.java create mode 100644 libjava/classpath/java/awt/peer/LabelPeer.java create mode 100644 libjava/classpath/java/awt/peer/LightweightPeer.java create mode 100644 libjava/classpath/java/awt/peer/ListPeer.java create mode 100644 libjava/classpath/java/awt/peer/MenuBarPeer.java create mode 100644 libjava/classpath/java/awt/peer/MenuComponentPeer.java create mode 100644 libjava/classpath/java/awt/peer/MenuItemPeer.java create mode 100644 libjava/classpath/java/awt/peer/MenuPeer.java create mode 100644 libjava/classpath/java/awt/peer/PanelPeer.java create mode 100644 libjava/classpath/java/awt/peer/PopupMenuPeer.java create mode 100644 libjava/classpath/java/awt/peer/RobotPeer.java create mode 100644 libjava/classpath/java/awt/peer/ScrollPanePeer.java create mode 100644 libjava/classpath/java/awt/peer/ScrollbarPeer.java create mode 100644 libjava/classpath/java/awt/peer/TextAreaPeer.java create mode 100644 libjava/classpath/java/awt/peer/TextComponentPeer.java create mode 100644 libjava/classpath/java/awt/peer/TextFieldPeer.java create mode 100644 libjava/classpath/java/awt/peer/WindowPeer.java create mode 100644 libjava/classpath/java/awt/peer/package.html create mode 100644 libjava/classpath/java/awt/print/Book.java create mode 100644 libjava/classpath/java/awt/print/PageFormat.java create mode 100644 libjava/classpath/java/awt/print/Pageable.java create mode 100644 libjava/classpath/java/awt/print/Paper.java create mode 100644 libjava/classpath/java/awt/print/Printable.java create mode 100644 libjava/classpath/java/awt/print/PrinterAbortException.java create mode 100644 libjava/classpath/java/awt/print/PrinterException.java create mode 100644 libjava/classpath/java/awt/print/PrinterGraphics.java create mode 100644 libjava/classpath/java/awt/print/PrinterIOException.java create mode 100644 libjava/classpath/java/awt/print/PrinterJob.java create mode 100644 libjava/classpath/java/awt/print/package.html create mode 100644 libjava/classpath/java/beans/AppletInitializer.java create mode 100644 libjava/classpath/java/beans/BeanDescriptor.java create mode 100644 libjava/classpath/java/beans/BeanInfo.java create mode 100644 libjava/classpath/java/beans/Beans.java create mode 100644 libjava/classpath/java/beans/Customizer.java create mode 100644 libjava/classpath/java/beans/DesignMode.java create mode 100644 libjava/classpath/java/beans/EventHandler.java create mode 100644 libjava/classpath/java/beans/EventSetDescriptor.java create mode 100644 libjava/classpath/java/beans/ExceptionListener.java create mode 100644 libjava/classpath/java/beans/Expression.java create mode 100644 libjava/classpath/java/beans/FeatureDescriptor.java create mode 100644 libjava/classpath/java/beans/IndexedPropertyDescriptor.java create mode 100644 libjava/classpath/java/beans/IntrospectionException.java create mode 100644 libjava/classpath/java/beans/Introspector.java create mode 100644 libjava/classpath/java/beans/MethodDescriptor.java create mode 100644 libjava/classpath/java/beans/ParameterDescriptor.java create mode 100644 libjava/classpath/java/beans/PropertyChangeEvent.java create mode 100644 libjava/classpath/java/beans/PropertyChangeListener.java create mode 100644 libjava/classpath/java/beans/PropertyChangeListenerProxy.java create mode 100644 libjava/classpath/java/beans/PropertyChangeSupport.java create mode 100644 libjava/classpath/java/beans/PropertyDescriptor.java create mode 100644 libjava/classpath/java/beans/PropertyEditor.java create mode 100644 libjava/classpath/java/beans/PropertyEditorManager.java create mode 100644 libjava/classpath/java/beans/PropertyEditorSupport.java create mode 100644 libjava/classpath/java/beans/PropertyVetoException.java create mode 100644 libjava/classpath/java/beans/SimpleBeanInfo.java create mode 100644 libjava/classpath/java/beans/Statement.java create mode 100644 libjava/classpath/java/beans/TODO create mode 100644 libjava/classpath/java/beans/VetoableChangeListener.java create mode 100644 libjava/classpath/java/beans/VetoableChangeListenerProxy.java create mode 100644 libjava/classpath/java/beans/VetoableChangeSupport.java create mode 100644 libjava/classpath/java/beans/Visibility.java create mode 100644 libjava/classpath/java/beans/XMLDecoder.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContext.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextChild.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextChildComponentProxy.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextChildSupport.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextContainerProxy.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextEvent.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextMembershipListener.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextProxy.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceProvider.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceProviderBeanInfo.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedListener.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServices.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServicesListener.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java create mode 100644 libjava/classpath/java/beans/beancontext/BeanContextSupport.java create mode 100644 libjava/classpath/java/beans/beancontext/package.html create mode 100644 libjava/classpath/java/beans/package.html create mode 100644 libjava/classpath/java/io/BufferedInputStream.java create mode 100644 libjava/classpath/java/io/BufferedOutputStream.java create mode 100644 libjava/classpath/java/io/BufferedReader.java create mode 100644 libjava/classpath/java/io/BufferedWriter.java create mode 100644 libjava/classpath/java/io/ByteArrayInputStream.java create mode 100644 libjava/classpath/java/io/ByteArrayOutputStream.java create mode 100644 libjava/classpath/java/io/CharArrayReader.java create mode 100644 libjava/classpath/java/io/CharArrayWriter.java create mode 100644 libjava/classpath/java/io/CharConversionException.java create mode 100644 libjava/classpath/java/io/Closeable.java create mode 100644 libjava/classpath/java/io/DataInput.java create mode 100644 libjava/classpath/java/io/DataInputStream.java create mode 100644 libjava/classpath/java/io/DataOutput.java create mode 100644 libjava/classpath/java/io/DataOutputStream.java create mode 100644 libjava/classpath/java/io/DeleteFileHelper.java create mode 100644 libjava/classpath/java/io/EOFException.java create mode 100644 libjava/classpath/java/io/Externalizable.java create mode 100644 libjava/classpath/java/io/File.java create mode 100644 libjava/classpath/java/io/FileDescriptor.java create mode 100644 libjava/classpath/java/io/FileFilter.java create mode 100644 libjava/classpath/java/io/FileInputStream.java create mode 100644 libjava/classpath/java/io/FileNotFoundException.java create mode 100644 libjava/classpath/java/io/FileOutputStream.java create mode 100644 libjava/classpath/java/io/FilePermission.java create mode 100644 libjava/classpath/java/io/FileReader.java create mode 100644 libjava/classpath/java/io/FileWriter.java create mode 100644 libjava/classpath/java/io/FilenameFilter.java create mode 100644 libjava/classpath/java/io/FilterInputStream.java create mode 100644 libjava/classpath/java/io/FilterOutputStream.java create mode 100644 libjava/classpath/java/io/FilterReader.java create mode 100644 libjava/classpath/java/io/FilterWriter.java create mode 100644 libjava/classpath/java/io/Flushable.java create mode 100644 libjava/classpath/java/io/IOException.java create mode 100644 libjava/classpath/java/io/InputStream.java create mode 100644 libjava/classpath/java/io/InputStreamReader.java create mode 100644 libjava/classpath/java/io/InterruptedIOException.java create mode 100644 libjava/classpath/java/io/InvalidClassException.java create mode 100644 libjava/classpath/java/io/InvalidObjectException.java create mode 100644 libjava/classpath/java/io/LineNumberInputStream.java create mode 100644 libjava/classpath/java/io/LineNumberReader.java create mode 100644 libjava/classpath/java/io/NotActiveException.java create mode 100644 libjava/classpath/java/io/NotSerializableException.java create mode 100644 libjava/classpath/java/io/ObjectInput.java create mode 100644 libjava/classpath/java/io/ObjectInputStream.java create mode 100644 libjava/classpath/java/io/ObjectInputValidation.java create mode 100644 libjava/classpath/java/io/ObjectOutput.java create mode 100644 libjava/classpath/java/io/ObjectOutputStream.java create mode 100644 libjava/classpath/java/io/ObjectStreamClass.java create mode 100644 libjava/classpath/java/io/ObjectStreamConstants.java create mode 100644 libjava/classpath/java/io/ObjectStreamException.java create mode 100644 libjava/classpath/java/io/ObjectStreamField.java create mode 100644 libjava/classpath/java/io/OptionalDataException.java create mode 100644 libjava/classpath/java/io/OutputStream.java create mode 100644 libjava/classpath/java/io/OutputStreamWriter.java create mode 100644 libjava/classpath/java/io/PipedInputStream.java create mode 100644 libjava/classpath/java/io/PipedOutputStream.java create mode 100644 libjava/classpath/java/io/PipedReader.java create mode 100644 libjava/classpath/java/io/PipedWriter.java create mode 100644 libjava/classpath/java/io/PrintStream.java create mode 100644 libjava/classpath/java/io/PrintWriter.java create mode 100644 libjava/classpath/java/io/PushbackInputStream.java create mode 100644 libjava/classpath/java/io/PushbackReader.java create mode 100644 libjava/classpath/java/io/RandomAccessFile.java create mode 100644 libjava/classpath/java/io/Reader.java create mode 100644 libjava/classpath/java/io/SequenceInputStream.java create mode 100644 libjava/classpath/java/io/Serializable.java create mode 100644 libjava/classpath/java/io/SerializablePermission.java create mode 100644 libjava/classpath/java/io/StreamCorruptedException.java create mode 100644 libjava/classpath/java/io/StreamTokenizer.java create mode 100644 libjava/classpath/java/io/StringBufferInputStream.java create mode 100644 libjava/classpath/java/io/StringReader.java create mode 100644 libjava/classpath/java/io/StringWriter.java create mode 100644 libjava/classpath/java/io/SyncFailedException.java create mode 100644 libjava/classpath/java/io/UTFDataFormatException.java create mode 100644 libjava/classpath/java/io/UnsupportedEncodingException.java create mode 100644 libjava/classpath/java/io/WriteAbortedException.java create mode 100644 libjava/classpath/java/io/Writer.java create mode 100644 libjava/classpath/java/io/class-dependencies.conf create mode 100644 libjava/classpath/java/io/package.html create mode 100644 libjava/classpath/java/lang/AbstractMethodError.java create mode 100644 libjava/classpath/java/lang/Appendable.java create mode 100644 libjava/classpath/java/lang/ArithmeticException.java create mode 100644 libjava/classpath/java/lang/ArrayIndexOutOfBoundsException.java create mode 100644 libjava/classpath/java/lang/ArrayStoreException.java create mode 100644 libjava/classpath/java/lang/AssertionError.java create mode 100644 libjava/classpath/java/lang/Boolean.java create mode 100644 libjava/classpath/java/lang/Byte.java create mode 100644 libjava/classpath/java/lang/CharSequence.java create mode 100644 libjava/classpath/java/lang/Character.java create mode 100644 libjava/classpath/java/lang/Class.java create mode 100644 libjava/classpath/java/lang/ClassCastException.java create mode 100644 libjava/classpath/java/lang/ClassCircularityError.java create mode 100644 libjava/classpath/java/lang/ClassFormatError.java create mode 100644 libjava/classpath/java/lang/ClassLoader.java create mode 100644 libjava/classpath/java/lang/ClassNotFoundException.java create mode 100644 libjava/classpath/java/lang/CloneNotSupportedException.java create mode 100644 libjava/classpath/java/lang/Cloneable.java create mode 100644 libjava/classpath/java/lang/Comparable.java create mode 100644 libjava/classpath/java/lang/Compiler.java create mode 100644 libjava/classpath/java/lang/Double.java create mode 100644 libjava/classpath/java/lang/Error.java create mode 100644 libjava/classpath/java/lang/Exception.java create mode 100644 libjava/classpath/java/lang/ExceptionInInitializerError.java create mode 100644 libjava/classpath/java/lang/Float.java create mode 100644 libjava/classpath/java/lang/IllegalAccessError.java create mode 100644 libjava/classpath/java/lang/IllegalAccessException.java create mode 100644 libjava/classpath/java/lang/IllegalArgumentException.java create mode 100644 libjava/classpath/java/lang/IllegalMonitorStateException.java create mode 100644 libjava/classpath/java/lang/IllegalStateException.java create mode 100644 libjava/classpath/java/lang/IllegalThreadStateException.java create mode 100644 libjava/classpath/java/lang/IncompatibleClassChangeError.java create mode 100644 libjava/classpath/java/lang/IndexOutOfBoundsException.java create mode 100644 libjava/classpath/java/lang/InheritableThreadLocal.java create mode 100644 libjava/classpath/java/lang/InstantiationError.java create mode 100644 libjava/classpath/java/lang/InstantiationException.java create mode 100644 libjava/classpath/java/lang/Integer.java create mode 100644 libjava/classpath/java/lang/InternalError.java create mode 100644 libjava/classpath/java/lang/InterruptedException.java create mode 100644 libjava/classpath/java/lang/LinkageError.java create mode 100644 libjava/classpath/java/lang/Long.java create mode 100644 libjava/classpath/java/lang/Math.java create mode 100644 libjava/classpath/java/lang/NegativeArraySizeException.java create mode 100644 libjava/classpath/java/lang/NoClassDefFoundError.java create mode 100644 libjava/classpath/java/lang/NoSuchFieldError.java create mode 100644 libjava/classpath/java/lang/NoSuchFieldException.java create mode 100644 libjava/classpath/java/lang/NoSuchMethodError.java create mode 100644 libjava/classpath/java/lang/NoSuchMethodException.java create mode 100644 libjava/classpath/java/lang/NullPointerException.java create mode 100644 libjava/classpath/java/lang/Number.java create mode 100644 libjava/classpath/java/lang/NumberFormatException.java create mode 100644 libjava/classpath/java/lang/Object.java create mode 100644 libjava/classpath/java/lang/OutOfMemoryError.java create mode 100644 libjava/classpath/java/lang/Package.java create mode 100644 libjava/classpath/java/lang/Process.java create mode 100644 libjava/classpath/java/lang/Readable.java create mode 100644 libjava/classpath/java/lang/Runnable.java create mode 100644 libjava/classpath/java/lang/Runtime.java create mode 100644 libjava/classpath/java/lang/RuntimeException.java create mode 100644 libjava/classpath/java/lang/RuntimePermission.java create mode 100644 libjava/classpath/java/lang/SecurityException.java create mode 100644 libjava/classpath/java/lang/SecurityManager.java create mode 100644 libjava/classpath/java/lang/Short.java create mode 100644 libjava/classpath/java/lang/StackOverflowError.java create mode 100644 libjava/classpath/java/lang/StackTraceElement.java create mode 100644 libjava/classpath/java/lang/StrictMath.java create mode 100644 libjava/classpath/java/lang/String.java create mode 100644 libjava/classpath/java/lang/StringBuffer.java create mode 100644 libjava/classpath/java/lang/StringBuilder.java create mode 100644 libjava/classpath/java/lang/StringIndexOutOfBoundsException.java create mode 100644 libjava/classpath/java/lang/System.java create mode 100644 libjava/classpath/java/lang/Thread.java create mode 100644 libjava/classpath/java/lang/ThreadDeath.java create mode 100644 libjava/classpath/java/lang/ThreadGroup.java create mode 100644 libjava/classpath/java/lang/ThreadLocal.java create mode 100644 libjava/classpath/java/lang/Throwable.java create mode 100644 libjava/classpath/java/lang/TypeNotPresentException.java create mode 100644 libjava/classpath/java/lang/UnknownError.java create mode 100644 libjava/classpath/java/lang/UnsatisfiedLinkError.java create mode 100644 libjava/classpath/java/lang/UnsupportedClassVersionError.java create mode 100644 libjava/classpath/java/lang/UnsupportedOperationException.java create mode 100644 libjava/classpath/java/lang/VerifyError.java create mode 100644 libjava/classpath/java/lang/VirtualMachineError.java create mode 100644 libjava/classpath/java/lang/Void.java create mode 100644 libjava/classpath/java/lang/annotation/AnnotationFormatError.java create mode 100644 libjava/classpath/java/lang/annotation/AnnotationTypeMismatchException.java create mode 100644 libjava/classpath/java/lang/annotation/package.html create mode 100644 libjava/classpath/java/lang/class-dependencies.conf create mode 100644 libjava/classpath/java/lang/package.html create mode 100644 libjava/classpath/java/lang/ref/PhantomReference.java create mode 100644 libjava/classpath/java/lang/ref/Reference.java create mode 100644 libjava/classpath/java/lang/ref/ReferenceQueue.java create mode 100644 libjava/classpath/java/lang/ref/SoftReference.java create mode 100644 libjava/classpath/java/lang/ref/WeakReference.java create mode 100644 libjava/classpath/java/lang/ref/package.html create mode 100644 libjava/classpath/java/lang/reflect/AccessibleObject.java create mode 100644 libjava/classpath/java/lang/reflect/Array.java create mode 100644 libjava/classpath/java/lang/reflect/GenericArrayType.java create mode 100644 libjava/classpath/java/lang/reflect/GenericSignatureFormatError.java create mode 100644 libjava/classpath/java/lang/reflect/InvocationHandler.java create mode 100644 libjava/classpath/java/lang/reflect/InvocationTargetException.java create mode 100644 libjava/classpath/java/lang/reflect/Member.java create mode 100644 libjava/classpath/java/lang/reflect/Modifier.java create mode 100644 libjava/classpath/java/lang/reflect/ParameterizedType.java create mode 100644 libjava/classpath/java/lang/reflect/Proxy.java create mode 100644 libjava/classpath/java/lang/reflect/README create mode 100644 libjava/classpath/java/lang/reflect/ReflectPermission.java create mode 100755 libjava/classpath/java/lang/reflect/TODO create mode 100644 libjava/classpath/java/lang/reflect/Type.java create mode 100644 libjava/classpath/java/lang/reflect/UndeclaredThrowableException.java create mode 100644 libjava/classpath/java/lang/reflect/WildcardType.java create mode 100644 libjava/classpath/java/lang/reflect/package.html create mode 100644 libjava/classpath/java/math/BigDecimal.java create mode 100644 libjava/classpath/java/math/BigInteger.java create mode 100644 libjava/classpath/java/math/class-dependencies.conf create mode 100644 libjava/classpath/java/math/package.html create mode 100644 libjava/classpath/java/net/Authenticator.java create mode 100644 libjava/classpath/java/net/BindException.java create mode 100644 libjava/classpath/java/net/ConnectException.java create mode 100644 libjava/classpath/java/net/ContentHandler.java create mode 100644 libjava/classpath/java/net/ContentHandlerFactory.java create mode 100644 libjava/classpath/java/net/DatagramPacket.java create mode 100644 libjava/classpath/java/net/DatagramSocket.java create mode 100644 libjava/classpath/java/net/DatagramSocketImpl.java create mode 100644 libjava/classpath/java/net/DatagramSocketImplFactory.java create mode 100644 libjava/classpath/java/net/FileNameMap.java create mode 100644 libjava/classpath/java/net/HttpURLConnection.java create mode 100644 libjava/classpath/java/net/Inet4Address.java create mode 100644 libjava/classpath/java/net/Inet6Address.java create mode 100644 libjava/classpath/java/net/InetAddress.java create mode 100644 libjava/classpath/java/net/InetSocketAddress.java create mode 100644 libjava/classpath/java/net/JarURLConnection.java create mode 100644 libjava/classpath/java/net/MalformedURLException.java create mode 100644 libjava/classpath/java/net/MimeTypeMapper.java create mode 100644 libjava/classpath/java/net/MulticastSocket.java create mode 100644 libjava/classpath/java/net/NetPermission.java create mode 100644 libjava/classpath/java/net/NetworkInterface.java create mode 100644 libjava/classpath/java/net/NoRouteToHostException.java create mode 100644 libjava/classpath/java/net/PasswordAuthentication.java create mode 100644 libjava/classpath/java/net/PortUnreachableException.java create mode 100644 libjava/classpath/java/net/ProtocolException.java create mode 100644 libjava/classpath/java/net/STATUS create mode 100644 libjava/classpath/java/net/ServerSocket.java create mode 100644 libjava/classpath/java/net/Socket.java create mode 100644 libjava/classpath/java/net/SocketAddress.java create mode 100644 libjava/classpath/java/net/SocketException.java create mode 100644 libjava/classpath/java/net/SocketImpl.java create mode 100644 libjava/classpath/java/net/SocketImplFactory.java create mode 100644 libjava/classpath/java/net/SocketOptions.java create mode 100644 libjava/classpath/java/net/SocketPermission.java create mode 100644 libjava/classpath/java/net/SocketTimeoutException.java create mode 100644 libjava/classpath/java/net/TODO create mode 100644 libjava/classpath/java/net/URI.java create mode 100644 libjava/classpath/java/net/URISyntaxException.java create mode 100644 libjava/classpath/java/net/URL.java create mode 100644 libjava/classpath/java/net/URLClassLoader.java create mode 100644 libjava/classpath/java/net/URLConnection.java create mode 100644 libjava/classpath/java/net/URLDecoder.java create mode 100644 libjava/classpath/java/net/URLEncoder.java create mode 100644 libjava/classpath/java/net/URLStreamHandler.java create mode 100644 libjava/classpath/java/net/URLStreamHandlerFactory.java create mode 100644 libjava/classpath/java/net/UnknownHostException.java create mode 100644 libjava/classpath/java/net/UnknownServiceException.java create mode 100644 libjava/classpath/java/net/class-dependencies.conf create mode 100644 libjava/classpath/java/net/package.html create mode 100644 libjava/classpath/java/nio/Buffer.java create mode 100644 libjava/classpath/java/nio/BufferOverflowException.java create mode 100644 libjava/classpath/java/nio/BufferUnderflowException.java create mode 100644 libjava/classpath/java/nio/ByteBuffer.java create mode 100644 libjava/classpath/java/nio/ByteBufferHelper.java create mode 100644 libjava/classpath/java/nio/ByteBufferImpl.java create mode 100644 libjava/classpath/java/nio/ByteOrder.java create mode 100644 libjava/classpath/java/nio/CharBuffer.java create mode 100644 libjava/classpath/java/nio/CharBufferImpl.java create mode 100644 libjava/classpath/java/nio/CharViewBufferImpl.java create mode 100644 libjava/classpath/java/nio/DirectByteBufferImpl.java create mode 100644 libjava/classpath/java/nio/DoubleBuffer.java create mode 100644 libjava/classpath/java/nio/DoubleBufferImpl.java create mode 100644 libjava/classpath/java/nio/DoubleViewBufferImpl.java create mode 100644 libjava/classpath/java/nio/FloatBuffer.java create mode 100644 libjava/classpath/java/nio/FloatBufferImpl.java create mode 100644 libjava/classpath/java/nio/FloatViewBufferImpl.java create mode 100644 libjava/classpath/java/nio/IntBuffer.java create mode 100644 libjava/classpath/java/nio/IntBufferImpl.java create mode 100644 libjava/classpath/java/nio/IntViewBufferImpl.java create mode 100644 libjava/classpath/java/nio/InvalidMarkException.java create mode 100644 libjava/classpath/java/nio/LongBuffer.java create mode 100644 libjava/classpath/java/nio/LongBufferImpl.java create mode 100644 libjava/classpath/java/nio/LongViewBufferImpl.java create mode 100644 libjava/classpath/java/nio/MappedByteBuffer.java create mode 100644 libjava/classpath/java/nio/MappedByteBufferImpl.java create mode 100644 libjava/classpath/java/nio/ReadOnlyBufferException.java create mode 100644 libjava/classpath/java/nio/ShortBuffer.java create mode 100644 libjava/classpath/java/nio/ShortBufferImpl.java create mode 100644 libjava/classpath/java/nio/ShortViewBufferImpl.java create mode 100644 libjava/classpath/java/nio/channels/AlreadyConnectedException.java create mode 100644 libjava/classpath/java/nio/channels/AsynchronousCloseException.java create mode 100644 libjava/classpath/java/nio/channels/ByteChannel.java create mode 100644 libjava/classpath/java/nio/channels/CancelledKeyException.java create mode 100644 libjava/classpath/java/nio/channels/Channel.java create mode 100644 libjava/classpath/java/nio/channels/Channels.java create mode 100644 libjava/classpath/java/nio/channels/ClosedByInterruptException.java create mode 100644 libjava/classpath/java/nio/channels/ClosedChannelException.java create mode 100644 libjava/classpath/java/nio/channels/ClosedSelectorException.java create mode 100644 libjava/classpath/java/nio/channels/ConnectionPendingException.java create mode 100644 libjava/classpath/java/nio/channels/DatagramChannel.java create mode 100644 libjava/classpath/java/nio/channels/FileChannel.java create mode 100644 libjava/classpath/java/nio/channels/FileLock.java create mode 100644 libjava/classpath/java/nio/channels/FileLockInterruptionException.java create mode 100644 libjava/classpath/java/nio/channels/GatheringByteChannel.java create mode 100644 libjava/classpath/java/nio/channels/IllegalBlockingModeException.java create mode 100644 libjava/classpath/java/nio/channels/IllegalSelectorException.java create mode 100644 libjava/classpath/java/nio/channels/InterruptibleChannel.java create mode 100644 libjava/classpath/java/nio/channels/NoConnectionPendingException.java create mode 100644 libjava/classpath/java/nio/channels/NonReadableChannelException.java create mode 100644 libjava/classpath/java/nio/channels/NonWritableChannelException.java create mode 100644 libjava/classpath/java/nio/channels/NotYetBoundException.java create mode 100644 libjava/classpath/java/nio/channels/NotYetConnectedException.java create mode 100644 libjava/classpath/java/nio/channels/OverlappingFileLockException.java create mode 100644 libjava/classpath/java/nio/channels/Pipe.java create mode 100644 libjava/classpath/java/nio/channels/ReadableByteChannel.java create mode 100644 libjava/classpath/java/nio/channels/ScatteringByteChannel.java create mode 100644 libjava/classpath/java/nio/channels/SelectableChannel.java create mode 100644 libjava/classpath/java/nio/channels/SelectionKey.java create mode 100644 libjava/classpath/java/nio/channels/Selector.java create mode 100644 libjava/classpath/java/nio/channels/ServerSocketChannel.java create mode 100644 libjava/classpath/java/nio/channels/SocketChannel.java create mode 100644 libjava/classpath/java/nio/channels/UnresolvedAddressException.java create mode 100644 libjava/classpath/java/nio/channels/UnsupportedAddressTypeException.java create mode 100644 libjava/classpath/java/nio/channels/WritableByteChannel.java create mode 100644 libjava/classpath/java/nio/channels/package.html create mode 100644 libjava/classpath/java/nio/channels/spi/AbstractInterruptibleChannel.java create mode 100644 libjava/classpath/java/nio/channels/spi/AbstractSelectableChannel.java create mode 100644 libjava/classpath/java/nio/channels/spi/AbstractSelectionKey.java create mode 100644 libjava/classpath/java/nio/channels/spi/AbstractSelector.java create mode 100644 libjava/classpath/java/nio/channels/spi/SelectorProvider.java create mode 100644 libjava/classpath/java/nio/channels/spi/package.html create mode 100644 libjava/classpath/java/nio/charset/CharacterCodingException.java create mode 100644 libjava/classpath/java/nio/charset/Charset.java create mode 100644 libjava/classpath/java/nio/charset/CharsetDecoder.java create mode 100644 libjava/classpath/java/nio/charset/CharsetEncoder.java create mode 100644 libjava/classpath/java/nio/charset/CoderMalfunctionError.java create mode 100644 libjava/classpath/java/nio/charset/CoderResult.java create mode 100644 libjava/classpath/java/nio/charset/CodingErrorAction.java create mode 100644 libjava/classpath/java/nio/charset/IllegalCharsetNameException.java create mode 100644 libjava/classpath/java/nio/charset/MalformedInputException.java create mode 100644 libjava/classpath/java/nio/charset/UnmappableCharacterException.java create mode 100644 libjava/classpath/java/nio/charset/UnsupportedCharsetException.java create mode 100644 libjava/classpath/java/nio/charset/package.html create mode 100644 libjava/classpath/java/nio/charset/spi/CharsetProvider.java create mode 100644 libjava/classpath/java/nio/charset/spi/package.html create mode 100644 libjava/classpath/java/nio/class-dependencies.conf create mode 100644 libjava/classpath/java/nio/package.html create mode 100644 libjava/classpath/java/rmi/AccessException.java create mode 100644 libjava/classpath/java/rmi/AlreadyBoundException.java create mode 100644 libjava/classpath/java/rmi/ConnectException.java create mode 100644 libjava/classpath/java/rmi/ConnectIOException.java create mode 100644 libjava/classpath/java/rmi/MarshalException.java create mode 100644 libjava/classpath/java/rmi/MarshalledObject.java create mode 100644 libjava/classpath/java/rmi/Naming.java create mode 100644 libjava/classpath/java/rmi/NoSuchObjectException.java create mode 100644 libjava/classpath/java/rmi/NotBoundException.java create mode 100644 libjava/classpath/java/rmi/RMISecurityException.java create mode 100644 libjava/classpath/java/rmi/RMISecurityManager.java create mode 100644 libjava/classpath/java/rmi/Remote.java create mode 100644 libjava/classpath/java/rmi/RemoteException.java create mode 100644 libjava/classpath/java/rmi/ServerError.java create mode 100644 libjava/classpath/java/rmi/ServerException.java create mode 100644 libjava/classpath/java/rmi/ServerRuntimeException.java create mode 100644 libjava/classpath/java/rmi/StubNotFoundException.java create mode 100644 libjava/classpath/java/rmi/UnexpectedException.java create mode 100644 libjava/classpath/java/rmi/UnknownHostException.java create mode 100644 libjava/classpath/java/rmi/UnmarshalException.java create mode 100644 libjava/classpath/java/rmi/activation/Activatable.java create mode 100644 libjava/classpath/java/rmi/activation/ActivateFailedException.java create mode 100644 libjava/classpath/java/rmi/activation/ActivationDesc.java create mode 100644 libjava/classpath/java/rmi/activation/ActivationException.java create mode 100644 libjava/classpath/java/rmi/activation/ActivationGroup.java create mode 100644 libjava/classpath/java/rmi/activation/ActivationGroupDesc.java create mode 100644 libjava/classpath/java/rmi/activation/ActivationGroupID.java create mode 100644 libjava/classpath/java/rmi/activation/ActivationID.java create mode 100644 libjava/classpath/java/rmi/activation/ActivationInstantiator.java create mode 100644 libjava/classpath/java/rmi/activation/ActivationMonitor.java create mode 100644 libjava/classpath/java/rmi/activation/ActivationSystem.java create mode 100644 libjava/classpath/java/rmi/activation/Activator.java create mode 100644 libjava/classpath/java/rmi/activation/UnknownGroupException.java create mode 100644 libjava/classpath/java/rmi/activation/UnknownObjectException.java create mode 100644 libjava/classpath/java/rmi/activation/package.html create mode 100644 libjava/classpath/java/rmi/dgc/DGC.java create mode 100644 libjava/classpath/java/rmi/dgc/Lease.java create mode 100644 libjava/classpath/java/rmi/dgc/VMID.java create mode 100644 libjava/classpath/java/rmi/dgc/package.html create mode 100644 libjava/classpath/java/rmi/package.html create mode 100644 libjava/classpath/java/rmi/registry/LocateRegistry.java create mode 100644 libjava/classpath/java/rmi/registry/Registry.java create mode 100644 libjava/classpath/java/rmi/registry/RegistryHandler.java create mode 100644 libjava/classpath/java/rmi/registry/package.html create mode 100644 libjava/classpath/java/rmi/server/ExportException.java create mode 100644 libjava/classpath/java/rmi/server/LoaderHandler.java create mode 100644 libjava/classpath/java/rmi/server/LogStream.java create mode 100644 libjava/classpath/java/rmi/server/ObjID.java create mode 100644 libjava/classpath/java/rmi/server/Operation.java create mode 100644 libjava/classpath/java/rmi/server/RMIClassLoader.java create mode 100644 libjava/classpath/java/rmi/server/RMIClassLoaderSpi.java create mode 100644 libjava/classpath/java/rmi/server/RMIClientSocketFactory.java create mode 100644 libjava/classpath/java/rmi/server/RMIFailureHandler.java create mode 100644 libjava/classpath/java/rmi/server/RMIServerSocketFactory.java create mode 100644 libjava/classpath/java/rmi/server/RMISocketFactory.java create mode 100644 libjava/classpath/java/rmi/server/RemoteCall.java create mode 100644 libjava/classpath/java/rmi/server/RemoteObject.java create mode 100644 libjava/classpath/java/rmi/server/RemoteRef.java create mode 100644 libjava/classpath/java/rmi/server/RemoteServer.java create mode 100644 libjava/classpath/java/rmi/server/RemoteStub.java create mode 100644 libjava/classpath/java/rmi/server/ServerCloneException.java create mode 100644 libjava/classpath/java/rmi/server/ServerNotActiveException.java create mode 100644 libjava/classpath/java/rmi/server/ServerRef.java create mode 100644 libjava/classpath/java/rmi/server/Skeleton.java create mode 100644 libjava/classpath/java/rmi/server/SkeletonMismatchException.java create mode 100644 libjava/classpath/java/rmi/server/SkeletonNotFoundException.java create mode 100644 libjava/classpath/java/rmi/server/SocketSecurityException.java create mode 100644 libjava/classpath/java/rmi/server/UID.java create mode 100644 libjava/classpath/java/rmi/server/UnicastRemoteObject.java create mode 100644 libjava/classpath/java/rmi/server/Unreferenced.java create mode 100644 libjava/classpath/java/rmi/server/package.html create mode 100644 libjava/classpath/java/security/AccessControlContext.java create mode 100644 libjava/classpath/java/security/AccessControlException.java create mode 100644 libjava/classpath/java/security/AccessController.java create mode 100644 libjava/classpath/java/security/AlgorithmParameterGenerator.java create mode 100644 libjava/classpath/java/security/AlgorithmParameterGeneratorSpi.java create mode 100644 libjava/classpath/java/security/AlgorithmParameters.java create mode 100644 libjava/classpath/java/security/AlgorithmParametersSpi.java create mode 100644 libjava/classpath/java/security/AllPermission.java create mode 100644 libjava/classpath/java/security/BasicPermission.java create mode 100644 libjava/classpath/java/security/Certificate.java create mode 100644 libjava/classpath/java/security/CodeSource.java create mode 100644 libjava/classpath/java/security/DigestException.java create mode 100644 libjava/classpath/java/security/DigestInputStream.java create mode 100644 libjava/classpath/java/security/DigestOutputStream.java create mode 100644 libjava/classpath/java/security/DomainCombiner.java create mode 100644 libjava/classpath/java/security/DummyKeyPairGenerator.java create mode 100644 libjava/classpath/java/security/DummyMessageDigest.java create mode 100644 libjava/classpath/java/security/DummySignature.java create mode 100644 libjava/classpath/java/security/GeneralSecurityException.java create mode 100644 libjava/classpath/java/security/Guard.java create mode 100644 libjava/classpath/java/security/GuardedObject.java create mode 100644 libjava/classpath/java/security/Identity.java create mode 100644 libjava/classpath/java/security/IdentityScope.java create mode 100644 libjava/classpath/java/security/IntersectingDomainCombiner.java create mode 100644 libjava/classpath/java/security/InvalidAlgorithmParameterException.java create mode 100644 libjava/classpath/java/security/InvalidKeyException.java create mode 100644 libjava/classpath/java/security/InvalidParameterException.java create mode 100644 libjava/classpath/java/security/Key.java create mode 100644 libjava/classpath/java/security/KeyException.java create mode 100644 libjava/classpath/java/security/KeyFactory.java create mode 100644 libjava/classpath/java/security/KeyFactorySpi.java create mode 100644 libjava/classpath/java/security/KeyManagementException.java create mode 100644 libjava/classpath/java/security/KeyPair.java create mode 100644 libjava/classpath/java/security/KeyPairGenerator.java create mode 100644 libjava/classpath/java/security/KeyPairGeneratorSpi.java create mode 100644 libjava/classpath/java/security/KeyStore.java create mode 100644 libjava/classpath/java/security/KeyStoreException.java create mode 100644 libjava/classpath/java/security/KeyStoreSpi.java create mode 100644 libjava/classpath/java/security/MessageDigest.java create mode 100644 libjava/classpath/java/security/MessageDigestSpi.java create mode 100644 libjava/classpath/java/security/NoSuchAlgorithmException.java create mode 100644 libjava/classpath/java/security/NoSuchProviderException.java create mode 100644 libjava/classpath/java/security/Permission.java create mode 100644 libjava/classpath/java/security/PermissionCollection.java create mode 100644 libjava/classpath/java/security/Permissions.java create mode 100644 libjava/classpath/java/security/Policy.java create mode 100644 libjava/classpath/java/security/Principal.java create mode 100644 libjava/classpath/java/security/PrivateKey.java create mode 100644 libjava/classpath/java/security/PrivilegedAction.java create mode 100644 libjava/classpath/java/security/PrivilegedActionException.java create mode 100644 libjava/classpath/java/security/PrivilegedExceptionAction.java create mode 100644 libjava/classpath/java/security/ProtectionDomain.java create mode 100644 libjava/classpath/java/security/Provider.java create mode 100644 libjava/classpath/java/security/ProviderException.java create mode 100644 libjava/classpath/java/security/PublicKey.java create mode 100644 libjava/classpath/java/security/SecureClassLoader.java create mode 100644 libjava/classpath/java/security/SecureRandom.java create mode 100644 libjava/classpath/java/security/SecureRandomSpi.java create mode 100644 libjava/classpath/java/security/Security.java create mode 100644 libjava/classpath/java/security/SecurityPermission.java create mode 100644 libjava/classpath/java/security/Signature.java create mode 100644 libjava/classpath/java/security/SignatureException.java create mode 100644 libjava/classpath/java/security/SignatureSpi.java create mode 100644 libjava/classpath/java/security/SignedObject.java create mode 100644 libjava/classpath/java/security/Signer.java create mode 100644 libjava/classpath/java/security/UnrecoverableKeyException.java create mode 100644 libjava/classpath/java/security/UnresolvedPermission.java create mode 100644 libjava/classpath/java/security/acl/Acl.java create mode 100644 libjava/classpath/java/security/acl/AclEntry.java create mode 100644 libjava/classpath/java/security/acl/AclNotFoundException.java create mode 100644 libjava/classpath/java/security/acl/Group.java create mode 100644 libjava/classpath/java/security/acl/LastOwnerException.java create mode 100644 libjava/classpath/java/security/acl/NotOwnerException.java create mode 100644 libjava/classpath/java/security/acl/Owner.java create mode 100644 libjava/classpath/java/security/acl/Permission.java create mode 100644 libjava/classpath/java/security/acl/package.html create mode 100644 libjava/classpath/java/security/cert/CRL.java create mode 100644 libjava/classpath/java/security/cert/CRLException.java create mode 100644 libjava/classpath/java/security/cert/CRLSelector.java create mode 100644 libjava/classpath/java/security/cert/CertPath.java create mode 100644 libjava/classpath/java/security/cert/CertPathBuilder.java create mode 100644 libjava/classpath/java/security/cert/CertPathBuilderException.java create mode 100644 libjava/classpath/java/security/cert/CertPathBuilderResult.java create mode 100644 libjava/classpath/java/security/cert/CertPathBuilderSpi.java create mode 100644 libjava/classpath/java/security/cert/CertPathParameters.java create mode 100644 libjava/classpath/java/security/cert/CertPathValidator.java create mode 100644 libjava/classpath/java/security/cert/CertPathValidatorException.java create mode 100644 libjava/classpath/java/security/cert/CertPathValidatorResult.java create mode 100644 libjava/classpath/java/security/cert/CertPathValidatorSpi.java create mode 100644 libjava/classpath/java/security/cert/CertSelector.java create mode 100644 libjava/classpath/java/security/cert/CertStore.java create mode 100644 libjava/classpath/java/security/cert/CertStoreException.java create mode 100644 libjava/classpath/java/security/cert/CertStoreParameters.java create mode 100644 libjava/classpath/java/security/cert/CertStoreSpi.java create mode 100644 libjava/classpath/java/security/cert/Certificate.java create mode 100644 libjava/classpath/java/security/cert/CertificateEncodingException.java create mode 100644 libjava/classpath/java/security/cert/CertificateException.java create mode 100644 libjava/classpath/java/security/cert/CertificateExpiredException.java create mode 100644 libjava/classpath/java/security/cert/CertificateFactory.java create mode 100644 libjava/classpath/java/security/cert/CertificateFactorySpi.java create mode 100644 libjava/classpath/java/security/cert/CertificateNotYetValidException.java create mode 100644 libjava/classpath/java/security/cert/CertificateParsingException.java create mode 100644 libjava/classpath/java/security/cert/CollectionCertStoreParameters.java create mode 100644 libjava/classpath/java/security/cert/LDAPCertStoreParameters.java create mode 100644 libjava/classpath/java/security/cert/PKIXBuilderParameters.java create mode 100644 libjava/classpath/java/security/cert/PKIXCertPathBuilderResult.java create mode 100644 libjava/classpath/java/security/cert/PKIXCertPathChecker.java create mode 100644 libjava/classpath/java/security/cert/PKIXCertPathValidatorResult.java create mode 100644 libjava/classpath/java/security/cert/PKIXParameters.java create mode 100644 libjava/classpath/java/security/cert/PolicyNode.java create mode 100644 libjava/classpath/java/security/cert/PolicyQualifierInfo.java create mode 100644 libjava/classpath/java/security/cert/TrustAnchor.java create mode 100644 libjava/classpath/java/security/cert/X509CRL.java create mode 100644 libjava/classpath/java/security/cert/X509CRLEntry.java create mode 100644 libjava/classpath/java/security/cert/X509CRLSelector.java create mode 100644 libjava/classpath/java/security/cert/X509CertSelector.java create mode 100644 libjava/classpath/java/security/cert/X509Certificate.java create mode 100644 libjava/classpath/java/security/cert/X509Extension.java create mode 100644 libjava/classpath/java/security/cert/package.html create mode 100644 libjava/classpath/java/security/interfaces/DSAKey.java create mode 100644 libjava/classpath/java/security/interfaces/DSAKeyPairGenerator.java create mode 100644 libjava/classpath/java/security/interfaces/DSAParams.java create mode 100644 libjava/classpath/java/security/interfaces/DSAPrivateKey.java create mode 100644 libjava/classpath/java/security/interfaces/DSAPublicKey.java create mode 100644 libjava/classpath/java/security/interfaces/RSAKey.java create mode 100644 libjava/classpath/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java create mode 100644 libjava/classpath/java/security/interfaces/RSAPrivateCrtKey.java create mode 100644 libjava/classpath/java/security/interfaces/RSAPrivateKey.java create mode 100644 libjava/classpath/java/security/interfaces/RSAPublicKey.java create mode 100644 libjava/classpath/java/security/interfaces/package.html create mode 100644 libjava/classpath/java/security/package.html create mode 100644 libjava/classpath/java/security/spec/AlgorithmParameterSpec.java create mode 100644 libjava/classpath/java/security/spec/DSAParameterSpec.java create mode 100644 libjava/classpath/java/security/spec/DSAPrivateKeySpec.java create mode 100644 libjava/classpath/java/security/spec/DSAPublicKeySpec.java create mode 100644 libjava/classpath/java/security/spec/EncodedKeySpec.java create mode 100644 libjava/classpath/java/security/spec/InvalidKeySpecException.java create mode 100644 libjava/classpath/java/security/spec/InvalidParameterSpecException.java create mode 100644 libjava/classpath/java/security/spec/KeySpec.java create mode 100644 libjava/classpath/java/security/spec/PKCS8EncodedKeySpec.java create mode 100644 libjava/classpath/java/security/spec/PSSParameterSpec.java create mode 100644 libjava/classpath/java/security/spec/RSAKeyGenParameterSpec.java create mode 100644 libjava/classpath/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java create mode 100644 libjava/classpath/java/security/spec/RSAOtherPrimeInfo.java create mode 100644 libjava/classpath/java/security/spec/RSAPrivateCrtKeySpec.java create mode 100644 libjava/classpath/java/security/spec/RSAPrivateKeySpec.java create mode 100644 libjava/classpath/java/security/spec/RSAPublicKeySpec.java create mode 100644 libjava/classpath/java/security/spec/X509EncodedKeySpec.java create mode 100644 libjava/classpath/java/security/spec/package.html create mode 100644 libjava/classpath/java/sql/Array.java create mode 100644 libjava/classpath/java/sql/BatchUpdateException.java create mode 100644 libjava/classpath/java/sql/Blob.java create mode 100644 libjava/classpath/java/sql/CallableStatement.java create mode 100644 libjava/classpath/java/sql/Clob.java create mode 100644 libjava/classpath/java/sql/Connection.java create mode 100644 libjava/classpath/java/sql/DataTruncation.java create mode 100644 libjava/classpath/java/sql/DatabaseMetaData.java create mode 100644 libjava/classpath/java/sql/Date.java create mode 100644 libjava/classpath/java/sql/Driver.java create mode 100644 libjava/classpath/java/sql/DriverManager.java create mode 100644 libjava/classpath/java/sql/DriverPropertyInfo.java create mode 100644 libjava/classpath/java/sql/ParameterMetaData.java create mode 100644 libjava/classpath/java/sql/PreparedStatement.java create mode 100644 libjava/classpath/java/sql/Ref.java create mode 100644 libjava/classpath/java/sql/ResultSet.java create mode 100644 libjava/classpath/java/sql/ResultSetMetaData.java create mode 100644 libjava/classpath/java/sql/SQLData.java create mode 100644 libjava/classpath/java/sql/SQLException.java create mode 100644 libjava/classpath/java/sql/SQLInput.java create mode 100644 libjava/classpath/java/sql/SQLOutput.java create mode 100644 libjava/classpath/java/sql/SQLPermission.java create mode 100644 libjava/classpath/java/sql/SQLWarning.java create mode 100644 libjava/classpath/java/sql/Savepoint.java create mode 100644 libjava/classpath/java/sql/Statement.java create mode 100644 libjava/classpath/java/sql/Struct.java create mode 100644 libjava/classpath/java/sql/Time.java create mode 100644 libjava/classpath/java/sql/Timestamp.java create mode 100644 libjava/classpath/java/sql/Types.java create mode 100644 libjava/classpath/java/sql/package.html create mode 100644 libjava/classpath/java/text/Annotation.java create mode 100644 libjava/classpath/java/text/AttributedCharacterIterator.java create mode 100644 libjava/classpath/java/text/AttributedString.java create mode 100644 libjava/classpath/java/text/AttributedStringIterator.java create mode 100644 libjava/classpath/java/text/BreakIterator.java create mode 100644 libjava/classpath/java/text/CharacterIterator.java create mode 100644 libjava/classpath/java/text/ChoiceFormat.java create mode 100644 libjava/classpath/java/text/CollationElementIterator.java create mode 100644 libjava/classpath/java/text/CollationKey.java create mode 100644 libjava/classpath/java/text/Collator.java create mode 100644 libjava/classpath/java/text/DateFormat.java create mode 100644 libjava/classpath/java/text/DateFormatSymbols.java create mode 100644 libjava/classpath/java/text/DecimalFormat.java create mode 100644 libjava/classpath/java/text/DecimalFormatSymbols.java create mode 100644 libjava/classpath/java/text/FieldPosition.java create mode 100644 libjava/classpath/java/text/Format.java create mode 100644 libjava/classpath/java/text/MessageFormat.java create mode 100644 libjava/classpath/java/text/NumberFormat.java create mode 100644 libjava/classpath/java/text/ParseException.java create mode 100644 libjava/classpath/java/text/ParsePosition.java create mode 100644 libjava/classpath/java/text/RuleBasedCollator.java create mode 100644 libjava/classpath/java/text/SimpleDateFormat.java create mode 100644 libjava/classpath/java/text/StringCharacterIterator.java create mode 100644 libjava/classpath/java/text/class-dependencies.conf create mode 100644 libjava/classpath/java/text/package.html create mode 100644 libjava/classpath/java/util/.cvsignore create mode 100644 libjava/classpath/java/util/AbstractCollection.java create mode 100644 libjava/classpath/java/util/AbstractList.java create mode 100644 libjava/classpath/java/util/AbstractMap.java create mode 100644 libjava/classpath/java/util/AbstractSequentialList.java create mode 100644 libjava/classpath/java/util/AbstractSet.java create mode 100644 libjava/classpath/java/util/ArrayList.java create mode 100644 libjava/classpath/java/util/Arrays.java create mode 100644 libjava/classpath/java/util/BitSet.java create mode 100644 libjava/classpath/java/util/Calendar.java create mode 100644 libjava/classpath/java/util/Collection.java create mode 100644 libjava/classpath/java/util/Collections.java create mode 100644 libjava/classpath/java/util/Comparator.java create mode 100644 libjava/classpath/java/util/ConcurrentModificationException.java create mode 100644 libjava/classpath/java/util/Currency.java create mode 100644 libjava/classpath/java/util/Date.java create mode 100644 libjava/classpath/java/util/Dictionary.java create mode 100644 libjava/classpath/java/util/EmptyStackException.java create mode 100644 libjava/classpath/java/util/Enumeration.java create mode 100644 libjava/classpath/java/util/EventListener.java create mode 100644 libjava/classpath/java/util/EventListenerProxy.java create mode 100644 libjava/classpath/java/util/EventObject.java create mode 100644 libjava/classpath/java/util/GregorianCalendar.java create mode 100644 libjava/classpath/java/util/HashMap.java create mode 100644 libjava/classpath/java/util/HashSet.java create mode 100644 libjava/classpath/java/util/Hashtable.java create mode 100644 libjava/classpath/java/util/IdentityHashMap.java create mode 100644 libjava/classpath/java/util/Iterator.java create mode 100644 libjava/classpath/java/util/LinkedHashMap.java create mode 100644 libjava/classpath/java/util/LinkedHashSet.java create mode 100644 libjava/classpath/java/util/LinkedList.java create mode 100644 libjava/classpath/java/util/List.java create mode 100644 libjava/classpath/java/util/ListIterator.java create mode 100644 libjava/classpath/java/util/ListResourceBundle.java create mode 100644 libjava/classpath/java/util/Locale.java create mode 100644 libjava/classpath/java/util/Map.java create mode 100644 libjava/classpath/java/util/MissingResourceException.java create mode 100644 libjava/classpath/java/util/NoSuchElementException.java create mode 100644 libjava/classpath/java/util/Observable.java create mode 100644 libjava/classpath/java/util/Observer.java create mode 100644 libjava/classpath/java/util/Properties.java create mode 100644 libjava/classpath/java/util/PropertyPermission.java create mode 100644 libjava/classpath/java/util/PropertyPermissionCollection.java create mode 100644 libjava/classpath/java/util/PropertyResourceBundle.java create mode 100644 libjava/classpath/java/util/Random.java create mode 100644 libjava/classpath/java/util/RandomAccess.java create mode 100644 libjava/classpath/java/util/ResourceBundle.java create mode 100644 libjava/classpath/java/util/Set.java create mode 100644 libjava/classpath/java/util/SimpleTimeZone.java create mode 100644 libjava/classpath/java/util/SortedMap.java create mode 100644 libjava/classpath/java/util/SortedSet.java create mode 100644 libjava/classpath/java/util/Stack.java create mode 100644 libjava/classpath/java/util/StringTokenizer.java create mode 100644 libjava/classpath/java/util/TimeZone.java create mode 100644 libjava/classpath/java/util/Timer.java create mode 100644 libjava/classpath/java/util/TimerTask.java create mode 100644 libjava/classpath/java/util/TooManyListenersException.java create mode 100644 libjava/classpath/java/util/TreeMap.java create mode 100644 libjava/classpath/java/util/TreeSet.java create mode 100644 libjava/classpath/java/util/Vector.java create mode 100644 libjava/classpath/java/util/WeakHashMap.java create mode 100644 libjava/classpath/java/util/class-dependencies.conf create mode 100644 libjava/classpath/java/util/jar/Attributes.java create mode 100644 libjava/classpath/java/util/jar/JarEntry.java create mode 100644 libjava/classpath/java/util/jar/JarException.java create mode 100644 libjava/classpath/java/util/jar/JarFile.java create mode 100644 libjava/classpath/java/util/jar/JarInputStream.java create mode 100644 libjava/classpath/java/util/jar/JarOutputStream.java create mode 100644 libjava/classpath/java/util/jar/Manifest.java create mode 100644 libjava/classpath/java/util/jar/package.html create mode 100644 libjava/classpath/java/util/logging/ConsoleHandler.java create mode 100644 libjava/classpath/java/util/logging/ErrorManager.java create mode 100644 libjava/classpath/java/util/logging/FileHandler.java create mode 100644 libjava/classpath/java/util/logging/Filter.java create mode 100644 libjava/classpath/java/util/logging/Formatter.java create mode 100644 libjava/classpath/java/util/logging/Handler.java create mode 100644 libjava/classpath/java/util/logging/Level.java create mode 100644 libjava/classpath/java/util/logging/LogManager.java create mode 100644 libjava/classpath/java/util/logging/LogRecord.java create mode 100644 libjava/classpath/java/util/logging/Logger.java create mode 100644 libjava/classpath/java/util/logging/LoggingPermission.java create mode 100644 libjava/classpath/java/util/logging/MemoryHandler.java create mode 100644 libjava/classpath/java/util/logging/SimpleFormatter.java create mode 100644 libjava/classpath/java/util/logging/SocketHandler.java create mode 100644 libjava/classpath/java/util/logging/StreamHandler.java create mode 100644 libjava/classpath/java/util/logging/XMLFormatter.java create mode 100644 libjava/classpath/java/util/logging/package.html create mode 100644 libjava/classpath/java/util/package.html create mode 100644 libjava/classpath/java/util/prefs/AbstractPreferences.java create mode 100644 libjava/classpath/java/util/prefs/BackingStoreException.java create mode 100644 libjava/classpath/java/util/prefs/InvalidPreferencesFormatException.java create mode 100644 libjava/classpath/java/util/prefs/NodeChangeEvent.java create mode 100644 libjava/classpath/java/util/prefs/NodeChangeListener.java create mode 100644 libjava/classpath/java/util/prefs/PreferenceChangeEvent.java create mode 100644 libjava/classpath/java/util/prefs/PreferenceChangeListener.java create mode 100644 libjava/classpath/java/util/prefs/Preferences.java create mode 100644 libjava/classpath/java/util/prefs/PreferencesFactory.java create mode 100644 libjava/classpath/java/util/prefs/package.html create mode 100644 libjava/classpath/java/util/regex/Matcher.java create mode 100644 libjava/classpath/java/util/regex/Pattern.java create mode 100644 libjava/classpath/java/util/regex/PatternSyntaxException.java create mode 100644 libjava/classpath/java/util/regex/package.html create mode 100644 libjava/classpath/java/util/zip/Adler32.java create mode 100644 libjava/classpath/java/util/zip/CRC32.java create mode 100644 libjava/classpath/java/util/zip/CheckedInputStream.java create mode 100644 libjava/classpath/java/util/zip/CheckedOutputStream.java create mode 100644 libjava/classpath/java/util/zip/Checksum.java create mode 100644 libjava/classpath/java/util/zip/DataFormatException.java create mode 100644 libjava/classpath/java/util/zip/Deflater.java create mode 100644 libjava/classpath/java/util/zip/DeflaterConstants.java create mode 100644 libjava/classpath/java/util/zip/DeflaterEngine.java create mode 100644 libjava/classpath/java/util/zip/DeflaterHuffman.java create mode 100644 libjava/classpath/java/util/zip/DeflaterOutputStream.java create mode 100644 libjava/classpath/java/util/zip/DeflaterPending.java create mode 100644 libjava/classpath/java/util/zip/GZIPInputStream.java create mode 100644 libjava/classpath/java/util/zip/GZIPOutputStream.java create mode 100644 libjava/classpath/java/util/zip/Inflater.java create mode 100644 libjava/classpath/java/util/zip/InflaterDynHeader.java create mode 100644 libjava/classpath/java/util/zip/InflaterHuffmanTree.java create mode 100644 libjava/classpath/java/util/zip/InflaterInputStream.java create mode 100644 libjava/classpath/java/util/zip/OutputWindow.java create mode 100644 libjava/classpath/java/util/zip/PendingBuffer.java create mode 100644 libjava/classpath/java/util/zip/StreamManipulator.java create mode 100644 libjava/classpath/java/util/zip/ZipConstants.java create mode 100644 libjava/classpath/java/util/zip/ZipEntry.java create mode 100644 libjava/classpath/java/util/zip/ZipException.java create mode 100644 libjava/classpath/java/util/zip/ZipFile.java create mode 100644 libjava/classpath/java/util/zip/ZipInputStream.java create mode 100644 libjava/classpath/java/util/zip/ZipOutputStream.java create mode 100644 libjava/classpath/java/util/zip/package.html (limited to 'libjava/classpath/java') diff --git a/libjava/classpath/java/applet/Applet.java b/libjava/classpath/java/applet/Applet.java new file mode 100644 index 0000000..d0610ba --- /dev/null +++ b/libjava/classpath/java/applet/Applet.java @@ -0,0 +1,524 @@ +/* Applet.java -- Java base applet class + Copyright (C) 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 java.applet; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Panel; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Locale; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * This is the base applet class. An applet is a Java program that + * runs inside a web browser or other applet viewer in a restricted + * environment. + * + *

To be useful, a subclass should override at least start(). Also useful + * are init, stop, and destroy for control purposes, and getAppletInfo and + * getParameterInfo for descriptive purposes. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Applet extends Panel +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -5836846270535785031L; + + /** The applet stub for this applet. */ + private transient AppletStub stub; + + /** Some applets call setSize in their constructors. In that case, + these fields are used to store width and height values until a + stub is set. */ + private transient int width; + private transient int height; + + /** + * The accessibility context for this applet. + * + * @serial the accessibleContext for this + * @since 1.2 + */ + private AccessibleContext accessibleContext; + + /** + * Default constructor for subclasses. + * + * @throws HeadlessException if in a headless environment + */ + public Applet() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } + + /** + * The browser calls this method to set the applet's stub, which is the + * low level interface to the browser. Manually setting this to null is + * asking for problems down the road. + * + * @param stub the applet stub for this applet + */ + public final void setStub(AppletStub stub) + { + this.stub = stub; + + if (width != 0 && height != 0) + stub.appletResize (width, height); + } + + /** + * Tests whether or not this applet is currently active. An applet is active + * just before the browser invokes start(), and becomes inactive just + * before the browser invokes stop(). + * + * @return true if this applet is active + */ + public boolean isActive() + { + return stub.isActive(); + } + + /** + * Returns the basename URL of the document this applet is embedded in. This + * is everything up to the final '/'. + * + * @return the URL of the document this applet is embedded in + * @see #getCodeBase() + */ + public URL getDocumentBase() + { + return stub.getDocumentBase(); + } + + /** + * Returns the URL of the code base for this applet. + * + * @return the URL of the code base for this applet + */ + public URL getCodeBase() + { + return stub.getCodeBase(); + } + + /** + * Returns the value of the specified parameter that was specified in + * the <APPLET> tag for this applet. + * + * @param name the parameter name + * @return the parameter value, or null if the parameter does not exist + * @throws NullPointerException if name is null + */ + public String getParameter(String name) + { + return stub.getParameter(name); + } + + /** + * Returns the applet context for this applet. + * + * @return the applet context for this applet + */ + public AppletContext getAppletContext() + { + return stub.getAppletContext(); + } + + /** + * Requests that the applet window for this applet be resized. + * + * @param width the new width in pixels + * @param height the new height in pixels + */ + public void resize(int width, int height) + { + if (stub == null) + { + this.width = width; + this.height = height; + } + else + stub.appletResize(width, height); + } + + /** + * Requests that the applet window for this applet be resized. + * + * @param dim the requested dimensions + * @throws NullPointerException if dim is null + */ + public void resize(Dimension dim) + { + resize(dim.width, dim.height); + } + + /** + * Displays the specified message in the status window if that window + * exists. + * + * @param message the status message, may be null + */ + public void showStatus(String message) + { + getAppletContext().showStatus(message); + } + + /** + * Returns an image from the specified URL. Note that the image is not + * actually retrieved until the applet attempts to display it, so this + * method returns immediately. + * + * @param url the URL of the image + * @return the retrieved image + * @throws NullPointerException if url is null + */ + public Image getImage(URL url) + { + return getAppletContext().getImage(url); + } + + /** + * Returns an image from the specified absolute URL, and relative path + * from that URL. Note that the image is not actually retrieved until the + * applet attempts to display it, so this method returns immediately. + * This calls getImage(new URL(url, name)), but if building + * the new URL fails, this returns null. + * + * @param url the base URL of the image + * @param name the name of the image relative to the URL + * @return the retrieved image, or null on failure + * @see #getImage(URL) + */ + public Image getImage(URL url, String name) + { + try + { + return getImage(new URL(url, name)); + } + catch (MalformedURLException e) + { + return null; + } + } + + /** + * Returns an audio clip from the specified URL. This clip is not tied to + * any particular applet. + * + * XXX Classpath does not yet implement this. + * + * @param url the URL of the audio clip + * @return the retrieved audio clip + * @throws NullPointerException if url is null + * @see #getAudioClip(URL) + * @since 1.2 + */ + public static final AudioClip newAudioClip(URL url) + { + // This requires an implementation of AudioClip in gnu.java.applet. + throw new Error("Not implemented"); + } + + /** + * Returns an audio clip from the specified URL. Note that the clip is not + * actually retrieved until the applet attempts to play it, so this method + * returns immediately. + * + * @param url the URL of the audio clip + * @return the retrieved audio clip + * @throws NullPointerException if url is null + */ + public AudioClip getAudioClip(URL url) + { + return getAppletContext().getAudioClip(url); + } + + /** + * Returns an audio clip from the specified absolute URL, and relative path + * from that URL. Note that the clip is not actually retrieved until the + * applet attempts to play it, so this method returns immediately. This + * calls getAudioClip(new URL(url, name)), but if building + * the new URL fails, this returns null. + * + * @param url the base URL of the audio clip + * @param name the name of the clip relative to the URL + * @return the retrieved audio clip, or null on failure + * @see #getAudioClip(URL) + */ + public AudioClip getAudioClip(URL url, String name) + { + try + { + return getAudioClip(new URL(url, name)); + } + catch (MalformedURLException e) + { + return null; + } + } + + /** + * Returns a descriptive string with applet defined information. The + * implementation in this class returns null, so subclasses + * must override to return information. + * + * @return a string describing the author, version, and applet copyright + */ + public String getAppletInfo() + { + return null; + } + + /** + * Returns the locale for this applet, if it has been set. If no applet + * specific locale has been set, the default locale is returned. + * + * @return the locale for this applet + * @see Component#setLocale(Locale) + * @since 1.1 + */ + public Locale getLocale() + { + return super.getLocale(); + } + + /** + * Returns a list of parameters this applet supports. Each element of + * the outer array is an array of three strings with the name of the + * parameter, the data type or valid values, and a description. This + * method is optional and the default implementation returns null. + * + * @return the list of parameters supported by this applet + */ + public String[][] getParameterInfo() + { + return null; + } + + /** + * Loads and plays the audio clip pointed to by the specified URL. This does + * nothing if the URL does not point to a valid audio clip. + * + * @param url the URL of the audio clip + * @throws NullPointerException if url is null + * @see #getAudioClip(URL) + */ + public void play(URL url) + { + AudioClip ac = getAudioClip(url); + try + { + ac.play(); + } + catch (Exception ignored) + { + } + } + + /** + * Loads and plays the audio clip pointed to by the specified absolute URL, + * and relative path from that URL. This does nothing if the URL cannot be + * constructed, or if it does not point to a valid audio clip. + * + * @param url the base URL of the audio clip + * @param name the name of the audio clip relative to the URL + * @see #getAudioClip(URL, String) + * @see #play(URL) + */ + public void play(URL url, String name) + { + try + { + getAudioClip(url, name).play(); + } + catch (Exception ignored) + { + } + } + + /** + * This method is called when the applet is first loaded, before start(). + * The default implementation does nothing; override to do any one-time + * initialization. + * + * @see #start() + * @see #stop() + * @see #destroy() + */ + public void init() + { + } + + /** + * This method is called when the applet should start running. This is + * normally each time a web page containing it is loaded. The default + * implemention does nothing; override for your applet to be useful. + * + * @see #init() + * @see #stop() + * @see #destroy() + */ + public void start() + { + } + + /** + * This method is called when the applet should stop running. This is + * normally when the next web page is loaded. The default implementation + * does nothing; override for your applet to stop using resources when + * it is no longer visible, but may be restarted soon. + * + * @see #init() + * @see #start() + * @see #destroy() + */ + public void stop() + { + } + + /** + * This method is called when the applet is being unloaded. The default + * implementation does nothing; override for your applet to clean up + * resources on exit. + * + * @see #init() + * @see #start() + * @see #stop() + */ + public void destroy() + { + } + + /** + * Gets the AccessibleContext associated with this applet, creating one if + * necessary. This always returns an instance of {@link AccessibleApplet}. + * + * @return the accessibility context of this applet + * @since 1.3 + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleApplet(); + return accessibleContext; + } + + /** + * Read an applet from an object stream. This checks for a headless + * environment, then does the normal read. + * + * @param s the stream to read from + * @throws ClassNotFoundException if a class is not found + * @throws IOException if deserialization fails + * @throws HeadlessException if this is a headless environment + * @see GraphicsEnvironment#isHeadless() + * @since 1.4 + */ + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + s.defaultReadObject(); + } + + /** + * This class provides accessibility support for Applets, and is the + * runtime type returned by {@link #getAccessibleContext()}. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + */ + protected class AccessibleApplet extends AccessibleAWTPanel + { + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 8127374778187708896L; + + /** + * The default constructor. + */ + protected AccessibleApplet() + { + } + + /** + * Get the role of this accessible object, a frame. + * + * @return the role of the object + * @see AccessibleRole#FRAME + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.FRAME; + } + + /** + * Get the state set of this accessible object. In addition to the default + * states of a Component, the applet can also be active. + * + * @return the role of the object + * @see AccessibleState + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet s = super.getAccessibleStateSet(); + if (isActive()) + s.add(AccessibleState.ACTIVE); + return s; + } + } // class AccessibleApplet +} // class Applet diff --git a/libjava/classpath/java/applet/AppletContext.java b/libjava/classpath/java/applet/AppletContext.java new file mode 100644 index 0000000..a17508f --- /dev/null +++ b/libjava/classpath/java/applet/AppletContext.java @@ -0,0 +1,154 @@ +/* AppletContext.java -- access the applet's runtime environment + Copyright (C) 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 java.applet; + +import java.awt.Image; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.Iterator; + +/** + * This interface allows an applet access to the browser to retrieve + * additional data files and display documents. It also allows the + * applet to find out other applets in the same document. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface AppletContext +{ + /** + * Returns an audio clip from the specified URL. + * + * @param url the URL of the audio clip + * @return the retrieved audio clip + * @throws NullPointerException if url is null + */ + AudioClip getAudioClip(URL url); + + /** + * Returns an image from the specified URL. Note that the image is not + * actually retrieved until the applet attempts to display it, so this + * method returns immediately. + * + * @param url the absolute URL of the image + * @return the retrieved image + * @throws NullPointerException if url is null + */ + Image getImage(URL url); + + /** + * Returns the applet in the document for this object that has the + * specified name. + * + * @param name the applet name + * @return the requested applet, or null if not found + */ + Applet getApplet(String name); + + /** + * Returns a list of all the applets in the document for this object. + * + * @return a list of all the applets + */ + Enumeration getApplets(); + + /** + * Displays the web page pointed to by the specified URL in the window + * for this object. This page replaces the document that is currently + * there. + * + * @param url the URL of the web page to load; unspecified on an error + */ + void showDocument(URL url); + + /** + * Displays the web page pointed to be the sepcified URL in the window + * with the specified name. The standard names "_top", "_blank", + * "_parent", and "_self" are allowed. An applet viewer may disregard + * this request. + * + * @param url the URL of the web page to load + * @param target the target window + */ + void showDocument(URL url, String target); + + /** + * Displays the specified message in the status window if that window + * exists. + * + * @param message the status message, may be null + */ + void showStatus(String message); + + /** + * Associate a stream to a key for this applet context, possibly replacing + * the old value. Stream associations are local to the applet context, for + * security purposes. + * + * @param key the key to associate with + * @param stream the stream value to tie to the key, or null to remove + * @throws IOException if the stream is too large + * @since 1.4 + */ + void setStream(String key, InputStream stream) throws IOException; + + /** + * Return the stream associated with a given key in this applet context, or + * null if nothing is associated. Stream associations are local to the + * applet context, for security purposes. + * + * @param key the key to look up + * @return the associated stream, or null + * @since 1.4 + */ + InputStream getStream(String key); + + /** + * Iterate over all keys that have associated streams. Stream associated + * are local to the applet context, for security purposes. + * + * @return an iterator over the association keys + * @since 1.4 + */ + Iterator getStreamKeys(); +} // interface AppletContext diff --git a/libjava/classpath/java/applet/AppletStub.java b/libjava/classpath/java/applet/AppletStub.java new file mode 100644 index 0000000..879a016 --- /dev/null +++ b/libjava/classpath/java/applet/AppletStub.java @@ -0,0 +1,103 @@ +/* AppletStub.java -- low level interface to the browser + Copyright (C) 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 java.applet; + +import java.net.URL; + +/** + * This interface is the low level interface between the applet and the + * browser. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Applet#setStub(AppletStub) + * @since 1.0 + * @status updated to 1.4 + */ +public interface AppletStub +{ + /** + * Tests whether or not this applet is currently active. An applet is active + * just before the browser invokes start(), and becomes inactive just + * before the browser invokes stop(). + * + * @return true if this applet is active + */ + boolean isActive(); + + /** + * Returns the basename URL of the document this applet is embedded in. This + * is everything up to the final '/'. + * + * @return the URL of the document this applet is embedded in + * @see #getCodeBase() + */ + URL getDocumentBase(); + + /** + * Returns the URL of the code base for this applet. + * + * @return the URL of the code base for this applet + */ + URL getCodeBase(); + + /** + * Returns the value of the specified parameter that was specified in + * the <APPLET> tag for this applet. + * + * @param name the parameter name + * @return the parameter value, or null if the parameter does not exist + * @throws NullPointerException if name is null + */ + String getParameter(String name); + + /** + * Returns the applet context for this applet. + * + * @return the applet context for this applet + */ + AppletContext getAppletContext(); + + /** + * Requests that the applet window for this applet be resized. + * + * @param width the new width in pixels + * @param height the new height in pixels + */ + void appletResize(int width, int height); +} // interface AppletStub diff --git a/libjava/classpath/java/applet/AudioClip.java b/libjava/classpath/java/applet/AudioClip.java new file mode 100644 index 0000000..eeafa8a --- /dev/null +++ b/libjava/classpath/java/applet/AudioClip.java @@ -0,0 +1,68 @@ +/* AudioClip.java -- play an audio clip in an applet + Copyright (C) 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 java.applet; + + +/** + * This interface provides a simple mechanism for playing audio clips. + * If multiple clips are played at once, the browser combines them into a + * composite clip. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface AudioClip +{ + /** + * Plays the audio clip starting from the beginning. + */ + void play(); + + /** + * Stops playing this audio clip. There is no mechanism for restarting + * at the point where the clip is stopped. + */ + void stop(); + + /** + * Plays this audio clip in a continuous loop. + */ + void loop(); +} // interface AudioClip diff --git a/libjava/classpath/java/applet/package.html b/libjava/classpath/java/applet/package.html new file mode 100644 index 0000000..f2cbc57 --- /dev/null +++ b/libjava/classpath/java/applet/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - java.applet + + +

Classes and interfaces for small embeddable applications +often used in web pages.

+ + + diff --git a/libjava/classpath/java/awt/AWTError.java b/libjava/classpath/java/awt/AWTError.java new file mode 100644 index 0000000..80356ee --- /dev/null +++ b/libjava/classpath/java/awt/AWTError.java @@ -0,0 +1,64 @@ +/* AWTError.java -- A serious AWT error occurred. + Copyright (C) 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 java.awt; + +/** + * This error is thrown when a critical Abstract Window Toolkit (AWT) error + * occurs. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class AWTError extends Error +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -1819846354050686206L; + + /** + * Create a new instance with the specified descriptive error message. + * + * @param message the descriptive error message + */ + public AWTError(String message) + { + super(message); + } +} // class AWTError diff --git a/libjava/classpath/java/awt/AWTEvent.java b/libjava/classpath/java/awt/AWTEvent.java new file mode 100644 index 0000000..ad9533f --- /dev/null +++ b/libjava/classpath/java/awt/AWTEvent.java @@ -0,0 +1,278 @@ + +/* AWTEvent.java -- the root event in AWT + Copyright (C) 1999, 2000, 2002, 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 java.awt; + +import java.util.EventObject; + +/** + * AWTEvent is the root event class for all AWT events in the JDK 1.1 event + * model. It supersedes the Event class from JDK 1.0. Subclasses outside of + * the java.awt package should have IDs greater than RESERVED_ID_MAX. + * + *

Event masks defined here are used by components in + * enableEvents to select event types not selected by registered + * listeners. Event masks are appropriately set when registering on + * components. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class AWTEvent extends EventObject +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -1825314779160409405L; + + /** + * The ID of the event. + * + * @see #getID() + * @see #AWTEvent(Object, int) + * @serial the identifier number of this event + */ + protected int id; + + /** + * Indicates if the event has been consumed. False mean it is passed to + * the peer, true means it has already been processed. Semantic events + * generated by low-level events always have the value true. + * + * @see #consume() + * @see #isConsumed() + * @serial whether the event has been consumed + */ + protected boolean consumed; + + /** + * Who knows? It's in the serial version. + * + * @serial No idea what this is for. + */ + byte[] bdata; + + /** Mask for selecting component events. */ + public static final long COMPONENT_EVENT_MASK = 0x00001; + + /** Mask for selecting container events. */ + public static final long CONTAINER_EVENT_MASK = 0x00002; + + /** Mask for selecting component focus events. */ + public static final long FOCUS_EVENT_MASK = 0x00004; + + /** Mask for selecting keyboard events. */ + public static final long KEY_EVENT_MASK = 0x00008; + + /** Mask for mouse button events. */ + public static final long MOUSE_EVENT_MASK = 0x00010; + + /** Mask for mouse motion events. */ + public static final long MOUSE_MOTION_EVENT_MASK = 0x00020; + + /** Mask for window events. */ + public static final long WINDOW_EVENT_MASK = 0x00040; + + /** Mask for action events. */ + public static final long ACTION_EVENT_MASK = 0x00080; + + /** Mask for adjustment events. */ + public static final long ADJUSTMENT_EVENT_MASK = 0x00100; + + /** Mask for item events. */ + public static final long ITEM_EVENT_MASK = 0x00200; + + /** Mask for text events. */ + public static final long TEXT_EVENT_MASK = 0x00400; + + /** + * Mask for input method events. + * @since 1.3 + */ + public static final long INPUT_METHOD_EVENT_MASK = 0x00800; + + /** + * Mask if input methods are enabled. Package visible only. + */ + static final long INPUT_ENABLED_EVENT_MASK = 0x01000; + + /** + * Mask for paint events. + * @since 1.3 + */ + public static final long PAINT_EVENT_MASK = 0x02000; + + /** + * Mask for invocation events. + * @since 1.3 + */ + public static final long INVOCATION_EVENT_MASK = 0x04000; + + /** + * Mask for hierarchy events. + * @since 1.3 + */ + public static final long HIERARCHY_EVENT_MASK = 0x08000; + + /** + * Mask for hierarchy bounds events. + * @since 1.3 + */ + public static final long HIERARCHY_BOUNDS_EVENT_MASK = 0x10000; + + /** + * Mask for mouse wheel events. + * @since 1.4 + */ + public static final long MOUSE_WHEEL_EVENT_MASK = 0x20000; + + /** + * Mask for window state events. + * @since 1.4 + */ + public static final long WINDOW_STATE_EVENT_MASK = 0x40000; + + /** + * Mask for window focus events. + * @since 1.4 + */ + public static final long WINDOW_FOCUS_EVENT_MASK = 0x80000; + + /** + * This is the highest number for event ids that are reserved for use by + * the AWT system itself. Subclasses outside of java.awt should use higher + * ids. + */ + public static final int RESERVED_ID_MAX = 1999; + + + /** + * Initializes a new AWTEvent from the old Java 1.0 event object. + * + * @param event the old-style event + * @throws NullPointerException if event is null + */ + public AWTEvent(Event event) + { + this(event.target, event.id); + consumed = event.consumed; + } + + /** + * Create an event on the specified source object and id. + * + * @param source the object that caused the event + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public AWTEvent(Object source, int id) + { + super(source); + this.id = id; + } + + /** + * Retarget the event, such as converting a heavyweight component to a + * lightweight child of the original. This is not for general use, but + * is for event targeting systems like KeyboardFocusManager. + * + * @param source the new source + */ + public void setSource(Object source) + { + this.source = source; + } + + /** + * Returns the event type id. + * + * @return the id number of this event + */ + public int getID() + { + return id; + } + + /** + * Create a string that represents this event in the format + * classname[eventstring] on sourcecomponentname. + * + * @return a string representing this event + */ + public String toString () + { + String string = getClass ().getName () + "[" + paramString () + "] on " + + source; + + return string; + } + + /** + * Returns a string representation of the state of this event. It may be + * empty, but must not be null; it is implementation defined. + * + * @return a string representation of this event + */ + public String paramString() + { + return ""; + } + + /** + * Consumes this event so that it will not be processed in the default + * manner. + */ + protected void consume() + { + consumed = true; + } + + /** + * Tests whether not not this event has been consumed. A consumed event + * is not processed in the default manner. + * + * @return true if this event has been consumed + */ + protected boolean isConsumed() + { + return consumed; + } +} // class AWTEvent diff --git a/libjava/classpath/java/awt/AWTEventMulticaster.java b/libjava/classpath/java/awt/AWTEventMulticaster.java new file mode 100644 index 0000000..f7b9163 --- /dev/null +++ b/libjava/classpath/java/awt/AWTEventMulticaster.java @@ -0,0 +1,1209 @@ +/* AWTEventMulticaster.java -- allows multicast chaining of listeners + Copyright (C) 1999, 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 java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.TextEvent; +import java.awt.event.TextListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.awt.event.WindowListener; +import java.awt.event.WindowStateListener; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.EventListener; + +/** + * This class is used to implement a chain of event handlers. Dispatching + * using this class is thread safe. Here is a quick example of how to + * add and delete listeners using this class. For this example, we will + * assume are firing AdjustmentEvent's. However, this + * same approach is useful for all events in the java.awt.event + * package, and more if this class is subclassed. + * + *

+ * AdjustmentListener al; + * public void addAdjustmentListener(AdjustmentListener listener) + * { + * al = AWTEventMulticaster.add(al, listener); + * } + * public void removeAdjustmentListener(AdjustmentListener listener) + * { + * al = AWTEventMulticaster.remove(al, listener); + * } + * + * + *

When it come time to process an event, simply call al, + * assuming it is not null, and all listeners in the chain will + * be fired. + * + *

The first time add is called it is passed + * null and listener as its arguments. This + * starts building the chain. This class returns listener + * which becomes the new al. The next time, add + * is called with al and listener and the + * new listener is then chained to the old. + * + * @author Bryce McKinlay + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public class AWTEventMulticaster + implements ComponentListener, ContainerListener, FocusListener, KeyListener, + MouseListener, MouseMotionListener, WindowListener, + WindowFocusListener, WindowStateListener, ActionListener, + ItemListener, AdjustmentListener, TextListener, + InputMethodListener, HierarchyListener, HierarchyBoundsListener, + MouseWheelListener +{ + /** + * A variable in the event chain. + */ + protected final EventListener a; + + /** + * A variable in the event chain. + */ + protected final EventListener b; + + /** + * Initializes a new instance of AWTEventMulticaster with + * the specified event listener parameters. The parameters should not be + * null, although it is not required to enforce this with a + * NullPointerException. + * + * @param a the "a" listener object + * @param b the "b" listener object + */ + protected AWTEventMulticaster(EventListener a, EventListener b) + { + this.a = a; + this.b = b; + } + + /** + * Removes one instance of the specified listener from this multicaster + * chain. This descends recursively if either child is a multicaster, and + * returns a multicaster chain with the old listener removed. + * + * @param oldl the object to remove from this multicaster + * @return the resulting multicaster with the specified listener removed + */ + protected EventListener remove(EventListener oldl) + { + // If oldl is an immediate child, return the other child. + if (a == oldl) + return b; + if (b == oldl) + return a; + // If a and/or b are Multicaster's, search them recursively. + if (a instanceof AWTEventMulticaster) + { + EventListener newa = ((AWTEventMulticaster) a).remove(oldl); + if (newa != a) + return new AWTEventMulticaster(newa, b); + } + if (b instanceof AWTEventMulticaster) + { + EventListener newb = ((AWTEventMulticaster) b).remove(oldl); + if (newb != b) + return new AWTEventMulticaster(a, newb); + } + // oldl was not found. + return this; + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentResized(ComponentEvent e) + { + ((ComponentListener) a).componentResized(e); + ((ComponentListener) b).componentResized(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentMoved(ComponentEvent e) + { + ((ComponentListener) a).componentMoved(e); + ((ComponentListener) b).componentMoved(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentShown(ComponentEvent e) + { + ((ComponentListener) a).componentShown(e); + ((ComponentListener) b).componentShown(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentHidden(ComponentEvent e) + { + ((ComponentListener) a).componentHidden(e); + ((ComponentListener) b).componentHidden(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentAdded(ContainerEvent e) + { + ((ContainerListener) a).componentAdded(e); + ((ContainerListener) b).componentAdded(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentRemoved(ContainerEvent e) + { + ((ContainerListener) a).componentRemoved(e); + ((ContainerListener) b).componentRemoved(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void focusGained(FocusEvent e) + { + ((FocusListener) a).focusGained(e); + ((FocusListener) b).focusGained(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void focusLost(FocusEvent e) + { + ((FocusListener) a).focusLost(e); + ((FocusListener) b).focusLost(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void keyTyped(KeyEvent e) + { + ((KeyListener) a).keyTyped(e); + ((KeyListener) b).keyTyped(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void keyPressed(KeyEvent e) + { + ((KeyListener) a).keyPressed(e); + ((KeyListener) b).keyPressed(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void keyReleased(KeyEvent e) + { + ((KeyListener) a).keyReleased(e); + ((KeyListener) b).keyReleased(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseClicked(MouseEvent e) + { + ((MouseListener) a).mouseClicked(e); + ((MouseListener) b).mouseClicked(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mousePressed(MouseEvent e) + { + ((MouseListener) a).mousePressed(e); + ((MouseListener) b).mousePressed(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseReleased(MouseEvent e) + { + ((MouseListener) a).mouseReleased(e); + ((MouseListener) b).mouseReleased(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseEntered(MouseEvent e) + { + ((MouseListener) a).mouseEntered(e); + ((MouseListener) b).mouseEntered(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseExited(MouseEvent e) + { + ((MouseListener) a).mouseExited(e); + ((MouseListener) b).mouseExited(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseDragged(MouseEvent e) + { + ((MouseMotionListener) a).mouseDragged(e); + ((MouseMotionListener) b).mouseDragged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseMoved(MouseEvent e) + { + ((MouseMotionListener) a).mouseMoved(e); + ((MouseMotionListener) b).mouseMoved(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowOpened(WindowEvent e) + { + ((WindowListener) a).windowOpened(e); + ((WindowListener) b).windowOpened(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowClosing(WindowEvent e) + { + ((WindowListener) a).windowClosing(e); + ((WindowListener) b).windowClosing(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowClosed(WindowEvent e) + { + ((WindowListener) a).windowClosed(e); + ((WindowListener) b).windowClosed(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowIconified(WindowEvent e) + { + ((WindowListener) a).windowIconified(e); + ((WindowListener) b).windowIconified(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowDeiconified(WindowEvent e) + { + ((WindowListener) a).windowDeiconified(e); + ((WindowListener) b).windowDeiconified(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowActivated(WindowEvent e) + { + ((WindowListener) a).windowActivated(e); + ((WindowListener) b).windowActivated(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowDeactivated(WindowEvent e) + { + ((WindowListener) a).windowDeactivated(e); + ((WindowListener) b).windowDeactivated(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.4 + */ + public void windowStateChanged(WindowEvent e) + { + ((WindowStateListener) a).windowStateChanged(e); + ((WindowStateListener) b).windowStateChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.4 + */ + public void windowGainedFocus(WindowEvent e) + { + ((WindowFocusListener) a).windowGainedFocus(e); + ((WindowFocusListener) b).windowGainedFocus(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.4 + */ + public void windowLostFocus(WindowEvent e) + { + ((WindowFocusListener) a).windowLostFocus(e); + ((WindowFocusListener) b).windowLostFocus(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void actionPerformed(ActionEvent e) + { + ((ActionListener) a).actionPerformed(e); + ((ActionListener) b).actionPerformed(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void itemStateChanged(ItemEvent e) + { + ((ItemListener) a).itemStateChanged(e); + ((ItemListener) b).itemStateChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void adjustmentValueChanged(AdjustmentEvent e) + { + ((AdjustmentListener) a).adjustmentValueChanged(e); + ((AdjustmentListener) b).adjustmentValueChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void textValueChanged(TextEvent e) + { + ((TextListener) a).textValueChanged(e); + ((TextListener) b).textValueChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.2 + */ + public void inputMethodTextChanged(InputMethodEvent e) + { + ((InputMethodListener) a).inputMethodTextChanged(e); + ((InputMethodListener) b).inputMethodTextChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.2 + */ + public void caretPositionChanged(InputMethodEvent e) + { + ((InputMethodListener) a).caretPositionChanged(e); + ((InputMethodListener) b).caretPositionChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.3 + */ + public void hierarchyChanged(HierarchyEvent e) + { + ((HierarchyListener) a).hierarchyChanged(e); + ((HierarchyListener) b).hierarchyChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.3 + */ + public void ancestorMoved(HierarchyEvent e) + { + ((HierarchyBoundsListener) a).ancestorMoved(e); + ((HierarchyBoundsListener) b).ancestorMoved(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.3 + */ + public void ancestorResized(HierarchyEvent e) + { + ((HierarchyBoundsListener) a).ancestorResized(e); + ((HierarchyBoundsListener) b).ancestorResized(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.4 + */ + public void mouseWheelMoved(MouseWheelEvent e) + { + ((MouseWheelListener) a).mouseWheelMoved(e); + ((MouseWheelListener) b).mouseWheelMoved(e); + } + + /** + * Chain ComponentListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static ComponentListener add(ComponentListener a, ComponentListener b) + { + return (ComponentListener) addInternal(a, b); + } + + /** + * Chain ContainerListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static ContainerListener add(ContainerListener a, ContainerListener b) + { + return (ContainerListener) addInternal(a, b); + } + + /** + * Chain FocusListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static FocusListener add(FocusListener a, FocusListener b) + { + return (FocusListener) addInternal(a, b); + } + + /** + * Chain KeyListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static KeyListener add(KeyListener a, KeyListener b) + { + return (KeyListener) addInternal(a, b); + } + + /** + * Chain MouseListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static MouseListener add(MouseListener a, MouseListener b) + { + return (MouseListener) addInternal(a, b); + } + + /** + * Chain MouseMotionListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static MouseMotionListener add(MouseMotionListener a, + MouseMotionListener b) + { + return (MouseMotionListener) addInternal(a, b); + } + + /** + * Chain WindowListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static WindowListener add(WindowListener a, WindowListener b) + { + return (WindowListener) addInternal(a, b); + } + + /** + * Chain WindowStateListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.4 + */ + public static WindowStateListener add(WindowStateListener a, + WindowStateListener b) + { + return (WindowStateListener) addInternal(a, b); + } + + /** + * Chain WindowFocusListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.4 + */ + public static WindowFocusListener add(WindowFocusListener a, + WindowFocusListener b) + { + return (WindowFocusListener) addInternal(a, b); + } + + /** + * Chain ActionListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static ActionListener add(ActionListener a, ActionListener b) + { + return (ActionListener) addInternal(a, b); + } + + /** + * Chain ItemListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static ItemListener add(ItemListener a, ItemListener b) + { + return (ItemListener) addInternal(a, b); + } + + /** + * Chain AdjustmentListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static AdjustmentListener add(AdjustmentListener a, + AdjustmentListener b) + { + return (AdjustmentListener) addInternal(a, b); + } + + /** + * Chain AdjustmentListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static TextListener add(TextListener a, TextListener b) + { + return (TextListener) addInternal(a, b); + } + + /** + * Chain InputMethodListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.2 + */ + public static InputMethodListener add(InputMethodListener a, + InputMethodListener b) + { + return (InputMethodListener) addInternal(a, b); + } + + /** + * Chain HierarchyListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.3 + */ + public static HierarchyListener add(HierarchyListener a, HierarchyListener b) + { + return (HierarchyListener) addInternal(a, b); + } + + /** + * Chain HierarchyBoundsListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.3 + */ + public static HierarchyBoundsListener add(HierarchyBoundsListener a, + HierarchyBoundsListener b) + { + return (HierarchyBoundsListener) addInternal(a, b); + } + + /** + * Chain MouseWheelListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.4 + */ + public static MouseWheelListener add(MouseWheelListener a, + MouseWheelListener b) + { + return (MouseWheelListener) addInternal(a, b); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static ComponentListener remove(ComponentListener l, + ComponentListener oldl) + { + return (ComponentListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static ContainerListener remove(ContainerListener l, + ContainerListener oldl) + { + return (ContainerListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static FocusListener remove(FocusListener l, FocusListener oldl) + { + return (FocusListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static KeyListener remove(KeyListener l, KeyListener oldl) + { + return (KeyListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static MouseListener remove(MouseListener l, MouseListener oldl) + { + return (MouseListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static MouseMotionListener remove(MouseMotionListener l, + MouseMotionListener oldl) + { + return (MouseMotionListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static WindowListener remove(WindowListener l, WindowListener oldl) + { + return (WindowListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.4 + */ + public static WindowStateListener remove(WindowStateListener l, + WindowStateListener oldl) + { + return (WindowStateListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.4 + */ + public static WindowFocusListener remove(WindowFocusListener l, + WindowFocusListener oldl) + { + return (WindowFocusListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static ActionListener remove(ActionListener l, ActionListener oldl) + { + return (ActionListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static ItemListener remove(ItemListener l, ItemListener oldl) + { + return (ItemListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static AdjustmentListener remove(AdjustmentListener l, + AdjustmentListener oldl) + { + return (AdjustmentListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static TextListener remove(TextListener l, TextListener oldl) + { + return (TextListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.2 + */ + public static InputMethodListener remove(InputMethodListener l, + InputMethodListener oldl) + { + return (InputMethodListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.3 + */ + public static HierarchyListener remove(HierarchyListener l, + HierarchyListener oldl) + { + return (HierarchyListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.3 + */ + public static HierarchyBoundsListener remove(HierarchyBoundsListener l, + HierarchyBoundsListener oldl) + { + return (HierarchyBoundsListener) removeInternal(l, oldl); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.4 + */ + public static MouseWheelListener remove(MouseWheelListener l, + MouseWheelListener oldl) + { + return (MouseWheelListener) removeInternal(l, oldl); + } + + /** + * Chain EventListener a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + protected static EventListener addInternal(EventListener a, EventListener b) + { + if (a == null) + return b; + if (b == null) + return a; + return new AWTEventMulticaster(a, b); + } + + /** + * Removes the listener oldl from the listener l. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + protected static EventListener removeInternal(EventListener l, + EventListener oldl) + { + if (l == oldl) + return null; + if (l instanceof AWTEventMulticaster) + return ((AWTEventMulticaster) l).remove(oldl); + return l; + } + + /** + * Saves all Serializable listeners to a serialization stream. + * + * @param s the stream to save to + * @param k a prefix stream put before each serializable listener + * @throws IOException if serialization fails + */ + protected void saveInternal(ObjectOutputStream s, String k) + throws IOException + { + // This is not documented by Sun, but I think it is correct. + if (a instanceof AWTEventMulticaster) + ((AWTEventMulticaster) a).saveInternal(s, k); + else if (a instanceof Serializable) + { + s.writeObject(k); + s.writeObject(a); + } + if (b instanceof AWTEventMulticaster) + ((AWTEventMulticaster) b).saveInternal(s, k); + else if (b instanceof Serializable) + { + s.writeObject(k); + s.writeObject(b); + } + } + + /** + * Saves a Serializable listener chain to a serialization stream. + * + * @param s the stream to save to + * @param k a prefix stream put before each serializable listener + * @param l the listener chain to save + * @throws IOException if serialization fails + */ + protected static void save(ObjectOutputStream s, String k, EventListener l) + throws IOException + { + // This is not documented by Sun, but I think it is correct. + if (l instanceof AWTEventMulticaster) + ((AWTEventMulticaster) l).saveInternal(s, k); + else if (l instanceof Serializable) + { + s.writeObject(k); + s.writeObject(l); + } + } + + /** + * Returns an array of all chained listeners of the specified type in the + * given chain. A null listener returns an empty array, and a listener + * which is not an AWTEventMulticaster returns an array of one element. If + * no listeners in the chain are of the specified type, an empty array is + * returned. + * + * @param l the listener chain to convert to an array + * @param type the type of listeners to collect + * @return an array of the listeners of that type in the chain + * @throws ClassCastException if type is not assignable from EventListener + * @throws NullPointerException if type is null + * @throws IllegalArgumentException if type is Void.TYPE + * @since 1.4 + */ + public static EventListener[] getListeners(EventListener l, Class type) + { + ArrayList list = new ArrayList(); + if (l instanceof AWTEventMulticaster) + ((AWTEventMulticaster) l).getListeners(list, type); + else if (type.isInstance(l)) + list.add(l); + EventListener[] r = (EventListener[]) Array.newInstance(type, list.size()); + list.toArray(r); + return r; + } + + /** + * Collects all instances of the given type in the chain into the list. + * + * @param l the list to collect into + * @param type the type of listeners to collect + * @throws NullPointerException if type is null + * @see #getListeners(EventListener, Class) + */ + private void getListeners(ArrayList l, Class type) + { + if (a instanceof AWTEventMulticaster) + ((AWTEventMulticaster) a).getListeners(l, type); + else if (type.isInstance(a)) + l.add(a); + if (b instanceof AWTEventMulticaster) + ((AWTEventMulticaster) b).getListeners(l, type); + else if (type.isInstance(b)) + l.add(b); + } +} // class AWTEventMulticaster diff --git a/libjava/classpath/java/awt/AWTException.java b/libjava/classpath/java/awt/AWTException.java new file mode 100644 index 0000000..2df3dd8 --- /dev/null +++ b/libjava/classpath/java/awt/AWTException.java @@ -0,0 +1,64 @@ +/* AWTException.java -- Generic AWT exception + Copyright (C) 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 java.awt; + +/** + * This is a generic exception that indicates an exception occurred in the + * Abstract Window Toolkit (AWT) system. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class AWTException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -1900414231151323879L; + + /** + * Create a new instance with the specified detailed error message. + * + * @param message the detailed error message + */ + public AWTException(String message) + { + super(message); + } +} // class AWTException diff --git a/libjava/classpath/java/awt/AWTKeyStroke.java b/libjava/classpath/java/awt/AWTKeyStroke.java new file mode 100644 index 0000000..c10d53e --- /dev/null +++ b/libjava/classpath/java/awt/AWTKeyStroke.java @@ -0,0 +1,660 @@ +/* AWTKeyStroke.java -- an immutable key stroke + Copyright (C) 2002, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * This class mirrors KeyEvents, representing both low-level key presses and + * key releases, and high level key typed inputs. However, this class forms + * immutable strokes, and can be efficiently reused via the factory methods + * for creating them. + * + *

For backwards compatibility with Swing, this supports a way to build + * instances of a subclass, using reflection, provided the subclass has a + * no-arg constructor (of any accessibility). + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see #getAWTKeyStroke(char) + * @since 1.4 + * @status updated to 1.4 + */ +public class AWTKeyStroke implements Serializable +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = -6430539691155161871L; + + /** The mask for modifiers. */ + private static final int MODIFIERS_MASK = 0x3fef; + + /** + * The cache of recently created keystrokes. This maps KeyStrokes to + * KeyStrokes in a cache which removes the least recently accessed entry, + * under the assumption that garbage collection of a new keystroke is + * easy when we find the old one that it matches in the cache. + */ + private static final LinkedHashMap cache = new LinkedHashMap(11, 0.75f, true) + { + /** The largest the keystroke cache can grow. */ + private static final int MAX_CACHE_SIZE = 2048; + + /** Prune stale entries. */ + protected boolean removeEldestEntry(Map.Entry eldest) + { // XXX - FIXME Use Map.Entry, not just Entry as gcj 3.1 workaround. + return size() > MAX_CACHE_SIZE; + } + }; + + /** The most recently generated keystroke, or null. */ + private static AWTKeyStroke recent; + + /** + * The no-arg constructor of a subclass, or null to use AWTKeyStroke. Note + * that this will be left accessible, to get around private access; but + * it should not be a security risk as it is highly unlikely that creating + * protected instances of the subclass via reflection will do much damage. + */ + private static Constructor ctor; + + /** + * A table of keyCode names to values. This is package-private to + * avoid an accessor method. + * + * @see #getAWTKeyStroke(String) + */ + static final HashMap vktable = new HashMap(); + static + { + // Using reflection saves the hassle of keeping this in sync with KeyEvent, + // at the price of an expensive initialization. + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + Field[] fields = KeyEvent.class.getFields(); + int i = fields.length; + try + { + while (--i >= 0) + { + Field f = fields[i]; + String name = f.getName(); + if (name.startsWith("VK_")) + vktable.put(name.substring(3), f.get(null)); + } + } + catch (Exception e) + { + throw (Error) new InternalError().initCause(e); + } + return null; + } + }); + } + + /** + * The typed character, or CHAR_UNDEFINED for key presses and releases. + * + * @serial the keyChar + */ + private char keyChar; + + /** + * The virtual key code, or VK_UNDEFINED for key typed. Package visible for + * use by Component. + * + * @serial the keyCode + */ + int keyCode; + + /** + * The modifiers in effect. To match Sun, this stores the old style masks + * for shift, control, alt, meta, and alt-graph (but not button1); as well + * as the new style of extended modifiers for all modifiers. + * + * @serial bitwise or of the *_DOWN_MASK modifiers + */ + private int modifiers; + + /** + * True if this is a key release; should only be true if keyChar is + * CHAR_UNDEFINED. + * + * @serial true to distinguish key pressed from key released + */ + private boolean onKeyRelease; + + /** + * Construct a keystroke with default values: it will be interpreted as a + * key typed event with an invalid character and no modifiers. Client code + * should use the factory methods instead. + * + * @see #getAWTKeyStroke(char) + * @see #getAWTKeyStroke(Character, int) + * @see #getAWTKeyStroke(int, int, boolean) + * @see #getAWTKeyStroke(int, int) + * @see #getAWTKeyStrokeForEvent(KeyEvent) + * @see #getAWTKeyStroke(String) + */ + protected AWTKeyStroke() + { + keyChar = KeyEvent.CHAR_UNDEFINED; + } + + /** + * Construct a keystroke with the given values. Client code should use the + * factory methods instead. + * + * @param keyChar the character entered, if this is a key typed + * @param keyCode the key pressed or released, or VK_UNDEFINED for key typed + * @param modifiers the modifier keys for the keystroke, in old or new style + * @param onKeyRelease true if this is a key release instead of a press + * @see #getAWTKeyStroke(char) + * @see #getAWTKeyStroke(Character, int) + * @see #getAWTKeyStroke(int, int, boolean) + * @see #getAWTKeyStroke(int, int) + * @see #getAWTKeyStrokeForEvent(KeyEvent) + * @see #getAWTKeyStroke(String) + */ + protected AWTKeyStroke(char keyChar, int keyCode, int modifiers, + boolean onKeyRelease) + { + this.keyChar = keyChar; + this.keyCode = keyCode; + // No need to call extend(), as only trusted code calls this constructor. + this.modifiers = modifiers; + this.onKeyRelease = onKeyRelease; + } + + /** + * Registers a new subclass as being the type of keystrokes to generate in + * the factory methods. This operation flushes the cache of stored keystrokes + * if the class differs from the current one. The new class must be + * AWTKeyStroke or a subclass, and must have a no-arg constructor (which may + * be private). + * + * @param subclass the new runtime type of generated keystrokes + * @throws IllegalArgumentException subclass doesn't have no-arg constructor + * @throws ClassCastException subclass doesn't extend AWTKeyStroke + */ + protected static void registerSubclass(final Class subclass) + { + if (subclass == null) + throw new IllegalArgumentException(); + if (subclass.equals(ctor == null ? AWTKeyStroke.class + : ctor.getDeclaringClass())) + return; + if (subclass.equals(AWTKeyStroke.class)) + { + cache.clear(); + recent = null; + ctor = null; + return; + } + try + { + ctor = (Constructor) AccessController.doPrivileged + (new PrivilegedExceptionAction() + { + public Object run() + throws NoSuchMethodException, InstantiationException, + IllegalAccessException, InvocationTargetException + { + Constructor c = subclass.getDeclaredConstructor(null); + c.setAccessible(true); + // Create a new instance, to make sure that we can, and + // to cause any ClassCastException. + AWTKeyStroke dummy = (AWTKeyStroke) c.newInstance(null); + return c; + } + }); + } + catch (PrivilegedActionException e) + { + // e.getCause() will not ever be ClassCastException; that should + // escape on its own. + throw (RuntimeException) + new IllegalArgumentException().initCause(e.getCause()); + } + cache.clear(); + recent = null; + } + + /** + * Returns a keystroke representing a typed character. + * + * @param keyChar the typed character + * @return the specified keystroke + */ + public static AWTKeyStroke getAWTKeyStroke(char keyChar) + { + return getAWTKeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false); + } + + /** + * Returns a keystroke representing a typed character with the given + * modifiers. Note that keyChar is a Character instead of a + * char to avoid accidental ambiguity with + * getAWTKeyStroke(int, int). The modifiers are the bitwise + * or of the masks found in {@link InputEvent}; the new style (*_DOWN_MASK) + * is preferred, but the old style will work. + * + * @param keyChar the typed character + * @param modifiers the modifiers, or 0 + * @return the specified keystroke + * @throws IllegalArgumentException if keyChar is null + */ + public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers) + { + if (keyChar == null) + throw new IllegalArgumentException(); + return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED, + extend(modifiers), false); + } + + /** + * Returns a keystroke representing a pressed or released key event, with + * the given modifiers. The "virtual key" should be one of the VK_* + * constants in {@link KeyEvent}. The modifiers are the bitwise or of the + * masks found in {@link InputEvent}; the new style (*_DOWN_MASK) is + * preferred, but the old style will work. + * + * @param keyCode the virtual key + * @param modifiers the modifiers, or 0 + * @param release true if this is a key release instead of a key press + * @return the specified keystroke + */ + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, + boolean release) + { + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, + extend(modifiers), release); + } + + /** + * Returns a keystroke representing a pressed key event, with the given + * modifiers. The "virtual key" should be one of the VK_* constants in + * {@link KeyEvent}. The modifiers are the bitwise or of the masks found + * in {@link InputEvent}; the new style (*_DOWN_MASK) is preferred, but the + * old style will work. + * + * @param keyCode the virtual key + * @param modifiers the modifiers, or 0 + * @return the specified keystroke + */ + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) + { + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, + extend(modifiers), false); + } + + /** + * Returns a keystroke representing what caused the key event. + * + * @param event the key event to convert + * @return the specified keystroke, or null if the event is invalid + * @throws NullPointerException if event is null + */ + public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent event) + { + switch (event.id) + { + case KeyEvent.KEY_TYPED: + return getAWTKeyStroke(event.getKeyChar(), KeyEvent.VK_UNDEFINED, + extend(event.getModifiersEx()), false); + case KeyEvent.KEY_PRESSED: + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, event.getKeyCode(), + extend(event.getModifiersEx()), false); + case KeyEvent.KEY_RELEASED: + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, event.getKeyCode(), + extend(event.getModifiersEx()), true); + default: + return null; + } + } + + /** + * Parses a string and returns the keystroke that it represents. The syntax + * for keystrokes is listed below, with tokens separated by an arbitrary + * number of spaces: + *

+   * keyStroke := <modifiers>* ( <typedID> | <codeID> )
+   * modifiers := ( shift | control | ctrl | meta | alt
+   *                | button1 | button2 | button3 )
+   * typedID := typed <single Unicode character>
+   * codeID := ( pressed | released )? <name>
+   * name := <the KeyEvent field name less the leading "VK_">
+   * 
+ * + *

Note that the grammar is rather weak, and not all valid keystrokes + * can be generated in this manner (for example, a typed space, or anything + * with the alt-graph modifier!). The output of AWTKeyStroke.toString() + * will not meet the grammar. If pressed or released is not specified, + * pressed is assumed. Examples:
+ * + * "INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0);
+ * "control DELETE" => + * getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);
+ * "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, + * InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);
+ * "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, + * InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);
+ * "typed a" => getAWTKeyStroke('a'); + *
+ * + * @param s the string to parse + * @throws IllegalArgumentException if s is null or cannot be parsed + * @return the specified keystroke + */ + public static AWTKeyStroke getAWTKeyStroke(String s) + { + if (s == null) + throw new IllegalArgumentException("null argument"); + StringTokenizer t = new StringTokenizer(s, " "); + if (! t.hasMoreTokens()) + throw new IllegalArgumentException("no tokens '" + s + "'"); + int modifiers = 0; + boolean released = false; + String token = null; + do + { + token = t.nextToken(); + if ("shift".equals(token)) + modifiers |= KeyEvent.SHIFT_DOWN_MASK; + else if ("ctrl".equals(token) || "control".equals(token)) + modifiers |= KeyEvent.CTRL_DOWN_MASK; + else if ("meta".equals(token)) + modifiers |= KeyEvent.META_DOWN_MASK; + else if ("alt".equals(token)) + modifiers |= KeyEvent.ALT_DOWN_MASK; + else if ("button1".equals(token)) + modifiers |= KeyEvent.BUTTON1_DOWN_MASK; + else if ("button2".equals(token)) + modifiers |= KeyEvent.BUTTON2_DOWN_MASK; + else if ("button3".equals(token)) + modifiers |= KeyEvent.BUTTON3_DOWN_MASK; + else if ("typed".equals(token)) + { + if (t.hasMoreTokens()) + { + token = t.nextToken(); + if (! t.hasMoreTokens() && token.length() == 1) + return getAWTKeyStroke(token.charAt(0), + KeyEvent.VK_UNDEFINED, modifiers, + false); + } + throw new IllegalArgumentException("Invalid 'typed' argument '" + + s + "'"); + } + else if ("pressed".equals(token)) + { + if (t.hasMoreTokens()) + token = t.nextToken(); + break; + } + else if ("released".equals(token)) + { + released = true; + if (t.hasMoreTokens()) + token = t.nextToken(); + break; + } + else + break; + } + while (t.hasMoreTokens()); + // Now token contains the VK name we must parse. + Integer code = (Integer) vktable.get(token); + if (code == null) + throw new IllegalArgumentException("Unknown token '" + token + + "' in '" + s + "'"); + if (t.hasMoreTokens()) + throw new IllegalArgumentException("Too many tokens: " + s); + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, code.intValue(), + modifiers, released); + } + + /** + * Returns the character of this keystroke, if it was typed. + * + * @return the character value, or CHAR_UNDEFINED + * @see #getAWTKeyStroke(char) + */ + public final char getKeyChar() + { + return keyChar; + } + + /** + * Returns the virtual key code of this keystroke, if it was pressed or + * released. This will be a VK_* constant from KeyEvent. + * + * @return the virtual key code value, or VK_UNDEFINED + * @see #getAWTKeyStroke(int, int) + */ + public final int getKeyCode() + { + return keyCode; + } + + /** + * Returns the modifiers for this keystroke. This will be a bitwise or of + * constants from InputEvent; it includes the old style masks for shift, + * control, alt, meta, and alt-graph (but not button1); as well as the new + * style of extended modifiers for all modifiers. + * + * @return the modifiers + * @see #getAWTKeyStroke(Character, int) + * @see #getAWTKeyStroke(int, int) + */ + public final int getModifiers() + { + return modifiers; + } + + /** + * Tests if this keystroke is a key release. + * + * @return true if this is a key release + * @see #getAWTKeyStroke(int, int, boolean) + */ + public final boolean isOnKeyRelease() + { + return onKeyRelease; + } + + /** + * Returns the AWT event type of this keystroke. This is one of + * {@link KeyEvent#KEY_TYPED}, {@link KeyEvent#KEY_PRESSED}, or + * {@link KeyEvent#KEY_RELEASED}. + * + * @return the key event type + */ + public final int getKeyEventType() + { + return keyCode == KeyEvent.VK_UNDEFINED ? KeyEvent.KEY_TYPED + : onKeyRelease ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED; + } + + /** + * Returns a hashcode for this key event. It is not documented, but appears + * to be: (getKeyChar() + 1) * (getKeyCode() + 1) + * * (getModifiers() + 1) * 2 + (isOnKeyRelease() ? 1 : 2). + * + * @return the hashcode + */ + public int hashCode() + { + return (keyChar + 1) * (keyCode + 1) * (modifiers + 1) * 2 + + (onKeyRelease ? 1 : 2); + } + + /** + * Tests two keystrokes for equality. + * + * @param o the object to test + * @return true if it is equal + */ + public final boolean equals(Object o) + { + if (! (o instanceof AWTKeyStroke)) + return false; + AWTKeyStroke s = (AWTKeyStroke) o; + return this == o || (keyChar == s.keyChar && keyCode == s.keyCode + && modifiers == s.modifiers + && onKeyRelease == s.onKeyRelease); + } + + /** + * Returns a string representation of this keystroke. For typed keystrokes, + * this is "keyChar " + KeyEvent.getKeyModifiersText(getModifiers()) + + getKeyChar(); for pressed and released keystrokes, this is + * "keyCode " + KeyEvent.getKeyModifiersText(getModifiers()) + * + KeyEvent.getKeyText(getKeyCode()) + * + (isOnKeyRelease() ? "-R" : "-P"). + * + * @return a string representation + */ + public String toString() + { + if (keyCode == KeyEvent.VK_UNDEFINED) + return "keyChar " + KeyEvent.getKeyModifiersText(modifiers) + keyChar; + return "keyCode " + KeyEvent.getKeyModifiersText(modifiers) + + KeyEvent.getKeyText(keyCode) + (onKeyRelease ? "-R" : "-P"); + } + + /** + * Returns a cached version of the deserialized keystroke, if available. + * + * @return a cached replacement + * @throws ObjectStreamException if something goes wrong + */ + protected Object readResolve() throws ObjectStreamException + { + AWTKeyStroke s = (AWTKeyStroke) cache.get(this); + if (s != null) + return s; + cache.put(this, this); + return this; + } + + /** + * Gets the appropriate keystroke, creating one if necessary. + * + * @param keyChar the keyChar + * @param keyCode the keyCode + * @param modifiers the modifiers + * @param release true for key release + * @return the specified keystroke + */ + private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode, + int modifiers, boolean release) + { + // Check level 0 cache. + AWTKeyStroke stroke = recent; // Avoid thread races. + if (stroke != null && stroke.keyChar == keyChar + && stroke.keyCode == keyCode && stroke.modifiers == modifiers + && stroke.onKeyRelease == release) + return stroke; + // Create a new object, on the assumption that if it has a match in the + // cache, the VM can easily garbage collect it as it is temporary. + Constructor c = ctor; // Avoid thread races. + if (c == null) + stroke = new AWTKeyStroke(keyChar, keyCode, modifiers, release); + else + try + { + stroke = (AWTKeyStroke) c.newInstance(null); + stroke.keyChar = keyChar; + stroke.keyCode = keyCode; + stroke.modifiers = modifiers; + stroke.onKeyRelease = release; + } + catch (Exception e) + { + throw (Error) new InternalError().initCause(e); + } + // Check level 1 cache. + AWTKeyStroke cached = (AWTKeyStroke) cache.get(stroke); + if (cached == null) + cache.put(stroke, stroke); + else + stroke = cached; + return recent = stroke; + } + + /** + * Converts the modifiers to the appropriate format. + * + * @param mod the modifiers to convert + * @return the adjusted modifiers + */ + private static int extend(int mod) + { + if ((mod & (KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK)) != 0) + mod |= KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK; + if ((mod & (KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK)) != 0) + mod |= KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK; + if ((mod & (KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK)) != 0) + mod |= KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK; + if ((mod & (KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK)) != 0) + mod |= KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK; + if ((mod & (KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK)) != 0) + mod |= KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK; + if ((mod & KeyEvent.BUTTON1_MASK) != 0) + mod |= KeyEvent.BUTTON1_DOWN_MASK; + return mod & MODIFIERS_MASK; + } +} // class AWTKeyStroke diff --git a/libjava/classpath/java/awt/AWTPermission.java b/libjava/classpath/java/awt/AWTPermission.java new file mode 100644 index 0000000..3e50c05 --- /dev/null +++ b/libjava/classpath/java/awt/AWTPermission.java @@ -0,0 +1,121 @@ +/* AWTPermission.java -- AWT related permissions + 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 java.awt; + +import java.security.BasicPermission; + +/** + * This class implements permissions for AWT. This is a named + * permission. No actions are defined. + * + *

The following table provides a list of all the possible AWTPermission + * permission names with a description of what that permission allows.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Permission NamePermission AllowsRisks + *
accessClipboardposting and reading the AWT clipboardthe clipboard may contain sensitive data
accessEventQueueaccess to the AWT event queuemalicious code could remove real events and replace them with bogus + * ones, including simulating the user granting permission
listenToAllAWTEventslisten to system-wide AWT eventsmalicious code can read passwords entered in an AWT event, and in + * combination with accessEventQueue, could fake system events
showWindowWithoutWarningBannerdisplay a window without a banner notification of insecuritymalicious code could install a Trojan horse applet that looks like + * a normal window, and thus steal data like passwords
readDisplayPixelsread back pixels from the display screenmalicious code could snoop on the user's actions
createRobotcreate an instance of java.awt.Robotthese objects can generate events as though they were the user; so + * malicious code could control the system
fullScreenExclusiveenter full-screen exclusive modemalicious code could masquerade as a trusted program
+ * + * @author Tom Tromey (tromey@redhat.com) + * @since 1.2 + * @status updated to 1.4 + */ +public final class AWTPermission extends BasicPermission +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 8890392402588814465L; + + /** + * Construct a AWTPermission with the given name. + * + * @param name the permission name + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if name is invalid + */ + public AWTPermission(String name) + { + super(name); + } + + /** + * Create a new permission with the specified name. The actions argument + * is ignored, as AWT permissions have no actions. + * + * @param name the permission name + * @param actions ignored + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if name is invalid + */ + public AWTPermission(String name, String actions) + { + super(name); + } +} // class AWTPermission diff --git a/libjava/classpath/java/awt/ActiveEvent.java b/libjava/classpath/java/awt/ActiveEvent.java new file mode 100644 index 0000000..e42959f --- /dev/null +++ b/libjava/classpath/java/awt/ActiveEvent.java @@ -0,0 +1,61 @@ +/* ActiveEvent.java -- a self-dispatching event + 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 java.awt; + +/** + * An interface for events which can dispatch themselves in another thread. + * This has two uses: first, if your code is in a critical section, calling a + * synchronized method might deadlock. But by using an ActiveEvent to call + * the second section, it will not obtain the lock until you have left the + * critical section, avoiding deadlock. The second use is for calling + * untrusted code. For example, system code should use an ActiveEvent to + * invoke user code securely. + * + * @author Tom Tromey (tromey@cygnus.com) + * @since 1.2 + * @status updated to 1.4 + */ +public interface ActiveEvent +{ + /** + * Dispatch the event, according to what the event needs done. Invoked + * automatically if this is placed on the EventDispatchQueue. + */ + void dispatch(); +} // interface ActiveEvent diff --git a/libjava/classpath/java/awt/Adjustable.java b/libjava/classpath/java/awt/Adjustable.java new file mode 100644 index 0000000..8f633e9 --- /dev/null +++ b/libjava/classpath/java/awt/Adjustable.java @@ -0,0 +1,171 @@ +/* Adjustable.java -- Objects with a numeric adjustment scale + Copyright (C) 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 java.awt; + +import java.awt.event.AdjustmentListener; + +/** + * This interface is for objects that take a numeric value that can be + * adjusted within a bounded range. For example, a scroll bar. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface Adjustable +{ + /** Constant for an adjustable object with horizontal orientation. */ + int HORIZONTAL = 0; + + /** Constant for an adjustable object with vertical orientation. */ + int VERTICAL = 1; + + /** Constant for an adjustable object with no orientation. */ + int NO_ORIENTATION = 2; + + /** + * Returns a constant representing the orientation of the object. + * + * @return the orientation of this object + * @see #HORIZONTAL + * @see #VERTICAL + * @see #NO_ORIENTATION + */ + int getOrientation(); + + /** + * Sets the minimum value this object can have. + * + * @param minimum the new minimum value + */ + void setMinimum(int minimum); + + /** + * Returns the minimum value this object can have. + * + * @return the minimum value + */ + int getMinimum(); + + /** + * Sets the maximum value this object can have. + * + * @param maximum the new maximum value + */ + void setMaximum(int maximum); + + /** + * Returns the maximum value this object can have. + * + * @return the maximum value + */ + int getMaximum(); + + /** + * Sets the increment value for incrementing the value by units. + * + * @param increment the unit increment value + */ + void setUnitIncrement(int increment); + + /** + * Returns the increment value for incrementing the value by units. + * + * @return the unit increment value + */ + int getUnitIncrement(); + + /** + * Sets the increment value for incrementing the value by blocks. + * + * @param increment the block increment value + */ + void setBlockIncrement(int increment); + + /** + * Returns the increment value for incrementing the value by blocks. + * + * @return the block increment value + */ + int getBlockIncrement(); + + /** + * Sets the length of the indicator for this object to the specified value. + * + * @param length the indicator length + */ + void setVisibleAmount(int length); + + /** + * Returns the length of the indicator for this object. + * + * @return the indicator length + */ + int getVisibleAmount(); + + /** + * Sets the current value of the object. + * + * @param value the new value + */ + void setValue(int value); + + /** + * Returns the current value of the object. + * + * @return the current value + */ + int getValue(); + + /** + * Adds a listener that will receive adjustment events for this object. + * + * @param listener the adjustment listener to add + * @see java.awt.event.AdjustmentEvent + */ + void addAdjustmentListener(AdjustmentListener listener); + + /** + * Removes an adjustment listener from this object. + * + * @param listener the adjustment listener to remove + * @see java.awt.event.AdjustmentEvent + */ + void removeAdjustmentListener(AdjustmentListener listener); +} // interface Adjustable diff --git a/libjava/classpath/java/awt/AlphaComposite.java b/libjava/classpath/java/awt/AlphaComposite.java new file mode 100644 index 0000000..435cfd0 --- /dev/null +++ b/libjava/classpath/java/awt/AlphaComposite.java @@ -0,0 +1,167 @@ +/* AlphaComposite.java -- provides a context for performing alpha compositing + 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 java.awt; + +import java.awt.image.ColorModel; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Composite + * @see CompositeContext + * @since 1.3 + * @status updated to 1.4 except for createContext, needs documentation + */ +public final class AlphaComposite implements Composite +{ + /** Map Long to AlphaComposites. See getInstance for details. */ + private static final LinkedHashMap cache = new LinkedHashMap(11, 0.75f, true) + { + /** The largest the alpha composite cache can grow. */ + private static final int MAX_CACHE_SIZE = 2048; + + /** Prune stale entries. */ + protected boolean removeEldestEntry(Map.Entry eldest) + { // XXX - FIXME Use Map.Entry, not just Entry as gcj 3.1 workaround. + return size() > MAX_CACHE_SIZE; + } + }; + + public static final int CLEAR = 1; + public static final int SRC = 2; + public static final int DST = 9; + public static final int SRC_OVER = 3; + public static final int DST_OVER = 4; + public static final int SRC_IN = 5; + public static final int DST_IN = 6; + public static final int SRC_OUT = 7; + public static final int DST_OUT = 8; + public static final int SRC_ATOP = 10; + public static final int DST_ATOP = 11; + public static final int XOR = 12; + public static final AlphaComposite Clear = getInstance(CLEAR); + public static final AlphaComposite Src = getInstance(SRC); + public static final AlphaComposite Dst = getInstance(DST); + public static final AlphaComposite SrcOver = getInstance(SRC_OVER); + public static final AlphaComposite DstOver = getInstance(DST_OVER); + public static final AlphaComposite SrcIn = getInstance(SRC_IN); + public static final AlphaComposite DstIn = getInstance(DST_IN); + public static final AlphaComposite SrcOut = getInstance(SRC_OUT); + public static final AlphaComposite DstOut = getInstance(DST_OUT); + public static final AlphaComposite SrcAtop = getInstance(SRC_ATOP); + public static final AlphaComposite DstAtop = getInstance(DST_ATOP); + public static final AlphaComposite Xor = getInstance(XOR); + + private final int rule; + private final float alpha; + private AlphaComposite(int rule, float alpha) + { + this.rule = rule; + this.alpha = alpha; + } + + /** + * Creates an AlphaComposite object with the specified rule. + * + * @param rule The compositing rule. + * + * @exception IllegalArgumentException If rule is not one of the following: + * CLEAR, SRC, DST, SRC_OVER, DST_OVER, SRC_IN, DST_IN, SRC_OUT, DST_OUT, + * SRC_ATOP, DST_ATOP, or XOR. + */ + public static AlphaComposite getInstance(int rule) + { + return getInstance(rule, 1); + } + + /** + * Creates an AlphaComposite object with the specified rule and the constant + * alpha to multiply with the alpha of the source. The source is multiplied + * with the specified alpha before being composited with the destination. + * + * @param rule The compositing rule. + * + * @exception IllegalArgumentException If rule is not one of the following: + * CLEAR, SRC, DST, SRC_OVER, DST_OVER, SRC_IN, DST_IN, SRC_OUT, DST_OUT, + * SRC_ATOP, DST_ATOP, or XOR. + */ + public static AlphaComposite getInstance(int rule, float alpha) + { + if (rule < CLEAR || rule > XOR || ! (alpha >= 0 && alpha <= 1)) + throw new IllegalArgumentException(); + // This long is guaranteed unique for all valid alpha composites. + Long l = new Long(rule + Double.doubleToLongBits(alpha)); + AlphaComposite a = (AlphaComposite) cache.get(l); + if (a == null) + { + a = new AlphaComposite(rule, alpha); + cache.put(l, a); + } + return a; + } + public CompositeContext createContext(ColorModel srcColorModel, + ColorModel dstColorModel, + RenderingHints hints) + { + // XXX Implement. Sun uses undocumented implementation class + // sun.java2d.SunCompositeContext. + throw new Error("not implemented"); + } + public float getAlpha() + { + return alpha; + } + public int getRule() + { + return rule; + } + public int hashCode() + { + return 31 * Float.floatToIntBits(alpha) + rule; + } + public boolean equals(Object o) + { + if (! (o instanceof AlphaComposite)) + return false; + AlphaComposite a = (AlphaComposite) o; + return rule == a.rule && alpha == a.alpha; + } +} // class AlphaComposite diff --git a/libjava/classpath/java/awt/AttributeValue.java b/libjava/classpath/java/awt/AttributeValue.java new file mode 100644 index 0000000..080e92e --- /dev/null +++ b/libjava/classpath/java/awt/AttributeValue.java @@ -0,0 +1,98 @@ +/* AttributeValue.java -- parent of type-safe enums of attributes + 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 java.awt; + +/** + * This class is undocumented by Sun, but it is the parent of several other + * classes, all of which are type-safe enumerations. This takes care of + * equals, toString, and hashCode, so + * that you don't have to (although hashCode is commonly overridden). + * + * @author Eric Blake (ebb9@email.byu.edu) + */ +class AttributeValue +{ + /** The value of the enumeration. Package visible for speed. */ + final int value; + + /** The list of enumeration names for the given subclass. */ + private final String[] names; + + /** + * Construct a type-safe enumeration element. For example,
+ *

+   * class Foo extends AttributeValue
+   * {
+   *   private static final String[] names = { "one", "two" }
+   *   public static final Foo ONE = new Foo(0);
+   *   public static final Foo TWO = new Foo(1);
+   *   private Foo(int value) { super(value, names); }
+   * }
+   * 
+ * + * @param value the position of this enumeration element, consecutive from 0 + * @param names the constant list of enumeration names for the subclass + */ + AttributeValue(int value, String[] names) + { + this.value = value; + this.names = names; + } + + /** + * Returns the hashcode of this element. This is the index of the element + * in the enumeration. Note that equals defaults to the == relation. + * + * @return the hashcode + */ + public int hashCode() + { + return value; + } + + /** + * Returns the name of this enumeration element. + * + * @return the element name + */ + public String toString() + { + return names[value]; + } +} // class AttributeValue diff --git a/libjava/classpath/java/awt/BasicStroke.java b/libjava/classpath/java/awt/BasicStroke.java new file mode 100644 index 0000000..bb008e4 --- /dev/null +++ b/libjava/classpath/java/awt/BasicStroke.java @@ -0,0 +1,248 @@ +/* BasicStroke.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 java.awt; + +import java.util.Arrays; + +/** + * STUB CLASS ONLY + */ +public class BasicStroke implements Stroke +{ + public static final int JOIN_MITER = 0; + public static final int JOIN_ROUND = 1; + public static final int JOIN_BEVEL = 2; + + public static final int CAP_BUTT = 0; + public static final int CAP_ROUND = 1; + public static final int CAP_SQUARE = 2; + + private final float width; + private final int cap; + private final int join; + private final float limit; + private final float[] dash; + private final float phase; + + /** + * Creates a basic stroke. + * + * @param width May not be negative . + * @param cap May be either CAP_BUTT, CAP_ROUND or CAP_SQUARE. + * @param join May be either JOIN_ROUND, JOIN_BEVEL, or JOIN_MITER. + * @param miterlimit the limit to trim the miter join. The miterlimit must be + * greater than or equal to 1.0f. + * @param dash The array representing the dashing pattern. There must be at + * least one non-zero entry. + * @param dashPhase is negative and dash is not null. + * + * @exception IllegalArgumentException If one input parameter doesn't meet + * its needs. + */ + public BasicStroke(float width, int cap, int join, float miterlimit, + float[] dash, float dashPhase) + { + if (width < 0.0f ) + throw new IllegalArgumentException("width " + width + " < 0"); + else if (cap < CAP_BUTT || cap > CAP_SQUARE) + throw new IllegalArgumentException("cap " + cap + " out of range [" + + CAP_BUTT + ".." + CAP_SQUARE + "]"); + else if (miterlimit < 1.0f && join == JOIN_MITER) + throw new IllegalArgumentException("miterlimit " + miterlimit + + " < 1.0f while join == JOIN_MITER"); + else if (join < JOIN_MITER || join > JOIN_BEVEL) + throw new IllegalArgumentException("join " + join + " out of range [" + + JOIN_MITER + ".." + JOIN_BEVEL + + "]"); + else if (dashPhase < 0.0f && dash != null) + throw new IllegalArgumentException("dashPhase " + dashPhase + + " < 0.0f while dash != null"); + else if (dash != null) + if (dash.length == 0) + throw new IllegalArgumentException("dash.length is 0"); + else + { + boolean allZero = true; + + for ( int i = 0; i < dash.length; ++i) + { + if (dash[i] != 0.0f) + { + allZero = false; + break; + } + } + + if (allZero) + throw new IllegalArgumentException("all dashes are 0.0f"); + } + + this.width = width; + this.cap = cap; + this.join = join; + limit = miterlimit; + this.dash = dash == null ? null : (float[]) dash.clone(); + phase = dashPhase; + } + + /** + * Creates a basic stroke. + * + * @param width The width of the BasicStroke. May not be negative . + * @param cap May be either CAP_BUTT, CAP_ROUND or CAP_SQUARE. + * @param join May be either JOIN_ROUND, JOIN_BEVEL, or JOIN_MITER. + * @param miterlimit the limit to trim the miter join. The miterlimit must be + * greater than or equal to 1.0f. + * + * @exception IllegalArgumentException If one input parameter doesn't meet + * its needs. + */ + public BasicStroke(float width, int cap, int join, float miterlimit) + { + this(width, cap, join, miterlimit, null, 0); + } + + /** + * Creates a basic stroke. + * + * @param width The width of the BasicStroke. May not be nehative. + * @param cap May be either CAP_BUTT, CAP_ROUND or CAP_SQUARE. + * @param join May be either JOIN_ROUND, JOIN_BEVEL, or JOIN_MITER. + * + * @exception IllegalArgumentException If one input parameter doesn't meet + * its needs. + * @exception IllegalArgumentException FIXME + */ + public BasicStroke(float width, int cap, int join) + { + this(width, cap, join, 10, null, 0); + } + + /** + * Creates a basic stroke. + * + * @param width The width of the BasicStroke. + * + * @exception IllegalArgumentException If width is negative. + */ + public BasicStroke(float width) + { + this(width, CAP_SQUARE, JOIN_MITER, 10, null, 0); + } + + /** + * Creates a basic stroke. + */ + public BasicStroke() + { + this(1, CAP_SQUARE, JOIN_MITER, 10, null, 0); + } + + public Shape createStrokedShape(Shape s) + { + throw new Error("not implemented"); + } + + public float getLineWidth() + { + return width; + } + + public int getEndCap() + { + return cap; + } + + public int getLineJoin() + { + return join; + } + + public float getMiterLimit() + { + return limit; + } + + public float[] getDashArray() + { + return dash; + } + + public float getDashPhase() + { + return phase; + } + + /** + * Returns the hash code for this object. The hash is calculated by + * xoring the hash, cap, join, limit, dash array and phase values + * (converted to int first with + * Float.floatToIntBits() if the value is a + * float). + */ + public int hashCode() + { + int hash = Float.floatToIntBits(width); + hash ^= cap; + hash ^= join; + hash ^= Float.floatToIntBits(limit); + + if (dash != null) + for (int i = 0; i < dash.length; i++) + hash ^= Float.floatToIntBits(dash[i]); + + hash ^= Float.floatToIntBits(phase); + + return hash; + } + + /** + * Returns true if the given Object is an instance of BasicStroke + * and the width, cap, join, limit, dash array and phase are all + * equal. + */ + public boolean equals(Object o) + { + if (! (o instanceof BasicStroke)) + return false; + BasicStroke s = (BasicStroke) o; + return width == s.width && cap == s.cap && join == s.join + && limit == s.limit && Arrays.equals(dash, s.dash) && phase == s.phase; + } +} // class BasicStroke diff --git a/libjava/classpath/java/awt/BorderLayout.java b/libjava/classpath/java/awt/BorderLayout.java new file mode 100644 index 0000000..c9eb5dd --- /dev/null +++ b/libjava/classpath/java/awt/BorderLayout.java @@ -0,0 +1,731 @@ +/* BorderLayout.java -- A layout manager class + Copyright (C) 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 java.awt; + +/** + * This class implements a layout manager that positions components + * in certain sectors of the parent container. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class BorderLayout implements LayoutManager2, java.io.Serializable +{ + +/* + * Static Variables + */ + +/** + * Constant indicating the top of the container + */ +public static final String NORTH = "North"; + +/** + * Constant indicating the bottom of the container + */ +public static final String SOUTH = "South"; + +/** + * Constant indicating the right side of the container + */ +public static final String EAST = "East"; + +/** + * Constant indicating the left side of the container + */ +public static final String WEST = "West"; + +/** + * Constant indicating the center of the container + */ +public static final String CENTER = "Center"; + + + /** + * The constant indicating the position before the first line of the + * layout. The exact position depends on the writing system: For a + * top-to-bottom orientation, it is the same as {@link #NORTH}, for + * a bottom-to-top orientation, it is the same as {@link #SOUTH}. + * + *

This constant is an older name for {@link #PAGE_START} which + * has exactly the same value. + * + * @since 1.2 + */ + public static final String BEFORE_FIRST_LINE = "First"; + + + /** + * The constant indicating the position after the last line of the + * layout. The exact position depends on the writing system: For a + * top-to-bottom orientation, it is the same as {@link #SOUTH}, for + * a bottom-to-top orientation, it is the same as {@link #NORTH}. + * + *

This constant is an older name for {@link #PAGE_END} which + * has exactly the same value. + * + * @since 1.2 + */ + public static final String AFTER_LAST_LINE = "Last"; + + + /** + * The constant indicating the position before the first item of the + * layout. The exact position depends on the writing system: For a + * left-to-right orientation, it is the same as {@link #WEST}, for + * a right-to-left orientation, it is the same as {@link #EAST}. + * + *

This constant is an older name for {@link #LINE_START} which + * has exactly the same value. + * + * @since 1.2 + */ + public static final String BEFORE_LINE_BEGINS = "Before"; + + + /** + * The constant indicating the position after the last item of the + * layout. The exact position depends on the writing system: For a + * left-to-right orientation, it is the same as {@link #EAST}, for + * a right-to-left orientation, it is the same as {@link #WEST}. + * + *

This constant is an older name for {@link #LINE_END} which + * has exactly the same value. + * + * @since 1.2 + */ + public static final String AFTER_LINE_ENDS = "After"; + + + /** + * The constant indicating the position before the first line of the + * layout. The exact position depends on the writing system: For a + * top-to-bottom orientation, it is the same as {@link #NORTH}, for + * a bottom-to-top orientation, it is the same as {@link #SOUTH}. + * + * @since 1.4 + */ + public static final String PAGE_START = BEFORE_FIRST_LINE; + + + /** + * The constant indicating the position after the last line of the + * layout. The exact position depends on the writing system: For a + * top-to-bottom orientation, it is the same as {@link #SOUTH}, for + * a bottom-to-top orientation, it is the same as {@link #NORTH}. + * + * @since 1.4 + */ + public static final String PAGE_END = AFTER_LAST_LINE; + + + /** + * The constant indicating the position before the first item of the + * layout. The exact position depends on the writing system: For a + * left-to-right orientation, it is the same as {@link #WEST}, for + * a right-to-left orientation, it is the same as {@link #EAST}. + * + * @since 1.4 + */ + public static final String LINE_START = BEFORE_LINE_BEGINS; + + + /** + * The constant indicating the position after the last item of the + * layout. The exact position depends on the writing system: For a + * left-to-right orientation, it is the same as {@link #EAST}, for + * a right-to-left orientation, it is the same as {@link #WEST}. + * + * @since 1.4 + */ + public static final String LINE_END = AFTER_LINE_ENDS; + + + +// Serialization constant +private static final long serialVersionUID = -8658291919501921765L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial + */ +private Component north; + +/** + * @serial + */ +private Component south; + +/** + * @serial + */ +private Component east; + +/** + * @serial + */ +private Component west; + +/** + * @serial + */ +private Component center; + +/** + * @serial + */ +private Component firstLine; + +/** + * @serial + */ +private Component lastLine; + +/** + * @serial + */ +private Component firstItem; + +/** + * @serial + */ +private Component lastItem; + +/** + * @serial The horizontal gap between components + */ +private int hgap; + +/** + * @serial The vertical gap between components + */ +private int vgap; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of BorderLayout with no + * horiztonal or vertical gaps between components. + */ +public +BorderLayout() +{ + this(0,0); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of BorderLayout with the + * specified horiztonal and vertical gaps between components. + * + * @param hgap The horizontal gap between components. + * @param vgap The vertical gap between components. + */ +public +BorderLayout(int hgap, int vgap) +{ + this.hgap = hgap; + this.vgap = vgap; +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the horitzontal gap value. + * + * @return The horitzontal gap value. + */ +public int +getHgap() +{ + return(hgap); +} + +/*************************************************************************/ + +/** + * Sets the horizontal gap to the specified value. + * + * @param hgap The new horizontal gap. + */ +public void +setHgap(int hgap) +{ + this.hgap = hgap; +} + +/*************************************************************************/ + +/** + * Returns the vertical gap value. + * + * @return The vertical gap value. + */ +public int +getVgap() +{ + return(vgap); +} + +/*************************************************************************/ + +/** + * Sets the vertical gap to the specified value. + * + * @param vgap The new vertical gap value. + */ +public void +setVgap(int vgap) +{ + this.vgap = vgap; +} + +/*************************************************************************/ + +/** + * Adds a component to the layout in the specified constraint position, + * which must be one of the string constants defined in this class. + * + * @param component The component to add. + * @param constraints The constraint string. + * + * @exception IllegalArgumentException If the constraint object is not + * a string, or is not one of the specified constants in this class. + */ +public void +addLayoutComponent(Component component, Object constraints) +{ + if (constraints != null && ! (constraints instanceof String)) + throw new IllegalArgumentException("Constraint must be a string"); + + addLayoutComponent((String) constraints, component); +} + +/*************************************************************************/ + +/** + * Adds a component to the layout in the specified constraint position, + * which must be one of the string constants defined in this class. + * + * @param constraints The constraint string. + * @param component The component to add. + * + * @exception IllegalArgumentException If the constraint object is not + * one of the specified constants in this class. + * + * @deprecated This method is deprecated in favor of + * addLayoutComponent(Component, Object). + */ +public void +addLayoutComponent(String constraints, Component component) +{ + String str = constraints; + + if (str == null || str.equals(CENTER)) + center = component; + else if (str.equals(NORTH)) + north = component; + else if (str.equals(SOUTH)) + south = component; + else if (str.equals(EAST)) + east = component; + else if (str.equals(WEST)) + west = component; + else if (str.equals(BEFORE_FIRST_LINE)) + firstLine = component; + else if (str.equals(AFTER_LAST_LINE)) + lastLine = component; + else if (str.equals(BEFORE_LINE_BEGINS)) + firstItem = component; + else if (str.equals(AFTER_LINE_ENDS)) + lastItem = component; + else + throw new IllegalArgumentException("Constraint value not valid: " + str); +} + +/*************************************************************************/ + +/** + * Removes the specified component from the layout. + * + * @param component The component to remove from the layout. + */ +public void +removeLayoutComponent(Component component) +{ + if (north == component) + north = null; + if (south == component) + south = null; + if (east == component) + east = null; + if (west == component) + west = null; + if (center == component) + center = null; + if (firstItem == component) + firstItem = null; + if (lastItem == component) + lastItem = null; + if (firstLine == component) + firstLine = null; + if (lastLine == component) + lastLine = null; +} + +/*************************************************************************/ + +/** + * Returns the minimum size of the specified container using this layout. + * + * @param target The container to calculate the minimum size for. + * + * @return The minimum size of the container + */ +public Dimension +minimumLayoutSize(Container target) +{ + return calcSize(target, MIN); +} + +/*************************************************************************/ + +/** + * Returns the preferred size of the specified container using this layout. + * + * @param target The container to calculate the preferred size for. + * + * @return The preferred size of the container + */ +public Dimension +preferredLayoutSize(Container target) +{ + return calcSize(target, PREF); +} + +/*************************************************************************/ + +/** + * Returns the maximum size of the specified container using this layout. + * + * @param target The container to calculate the maximum size for. + * + * @return The maximum size of the container + */ +public Dimension +maximumLayoutSize(Container target) +{ + return calcSize(target, MAX); +} + +/*************************************************************************/ + +/** + * Returns the X axis alignment, which is a float indicating + * where along the X axis this container wishs to position its layout. + * 0 indicates align to the left, 1 indicates align to the right, and 0.5 + * indicates align to the center. + * + * @param parent The parent container. + * + * @return The X alignment value. + */ +public float +getLayoutAlignmentX(Container parent) +{ + return(parent.getAlignmentX()); +} + +/*************************************************************************/ + +/** + * Returns the Y axis alignment, which is a float indicating + * where along the Y axis this container wishs to position its layout. + * 0 indicates align to the top, 1 indicates align to the bottom, and 0.5 + * indicates align to the center. + * + * @param parent The parent container. + * + * @return The Y alignment value. + */ +public float +getLayoutAlignmentY(Container parent) +{ + return(parent.getAlignmentY()); +} + +/*************************************************************************/ + +/** + * Instructs this object to discard any layout information it might + * have cached. + * + * @param parent The parent container. + */ +public void +invalidateLayout(Container parent) +{ +} + +/*************************************************************************/ + +/** + * Lays out the specified container according to the constraints + * in this object. + * + * @param target The container to lay out. + */ +public void +layoutContainer(Container target) +{ + synchronized (target.getTreeLock ()) + { + Insets i = target.getInsets(); + + ComponentOrientation orient = target.getComponentOrientation (); + boolean left_to_right = orient.isLeftToRight (); + + Component my_north = north; + Component my_east = east; + Component my_south = south; + Component my_west = west; + + // Note that we currently don't handle vertical layouts. Neither + // does JDK 1.3. + if (firstLine != null) + my_north = firstLine; + if (lastLine != null) + my_south = lastLine; + if (firstItem != null) + { + if (left_to_right) + my_west = firstItem; + else + my_east = firstItem; + } + if (lastItem != null) + { + if (left_to_right) + my_east = lastItem; + else + my_west = lastItem; + } + + Dimension c = calcCompSize(center, PREF); + Dimension n = calcCompSize(my_north, PREF); + Dimension s = calcCompSize(my_south, PREF); + Dimension e = calcCompSize(my_east, PREF); + Dimension w = calcCompSize(my_west, PREF); + Dimension t = target.getSize(); + + /* + <-> hgap <-> hgap + +----------------------------+ } + |t | } i.top + | +----------------------+ | --- y1 } + | |n | | + | +----------------------+ | } vgap + | +---+ +----------+ +---+ | --- y2 } } + | |w | |c | |e | | } hh + | +---+ +----------+ +---+ | } vgap } + | +----------------------+ | --- y3 } + | |s | | + | +----------------------+ | } + | | } i.bottom + +----------------------------+ } + |x1 |x2 |x3 + <----------------------> + <--> ww <--> + i.left i.right + */ + + int x1 = i.left; + int x2 = x1 + w.width + hgap; + int x3; + if (t.width <= i.right + e.width) + x3 = x2 + w.width + hgap; + else + x3 = t.width - i.right - e.width; + int ww = t.width - i.right - i.left; + + int y1 = i.top; + int y2 = y1 + n.height + vgap; + int midh = Math.max(e.height, Math.max(w.height, c.height)); + int y3; + if (t.height <= i.bottom + s.height) + y3 = y2 + midh + vgap; + else + y3 = t.height - i.bottom - s.height; + int hh = y3-y2-vgap; + + setBounds(center, x2, y2, x3-x2-hgap, hh); + setBounds(my_north, x1, y1, ww, n.height); + setBounds(my_south, x1, y3, ww, s.height); + setBounds(my_west, x1, y2, w.width, hh); + setBounds(my_east, x3, y2, e.width, hh); + } +} + +/*************************************************************************/ + +/** + * Returns a string representation of this layout manager. + * + * @return A string representation of this object. + */ +public String +toString() +{ + return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]"; +} + +private void +setBounds(Component comp, int x, int y, int w, int h) +{ + if (comp == null) + return; + comp.setBounds(x, y, w, h); +} + +// Some constants for use with calcSize(). +private static final int MIN = 0; +private static final int MAX = 1; +private static final int PREF = 2; + +private Dimension +calcCompSize(Component comp, int what) +{ + if (comp == null || !comp.isVisible()) + return new Dimension(0, 0); + if (what == MIN) + return comp.getMinimumSize(); + else if (what == MAX) + return comp.getMaximumSize(); + return comp.getPreferredSize(); +} + +// This is a helper function used to compute the various sizes for +// this layout. +private Dimension +calcSize(Container target, int what) +{ + synchronized (target.getTreeLock ()) + { + Insets ins = target.getInsets(); + + ComponentOrientation orient = target.getComponentOrientation (); + boolean left_to_right = orient.isLeftToRight (); + + Component my_north = north; + Component my_east = east; + Component my_south = south; + Component my_west = west; + + // Note that we currently don't handle vertical layouts. Neither + // does JDK 1.3. + if (firstLine != null) + my_north = firstLine; + if (lastLine != null) + my_south = lastLine; + if (firstItem != null) + { + if (left_to_right) + my_west = firstItem; + else + my_east = firstItem; + } + if (lastItem != null) + { + if (left_to_right) + my_east = lastItem; + else + my_west = lastItem; + } + + Dimension ndim = calcCompSize(my_north, what); + Dimension sdim = calcCompSize(my_south, what); + Dimension edim = calcCompSize(my_east, what); + Dimension wdim = calcCompSize(my_west, what); + Dimension cdim = calcCompSize(center, what); + + int width = edim.width + cdim.width + wdim.width + (hgap * 2); + // check for overflow + if (width < edim.width || width < cdim.width || width < cdim.width) + width = Integer.MAX_VALUE; + + if (ndim.width > width) + width = ndim.width; + if (sdim.width > width) + width = sdim.width; + + width += (ins.left + ins.right); + + int height = edim.height; + if (cdim.height > height) + height = cdim.height; + if (wdim.height > height) + height = wdim.height; + + int addedHeight = height + (ndim.height + sdim.height + (vgap * 2) + + ins.top + ins.bottom); + // check for overflow + if (addedHeight < height) + height = Integer.MAX_VALUE; + else + height = addedHeight; + + return(new Dimension(width, height)); + } +} +} // class BorderLayout diff --git a/libjava/classpath/java/awt/BufferCapabilities.java b/libjava/classpath/java/awt/BufferCapabilities.java new file mode 100644 index 0000000..bba83dc --- /dev/null +++ b/libjava/classpath/java/awt/BufferCapabilities.java @@ -0,0 +1,253 @@ +/* BufferCapabilities.java -- double-buffering capabilities descriptor + 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 java.awt; + +import java.awt.image.BufferStrategy; + +/** + * A double-buffering capability descriptor. This class exposes + * details about the double-buffering algorithms used by image + * buffers. + * + * BufferCapabilities represents algorithms that involve at least two + * buffers but it can also specify so-called "multi-buffer" schemes + * involving more than two buffers. This class describes the + * capabilities of the front and back buffers as well as the results + * of "flipping" -- that is, what happens when an image is transferred + * from the back buffer to the front buffer. + * + * Flipping may or may not be supported or may be supported only in + * fullscreen mode. If it is not supported then "blitting" is implied + * -- that is, the contents of the back buffer are copied using a fast + * block transfer operation from the back buffer to the front buffer. + * + * The front buffer is the one that is displayed. + * + * @author Eric Blake (ebb9@email.byu.edu) + * + * @see BufferStrategy#getCapabilities() + * @see GraphicsConfiguration#getBufferCapabilities() + * + * @since 1.4 + */ +public class BufferCapabilities implements Cloneable +{ + /** + * A type-safe enumeration of buffer flipping results. + * + * @see AttributeValue + */ + public static final class FlipContents extends AttributeValue + { + /** + * The names of the different flipping results. + */ + private static final String[] NAMES + = { "undefined", "background", "prior", "copied" }; + + /** + * The contents of the back buffer are undefined after flipping. + */ + public static final FlipContents UNDEFINED = new FlipContents(0); + + /** + * The back buffer is cleared with the background color after + * flipping. + */ + public static final FlipContents BACKGROUND = new FlipContents(1); + + /** + * The back buffer contains the pre-flipping contents of the front + * buffer after flipping. In other words a true "flip" has been + * performed. + */ + public static final FlipContents PRIOR = new FlipContents(2); + + /** + * The back buffer has the same contents as the front buffer after + * flipping. + */ + public static final FlipContents COPIED = new FlipContents(3); + + /** + * Create a new flipping result descriptor. + * + * @param value the enumeration value + */ + private FlipContents(int value) + { + super(value, NAMES); + } + } + + /** + * Front buffer capabilities descriptor. + */ + private final ImageCapabilities front; + + /** + * Back buffer capabilities descriptor. + */ + private final ImageCapabilities back; + + /** + * Describes the results of a "flip" operation. + */ + private final FlipContents flip; + + /** + * Creates a buffer capabilities object. + * + * @param frontCaps front buffer capabilities descriptor + * @param backCaps back buffer capabilities descriptor + * @param flip the results of a flip operation or null if + * flipping is not supported + * + * @exception IllegalArgumentException if frontCaps or backCaps is + * null + */ + public BufferCapabilities(ImageCapabilities frontCaps, + ImageCapabilities backCaps, + FlipContents flip) + { + if (frontCaps == null || backCaps == null) + throw new IllegalArgumentException(); + this.front = frontCaps; + this.back = backCaps; + this.flip = flip; + } + + /** + * Retrieve the front buffer's image capabilities. + * + * @return the front buffer's image capabilities + */ + public ImageCapabilities getFrontBufferCapabilities() + { + return front; + } + + /** + * Retrieve the back buffer's image capabilities. + * + * @return the back buffer's image capabilities + */ + public ImageCapabilities getBackBufferCapabilities() + { + return back; + } + + /** + * Return whether or not flipping is supported. + * + * @return true if flipping is supported, false otherwise + */ + public boolean isPageFlipping() + { + return flip != null; + } + + /** + * Retrieve the result of a flipping operation. If this method + * returns null then flipping is not supported. This implies that + * "blitting", a fast block transfer, is used to copy the contents + * of the back buffer to the front buffer. Other possible return + * values are: + *

+ * + * @return the result of a flipping operation or null if flipping is + * not supported + */ + public FlipContents getFlipContents() + { + return flip; + } + + /** + * Returns true if flipping is only supported in fullscreen mode. + * + * @return true if flipping is only supported in fullscreen mode, + * false otherwise + */ + public boolean isFullScreenRequired() + { + return true; + } + + /** + * Returns true if flipping can involve more than two buffers. One + * or more intermediate buffers may be available in addition to the + * front and back buffers. + * + * @return true if there are more than two buffers available for + * flipping, false otherwise + */ + public boolean isMultiBufferAvailable() + { + return false; + } + + /** + * Clone this buffering capability descriptor. + * + * @return a clone of this buffer capability descriptor + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); + } + } +} diff --git a/libjava/classpath/java/awt/Button.java b/libjava/classpath/java/awt/Button.java new file mode 100644 index 0000000..90be1e5 --- /dev/null +++ b/libjava/classpath/java/awt/Button.java @@ -0,0 +1,466 @@ +/* Button.java -- AWT button widget + Copyright (C) 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 java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.peer.ButtonPeer; +import java.lang.reflect.Array; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleValue; + +/** + * This class provides a button widget for the AWT. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class Button extends Component + implements java.io.Serializable, Accessible +{ + +/* + * Static Variables + */ + +// FIXME: Need readObject/writeObject for serialization + +// Serialization version constant +private static final long serialVersionUID = -8774683716313001058L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The action command name for this button. + * This is package-private to avoid an accessor method. + */ +String actionCommand; + +/** + * @serial The label for this button. + * This is package-private to avoid an accessor method. + */ +String label; + +// List of ActionListeners for this class. +private transient ActionListener action_listeners; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_button_number; + + protected class AccessibleAWTButton extends AccessibleAWTComponent + implements AccessibleAction, AccessibleValue + { + protected AccessibleAWTButton() + { + // Do nothing here. + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#getAccessibleActionCount() + */ + public int getAccessibleActionCount() + { + // Only 1 action possible + return 1; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int) + */ + public String getAccessibleActionDescription(int i) + { + // JDK 1.4.2 returns the string "click" for action 0. However, the API + // docs don't say what the string to be returned is, beyond being a + // description of the action. So we return the same thing for + // compatibility with 1.4.2. + if (i == 0) + return "click"; + return null; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#doAccessibleAction(int) + */ + public boolean doAccessibleAction(int i) + { + if (i != 0) + return false; + processActionEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, actionCommand)); + return true; + } + + public String getAccessibleName() + { + return label; + } + + public AccessibleAction getAccessibleAction() + { + return this; + } + + public AccessibleValue getAccessibleValue() + { + return this; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() + */ + public Number getCurrentAccessibleValue() + { + // Docs say return 1 if selected, but buttons can't be selected, right? + return new Integer(0); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) + */ + public boolean setCurrentAccessibleValue(Number number) + { + // Since there's no selection with buttons, we're ignoring this. + // TODO someone who knows shoulw check this. + return false; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() + */ + public Number getMinimumAccessibleValue() + { + return new Integer(0); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() + */ + public Number getMaximumAccessibleValue() + { + return new Integer(0); + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PUSH_BUTTON; + } + } + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of Button with no label. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true + */ +public +Button() +{ + this(""); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Button with the specified + * label. The action command name is also initialized to this value. + * + * @param label The label to display on the button. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true + */ +public +Button(String label) +{ + this.label = label; + actionCommand = label; + + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the label for this button. + * + * @return The label for this button. + */ +public String +getLabel() +{ + return(label); +} + +/*************************************************************************/ + +/** + * Sets the label for this button to the specified value. + * + * @param label The new label for this button. + */ +public synchronized void +setLabel(String label) +{ + this.label = label; + actionCommand = label; + if (peer != null) + { + ButtonPeer bp = (ButtonPeer) peer; + bp.setLabel (label); + } +} + +/*************************************************************************/ + +/** + * Returns the action command name for this button. + * + * @return The action command name for this button. + */ +public String +getActionCommand() +{ + return(actionCommand); +} + +/*************************************************************************/ + +/** + * Sets the action command name for this button to the specified value. + * + * @param actionCommand The new action command name. + */ +public void +setActionCommand(String actionCommand) +{ + this.actionCommand = actionCommand == null ? label : actionCommand; +} + +/*************************************************************************/ + +/** + * Adds a new entry to the list of listeners that will receive + * action events from this button. + * + * @param listener The listener to add. + */ +public synchronized void +addActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.add(action_listeners, listener); +} + +/*************************************************************************/ + +/** + * Removes the specified listener from the list of listeners that will + * receive action events from this button. + * + * @param listener The listener to remove. + */ +public synchronized void +removeActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.remove(action_listeners, listener); +} + + /** + * Returns all added ActionListener objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public synchronized ActionListener[] getActionListeners() + { + return (ActionListener[]) + AWTEventMulticaster.getListeners(action_listeners, + ActionListener.class); + } + +/** + * Returns all registered EventListers of the given listenerType. + * listenerType must be a subclass of EventListener, or a + * ClassClassException is thrown. + * + * @param listenerType the listener type to return + * + * @return an array of listeners + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements @see java.util.EventListener. + * + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + if (listenerType == ActionListener.class) + return getActionListeners(); + return (EventListener[]) Array.newInstance(listenerType, 0); + } + +/*************************************************************************/ + +/** + * Notifies this button that it should create its native peer object. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createButton (this); + super.addNotify(); +} + +/*************************************************************************/ + +/** + * Processes an event for this button. If the specified event is an + * instance of ActionEvent, then the + * processActionEvent() method is called to dispatch it + * to any registered listeners. Otherwise, the superclass method + * will be invoked. Note that this method will not be called at all + * unless ActionEvent's are enabled. This will be done + * implicitly if any listeners are added. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ActionEvent) + processActionEvent((ActionEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * This method dispatches an action event for this button to any + * registered listeners. + * + * @param event The event to process. + */ +protected void +processActionEvent(ActionEvent event) +{ + if (action_listeners != null) + action_listeners.actionPerformed(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ActionEvent.ACTION_LAST + && e.id >= ActionEvent.ACTION_FIRST + && (action_listeners != null + || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this button. + * + * @return A debugging string for this button. + */ +protected String +paramString() +{ + return getName () + "," + getX () + "," + getY () + "," + + getWidth () + "x" + getHeight () + ",label=" + getLabel (); +} + +/** + * Gets the AccessibleContext associated with this Button. + * The context is created, if necessary. + * + * @return the associated context + */ +public AccessibleContext getAccessibleContext() +{ + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTButton(); + return accessibleContext; +} + + /** + * Generate a unique name for this button. + * + * @return A unique name for this button. + */ + String generateName () + { + return "button" + getUniqueLong (); + } + + private static synchronized long getUniqueLong () + { + return next_button_number++; + } + +} // class Button + diff --git a/libjava/classpath/java/awt/Canvas.java b/libjava/classpath/java/awt/Canvas.java new file mode 100644 index 0000000..fe2f854 --- /dev/null +++ b/libjava/classpath/java/awt/Canvas.java @@ -0,0 +1,354 @@ +/* Canvas.java -- + Copyright (C) 1999, 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 java.awt; + +import java.awt.image.BufferStrategy; +import java.awt.peer.ComponentPeer; +import java.io.Serializable; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * The Canvas component provides a blank rectangular + * area, which the client application can use for drawing and for + * capturing events. By overriding the paint() method, + * the canvas can be used for anything from simple line drawings to + * full-scale custom components. + * + * @author Original author unknown + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.0 + */ + +public class Canvas + extends Component + implements Serializable, Accessible +{ + + /** + * Compatible with Sun's JDK. + */ + private static final long serialVersionUID = -2284879212465893870L; + + /** + * The graphics configuration associated with the canvas. + */ + transient GraphicsConfiguration graphicsConfiguration; + + /** + * The buffer strategy associated with this canvas. + */ + transient BufferStrategy bufferStrategy; + + /** + * Initializes a new instance of Canvas. + */ + public Canvas() + { + } + + /** + * Initializes a new instance of Canvas + * with the supplied graphics configuration. + * + * @param graphicsConfiguration the graphics configuration to use + * for this particular canvas. + */ + public Canvas(GraphicsConfiguration graphicsConfiguration) + { + this.graphicsConfiguration = graphicsConfiguration; + } + + GraphicsConfiguration getGraphicsConfigurationImpl() + { + if (graphicsConfiguration != null) + return graphicsConfiguration; + return super.getGraphicsConfigurationImpl(); + } + + /** + * Creates the native peer for this object. + */ + public void addNotify() + { + if (peer == null) + peer = (ComponentPeer) getToolkit().createCanvas(this); + super.addNotify(); + } + + /** + * Repaints the canvas window. This method should be overridden by + * a subclass to do something useful, as this method simply paints + * the window with the background color. + * + * @param gfx the Graphics to use for painting + */ + public void paint(Graphics gfx) + { + /* This implementation doesn't make much sense since the filling + of background color is guaranteed for heavyweight components + such as this. But there's no need to worry, since paint() is + usually overridden anyway. */ + gfx.setColor(getBackground()); + Dimension size = getSize(); + gfx.fillRect(0, 0, size.width, size.height); + } + + /** + * This class provides accessibility support for the canvas. + */ + protected class AccessibleAWTCanvas + extends AccessibleAWTComponent + { + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = -6325592262103146699L; + + /** + * Constructor for the accessible canvas. + */ + protected AccessibleAWTCanvas() + { + } + + /** + * Returns the accessible role for the canvas. + * + * @return an instance of AccessibleRole, describing + * the role of the canvas. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.CANVAS; + } + + } + + /** + * Gets the AccessibleContext associated with this Canvas. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTCanvas(); + return accessibleContext; + } + + /** + * A BltBufferStrategy for canvases. + */ + private class CanvasBltBufferStrategy extends BltBufferStrategy + { + /** + * Creates a block transfer strategy for this canvas. + * + * @param numBuffers the number of buffers in this strategy + * @param accelerated true if the buffer should be accelerated, + * false otherwise + */ + CanvasBltBufferStrategy(int numBuffers, boolean accelerated) + { + super(numBuffers, + new BufferCapabilities(new ImageCapabilities(accelerated), + new ImageCapabilities(accelerated), + BufferCapabilities.FlipContents.COPIED)); + } + } + + /** + * A FlipBufferStrategy for canvases. + */ + private class CanvasFlipBufferStrategy extends FlipBufferStrategy + { + /** + * Creates a flip buffer strategy for this canvas. + * + * @param numBuffers the number of buffers in this strategy + * + * @throws AWTException if the requested number of buffers is not + * supported + */ + CanvasFlipBufferStrategy(int numBuffers) + throws AWTException + { + super(numBuffers, + new BufferCapabilities(new ImageCapabilities(true), + new ImageCapabilities(true), + BufferCapabilities.FlipContents.COPIED)); + } + } + + /** + * Creates a buffering strategy that manages how this canvas is + * repainted. This method attempts to create the optimum strategy + * based on the desired number of buffers. Hardware or software + * acceleration may be used. + * + * createBufferStrategy attempts different levels of optimization, + * but guarantees that some strategy with the requested number of + * buffers will be created even if it is not optimal. First it + * attempts to create a page flipping strategy, then an accelerated + * blitting strategy, then an unaccelerated blitting strategy. + * + * Calling this method causes any existing buffer strategy to be + * destroyed. + * + * @param numBuffers the number of buffers in this strategy + * + * @throws IllegalArgumentException if requested number of buffers + * is less than one + * @throws IllegalStateException if this canvas is not displayable + * + * @since 1.4 + */ + public void createBufferStrategy(int numBuffers) + { + if (numBuffers < 1) + throw new IllegalArgumentException("Canvas.createBufferStrategy: number" + + " of buffers is less than one"); + + if (!isDisplayable()) + throw new IllegalStateException("Canvas.createBufferStrategy: canvas is" + + " not displayable"); + + BufferStrategy newStrategy = null; + + // try a flipping strategy + try + { + newStrategy = new CanvasFlipBufferStrategy(numBuffers); + } + catch (AWTException e) + { + } + + // fall back to an accelerated blitting strategy + if (newStrategy == null) + newStrategy = new CanvasBltBufferStrategy(numBuffers, true); + + bufferStrategy = newStrategy; + } + + /** + * Creates a buffering strategy that manages how this canvas is + * repainted. This method attempts to create a strategy based on + * the specified capabilities and throws an exception if the + * requested strategy is not supported. + * + * Calling this method causes any existing buffer strategy to be + * destroyed. + * + * @param numBuffers the number of buffers in this strategy + * @param caps the requested buffering capabilities + * + * @throws AWTException if the requested capabilities are not + * supported + * @throws IllegalArgumentException if requested number of buffers + * is less than one or if caps is null + * + * @since 1.4 + */ + public void createBufferStrategy(int numBuffers, + BufferCapabilities caps) + { + if (numBuffers < 1) + throw new IllegalArgumentException("Canvas.createBufferStrategy: number" + + " of buffers is less than one"); + + if (caps == null) + throw new IllegalArgumentException("Canvas.createBufferStrategy:" + + " capabilities object is null"); + + // a flipping strategy was requested + if (caps.isPageFlipping()) + { + try + { + bufferStrategy = new CanvasFlipBufferStrategy(numBuffers); + } + catch (AWTException e) + { + } + } + else + bufferStrategy = new CanvasBltBufferStrategy(numBuffers, true); + } + + /** + * Returns the buffer strategy used by the canvas. + * + * @return the buffer strategy. + * @since 1.4 + */ + public BufferStrategy getBufferStrategy() + { + return bufferStrategy; + } + + /** + * Updates the canvas in response to a request to + * repaint() it. The canvas is cleared + * with the current background colour, before paint() + * is called to add the new contents. Subclasses + * which override this method should either call this + * method via super.update(graphics) or re-implement + * this behaviour, so as to ensure that the canvas is + * clear before painting takes place. + * + * @param graphics the graphics context. + */ + public void update(Graphics graphics) + { + Dimension size; + + /* Clear the canvas */ + size = getSize(); + graphics.clearRect(0, 0, size.width, size.height); + /* Call the paint method */ + paint(graphics); + } +} diff --git a/libjava/classpath/java/awt/CardLayout.java b/libjava/classpath/java/awt/CardLayout.java new file mode 100644 index 0000000..8582c5f --- /dev/null +++ b/libjava/classpath/java/awt/CardLayout.java @@ -0,0 +1,483 @@ +/* CardLayout.java -- Card-based layout engine + Copyright (C) 1999, 2000, 2002, 2003, 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 java.awt; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * This class implements a card-based layout scheme. Each included + * component is treated as a card. Only one card can be shown at a + * time. This class includes methods for changing which card is + * shown. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class CardLayout implements LayoutManager2, Serializable +{ + private static final long serialVersionUID = -4328196481005934313L; + + /** + * Initializes a new instance of CardLayout with horizontal + * and vertical gaps of 0. + */ + public CardLayout () + { + this (0, 0); + } + + /** + * Create a new CardLayout object with the specified + * horizontal and vertical gaps. + * + * @param hgap The horizontal gap + * @param vgap The vertical gap + */ + public CardLayout (int hgap, int vgap) + { + this.hgap = hgap; + this.vgap = vgap; + this.tab = new Hashtable (); + } + + /** + * Add a new component to the layout. The constraint must be a + * string which is used to name the component. This string can + * later be used to refer to the particular component. + * + * @param comp The component to add + * @param constraints The name by which the component can later be called + * + * @exception IllegalArgumentException If `constraints' is not a + * String + */ + public void addLayoutComponent (Component comp, Object constraints) + { + if (! (constraints instanceof String)) + throw new IllegalArgumentException ("Object " + constraints + + " is not a string"); + addLayoutComponent ((String) constraints, comp); + } + + /** + * Add a new component to the layout. The name can be used later + * to refer to the component. + * + * @param name The name by which the component can later be called + * @param comp The component to add + * + * @deprecated This method is deprecated in favor of + * addLayoutComponent(Component, Object). + */ + public void addLayoutComponent (String name, Component comp) + { + tab.put (name, comp); + // First component added is the default component. + comp.setVisible(tab.size() == 1); + } + + /** + * Cause the first component in the container to be displayed. + * + * @param parent The parent container + */ + public void first (Container parent) + { + gotoComponent (parent, FIRST); + } + + /** + * Return this layout manager's horizontal gap. + * + * @return the horizontal gap + */ + public int getHgap () + { + return hgap; + } + + /** + * Return this layout manager's x alignment. This method always + * returns Component.CENTER_ALIGNMENT. + * + * @param parent Container using this layout manager instance + * + * @return the x-axis alignment + */ + public float getLayoutAlignmentX (Container parent) + { + return Component.CENTER_ALIGNMENT; + } + + /** + * Returns this layout manager's y alignment. This method always + * returns Component.CENTER_ALIGNMENT. + * + * @param parent Container using this layout manager instance + * + * @return the y-axis alignment + */ + public float getLayoutAlignmentY (Container parent) + { + return Component.CENTER_ALIGNMENT; + } + + /** + * Return this layout manager's vertical gap. + * + * @return the vertical gap + */ + public int getVgap () + { + return vgap; + } + + /** + * Invalidate this layout manager's state. + */ + public void invalidateLayout (Container target) + { + // Do nothing. + } + + /** + * Cause the last component in the container to be displayed. + * + * @param parent The parent container + */ + public void last (Container parent) + { + gotoComponent (parent, LAST); + } + + /** + * Lays out the container. This is done by resizing the child components + * to be the same size as the parent, less insets and gaps. + * + * @param parent The parent container. + */ + public void layoutContainer (Container parent) + { + synchronized (parent.getTreeLock ()) + { + int width = parent.width; + int height = parent.height; + + Insets ins = parent.getInsets (); + + int num = parent.ncomponents; + Component[] comps = parent.component; + + int x = ins.left + hgap; + int y = ins.top + vgap; + width = width - 2 * hgap - ins.left - ins.right; + height = height - 2 * vgap - ins.top - ins.bottom; + + for (int i = 0; i < num; ++i) + comps[i].setBounds (x, y, width, height); + } + } + + /** + * Get the maximum layout size of the container. + * + * @param target The parent container + * + * @return the maximum layout size + */ + public Dimension maximumLayoutSize (Container target) + { + // The JCL says that this returns Integer.MAX_VALUE for both + // dimensions. But that just seems wrong to me. + return getSize (target, MAX); + } + + /** + * Get the minimum layout size of the container. + * + * @param target The parent container + * + * @return the minimum layout size + */ + public Dimension minimumLayoutSize (Container target) + { + return getSize (target, MIN); + } + + /** + * Cause the next component in the container to be displayed. If + * this current card is the last one in the deck, the first + * component is displayed. + * + * @param parent The parent container + */ + public void next (Container parent) + { + gotoComponent (parent, NEXT); + } + + /** + * Get the preferred layout size of the container. + * + * @param parent The parent container + * + * @return the preferred layout size + */ + public Dimension preferredLayoutSize (Container parent) + { + return getSize (parent, PREF); + } + + /** + * Cause the previous component in the container to be displayed. + * If this current card is the first one in the deck, the last + * component is displayed. + * + * @param parent The parent container + */ + public void previous (Container parent) + { + gotoComponent (parent, PREV); + } + + /** + * Remove the indicated component from this layout manager. + * + * @param comp The component to remove + */ + public void removeLayoutComponent (Component comp) + { + Enumeration e = tab.keys (); + while (e.hasMoreElements ()) + { + Object key = e.nextElement (); + if (tab.get (key) == comp) + { + tab.remove (key); + Container parent = comp.getParent(); + next(parent); + break; + } + } + } + + /** + * Set this layout manager's horizontal gap. + * + * @param hgap The new gap + */ + public void setHgap (int hgap) + { + this.hgap = hgap; + } + + /** + * Set this layout manager's vertical gap. + * + * @param vgap The new gap + */ + public void setVgap (int vgap) + { + this.vgap = vgap; + } + + /** + * Cause the named component to be shown. If the component name is + * unknown, this method does nothing. + * + * @param parent The parent container + * @param name The name of the component to show + */ + public void show (Container parent, String name) + { + Object target = tab.get (name); + if (target != null) + { + int num = parent.ncomponents; + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + for (int i = 0; i < num; ++i) + { + if (comps[i].isVisible()) + { + if (target == comps[i]) + return; + comps[i].setVisible (false); + } + } + ((Component) target).setVisible (true); + } + } + + /** + * Returns a string representation of this layout manager. + * + * @return A string representation of this object. + */ + public String toString () + { + return getClass ().getName () + "[" + hgap + "," + vgap + "]"; + } + + /** + * This implements first(), last(), next(), and previous(). + * + * @param parent The parent container + * @param what The type of goto: FIRST, LAST, NEXT or PREV + */ + private void gotoComponent (Container parent, int what) + { + synchronized (parent.getTreeLock ()) + { + int num = parent.ncomponents; + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + if (num == 1) + { + comps[0].setVisible(true); + return; + } + + int choice = -1; + + if (what == FIRST) + choice = 0; + else if (what == LAST) + choice = num - 1; + + for (int i = 0; i < num; ++i) + { + if (comps[i].isVisible ()) + { + if (what == NEXT) + { + choice = i + 1; + if (choice == num) + choice = 0; + } + else if (what == PREV) + { + choice = i - 1; + if (choice < 0) + choice = num - 1; + } + else if (choice == i) + { + // Do nothing if we're already looking at the right + // component. + return; + } + comps[i].setVisible (false); + + if (choice >= 0) + break; + } + } + + if (choice >= 0 && choice < num) + comps[choice].setVisible (true); + } + } + + // Compute the size according to WHAT. + private Dimension getSize (Container parent, int what) + { + synchronized (parent.getTreeLock ()) + { + int w = 0, h = 0, num = parent.ncomponents; + Component[] comps = parent.component; + + for (int i = 0; i < num; ++i) + { + Dimension d; + + if (what == MIN) + d = comps[i].getMinimumSize (); + else if (what == MAX) + d = comps[i].getMaximumSize (); + else + d = comps[i].getPreferredSize (); + + w = Math.max (d.width, w); + h = Math.max (d.height, h); + } + + Insets i = parent.getInsets (); + w += 2 * hgap + i.right + i.left; + h += 2 * vgap + i.bottom + i.top; + + // Handle overflow. + if (w < 0) + w = Integer.MAX_VALUE; + if (h < 0) + h = Integer.MAX_VALUE; + + return new Dimension (w, h); + } + } + + /** + * @serial Horizontal gap value. + */ + private int hgap; + + /** + * @serial Vertical gap value. + */ + private int vgap; + + /** + * @serial Table of named components. + */ + private Hashtable tab; + + // These constants are used by the private gotoComponent method. + private static final int FIRST = 0; + private static final int LAST = 1; + private static final int NEXT = 2; + private static final int PREV = 3; + + // These constants are used by the private getSize method. + private static final int MIN = 0; + private static final int MAX = 1; + private static final int PREF = 2; +} diff --git a/libjava/classpath/java/awt/Checkbox.java b/libjava/classpath/java/awt/Checkbox.java new file mode 100644 index 0000000..cd39ad4 --- /dev/null +++ b/libjava/classpath/java/awt/Checkbox.java @@ -0,0 +1,649 @@ +/* Checkbox.java -- An AWT checkbox widget + Copyright (C) 1999, 2000, 2001, 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 java.awt; + +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.peer.CheckboxPeer; +import java.io.Serializable; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleValue; + +/** + * This class implements a component which has an on/off state. Two + * or more Checkboxes can be grouped by a CheckboxGroup. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class Checkbox extends Component + implements ItemSelectable, Accessible, Serializable +{ + +// FIXME: Need readObject/writeObject for this. + +/* + * Static Variables + */ + +// Serialization Constant +private static final long serialVersionUID = 7270714317450821763L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The checkbox group for this checkbox. + */ +private CheckboxGroup group; + +/** + * @serial The label on this checkbox. + */ +private String label; + +/** + * @serial The state of this checkbox. + * This is package-private to avoid an accessor method. + */ +boolean state; + +// The list of listeners for this object. +private transient ItemListener item_listeners; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_checkbox_number; + +/** + * This class provides accessibility support for the + * checkbox. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +protected class AccessibleAWTCheckbox + extends AccessibleAWTComponent + implements ItemListener, AccessibleAction, AccessibleValue +{ + /** + * Serialization constant to match JDK 1.5 + */ + private static final long serialVersionUID = 7881579233144754107L; + + /** + * Default constructor which simply calls the + * super class for generic component accessibility + * handling. + */ + public AccessibleAWTCheckbox() + { + super(); + } + + /** + * Captures changes to the state of the checkbox and + * fires appropriate accessible property change events. + * + * @param event the event fired. + * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) + */ + public void itemStateChanged(ItemEvent event) + { + firePropertyChange(ACCESSIBLE_STATE_PROPERTY, + state ? null : AccessibleState.CHECKED, + state ? AccessibleState.CHECKED : null); + } + + /** + * Returns an implementation of the AccessibleAction + * interface for this accessible object. In this case, the + * current instance is simply returned (with a more appropriate + * type), as it also implements the accessible action as well as + * the context. + * + * @return the accessible action associated with this context. + * @see javax.accessibility.AccessibleAction + */ + public AccessibleAction getAccessibleAction() + { + return this; + } + + /** + * Returns an implementation of the AccessibleValue + * interface for this accessible object. In this case, the + * current instance is simply returned (with a more appropriate + * type), as it also implements the accessible value as well as + * the context. + * + * @return the accessible value associated with this context. + * @see javax.accessibility.AccessibleValue + */ + public AccessibleValue getAccessibleValue() + { + return this; + } + + /* + * The following methods are implemented in the JDK (up to + * 1.5) as stubs. We do likewise here. + */ + + /** + * Returns the number of actions associated with this accessible + * object. This default implementation returns 0. + * + * @return the number of accessible actions available. + * @see javax.accessibility.AccessibleAction#getAccessibleActionCount() + */ + public int getAccessibleActionCount() + { + // 1.4.1 and 1.5 do this + return 0; + } + + /** + * Returns a description of the action with the supplied id. + * This default implementation always returns null. + * + * @param i the id of the action whose description should be + * retrieved. + * @return a String describing the action. + * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int) + */ + public String getAccessibleActionDescription(int i) + { + // 1.5 does this + return null; + } + + /** + * Executes the action with the specified id. This + * default implementation simply returns false. + * + * @param i the id of the action to perform. + * @return true if the action was performed. + * @see javax.accessibility.AccessibleAction#doAccessibleAction(int) + */ + public boolean doAccessibleAction(int i) + { + // 1.5 does this + return false; + } + + /** + * Returns the current value of this accessible object. + * If no value has been set, null is returned. This + * default implementation always returns null, regardless. + * + * @return the numeric value of this object, or null if + * no value has been set. + * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() + */ + public Number getCurrentAccessibleValue() + { + // 1.5 does this + return null; + } + + /** + * Sets the current value of this accessible object + * to that supplied. In this default implementation, + * the value is never set and the method always returns + * false. + * + * @param number the new accessible value. + * @return true if the value was set. + * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) + */ + public boolean setCurrentAccessibleValue(Number number) + { + // 1.5 does this + return false; + } + + /** + * Returns the minimum acceptable accessible value used + * by this object, or null if no minimum value exists. + * This default implementation always returns null. + * + * @return the minimum acceptable accessible value, or null + * if there is no minimum. + * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * Returns the maximum acceptable accessible value used + * by this object, or null if no maximum value exists. + * This default implementation always returns null. + * + * @return the maximum acceptable accessible value, or null + * if there is no maximum. + * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() + */ + public Number getMaximumAccessibleValue() + { + return null; + } + + /** + * Returns the role of this accessible object. + * + * @return the instance of AccessibleRole, + * which describes this object. + * @see javax.accessibility.AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.CHECK_BOX; + } + + /** + * Returns the state set of this accessible object. + * + * @return a set of AccessibleStates + * which represent the current state of the + * accessible object. + * @see javax.accessibility.AccessibleState + * @see javax.accessibility.AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet set = super.getAccessibleStateSet(); + if (state) + set.add(AccessibleState.CHECKED); + return set; + } + +} + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of Checkbox with no label, + * an initial state of off, and that is not part of any checkbox group. + */ +public +Checkbox() +{ + this("", false, null); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Checkbox with the specified + * label, an initial state of off, and that is not part of any checkbox + * group. + * + * @param label The label for this checkbox. + */ +public +Checkbox(String label) +{ + this(label, false, null); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Checkbox with the specified + * label and initial state, and that is not part of any checkbox + * group. + * + * @param label The label for this checkbox. + * @param state The initial state of the checkbox, true for + * on, false for off. + */ +public +Checkbox(String label, boolean state) +{ + this(label, state, null); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Checkbox with the specified + * label, initial state, and checkbox group. + * + * @param label The label for this checkbox. + * @param group The checkbox group for this box, or null + * if there is no checkbox group. + * @param state The initial state of the checkbox, true for + * on, false for off. + */ +public +Checkbox(String label, CheckboxGroup group, boolean state) +{ + this(label, state, group); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Checkbox with the specified + * label, initial state, and checkbox group. + * + * @param label The label for this checkbox. + * @param state The initial state of the checkbox, true for + * on, false for off. + * @param group The checkbox group for this box, or null + * if there is no checkbox group. + */ +public +Checkbox(String label, boolean state, CheckboxGroup group) +{ + this.label = label; + this.state = state; + this.group = group; +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the label for this checkbox. + * + * @return The label for this checkbox. + */ +public String +getLabel() +{ + return(label); +} + +/*************************************************************************/ + +/** + * Sets the label for this checkbox to the specified value. + * + * @param label The new checkbox label. + */ +public synchronized void +setLabel(String label) +{ + this.label = label; + if (peer != null) + { + CheckboxPeer cp = (CheckboxPeer) peer; + cp.setLabel(label); + } +} + +/*************************************************************************/ + +/** + * Returns the state of this checkbox. + * + * @return The state of this checkbox, which will be true for + * on and false for off. + */ +public boolean +getState() +{ + return(state); +} + +/*************************************************************************/ + +/** + * Sets the state of this checkbox to the specified value. + * + * @param state The new state of the checkbox, which will be true + * for on or false for off. + */ +public synchronized void +setState(boolean state) +{ + this.state = state; + if (peer != null) + { + CheckboxPeer cp = (CheckboxPeer) peer; + cp.setState (state); + } +} + +/*************************************************************************/ + +/** + * Returns an array of length one containing the checkbox label if this + * checkbox is selected. Otherwise null is returned. + * + * @return The selection state of this checkbox. + */ +public Object[] +getSelectedObjects() +{ + if (state == false) + return(null); + + Object[] objs = new Object[1]; + objs[0] = label; + + return(objs); +} + +/*************************************************************************/ + +/** + * Returns the checkbox group this object is a member of, if any. + * + * @return This object's checkbox group, of null if it is + * not a member of any group. + */ +public CheckboxGroup +getCheckboxGroup() +{ + return(group); +} + +/*************************************************************************/ + +/** + * Sets this object's checkbox group to the specified group. + * + * @param group The new checkbox group, or null to make this + * object part of no checkbox group. + */ +public synchronized void +setCheckboxGroup(CheckboxGroup group) +{ + this.group = group; + if (peer != null) + { + CheckboxPeer cp = (CheckboxPeer) peer; + cp.setCheckboxGroup (group); + } +} + +/*************************************************************************/ + +/** + * Creates this object's native peer. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createCheckbox (this); + super.addNotify (); +} + + public ItemListener[] getItemListeners () + { + return (ItemListener[]) + AWTEventMulticaster.getListeners (item_listeners, ItemListener.class); + } + +/** + * Adds a new listeners to the list of registered listeners for this object. + * + * @param listener The new listener to add. + */ +public synchronized void +addItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.add(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Removes a listener from the list of registered listeners for this object. + * + * @param listener The listener to remove. + */ +public synchronized void +removeItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.remove(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Processes this event by calling processItemEvent() if it + * is any instance of ItemEvent. Otherwise it is passed to + * the superclass for processing. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ItemEvent) + processItemEvent((ItemEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * Processes this event by dispatching it to any registered listeners. + * + * @param event The ItemEvent to process. + */ +protected void +processItemEvent(ItemEvent event) +{ + if (item_listeners != null) + item_listeners.itemStateChanged(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ItemEvent.ITEM_LAST + && e.id >= ItemEvent.ITEM_FIRST + && (item_listeners != null + || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + */ +protected String +paramString() +{ + return ("label=" + label + ",state=" + state + ",group=" + group + + "," + super.paramString()); +} + +/** + * Gets the AccessibleContext associated with this Checkbox. + * The context is created, if necessary. + * + * @return the associated context + */ +public AccessibleContext getAccessibleContext() +{ + /* Create the context if this is the first request */ + if (accessibleContext == null) + { + AccessibleAWTCheckbox ac = new AccessibleAWTCheckbox(); + accessibleContext = ac; + addItemListener(ac); + } + return accessibleContext; +} + + /** + * Generate a unique name for this checkbox. + * + * @return A unique name for this checkbox. + */ + String generateName() + { + return "checkbox" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_checkbox_number++; + } +} diff --git a/libjava/classpath/java/awt/CheckboxGroup.java b/libjava/classpath/java/awt/CheckboxGroup.java new file mode 100644 index 0000000..31b573e --- /dev/null +++ b/libjava/classpath/java/awt/CheckboxGroup.java @@ -0,0 +1,173 @@ +/* CheckboxGroup.java -- A grouping class for checkboxes. + Copyright (C) 1999, 2000, 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 java.awt; + +/** + * This class if for combining checkboxes into groups so that only + * one checkbox in the group can be selected at any one time. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class CheckboxGroup implements java.io.Serializable +{ + +/* + * Static Variables + */ + +// Serialization constant +private static final long serialVersionUID = 3729780091441768983L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The currently selected checkbox. + */ +private Checkbox selectedCheckbox; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of CheckboxGroup. + */ +public +CheckboxGroup() +{ +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the currently selected checkbox, or null if none + * of the checkboxes in this group are selected. + * + * @return The selected checkbox. + */ +public Checkbox +getSelectedCheckbox() +{ + return getCurrent (); +} + +/*************************************************************************/ + +/** + * Returns the currently selected checkbox, or null if none + * of the checkboxes in this group are selected. + * + * @return The selected checkbox. + * + * @deprecated This method is deprecated in favor of + * getSelectedCheckbox(). + */ +public Checkbox +getCurrent() +{ + return(selectedCheckbox); +} + +/*************************************************************************/ + +/** + * This method sets the specified checkbox to be the selected on in this + * group, and unsets all others. + * + * @param selectedCheckbox The new selected checkbox. + */ +public void +setSelectedCheckbox(Checkbox selectedCheckbox) +{ + setCurrent (selectedCheckbox); +} + +/*************************************************************************/ + +/** + * This method sets the specified checkbox to be the selected on in this + * group, and unsets all others. + * + * @param selectedCheckbox The new selected checkbox. + * + * @deprecated This method is deprecated in favor of + * setSelectedCheckbox(). + */ +public void +setCurrent(Checkbox selectedCheckbox) +{ + if (this.selectedCheckbox != null) + { + if (this.selectedCheckbox.getCheckboxGroup() != this) + return; + + this.selectedCheckbox.setState(false); + } + + this.selectedCheckbox = selectedCheckbox; + if (selectedCheckbox != null) + selectedCheckbox.setState(true); +} + +/*************************************************************************/ + +/** + * Returns a string representation of this checkbox group. + * + * @return A string representation of this checkbox group. + */ +public String +toString() +{ + return(getClass().getName() + "[selectedCheckbox=" + selectedCheckbox + "]"); +} + +} // class CheckboxGroup + diff --git a/libjava/classpath/java/awt/CheckboxMenuItem.java b/libjava/classpath/java/awt/CheckboxMenuItem.java new file mode 100644 index 0000000..5e446b8 --- /dev/null +++ b/libjava/classpath/java/awt/CheckboxMenuItem.java @@ -0,0 +1,355 @@ +/* CheckboxMenuItem.java -- A menu option with a checkbox on it. + Copyright (C) 1999, 2000, 2001, 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 java.awt; + +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.peer.CheckboxMenuItemPeer; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleValue; + +/** + * This class implements a menu item that has a checkbox on it indicating + * the selected state of some option. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class CheckboxMenuItem extends MenuItem + implements ItemSelectable, Accessible +{ + +/* + * Static Variables + */ + +// Serialization constant +private static final long serialVersionUID = 6190621106981774043L; + +/* + * Instance Variables + */ + +/** + * @serial The state of the checkbox, with true being on and + * false being off. + */ +private boolean state; + +// List of registered ItemListeners +private transient ItemListener item_listeners; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of CheckboxMenuItem with no + * label and an initial state of off. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +CheckboxMenuItem() +{ + this("", false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of CheckboxMenuItem with the + * specified label and an initial state of off. + * + * @param label The label of the menu item. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +CheckboxMenuItem(String label) +{ + this(label, false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of CheckboxMenuItem with the + * specified label and initial state. + * + * @param label The label of the menu item. + * @param state The initial state of the menu item, where true + * is on, and false is off. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +CheckboxMenuItem(String label, boolean state) +{ + super(label); + this.state = state; + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the state of this menu item. + * + * @return The state of this menu item. + */ +public boolean +getState() +{ + return(state); +} + +/*************************************************************************/ + +/** + * Sets the state of this menu item. + * + * @param state The initial state of the menu item, where true + * is on, and false is off. + */ +public synchronized void +setState(boolean state) +{ + this.state = state; + if (peer != null) + { + CheckboxMenuItemPeer cp = (CheckboxMenuItemPeer) peer; + cp.setState (state); + } +} + +/*************************************************************************/ + +/** + * Returns an array of length 1 with the menu item label for this object + * if the state is on. Otherwise null is returned. + * + * @return An array with this menu item's label if it has a state of on, + * or null otherwise. + */ +public Object[] +getSelectedObjects() +{ + if (state == false) + return(null); + + Object[] obj = new Object[1]; + obj[0] = getLabel(); + + return(obj); +} + +/*************************************************************************/ + +/** + * Create's this object's native peer + */ +public synchronized void +addNotify() +{ + if (peer == null) + peer = getToolkit().createCheckboxMenuItem(this); + + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Adds the specified listener to the list of registered item listeners + * for this object. + * + * @param listener The listener to add. + */ +public synchronized void +addItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.add(item_listeners, listener); + + enableEvents(AWTEvent.ITEM_EVENT_MASK); +} + +/*************************************************************************/ + +/** + * Removes the specified listener from the list of registered item + * listeners for this object. + * + * @param listener The listener to remove. + */ +public synchronized void +removeItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.remove(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Processes the specified event by calling processItemEvent() + * if it is an instance of ItemEvent or calling the superclass + * method otherwise. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ItemEvent) + processItemEvent((ItemEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * Processes the specified event by dispatching it to any registered listeners. + * + * @param event The event to process. + */ +protected void +processItemEvent(ItemEvent event) +{ + if (item_listeners != null) + item_listeners.itemStateChanged(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e instanceof ItemEvent) + { + synchronized (this) + { + state = (((ItemEvent) e).getStateChange() == ItemEvent.SELECTED); + } + } + + if (e.id <= ItemEvent.ITEM_LAST + && e.id >= ItemEvent.ITEM_FIRST + && (item_listeners != null + || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +public String +paramString() +{ + return ("label=" + getLabel() + ",state=" + state + + "," + super.paramString()); +} + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this CheckboxMenuItem. FooListeners are registered using + * the addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + */ + public EventListener[] getListeners (Class listenerType) + { + if (listenerType == ItemListener.class) + return AWTEventMulticaster.getListeners (item_listeners, listenerType); + + return super.getListeners (listenerType); + } + + /** + * Returns an aray of all item listeners currently registered to this + * CheckBoxMenuItem. + */ + public ItemListener[] getItemListeners () + { + return (ItemListener[]) getListeners (ItemListener.class); + } + + + protected class AccessibleAWTCheckboxMenuItem extends AccessibleAWTMenuItem + implements AccessibleAction, AccessibleValue + { + // I think the base class provides the necessary implementation + } + + /** + * Gets the AccessibleContext associated with this CheckboxMenuItem. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTCheckboxMenuItem(); + return accessibleContext; + } + +} // class CheckboxMenuItem + diff --git a/libjava/classpath/java/awt/Choice.java b/libjava/classpath/java/awt/Choice.java new file mode 100644 index 0000000..5075ea9 --- /dev/null +++ b/libjava/classpath/java/awt/Choice.java @@ -0,0 +1,638 @@ +/* Choice.java -- Java choice button widget. + Copyright (C) 1999, 2000, 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 java.awt; + +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.peer.ChoicePeer; +import java.io.Serializable; +import java.util.EventListener; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class implements a drop down choice list. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Choice extends Component + implements ItemSelectable, Serializable, Accessible +{ + +/* + * Static Variables + */ + +// Serialization constant +private static final long serialVersionUID = -4075310674757313071L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial A list of items for the choice box, which can be null. + * This is package-private to avoid an accessor method. + */ +Vector pItems = new Vector(); + +/** + * @serial The index of the selected item in the choice box. + */ +private int selectedIndex = -1; + +// Listener chain +private ItemListener item_listeners; + +/** + * This class provides accessibility support for the + * combo box. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + protected class AccessibleAWTChoice + extends AccessibleAWTComponent + implements AccessibleAction + { + + /** + * Serialization constant to match JDK 1.5 + */ + private static final long serialVersionUID = 7175603582428509322L; + + /** + * Default constructor which simply calls the + * super class for generic component accessibility + * handling. + */ + public AccessibleAWTChoice() + { + super(); + } + + /** + * Returns an implementation of the AccessibleAction + * interface for this accessible object. In this case, the + * current instance is simply returned (with a more appropriate + * type), as it also implements the accessible action as well as + * the context. + * + * @return the accessible action associated with this context. + * @see javax.accessibility.AccessibleAction + */ + public AccessibleAction getAccessibleAction() + { + return this; + } + + /** + * Returns the role of this accessible object. + * + * @return the instance of AccessibleRole, + * which describes this object. + * @see javax.accessibility.AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.COMBO_BOX; + } + + /** + * Returns the number of actions associated with this accessible + * object. In this case, it is the number of choices available. + * + * @return the number of choices available. + * @see javax.accessibility.AccessibleAction#getAccessibleActionCount() + */ + public int getAccessibleActionCount() + { + return pItems.size(); + } + + /** + * Returns a description of the action with the supplied id. + * In this case, it is the text used in displaying the particular + * choice on-screen. + * + * @param i the id of the choice whose description should be + * retrieved. + * @return the String used to describe the choice. + * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int) + */ + public String getAccessibleActionDescription(int i) + { + return (String) pItems.get(i); + } + + /** + * Executes the action with the specified id. In this case, + * calling this method provides the same behaviour as would + * choosing a choice from the list in a visual manner. + * + * @param i the id of the choice to select. + * @return true if a valid choice was specified. + * @see javax.accessibility.AccessibleAction#doAccessibleAction(int) + */ + public boolean doAccessibleAction(int i) + { + if (i < 0 || i >= pItems.size()) + return false; + + Choice.this.processItemEvent(new ItemEvent(Choice.this, + ItemEvent.ITEM_STATE_CHANGED, + this, ItemEvent.SELECTED)); + return true; + } + } + +/*************************************************************************/ + +/* + * Constructors + */ + + /** + * Initializes a new instance of Choice. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true + */ + public Choice() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); + } + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the number of items in the list. + * + * @return The number of items in the list. + */ +public int +getItemCount() +{ + return countItems (); +} + +/*************************************************************************/ + +/** + * Returns the number of items in the list. + * + * @return The number of items in the list. + * + * @deprecated This method is deprecated in favor of getItemCount. + */ +public int +countItems() +{ + return(pItems.size()); +} + +/*************************************************************************/ + +/** + * Returns the item at the specified index in the list. + * + * @param index The index into the list to return the item from. + * + * @exception ArrayIndexOutOfBoundsException If the index is invalid. + */ +public String +getItem(int index) +{ + return((String)pItems.elementAt(index)); +} + +/*************************************************************************/ + +/** + * Adds the specified item to this choice box. + * + * @param item The item to add. + * + * @exception NullPointerException If the item's value is null + * + * @since 1.1 + */ +public synchronized void +add(String item) +{ + if (item == null) + throw new NullPointerException ("item must be non-null"); + + pItems.addElement(item); + + int i = pItems.size () - 1; + if (peer != null) + { + ChoicePeer cp = (ChoicePeer) peer; + cp.add (item, i); + } + else if (selectedIndex == -1) + select(0); +} + +/*************************************************************************/ + +/** + * Adds the specified item to this choice box. + * + * This method is oboslete since Java 2 platform 1.1. Please use @see add + * instead. + * + * @param item The item to add. + * + * @exception NullPointerException If the item's value is equal to null + */ +public synchronized void +addItem(String item) +{ + add(item); +} + +/*************************************************************************/ + +/** Inserts an item into this Choice. Existing items are shifted + * upwards. If the new item is the only item, then it is selected. + * If the currently selected item is shifted, then the first item is + * selected. If the currently selected item is not shifted, then it + * remains selected. + * + * @param item The item to add. + * @param index The index at which the item should be inserted. + * + * @exception IllegalArgumentException If index is less than 0 + */ +public synchronized void +insert(String item, int index) +{ + if (index < 0) + throw new IllegalArgumentException ("index may not be less then 0"); + + if (index > getItemCount ()) + index = getItemCount (); + + pItems.insertElementAt(item, index); + + if (peer != null) + { + ChoicePeer cp = (ChoicePeer) peer; + cp.add (item, index); + } + else if (selectedIndex == -1 || selectedIndex >= index) + select(0); +} + +/*************************************************************************/ + +/** + * Removes the specified item from the choice box. + * + * @param item The item to remove. + * + * @exception IllegalArgumentException If the specified item doesn't exist. + */ +public synchronized void +remove(String item) +{ + int index = pItems.indexOf(item); + if (index == -1) + throw new IllegalArgumentException ("item \"" + + item + "\" not found in Choice"); + remove(index); +} + +/*************************************************************************/ + +/** + * Removes the item at the specified index from the choice box. + * + * @param index The index of the item to remove. + * + * @exception IndexOutOfBoundsException If the index is not valid. + */ +public synchronized void +remove(int index) +{ + if ((index < 0) || (index > getItemCount())) + throw new IllegalArgumentException("Bad index: " + index); + + pItems.removeElementAt(index); + + if (peer != null) + { + ChoicePeer cp = (ChoicePeer) peer; + cp.remove (index); + } + else + { + if (getItemCount() == 0) + selectedIndex = -1; + else if (index == selectedIndex) + select(0); + } + + if (selectedIndex > index) + --selectedIndex; +} + +/*************************************************************************/ + +/** + * Removes all of the objects from this choice box. + */ +public synchronized void +removeAll() +{ + if (getItemCount() <= 0) + return; + + pItems.removeAllElements (); + + if (peer != null) + { + ChoicePeer cp = (ChoicePeer) peer; + cp.removeAll (); + } + + selectedIndex = -1; +} + +/*************************************************************************/ + +/** + * Returns the currently selected item, or null if no item is + * selected. + * + * @return The currently selected item. + */ +public synchronized String +getSelectedItem() +{ + return (selectedIndex == -1 + ? null + : ((String)pItems.elementAt(selectedIndex))); +} + +/*************************************************************************/ + +/** + * Returns an array with one row containing the selected item. + * + * @return An array containing the selected item. + */ +public synchronized Object[] +getSelectedObjects() +{ + if (selectedIndex == -1) + return null; + + Object[] objs = new Object[1]; + objs[0] = pItems.elementAt(selectedIndex); + + return(objs); +} + +/*************************************************************************/ + +/** + * Returns the index of the selected item. + * + * @return The index of the selected item. + */ +public int +getSelectedIndex() +{ + return(selectedIndex); +} + +/*************************************************************************/ + +/** + * Forces the item at the specified index to be selected. + * + * @param index The index of the row to make selected. + * + * @exception IllegalArgumentException If the specified index is invalid. + */ +public synchronized void +select(int index) +{ + if ((index < 0) || (index > getItemCount())) + throw new IllegalArgumentException("Bad index: " + index); + + this.selectedIndex = index; + if (peer != null) + { + ChoicePeer cp = (ChoicePeer) peer; + cp.select (index); + } +} + +/*************************************************************************/ + +/** + * Forces the named item to be selected. + * + * @param item The item to be selected. + * + * @exception IllegalArgumentException If the specified item does not exist. + */ +public synchronized void +select(String item) +{ + int index = pItems.indexOf(item); + if (index >= 0) + select(index); +} + +/*************************************************************************/ + +/** + * Creates the native peer for this object. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createChoice (this); + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Adds the specified listener to the list of registered listeners for + * this object. + * + * @param listener The listener to add. + */ +public synchronized void +addItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.add(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Removes the specified listener from the list of registered listeners for + * this object. + * + * @param listener The listener to remove. + */ +public synchronized void +removeItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.remove(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Processes this event by invoking processItemEvent() if the + * event is an instance of ItemEvent, otherwise the event + * is passed to the superclass. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ItemEvent) + processItemEvent((ItemEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * Processes item event by dispatching to any registered listeners. + * + * @param event The event to process. + */ +protected void +processItemEvent(ItemEvent event) +{ + if (item_listeners != null) + item_listeners.itemStateChanged(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ItemEvent.ITEM_LAST + && e.id >= ItemEvent.ITEM_FIRST + && (item_listeners != null + || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +protected String +paramString() +{ + return ("selectedIndex=" + selectedIndex + "," + super.paramString()); +} + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this Choice. FooListeners are registered using the addFooListener + * method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + * + * @since 1.3 + */ + public EventListener[] getListeners (Class listenerType) + { + if (listenerType == ItemListener.class) + return AWTEventMulticaster.getListeners (item_listeners, listenerType); + + return super.getListeners (listenerType); + } + + /** + * Returns all registered item listeners. + * + * @since 1.4 + */ + public ItemListener[] getItemListeners () + { + return (ItemListener[]) getListeners (ItemListener.class); + } + + /** + * Gets the AccessibleContext associated with this Choice. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTChoice(); + return accessibleContext; + } +} // class Choice diff --git a/libjava/classpath/java/awt/Color.java b/libjava/classpath/java/awt/Color.java new file mode 100644 index 0000000..4ad46d0 --- /dev/null +++ b/libjava/classpath/java/awt/Color.java @@ -0,0 +1,1008 @@ +/* Color.java -- represents a color in Java + Copyright (C) 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 java.awt; + +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.io.Serializable; + +/** + * This class represents a color value in the AWT system. It uses the sRGB + * (standard Red-Green-Blue) system, along with an alpha value ranging from + * transparent (0.0f or 0) and opaque (1.0f or 255). The color is not + * pre-multiplied by the alpha value an any of the accessor methods. Further + * information about sRGB can be found at + * + * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ColorSpace + * @see AlphaComposite + * @since 1.0 + * @status updated to 1.4 + */ +public class Color implements Paint, Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 118526816881161077L; + + /** Constant for the color white: R=255, G=255, B=255. */ + public static final Color white = new Color(0xffffff, false); + + /** + * Constant for the color white: R=255, G=255, B=255. + * + * @since 1.4 + */ + public static final Color WHITE = white; + + /** Constant for the color light gray: R=192, G=192, B=192. */ + public static final Color lightGray = new Color(0xc0c0c0, false); + + /** + * Constant for the color light gray: R=192, G=192, B=192. + * + * @since 1.4 + */ + public static final Color LIGHT_GRAY = lightGray; + + /** Constant for the color gray: R=128, G=128, B=128. */ + public static final Color gray = new Color(0x808080, false); + + /** + * Constant for the color gray: R=128, G=128, B=128. + * + * @since 1.4 + */ + public static final Color GRAY = gray; + + /** Constant for the color dark gray: R=64, G=64, B=64. */ + public static final Color darkGray = new Color(0x404040, false); + + /** + * Constant for the color dark gray: R=64, G=64, B=64. + * + * @since 1.4 + */ + public static final Color DARK_GRAY = darkGray; + + /** Constant for the color black: R=0, G=0, B=0. */ + public static final Color black = new Color(0x000000, false); + + /** + * Constant for the color black: R=0, G=0, B=0. + * + * @since 1.4 + */ + public static final Color BLACK = black; + + /** Constant for the color red: R=255, G=0, B=0. */ + public static final Color red = new Color(0xff0000, false); + + /** + * Constant for the color red: R=255, G=0, B=0. + * + * @since 1.4 + */ + public static final Color RED = red; + + /** Constant for the color pink: R=255, G=175, B=175. */ + public static final Color pink = new Color(0xffafaf, false); + + /** + * Constant for the color pink: R=255, G=175, B=175. + * + * @since 1.4 + */ + public static final Color PINK = pink; + + /** Constant for the color orange: R=255, G=200, B=0. */ + public static final Color orange = new Color(0xffc800, false); + + /** + * Constant for the color orange: R=255, G=200, B=0. + * + * @since 1.4 + */ + public static final Color ORANGE = orange; + + /** Constant for the color yellow: R=255, G=255, B=0. */ + public static final Color yellow = new Color(0xffff00, false); + + /** + * Constant for the color yellow: R=255, G=255, B=0. + * + * @since 1.4 + */ + public static final Color YELLOW = yellow; + + /** Constant for the color green: R=0, G=255, B=0. */ + public static final Color green = new Color(0x00ff00, false); + + /** + * Constant for the color green: R=0, G=255, B=0. + * + * @since 1.4 + */ + public static final Color GREEN = green; + + /** Constant for the color magenta: R=255, G=0, B=255. */ + public static final Color magenta = new Color(0xff00ff, false); + + /** + * Constant for the color magenta: R=255, G=0, B=255. + * + * @since 1.4 + */ + public static final Color MAGENTA = magenta; + + /** Constant for the color cyan: R=0, G=255, B=255. */ + public static final Color cyan = new Color(0x00ffff, false); + + /** + * Constant for the color cyan: R=0, G=255, B=255. + * + * @since 1.4 + */ + public static final Color CYAN = cyan; + + /** Constant for the color blue: R=0, G=0, B=255. */ + public static final Color blue = new Color(0x0000ff, false); + + /** + * Constant for the color blue: R=0, G=0, B=255. + * + * @since 1.4 + */ + public static final Color BLUE = blue; + + /** Internal mask for red. */ + private static final int RED_MASK = 255 << 16; + + /** Internal mask for green. */ + private static final int GREEN_MASK = 255 << 8; + + /** Internal mask for blue. */ + private static final int BLUE_MASK = 255; + + /** Internal mask for alpha. Package visible for use in subclass. */ + static final int ALPHA_MASK = 255 << 24; + + /** Amount to scale a color by when brightening or darkening. */ + private static final float BRIGHT_SCALE = 0.7f; + + /** + * The color value, in sRGB. Note that the actual color may be more + * precise if frgbvalue or fvalue is non-null. This class stores alpha, red, + * green, and blue, each 0-255, packed in an int. However, the subclass + * SystemColor stores an index into an array. Therefore, for serial + * compatibility (and because of poor design on Sun's part), this value + * cannot be used directly; instead you must use getRGB(). + * + * @see #getRGB() + * @serial the value of the color, whether an RGB literal or array index + */ + final int value; + + /** + * The color value, in sRGB. This may be null if the color was constructed + * with ints; and it does not include alpha. This stores red, green, and + * blue, in the range 0.0f - 1.0f. + * + * @see #getRGBColorComponents(float[]) + * @see #getRGBComponents(float[]) + * @serial the rgb components of the value + * @since 1.2 + */ + private float[] frgbvalue; + + /** + * The color value, in the native ColorSpace components. This may be null + * if the color was constructed with ints or in the sRGB color space; and + * it does not include alpha. + * + * @see #getRGBColorComponents(float[]) + * @see #getRGBComponents(float[]) + * @serial the original color space components of the color + * @since 1.2 + */ + private float[] fvalue; + + /** + * The alpha value. This is in the range 0.0f - 1.0f, but is invalid if + * deserialized as 0.0 when frgbvalue is null. + * + * @see #getRGBComponents(float[]) + * @see #getComponents(float[]) + * @serial the alpha component of this color + * @since 1.2 + */ + private final float falpha; + + /** + * The ColorSpace. Null means the default sRGB space. + * + * @see #getColor(String) + * @see #getColorSpace() + * @see #getColorComponents(float[]) + * @serial the color space for this color + * @since 1.2 + */ + private final ColorSpace cs; + + /** + * The paint context for this solid color. Package visible for use in + * subclass. + */ + transient ColorPaintContext context; + + /** + * Initializes a new instance of Color using the specified + * red, green, and blue values, which must be given as integers in the + * range of 0-255. Alpha will default to 255 (opaque). When drawing to + * screen, the actual color may be adjusted to the best match of hardware + * capabilities. + * + * @param red the red component of the RGB value + * @param green the green component of the RGB value + * @param blue the blue component of the RGB value + * @throws IllegalArgumentException if the values are out of range 0-255 + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getRGB() + * @see #Color(int, int, int, int) + */ + public Color(int red, int green, int blue) + { + this(red, green, blue, 255); + } + + /** + * Initializes a new instance of Color using the specified + * red, green, blue, and alpha values, which must be given as integers in + * the range of 0-255. When drawing to screen, the actual color may be + * adjusted to the best match of hardware capabilities. + * + * @param red the red component of the RGB value + * @param green the green component of the RGB value + * @param blue the blue component of the RGB value + * @param alpha the alpha value of the color + * @throws IllegalArgumentException if the values are out of range 0-255 + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getAlpha() + * @see #getRGB() + */ + public Color(int red, int green, int blue, int alpha) + { + if ((red & 255) != red || (green & 255) != green || (blue & 255) != blue + || (alpha & 255) != alpha) + throw new IllegalArgumentException("Bad RGB values" + +" red=0x"+Integer.toHexString(red) + +" green=0x"+Integer.toHexString(green) + +" blue=0x"+Integer.toHexString(blue) + +" alpha=0x"+Integer.toHexString(alpha) ); + + value = (alpha << 24) | (red << 16) | (green << 8) | blue; + falpha = 1; + cs = null; + } + + /** + * Initializes a new instance of Color using the specified + * RGB value. The blue value is in bits 0-7, green in bits 8-15, and + * red in bits 16-23. The other bits are ignored. The alpha value is set + * to 255 (opaque). When drawing to screen, the actual color may be + * adjusted to the best match of hardware capabilities. + * + * @param value the RGB value + * @see ColorModel#getRGBdefault() + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getRGB() + * @see #Color(int, boolean) + */ + public Color(int value) + { + this(value, false); + } + + /** + * Initializes a new instance of Color using the specified + * RGB value. The blue value is in bits 0-7, green in bits 8-15, and + * red in bits 16-23. The alpha value is in bits 24-31, unless hasalpha + * is false, in which case alpha is set to 255. When drawing to screen, the + * actual color may be adjusted to the best match of hardware capabilities. + * + * @param value the RGB value + * @param hasalpha true if value includes the alpha + * @see ColorModel#getRGBdefault() + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getAlpha() + * @see #getRGB() + */ + public Color(int value, boolean hasalpha) + { + // Note: SystemColor calls this constructor, setting falpha to 0; but + // code in getRGBComponents correctly reports falpha as 1.0 to the user + // for all instances of SystemColor since frgbvalue is left null here. + if (hasalpha) + falpha = ((value & ALPHA_MASK) >> 24) / 255f; + else + { + value |= ALPHA_MASK; + falpha = 1; + } + this.value = value; + cs = null; + } + + /** + * Initializes a new instance of Color using the specified + * RGB values. These must be in the range of 0.0-1.0. Alpha is assigned + * the value of 1.0 (opaque). When drawing to screen, the actual color may + * be adjusted to the best match of hardware capabilities. + * + * @param red the red component of the RGB value + * @param green the green component of the RGB value + * @param blue the blue component of the RGB value + * @throws IllegalArgumentException tf the values are out of range 0.0f-1.0f + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getRGB() + * @see #Color(float, float, float, float) + */ + public Color(float red, float green, float blue) + { + this(red, green, blue, 1.0f); + } + + /** + * Initializes a new instance of Color using the specified + * RGB and alpha values. These must be in the range of 0.0-1.0. When drawing + * to screen, the actual color may be adjusted to the best match of + * hardware capabilities. + * + * @param red the red component of the RGB value + * @param green the green component of the RGB value + * @param blue the blue component of the RGB value + * @param alpha the alpha value of the color + * @throws IllegalArgumentException tf the values are out of range 0.0f-1.0f + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getAlpha() + * @see #getRGB() + */ + public Color(float red, float green, float blue, float alpha) + { + value = convert(red, green, blue, alpha); + frgbvalue = new float[] {red, green, blue}; + falpha = alpha; + cs = null; + } + + /** + * Creates a color in the given ColorSpace with the specified alpha. The + * array must be non-null and have enough elements for the color space + * (for example, RGB requires 3 elements, CMYK requires 4). When drawing + * to screen, the actual color may be adjusted to the best match of + * hardware capabilities. + * + * @param space the color space of components + * @param components the color components, except alpha + * @param alpha the alpha value of the color + * @throws NullPointerException if cpsace or components is null + * @throws ArrayIndexOutOfBoundsException if components is too small + * @throws IllegalArgumentException if alpha or any component is out of range + * @see #getComponents(float[]) + * @see #getColorComponents(float[]) + */ + public Color(ColorSpace space, float[] components, float alpha) + { + frgbvalue = space.toRGB(components); + fvalue = components; + falpha = alpha; + cs = space; + value = convert(frgbvalue[0], frgbvalue[1], frgbvalue[2], alpha); + } + + /** + * Returns the red value for this color, as an integer in the range 0-255 + * in the sRGB color space. + * + * @return the red value for this color + * @see #getRGB() + */ + public int getRed() + { + // Do not inline getRGB() to value, because of SystemColor. + return (getRGB() & RED_MASK) >> 16; + } + + /** + * Returns the green value for this color, as an integer in the range 0-255 + * in the sRGB color space. + * + * @return the green value for this color + * @see #getRGB() + */ + public int getGreen() + { + // Do not inline getRGB() to value, because of SystemColor. + return (getRGB() & GREEN_MASK) >> 8; + } + + /** + * Returns the blue value for this color, as an integer in the range 0-255 + * in the sRGB color space. + * + * @return the blue value for this color + * @see #getRGB() + */ + public int getBlue() + { + // Do not inline getRGB() to value, because of SystemColor. + return getRGB() & BLUE_MASK; + } + + /** + * Returns the alpha value for this color, as an integer in the range 0-255. + * + * @return the alpha value for this color + * @see #getRGB() + */ + public int getAlpha() + { + // Do not inline getRGB() to value, because of SystemColor. + return (getRGB() & ALPHA_MASK) >>> 24; + } + + /** + * Returns the RGB value for this color, in the sRGB color space. The blue + * value will be in bits 0-7, green in 8-15, red in 16-23, and alpha value in + * 24-31. + * + * @return the RGB value for this color + * @see ColorModel#getRGBdefault() + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getAlpha() + */ + public int getRGB() + { + return value; + } + + /** + * Returns a brighter version of this color. This is done by increasing the + * RGB values by an arbitrary scale factor. The new color is opaque (an + * alpha of 255). Note that this method and the darker() + * method are not necessarily inverses. + * + * @return a brighter version of this color + * @see #darker() + */ + public Color brighter() + { + // Do not inline getRGB() to this.value, because of SystemColor. + int value = getRGB(); + int red = (value & RED_MASK) >> 16; + int green = (value & GREEN_MASK) >> 8; + int blue = value & BLUE_MASK; + // We have to special case 0-2 because they won't scale by division. + red = red < 3 ? 3 : (int) Math.min(255, red / BRIGHT_SCALE); + green = green < 3 ? 3 : (int) Math.min(255, green / BRIGHT_SCALE); + blue = blue < 3 ? 3 : (int) Math.min(255, blue / BRIGHT_SCALE); + return new Color(red, green, blue, 255); + } + + /** + * Returns a darker version of this color. This is done by decreasing the + * RGB values by an arbitrary scale factor. The new color is opaque (an + * alpha of 255). Note that this method and the brighter() + * method are not necessarily inverses. + * + * @return a darker version of this color + * @see #brighter() + */ + public Color darker() + { + // Do not inline getRGB() to this.value, because of SystemColor. + int value = getRGB(); + return new Color((int) (((value & RED_MASK) >> 16) * BRIGHT_SCALE), + (int) (((value & GREEN_MASK) >> 8) * BRIGHT_SCALE), + (int) ((value & BLUE_MASK) * BRIGHT_SCALE), 255); + } + + /** + * Returns a hash value for this color. This is simply the color in 8-bit + * precision, in the format 0xAARRGGBB (alpha, red, green, blue). + * + * @return a hash value for this color + */ + public int hashCode() + { + return value; + } + + /** + * Tests this object for equality against the specified object. This will + * be true if and only if the specified object is an instance of + * Color and has the same 8-bit integer red, green, and blue + * values as this object. Note that two colors may be slightly different + * as float values, but round to the same integer values. Also note that + * this does not accurately compare SystemColors, since that class does + * not store its internal data in RGB format like regular colors. + * + * @param obj the object to compare to + * @return true if the specified object is semantically equal to this one + */ + public boolean equals(Object obj) + { + return obj instanceof Color && ((Color) obj).value == value; + } + + /** + * Returns a string representation of this object. Subclasses may return + * any desired format, except for null, but this implementation returns + * getClass().getName() + "[r=" + getRed() + ",g=" + getGreen() + * + ",b=" + getBlue() + ']'. + * + * @return a string representation of this object + */ + public String toString() + { + return getClass().getName() + "[r=" + ((value & RED_MASK) >> 16) + + ",g=" + ((value & GREEN_MASK) >> 8) + ",b=" + (value & BLUE_MASK) + + ']'; + } + + /** + * Converts the specified string to a number, using Integer.decode, and + * creates a new instance of Color from the value. The alpha + * value will be 255 (opaque). + * + * @param str the numeric color string + * @return a new instance of Color for the string + * @throws NumberFormatException if the string cannot be parsed + * @throws NullPointerException if the string is null + * @see Integer#decode(String) + * @see #Color(int) + * @since 1.1 + */ + public static Color decode(String str) + { + return new Color(Integer.decode(str).intValue(), false); + } + + /** + * Returns a new instance of Color from the value of the + * system property named by the specified string. If the property does not + * exist, or cannot be parsed, then null will be returned. + * + * @param prop the system property to retrieve + * @throws SecurityException if getting the property is denied + * @see #getColor(String, Color) + * @see Integer#getInteger(String) + */ + public static Color getColor(String prop) + { + return getColor(prop, null); + } + + /** + * Returns a new instance of Color from the value of the + * system property named by the specified string. If the property does + * not exist, or cannot be parsed, then the default color value will be + * returned. + * + * @param prop the system property to retrieve + * @param defcolor the default color + * @throws SecurityException if getting the property is denied + * @see Integer#getInteger(String) + */ + public static Color getColor(String prop, Color defcolor) + { + Integer val = Integer.getInteger(prop, null); + return val == null ? defcolor + : new Color(val.intValue(), false); + } + + /** + * Returns a new instance of Color from the value of the + * system property named by the specified string. If the property does + * not exist, or cannot be parsed, then the default RGB value will be + * used to create a return value. + * + * @param prop the system property to retrieve + * @param defrgb the default RGB value + * @throws SecurityException if getting the property is denied + * @see #getColor(String, Color) + * @see Integer#getInteger(String, int) + */ + public static Color getColor(String prop, int defrgb) + { + Color c = getColor(prop, null); + return c == null ? new Color(defrgb, false) : c; + } + + /** + * Converts from the HSB (hue, saturation, brightness) color model to the + * RGB (red, green, blue) color model. The hue may be any floating point; + * it's fractional portion is used to select the angle in the HSB model. + * The saturation and brightness must be between 0 and 1. The result is + * suitable for creating an RGB color with the one-argument constructor. + * + * @param hue the hue of the HSB value + * @param saturation the saturation of the HSB value + * @param brightness the brightness of the HSB value + * @return the RGB value + * @see #getRGB() + * @see #Color(int) + * @see ColorModel#getRGBdefault() + */ + public static int HSBtoRGB(float hue, float saturation, float brightness) + { + if (saturation == 0) + return convert(brightness, brightness, brightness, 0); + if (saturation < 0 || saturation > 1 || brightness < 0 || brightness > 1) + throw new IllegalArgumentException(); + hue = hue - (float) Math.floor(hue); + int i = (int) (6 * hue); + float f = 6 * hue - i; + float p = brightness * (1 - saturation); + float q = brightness * (1 - saturation * f); + float t = brightness * (1 - saturation * (1 - f)); + switch (i) + { + case 0: + return convert(brightness, t, p, 0); + case 1: + return convert(q, brightness, p, 0); + case 2: + return convert(p, brightness, t, 0); + case 3: + return convert(p, q, brightness, 0); + case 4: + return convert(t, p, brightness, 0); + case 5: + return convert(brightness, p, q, 0); + default: + throw new InternalError("impossible"); + } + } + + /** + * Converts from the RGB (red, green, blue) color model to the HSB (hue, + * saturation, brightness) color model. If the array is null, a new one + * is created, otherwise it is recycled. The results will be in the range + * 0.0-1.0 if the inputs are in the range 0-255. + * + * @param red the red part of the RGB value + * @param green the green part of the RGB value + * @param blue the blue part of the RGB value + * @param array an array for the result (at least 3 elements), or null + * @return the array containing HSB value + * @throws ArrayIndexOutOfBoundsException of array is too small + * @see #getRGB() + * @see #Color(int) + * @see ColorModel#getRGBdefault() + */ + public static float[] RGBtoHSB(int red, int green, int blue, float array[]) + { + if (array == null) + array = new float[3]; + // Calculate brightness. + int min; + int max; + if (red < green) + { + min = red; + max = green; + } + else + { + min = green; + max = red; + } + if (blue > max) + max = blue; + else if (blue < min) + min = blue; + array[2] = max / 255f; + // Calculate saturation. + if (max == 0) + array[1] = 0; + else + array[1] = (max - min) / max; + // Calculate hue. + if (array[1] == 0) + array[0] = 0; + else + { + float delta = (max - min) * 6; + if (red == max) + array[0] = (green - blue) / delta; + else if (green == max) + array[0] = 1f / 3 + (blue - red) / delta; + else + array[0] = 2f / 3 + (red - green) / delta; + if (array[0] < 0) + array[0]++; + } + return array; + } + + /** + * Returns a new instance of Color based on the specified + * HSB values. The hue may be any floating point; it's fractional portion + * is used to select the angle in the HSB model. The saturation and + * brightness must be between 0 and 1. + * + * @param hue the hue of the HSB value + * @param saturation the saturation of the HSB value + * @param brightness the brightness of the HSB value + * @return the new Color object + */ + public static Color getHSBColor(float hue, float saturation, + float brightness) + { + return new Color(HSBtoRGB(hue, saturation, brightness), false); + } + + /** + * Returns a float array with the red, green, and blue components, and the + * alpha value, in the default sRGB space, with values in the range 0.0-1.0. + * If the array is null, a new one is created, otherwise it is recycled. + * + * @param array the array to put results into (at least 4 elements), or null + * @return the RGB components and alpha value + * @throws ArrayIndexOutOfBoundsException if array is too small + */ + public float[] getRGBComponents(float[] array) + { + if (array == null) + array = new float[4]; + getRGBColorComponents(array); + // Stupid serialization issues require this check. + array[3] = (falpha == 0 && frgbvalue == null + ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha); + return array; + } + + /** + * Returns a float array with the red, green, and blue components, in the + * default sRGB space, with values in the range 0.0-1.0. If the array is + * null, a new one is created, otherwise it is recycled. + * + * @param array the array to put results into (at least 3 elements), or null + * @return the RGB components + * @throws ArrayIndexOutOfBoundsException if array is too small + */ + public float[] getRGBColorComponents(float[] array) + { + if (array == null) + array = new float[3]; + else if (array == frgbvalue) + return array; // Optimization for getColorComponents(float[]). + if (frgbvalue == null) + { + // Do not inline getRGB() to this.value, because of SystemColor. + int value = getRGB(); + frgbvalue = new float[] { ((value & RED_MASK) >> 16) / 255f, + ((value & GREEN_MASK) >> 8) / 255f, + (value & BLUE_MASK) / 255f }; + } + array[0] = frgbvalue[0]; + array[1] = frgbvalue[1]; + array[2] = frgbvalue[2]; + return array; + } + + /** + * Returns a float array containing the color and alpha components of this + * color in the ColorSpace it was created with (the constructors which do + * not take a ColorSpace parameter use a default sRGB ColorSpace). If the + * array is null, a new one is created, otherwise it is recycled, and must + * have at least one more position than components used in the color space. + * + * @param array the array to put results into, or null + * @return the original color space components and alpha value + * @throws ArrayIndexOutOfBoundsException if array is too small + */ + public float[] getComponents(float[] array) + { + int numComponents = cs == null ? 3 : cs.getNumComponents(); + if (array == null) + array = new float[1 + numComponents]; + getColorComponents(array); + // Stupid serialization issues require this check. + array[numComponents] = (falpha == 0 && frgbvalue == null + ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha); + return array; + } + + /** + * Returns a float array containing the color components of this color in + * the ColorSpace it was created with (the constructors which do not take + * a ColorSpace parameter use a default sRGB ColorSpace). If the array is + * null, a new one is created, otherwise it is recycled, and must have at + * least as many positions as used in the color space. + * + * @param array the array to put results into, or null + * @return the original color space components + * @throws ArrayIndexOutOfBoundsException if array is too small + */ + public float[] getColorComponents(float[] array) + { + int numComponents = cs == null ? 3 : cs.getNumComponents(); + if (array == null) + array = new float[numComponents]; + if (fvalue == null) // If fvalue is null, cs should be null too. + fvalue = getRGBColorComponents(frgbvalue); + System.arraycopy(fvalue, 0, array, 0, numComponents); + return array; + } + + /** + * Returns a float array containing the color and alpha components of this + * color in the given ColorSpace. If the array is null, a new one is + * created, otherwise it is recycled, and must have at least one more + * position than components used in the color space. + * + * @param space the color space to translate to + * @param array the array to put results into, or null + * @return the color space components and alpha value + * @throws ArrayIndexOutOfBoundsException if array is too small + * @throws NullPointerException if space is null + */ + public float[] getComponents(ColorSpace space, float[] array) + { + int numComponents = space.getNumComponents(); + if (array == null) + array = new float[1 + numComponents]; + getColorComponents(space, array); + // Stupid serialization issues require this check. + array[numComponents] = (falpha == 0 && frgbvalue == null + ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha); + return array; + } + + /** + * Returns a float array containing the color components of this color in + * the given ColorSpace. If the array is null, a new one is created, + * otherwise it is recycled, and must have at least as many positions as + * used in the color space. + * + * @param space the color space to translate to + * @return the color space components + * @throws ArrayIndexOutOfBoundsException if array is too small + * @throws NullPointerException if space is null + */ + public float[] getColorComponents(ColorSpace space, float[] array) + { + float[] components = space.fromRGB(getRGBColorComponents(frgbvalue)); + if (array == null) + return components; + System.arraycopy(components, 0, array, 0, components.length); + return array; + } + + /** + * Returns the color space of this color. Except for the constructor which + * takes a ColorSpace argument, this will be an implementation of + * ColorSpace.CS_sRGB. + * + * @return the color space + */ + public ColorSpace getColorSpace() + { + return cs == null ? ColorSpace.getInstance(ColorSpace.CS_sRGB) : cs; + } + + /** + * Returns a paint context, used for filling areas of a raster scan with + * this color. Since the color is constant across the entire rectangle, and + * since it is always in sRGB space, this implementation returns the same + * object, regardless of the parameters. Subclasses, however, may have a + * mutable result. + * + * @param cm the requested color model + * @param deviceBounds the bounding box in device coordinates, ignored + * @param userBounds the bounding box in user coordinates, ignored + * @param xform the bounds transformation, ignored + * @param hints any rendering hints, ignored + * @return a context for painting this solid color + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + if (context == null || !context.getColorModel().equals(cm)) + context = new ColorPaintContext(cm,value); + return context; + } + + /** + * Returns the transparency level of this color. + * + * @return one of {@link #OPAQUE}, {@link #BITMASK}, or {@link #TRANSLUCENT} + */ + public int getTransparency() + { + // Do not inline getRGB() to this.value, because of SystemColor. + int alpha = getRGB() & ALPHA_MASK; + return alpha == (255 << 24) ? OPAQUE : alpha == 0 ? BITMASK : TRANSLUCENT; + } + + /** + * Converts float values to integer value. + * + * @param red the red value + * @param green the green value + * @param blue the blue value + * @param alpha the alpha value + * @return the integer value made of 8-bit sections + * @throws IllegalArgumentException if parameters are out of range 0.0-1.0 + */ + private static int convert(float red, float green, float blue, float alpha) + { + if (red < 0 || red > 1 || green < 0 || green > 1 || blue < 0 || blue > 1 + || alpha < 0 || alpha > 1) + throw new IllegalArgumentException("Bad RGB values"); + int redval = Math.round(255 * red); + int greenval = Math.round(255 * green); + int blueval = Math.round(255 * blue); + int alphaval = Math.round(255 * alpha); + return (alphaval << 24) | (redval << 16) | (greenval << 8) | blueval; + } +} // class Color diff --git a/libjava/classpath/java/awt/ColorPaintContext.java b/libjava/classpath/java/awt/ColorPaintContext.java new file mode 100644 index 0000000..759ba9d --- /dev/null +++ b/libjava/classpath/java/awt/ColorPaintContext.java @@ -0,0 +1,195 @@ +/* ColorPaintContext.java -- context for painting solid colors + 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 java.awt; + +import java.awt.image.ColorModel; +import java.awt.image.Raster; + +/** + * This class provides a paint context which will fill a rectanglar region of + * a raster scan with the given color. However, it is not yet completely + * implemented. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ +class ColorPaintContext implements PaintContext +{ + /** + * The color to fill any raster with. Package visible for use in + * SystemColor. + */ + final int color; + final ColorModel colorModel; + + private ColorRaster cachedRaster; + + + /** + * Create the context for a given color. + * + * @param c The solid color to use. + */ + ColorPaintContext(int colorRGB) + { + this(ColorModel.getRGBdefault(), colorRGB); + } + + /** + * Create the context for a given color. + * + * @param cm The color model of this context. + * @param c The solid color to use. + */ + ColorPaintContext(ColorModel cm,int colorRGB) + { + color = colorRGB; + colorModel = cm; + } + + /** + * Release the resources allocated for the paint. As the color is constant, + * there aren't any resources. + */ + public void dispose() + { + } + + /** + * Return the color model of this context. + * + * @return the context color model + */ + public ColorModel getColorModel() + { + return colorModel; + } + + /** + * Return a raster containing the colors for the graphics operation. + * + * @param x the x-coordinate, in device space + * @param y the y-coordinate, in device space + * @param width the width, in device space + * @param height the height, in device space + * @return a raster for the given area and color + */ + public Raster getRaster(int x, int y, int width, int height) + { + if( cachedRaster == null + || cachedRaster.getWidth() < width + || cachedRaster.getHeight() < height) + { + cachedRaster = new ColorRaster(colorModel, 0, 0, width, height, color); + } + return cachedRaster.createChild(0 ,0 ,width ,height ,x ,y , null); + } + + /** + * A ColorRaster is a raster that is completely filled with one color. The + * data layout is taken from the color model given to the constructor. + */ + private class ColorRaster extends Raster + { + + /** + * Create a raster that is compaltible with the given color model and + * filled with the given color. + * @param cm The color model for this raster. + * @param x The smallest horizontal corrdinate in the raster. + * @param y The smallest vertical coordinate in the raster. + * @param width The width of the raster. + * @param height The height of the raster. + * @param rgbPixel The RGB value of the color for this raster. + */ + ColorRaster(ColorModel cm,int x, int y, int width, int height, int rgbPixel) + { + super(cm.createCompatibleSampleModel(width,height),new Point(x,y)); + Object pixel = cm.getDataElements(rgbPixel,null); + getSampleModel().setDataElements(0, 0, + width, height, + multiplyData(pixel,null,width*height), + dataBuffer); + } + + + + private Object multiplyData(Object src, Object dest, int factor) + { + Object from; + int srcLength = 0; + if (src instanceof byte[]) + { + srcLength = ((byte[])src).length; + + if (dest == null) dest = new byte[factor * srcLength]; + } + else if (src instanceof short[]) + { + srcLength = ((short[])src).length; + if (dest == null) dest = new short[factor * srcLength]; + } + else if (src instanceof int[]) + { + srcLength = ((int[]) src).length; + if (dest == null) dest = new int[factor * srcLength]; + } + else + { + throw new ClassCastException("Unknown data buffer type"); + } + + System.arraycopy(src,0,dest,0,srcLength); + + int count = 1; + while(count*2 < factor) + { + System.arraycopy(dest, 0, dest, count * srcLength, count*srcLength); + count *= 2; + } + + if(factor > count) + System.arraycopy(dest,0, dest, count * srcLength, + (factor - count) * srcLength ); + + return dest; + } + + } + +} // class ColorPaintContext diff --git a/libjava/classpath/java/awt/Component.java b/libjava/classpath/java/awt/Component.java new file mode 100644 index 0000000..4491904 --- /dev/null +++ b/libjava/classpath/java/awt/Component.java @@ -0,0 +1,6017 @@ +/* Component.java -- a graphics component + Copyright (C) 1999, 2000, 2001, 2002, 2003, 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 java.awt; + +import java.awt.dnd.DropTarget; +import java.awt.event.ActionEvent; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.im.InputContext; +import java.awt.im.InputMethodRequests; +import java.awt.image.BufferStrategy; +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.LightweightPeer; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.Collections; +import java.util.EventListener; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleComponent; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * The root of all evil. All graphical representations are subclasses of this + * giant class, which is designed for screen display and user interaction. + * This class can be extended directly to build a lightweight component (one + * not associated with a native window); lightweight components must reside + * inside a heavyweight window. + * + *

This class is Serializable, which has some big implications. A user can + * save the state of all graphical components in one VM, and reload them in + * another. Note that this class will only save Serializable listeners, and + * ignore the rest, without causing any serialization exceptions. However, by + * making a listener serializable, and adding it to another element, you link + * in that entire element to the state of this component. To get around this, + * use the idiom shown in the example below - make listeners non-serializable + * in inner classes, rather than using this object itself as the listener, if + * external objects do not need to save the state of this object. + * + *

+ * import java.awt.*;
+ * import java.awt.event.*;
+ * import java.io.Serializable;
+ * class MyApp implements Serializable
+ * {
+ *   BigObjectThatShouldNotBeSerializedWithAButton bigOne;
+ *   // Serializing aButton will not suck in an instance of MyApp, with its
+ *   // accompanying field bigOne.
+ *   Button aButton = new Button();
+ *   class MyActionListener implements ActionListener
+ *   {
+ *     public void actionPerformed(ActionEvent e)
+ *     {
+ *       System.out.println("Hello There");
+ *     }
+ *   }
+ *   MyApp()
+ *   {
+ *     aButton.addActionListener(new MyActionListener());
+ *   }
+ * }
+ * 
+ * + *

Status: Incomplete. The event dispatch mechanism is implemented. All + * other methods defined in the J2SE 1.3 API javadoc exist, but are mostly + * incomplete or only stubs; except for methods relating to the Drag and + * Drop, Input Method, and Accessibility frameworks: These methods are + * present but commented out. + * + * @author original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status still missing 1.4 support + */ +public abstract class Component + implements ImageObserver, MenuContainer, Serializable +{ + // Word to the wise - this file is huge. Search for '\f' (^L) for logical + // sectioning by fields, public API, private API, and nested classes. + + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -7644114512714619750L; + + /** + * Constant returned by the getAlignmentY method to indicate + * that the component wishes to be aligned to the top relative to + * other components. + * + * @see #getAlignmentY() + */ + public static final float TOP_ALIGNMENT = 0; + + /** + * Constant returned by the getAlignmentY and + * getAlignmentX methods to indicate + * that the component wishes to be aligned to the center relative to + * other components. + * + * @see #getAlignmentX() + * @see #getAlignmentY() + */ + public static final float CENTER_ALIGNMENT = 0.5f; + + /** + * Constant returned by the getAlignmentY method to indicate + * that the component wishes to be aligned to the bottom relative to + * other components. + * + * @see #getAlignmentY() + */ + public static final float BOTTOM_ALIGNMENT = 1; + + /** + * Constant returned by the getAlignmentX method to indicate + * that the component wishes to be aligned to the right relative to + * other components. + * + * @see #getAlignmentX() + */ + public static final float RIGHT_ALIGNMENT = 1; + + /** + * Constant returned by the getAlignmentX method to indicate + * that the component wishes to be aligned to the left relative to + * other components. + * + * @see #getAlignmentX() + */ + public static final float LEFT_ALIGNMENT = 0; + + /** + * Make the treelock a String so that it can easily be identified + * in debug dumps. We clone the String in order to avoid a conflict in + * the unlikely event that some other package uses exactly the same string + * as a lock object. + */ + static final Object treeLock = new String("AWT_TREE_LOCK"); + + // Serialized fields from the serialization spec. + + /** + * The x position of the component in the parent's coordinate system. + * + * @see #getLocation() + * @serial the x position + */ + int x; + + /** + * The y position of the component in the parent's coordinate system. + * + * @see #getLocation() + * @serial the y position + */ + int y; + + /** + * The component width. + * + * @see #getSize() + * @serial the width + */ + int width; + + /** + * The component height. + * + * @see #getSize() + * @serial the height + */ + int height; + + /** + * The foreground color for the component. This may be null. + * + * @see #getForeground() + * @see #setForeground(Color) + * @serial the foreground color + */ + Color foreground; + + /** + * The background color for the component. This may be null. + * + * @see #getBackground() + * @see #setBackground(Color) + * @serial the background color + */ + Color background; + + /** + * The default font used in the component. This may be null. + * + * @see #getFont() + * @see #setFont(Font) + * @serial the font + */ + Font font; + + /** + * The font in use by the peer, or null if there is no peer. + * + * @serial the peer's font + */ + Font peerFont; + + /** + * The cursor displayed when the pointer is over this component. This may + * be null. + * + * @see #getCursor() + * @see #setCursor(Cursor) + */ + Cursor cursor; + + /** + * The locale for the component. + * + * @see #getLocale() + * @see #setLocale(Locale) + */ + Locale locale = Locale.getDefault (); + + /** + * True if the object should ignore repaint events (usually because it is + * not showing). + * + * @see #getIgnoreRepaint() + * @see #setIgnoreRepaint(boolean) + * @serial true to ignore repaints + * @since 1.4 + */ + boolean ignoreRepaint; + + /** + * True when the object is visible (although it is only showing if all + * ancestors are likewise visible). For component, this defaults to true. + * + * @see #isVisible() + * @see #setVisible(boolean) + * @serial true if visible + */ + boolean visible = true; + + /** + * True if the object is enabled, meaning it can interact with the user. + * For component, this defaults to true. + * + * @see #isEnabled() + * @see #setEnabled(boolean) + * @serial true if enabled + */ + boolean enabled = true; + + /** + * True if the object is valid. This is set to false any time a size + * adjustment means the component need to be layed out again. + * + * @see #isValid() + * @see #validate() + * @see #invalidate() + * @serial true if layout is valid + */ + boolean valid; + + /** + * The DropTarget for drag-and-drop operations. + * + * @see #getDropTarget() + * @see #setDropTarget(DropTarget) + * @serial the drop target, or null + * @since 1.2 + */ + DropTarget dropTarget; + + /** + * The list of popup menus for this component. + * + * @see #add(PopupMenu) + * @serial the list of popups + */ + Vector popups; + + /** + * The component's name. May be null, in which case a default name is + * generated on the first use. + * + * @see #getName() + * @see #setName(String) + * @serial the name + */ + String name; + + /** + * True once the user has set the name. Note that the user may set the name + * to null. + * + * @see #name + * @see #getName() + * @see #setName(String) + * @serial true if the name has been explicitly set + */ + boolean nameExplicitlySet; + + /** + * Indicates if the object can be focused. Defaults to true for components. + * + * @see #isFocusable() + * @see #setFocusable(boolean) + * @since 1.4 + */ + boolean focusable = true; + + /** + * Tracks whether this component's {@link #isFocusTraversable} + * method has been overridden. + * + * @since 1.4 + */ + int isFocusTraversableOverridden; + + /** + * The focus traversal keys, if not inherited from the parent or + * default keyboard focus manager. These sets will contain only + * AWTKeyStrokes that represent press and release events to use as + * focus control. + * + * @see #getFocusTraversalKeys(int) + * @see #setFocusTraversalKeys(int, Set) + * @since 1.4 + */ + Set[] focusTraversalKeys; + + /** + * True if focus traversal keys are enabled. This defaults to true for + * Component. If this is true, keystrokes in focusTraversalKeys are trapped + * and processed automatically rather than being passed on to the component. + * + * @see #getFocusTraversalKeysEnabled() + * @see #setFocusTraversalKeysEnabled(boolean) + * @since 1.4 + */ + boolean focusTraversalKeysEnabled = true; + + /** + * Cached information on the minimum size. Should have been transient. + * + * @serial ignore + */ + Dimension minSize; + + /** + * Cached information on the preferred size. Should have been transient. + * + * @serial ignore + */ + Dimension prefSize; + + /** + * Set to true if an event is to be handled by this component, false if + * it is to be passed up the hierarcy. + * + * @see #dispatchEvent(AWTEvent) + * @serial true to process event locally + */ + boolean newEventsOnly; + + /** + * Set by subclasses to enable event handling of particular events, and + * left alone when modifying listeners. For component, this defaults to + * enabling only input methods. + * + * @see #enableInputMethods(boolean) + * @see AWTEvent + * @serial the mask of events to process + */ + long eventMask = AWTEvent.INPUT_ENABLED_EVENT_MASK; + + /** + * Describes all registered PropertyChangeListeners. + * + * @see #addPropertyChangeListener(PropertyChangeListener) + * @see #removePropertyChangeListener(PropertyChangeListener) + * @see #firePropertyChange(String, Object, Object) + * @serial the property change listeners + * @since 1.2 + */ + PropertyChangeSupport changeSupport; + + /** + * True if the component has been packed (layed out). + * + * @serial true if this is packed + */ + boolean isPacked; + + /** + * The serialization version for this class. Currently at version 4. + * + * XXX How do we handle prior versions? + * + * @serial the serialization version + */ + int componentSerializedDataVersion = 4; + + /** + * The accessible context associated with this component. This is only set + * by subclasses. + * + * @see #getAccessibleContext() + * @serial the accessibility context + * @since 1.2 + */ + AccessibleContext accessibleContext; + + + // Guess what - listeners are special cased in serialization. See + // readObject and writeObject. + + /** Component listener chain. */ + transient ComponentListener componentListener; + + /** Focus listener chain. */ + transient FocusListener focusListener; + + /** Key listener chain. */ + transient KeyListener keyListener; + + /** Mouse listener chain. */ + transient MouseListener mouseListener; + + /** Mouse motion listener chain. */ + transient MouseMotionListener mouseMotionListener; + + /** + * Mouse wheel listener chain. + * + * @since 1.4 + */ + transient MouseWheelListener mouseWheelListener; + + /** + * Input method listener chain. + * + * @since 1.2 + */ + transient InputMethodListener inputMethodListener; + + /** + * Hierarcy listener chain. + * + * @since 1.3 + */ + transient HierarchyListener hierarchyListener; + + /** + * Hierarcy bounds listener chain. + * + * @since 1.3 + */ + transient HierarchyBoundsListener hierarchyBoundsListener; + + // Anything else is non-serializable, and should be declared "transient". + + /** The parent. */ + transient Container parent; + + /** The associated native peer. */ + transient ComponentPeer peer; + + /** The preferred component orientation. */ + transient ComponentOrientation orientation = ComponentOrientation.UNKNOWN; + + /** + * The associated graphics configuration. + * + * @since 1.4 + */ + transient GraphicsConfiguration graphicsConfig; + + /** + * The buffer strategy for repainting. + * + * @since 1.4 + */ + transient BufferStrategy bufferStrategy; + + /** + * true if requestFocus was called on this component when its + * top-level ancestor was not focusable. + */ + private transient FocusEvent pendingFocusRequest = null; + + /** + * The system properties that affect image updating. + */ + private static transient boolean incrementalDraw; + private static transient Long redrawRate; + + static + { + incrementalDraw = Boolean.getBoolean ("awt.image.incrementalDraw"); + redrawRate = Long.getLong ("awt.image.redrawrate"); + } + + // Public and protected API. + + /** + * Default constructor for subclasses. When Component is extended directly, + * it forms a lightweight component that must be hosted in an opaque native + * container higher in the tree. + */ + protected Component() + { + } + + /** + * Returns the name of this component. + * + * @return the name of this component + * @see #setName(String) + * @since 1.1 + */ + public String getName() + { + if (name == null && ! nameExplicitlySet) + name = generateName(); + return name; + } + + /** + * Sets the name of this component to the specified name. + * + * @param name the new name of this component + * @see #getName() + * @since 1.1 + */ + public void setName(String name) + { + nameExplicitlySet = true; + this.name = name; + } + + /** + * Returns the parent of this component. + * + * @return the parent of this component + */ + public Container getParent() + { + return parent; + } + + /** + * Returns the native windowing system peer for this component. Only the + * platform specific implementation code should call this method. + * + * @return the peer for this component + * @deprecated user programs should not directly manipulate peers; use + * {@link #isDisplayable()} instead + */ + // Classpath's Gtk peers rely on this. + public ComponentPeer getPeer() + { + return peer; + } + + /** + * Set the associated drag-and-drop target, which receives events when this + * is enabled. + * + * @param dt the new drop target + * @see #isEnabled() + */ + public void setDropTarget(DropTarget dt) + { + this.dropTarget = dt; + } + + /** + * Gets the associated drag-and-drop target, if there is one. + * + * @return the drop target + */ + public DropTarget getDropTarget() + { + return dropTarget; + } + + /** + * Returns the graphics configuration of this component, if there is one. + * If it has not been set, it is inherited from the parent. + * + * @return the graphics configuration, or null + * @since 1.3 + */ + public GraphicsConfiguration getGraphicsConfiguration() + { + return getGraphicsConfigurationImpl(); + } + + /** + * Returns the object used for synchronization locks on this component + * when performing tree and layout functions. + * + * @return the synchronization lock for this component + */ + public final Object getTreeLock() + { + return treeLock; + } + + /** + * Returns the toolkit in use for this component. The toolkit is associated + * with the frame this component belongs to. + * + * @return the toolkit for this component + */ + public Toolkit getToolkit() + { + if (peer != null) + { + Toolkit tk = peer.getToolkit(); + if (tk != null) + return tk; + } + // Get toolkit for lightweight component. + if (parent != null) + return parent.getToolkit(); + return Toolkit.getDefaultToolkit(); + } + + /** + * Tests whether or not this component is valid. A invalid component needs + * to have its layout redone. + * + * @return true if this component is valid + * @see #validate() + * @see #invalidate() + */ + public boolean isValid() + { + return valid; + } + + /** + * Tests if the component is displayable. It must be connected to a native + * screen resource, and all its ancestors must be displayable. A containment + * hierarchy is made displayable when a window is packed or made visible. + * + * @return true if the component is displayable + * @see Container#add(Component) + * @see Container#remove(Component) + * @see Window#pack() + * @see Window#show() + * @see Window#dispose() + * @since 1.2 + */ + public boolean isDisplayable() + { + if (parent != null) + return parent.isDisplayable(); + return false; + } + + /** + * Tests whether or not this component is visible. Except for top-level + * frames, components are initially visible. + * + * @return true if the component is visible + * @see #setVisible(boolean) + */ + public boolean isVisible() + { + return visible; + } + + /** + * Tests whether or not this component is actually being shown on + * the screen. This will be true if and only if it this component is + * visible and its parent components are all visible. + * + * @return true if the component is showing on the screen + * @see #setVisible(boolean) + */ + public boolean isShowing() + { + if (! visible || peer == null) + return false; + + return parent == null ? true : parent.isShowing(); + } + + /** + * Tests whether or not this component is enabled. Components are enabled + * by default, and must be enabled to receive user input or generate events. + * + * @return true if the component is enabled + * @see #setEnabled(boolean) + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * Enables or disables this component. The component must be enabled to + * receive events (except that lightweight components always receive mouse + * events). + * + * @param enabled true to enable this component + * + * @see #isEnabled() + * @see #isLightweight() + * + * @since 1.1 + */ + public void setEnabled(boolean enabled) + { + enable(enabled); + } + + /** + * Enables this component. + * + * @deprecated use {@link #setEnabled(boolean)} instead + */ + public void enable() + { + this.enabled = true; + if (peer != null) + peer.setEnabled (true); + } + + /** + * Enables or disables this component. + * + * @param enabled true to enable this component + * + * @deprecated use {@link #setEnabled(boolean)} instead + */ + public void enable(boolean enabled) + { + if (enabled) + enable(); + else + disable(); + } + + /** + * Disables this component. + * + * @deprecated use {@link #setEnabled(boolean)} instead + */ + public void disable() + { + this.enabled = false; + if (peer != null) + peer.setEnabled (false); + } + + /** + * Checks if this image is painted to an offscreen image buffer that is + * later copied to screen (double buffering reduces flicker). This version + * returns false, so subclasses must override it if they provide double + * buffering. + * + * @return true if this is double buffered; defaults to false + */ + public boolean isDoubleBuffered() + { + return false; + } + + /** + * Enables or disables input method support for this component. By default, + * components have this enabled. Input methods are given the opportunity + * to process key events before this component and its listeners. + * + * @param enable true to enable input method processing + * @see #processKeyEvent(KeyEvent) + * @since 1.2 + */ + public void enableInputMethods(boolean enable) + { + if (enable) + eventMask |= AWTEvent.INPUT_ENABLED_EVENT_MASK; + else + eventMask &= ~AWTEvent.INPUT_ENABLED_EVENT_MASK; + } + + /** + * Makes this component visible or invisible. Note that it wtill might + * not show the component, if a parent is invisible. + * + * @param visible true to make this component visible + * + * @see #isVisible() + * + * @since 1.1 + */ + public void setVisible(boolean visible) + { + // Inspection by subclassing shows that Sun's implementation calls + // show(boolean) which then calls show() or hide(). It is the show() + // method that is overriden in subclasses like Window. + show(visible); + } + + /** + * Makes this component visible on the screen. + * + * @deprecated use {@link #setVisible(boolean)} instead + */ + public void show() + { + // We must set visible before showing the peer. Otherwise the + // peer could post paint events before visible is true, in which + // case lightweight components are not initially painted -- + // Container.paint first calls isShowing () before painting itself + // and its children. + if(!isVisible()) + { + this.visible = true; + if (peer != null) + peer.setVisible(true); + invalidate(); + ComponentEvent ce = + new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + + /** + * Makes this component visible or invisible. + * + * @param visible true to make this component visible + * + * @deprecated use {@link #setVisible(boolean)} instead + */ + public void show(boolean visible) + { + if (visible) + show(); + else + hide(); + } + + /** + * Hides this component so that it is no longer shown on the screen. + * + * @deprecated use {@link #setVisible(boolean)} instead + */ + public void hide() + { + if (isVisible()) + { + if (peer != null) + peer.setVisible(false); + this.visible = false; + invalidate(); + ComponentEvent ce = + new ComponentEvent(this,ComponentEvent.COMPONENT_HIDDEN); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + + /** + * Returns this component's foreground color. If not set, this is inherited + * from the parent. + * + * @return this component's foreground color, or null + * @see #setForeground(Color) + */ + public Color getForeground() + { + if (foreground != null) + return foreground; + return parent == null ? SystemColor.windowText : parent.getForeground(); + } + + /** + * Sets this component's foreground color to the specified color. This is a + * bound property. + * + * @param c the new foreground color + * @see #getForeground() + */ + public void setForeground(Color c) + { + firePropertyChange("foreground", foreground, c); + if (peer != null) + peer.setForeground(c); + foreground = c; + } + + /** + * Tests if the foreground was explicitly set, or just inherited from the + * parent. + * + * @return true if the foreground has been set + * @since 1.4 + */ + public boolean isForegroundSet() + { + return foreground != null; + } + + /** + * Returns this component's background color. If not set, this is inherited + * from the parent. + * + * @return the background color of the component, or null + * @see #setBackground(Color) + */ + public Color getBackground() + { + if (background != null) + return background; + return parent == null ? SystemColor.window : parent.getBackground(); + } + + /** + * Sets this component's background color to the specified color. The parts + * of the component affected by the background color may by system dependent. + * This is a bound property. + * + * @param c the new background color + * @see #getBackground() + */ + public void setBackground(Color c) + { + // return if the background is already set to that color. + if (background != null && c != null) + if (background.equals(c)) + return; + // If c is null, inherit from closest ancestor whose bg is set. + if (c == null && parent != null) + c = parent.getBackground(); + firePropertyChange("background", background, c); + if (peer != null && c != null) + peer.setBackground(c); + background = c; + } + + /** + * Tests if the background was explicitly set, or just inherited from the + * parent. + * + * @return true if the background has been set + * @since 1.4 + */ + public boolean isBackgroundSet() + { + return background != null; + } + + /** + * Returns the font in use for this component. If not set, this is inherited + * from the parent. + * + * @return the font for this component + * @see #setFont(Font) + */ + public Font getFont() + { + if (font != null) + return font; + + if (parent != null) + return parent.getFont (); + else + return new Font ("Dialog", Font.PLAIN, 12); + } + + /** + * Sets the font for this component to the specified font. This is a bound + * property. + * + * @param newFont the new font for this component + * + * @see #getFont() + */ + public void setFont(Font newFont) + { + if (font == newFont) + return; + + Font oldFont = font; + font = newFont; + if (peer != null) + peer.setFont(font); + firePropertyChange("font", oldFont, newFont); + invalidate(); + } + + /** + * Tests if the font was explicitly set, or just inherited from the parent. + * + * @return true if the font has been set + * @since 1.4 + */ + public boolean isFontSet() + { + return font != null; + } + + /** + * Returns the locale for this component. If this component does not + * have a locale, the locale of the parent component is returned. + * + * @return the locale for this component + * @throws IllegalComponentStateException if it has no locale or parent + * @see #setLocale(Locale) + * @since 1.1 + */ + public Locale getLocale() + { + if (locale != null) + return locale; + if (parent == null) + throw new IllegalComponentStateException + ("Component has no parent: can't determine Locale"); + return parent.getLocale(); + } + + /** + * Sets the locale for this component to the specified locale. This is a + * bound property. + * + * @param newLocale the new locale for this component + */ + public void setLocale(Locale newLocale) + { + if (locale == newLocale) + return; + + Locale oldLocale = locale; + locale = newLocale; + firePropertyChange("locale", oldLocale, newLocale); + // New writing/layout direction or more/less room for localized labels. + invalidate(); + } + + /** + * Returns the color model of the device this componet is displayed on. + * + * @return this object's color model + * @see Toolkit#getColorModel() + */ + public ColorModel getColorModel() + { + GraphicsConfiguration config = getGraphicsConfiguration(); + return config != null ? config.getColorModel() + : getToolkit().getColorModel(); + } + + /** + * Returns the location of this component's top left corner relative to + * its parent component. This may be outdated, so for synchronous behavior, + * you should use a component listner. + * + * @return the location of this component + * @see #setLocation(int, int) + * @see #getLocationOnScreen() + * @since 1.1 + */ + public Point getLocation() + { + return location (); + } + + /** + * Returns the location of this component's top left corner in screen + * coordinates. + * + * @return the location of this component in screen coordinates + * @throws IllegalComponentStateException if the component is not showing + */ + public Point getLocationOnScreen() + { + if (! isShowing()) + throw new IllegalComponentStateException("component " + + getClass().getName() + + " not showing"); + // We know peer != null here. + return peer.getLocationOnScreen(); + } + + /** + * Returns the location of this component's top left corner relative to + * its parent component. + * + * @return the location of this component + * @deprecated use {@link #getLocation()} instead + */ + public Point location() + { + return new Point (x, y); + } + + /** + * Moves this component to the specified location, relative to the parent's + * coordinates. The coordinates are the new upper left corner of this + * component. + * + * @param x the new X coordinate of this component + * @param y the new Y coordinate of this component + * @see #getLocation() + * @see #setBounds(int, int, int, int) + */ + public void setLocation(int x, int y) + { + move (x, y); + } + + /** + * Moves this component to the specified location, relative to the parent's + * coordinates. The coordinates are the new upper left corner of this + * component. + * + * @param x the new X coordinate of this component + * @param y the new Y coordinate of this component + * @deprecated use {@link #setLocation(int, int)} instead + */ + public void move(int x, int y) + { + setBounds(x, y, this.width, this.height); + } + + /** + * Moves this component to the specified location, relative to the parent's + * coordinates. The coordinates are the new upper left corner of this + * component. + * + * @param p new coordinates for this component + * @throws NullPointerException if p is null + * @see #getLocation() + * @see #setBounds(int, int, int, int) + * @since 1.1 + */ + public void setLocation(Point p) + { + setLocation(p.x, p.y); + } + + /** + * Returns the size of this object. + * + * @return the size of this object + * @see #setSize(int, int) + * @since 1.1 + */ + public Dimension getSize() + { + return size (); + } + + /** + * Returns the size of this object. + * + * @return the size of this object + * @deprecated use {@link #getSize()} instead + */ + public Dimension size() + { + return new Dimension (width, height); + } + + /** + * Sets the size of this component to the specified width and height. + * + * @param width the new width of this component + * @param height the new height of this component + * @see #getSize() + * @see #setBounds(int, int, int, int) + */ + public void setSize(int width, int height) + { + resize (width, height); + } + + /** + * Sets the size of this component to the specified value. + * + * @param width the new width of the component + * @param height the new height of the component + * @deprecated use {@link #setSize(int, int)} instead + */ + public void resize(int width, int height) + { + setBounds(this.x, this.y, width, height); + } + + /** + * Sets the size of this component to the specified value. + * + * @param d the new size of this component + * @throws NullPointerException if d is null + * @see #setSize(int, int) + * @see #setBounds(int, int, int, int) + * @since 1.1 + */ + public void setSize(Dimension d) + { + resize (d); + } + + /** + * Sets the size of this component to the specified value. + * + * @param d the new size of this component + * @throws NullPointerException if d is null + * @deprecated use {@link #setSize(Dimension)} instead + */ + public void resize(Dimension d) + { + resize (d.width, d.height); + } + + /** + * Returns a bounding rectangle for this component. Note that the + * returned rectange is relative to this component's parent, not to + * the screen. + * + * @return the bounding rectangle for this component + * @see #setBounds(int, int, int, int) + * @see #getLocation() + * @see #getSize() + */ + public Rectangle getBounds() + { + return bounds (); + } + + /** + * Returns a bounding rectangle for this component. Note that the + * returned rectange is relative to this component's parent, not to + * the screen. + * + * @return the bounding rectangle for this component + * @deprecated use {@link #getBounds()} instead + */ + public Rectangle bounds() + { + return new Rectangle (x, y, width, height); + } + + /** + * Sets the bounding rectangle for this component to the specified values. + * Note that these coordinates are relative to the parent, not to the screen. + * + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @see #getBounds() + * @see #setLocation(int, int) + * @see #setLocation(Point) + * @see #setSize(int, int) + * @see #setSize(Dimension) + * @since 1.1 + */ + public void setBounds(int x, int y, int w, int h) + { + reshape (x, y, w, h); + } + + /** + * Sets the bounding rectangle for this component to the specified values. + * Note that these coordinates are relative to the parent, not to the screen. + * + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * @deprecated use {@link #setBounds(int, int, int, int)} instead + */ + public void reshape(int x, int y, int width, int height) + { + int oldx = this.x; + int oldy = this.y; + int oldwidth = this.width; + int oldheight = this.height; + + if (this.x == x && this.y == y + && this.width == width && this.height == height) + return; + invalidate (); + this.x = x; + this.y = y; + this.width = width; + this.height = height; + if (peer != null) + peer.setBounds (x, y, width, height); + + // Erase old bounds and repaint new bounds for lightweights. + if (isLightweight() && isShowing ()) + { + boolean shouldRepaintParent = false; + boolean shouldRepaintSelf = false; + + if (parent != null) + { + Rectangle parentBounds = parent.getBounds(); + Rectangle oldBounds = new Rectangle(parent.getX() + oldx, + parent.getY() + oldy, + oldwidth, oldheight); + Rectangle newBounds = new Rectangle(parent.getX() + x, + parent.getY() + y, + width, height); + shouldRepaintParent = parentBounds.intersects(oldBounds); + shouldRepaintSelf = parentBounds.intersects(newBounds); + } + + if (shouldRepaintParent && parent != null) + parent.repaint(oldx, oldy, oldwidth, oldheight); + if (shouldRepaintSelf) + repaint(); + } + + // Only post event if this component is visible and has changed size. + if (isShowing () + && (oldx != x || oldy != y)) + { + ComponentEvent ce = new ComponentEvent(this, + ComponentEvent.COMPONENT_MOVED); + getToolkit().getSystemEventQueue().postEvent(ce); + } + if (isShowing () + && (oldwidth != width || oldheight != height)) + { + ComponentEvent ce = new ComponentEvent(this, + ComponentEvent.COMPONENT_RESIZED); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + + /** + * Sets the bounding rectangle for this component to the specified + * rectangle. Note that these coordinates are relative to the parent, not + * to the screen. + * + * @param r the new bounding rectangle + * @throws NullPointerException if r is null + * @see #getBounds() + * @see #setLocation(Point) + * @see #setSize(Dimension) + * @since 1.1 + */ + public void setBounds(Rectangle r) + { + setBounds (r.x, r.y, r.width, r.height); + } + + /** + * Gets the x coordinate of the upper left corner. This is more efficient + * than getBounds().x or getLocation().x. + * + * @return the current x coordinate + * @since 1.2 + */ + public int getX() + { + return x; + } + + /** + * Gets the y coordinate of the upper left corner. This is more efficient + * than getBounds().y or getLocation().y. + * + * @return the current y coordinate + * @since 1.2 + */ + public int getY() + { + return y; + } + + /** + * Gets the width of the component. This is more efficient than + * getBounds().width or getSize().width. + * + * @return the current width + * @since 1.2 + */ + public int getWidth() + { + return width; + } + + /** + * Gets the height of the component. This is more efficient than + * getBounds().height or getSize().height. + * + * @return the current width + * @since 1.2 + */ + public int getHeight() + { + return height; + } + + /** + * Returns the bounds of this component. This allows reuse of an existing + * rectangle, if r is non-null. + * + * @param r the rectangle to use, or null + * @return the bounds + */ + public Rectangle getBounds(Rectangle r) + { + if (r == null) + r = new Rectangle(); + r.x = x; + r.y = y; + r.width = width; + r.height = height; + return r; + } + + /** + * Returns the size of this component. This allows reuse of an existing + * dimension, if d is non-null. + * + * @param d the dimension to use, or null + * @return the size + */ + public Dimension getSize(Dimension d) + { + if (d == null) + d = new Dimension(); + d.width = width; + d.height = height; + return d; + } + + /** + * Returns the location of this component. This allows reuse of an existing + * point, if p is non-null. + * + * @param p the point to use, or null + * @return the location + */ + public Point getLocation(Point p) + { + if (p == null) + p = new Point(); + p.x = x; + p.y = y; + return p; + } + + /** + * Tests if this component is opaque. All "heavyweight" (natively-drawn) + * components are opaque. A component is opaque if it draws all pixels in + * the bounds; a lightweight component is partially transparent if it lets + * pixels underneath show through. Subclasses that guarantee that all pixels + * will be drawn should override this. + * + * @return true if this is opaque + * @see #isLightweight() + * @since 1.2 + */ + public boolean isOpaque() + { + return ! isLightweight(); + } + + /** + * Return whether the component is lightweight. That means the component has + * no native peer, but is displayable. This applies to subclasses of + * Component not in this package, such as javax.swing. + * + * @return true if the component has a lightweight peer + * @see #isDisplayable() + * @since 1.2 + */ + public boolean isLightweight() + { + return peer instanceof LightweightPeer; + } + + /** + * Returns the component's preferred size. + * + * @return the component's preferred size + * @see #getMinimumSize() + * @see LayoutManager + */ + public Dimension getPreferredSize() + { + return preferredSize(); + } + + /** + * Returns the component's preferred size. + * + * @return the component's preferred size + * @deprecated use {@link #getPreferredSize()} instead + */ + public Dimension preferredSize() + { + if (prefSize == null) + if (peer == null) + return new Dimension(width, height); + else + prefSize = peer.getPreferredSize(); + return prefSize; + } + + /** + * Returns the component's minimum size. + * + * @return the component's minimum size + * @see #getPreferredSize() + * @see LayoutManager + */ + public Dimension getMinimumSize() + { + return minimumSize(); + } + + /** + * Returns the component's minimum size. + * + * @return the component's minimum size + * @deprecated use {@link #getMinimumSize()} instead + */ + public Dimension minimumSize() + { + if (minSize == null) + minSize = (peer != null ? peer.getMinimumSize() + : new Dimension(width, height)); + return minSize; + } + + /** + * Returns the component's maximum size. + * + * @return the component's maximum size + * @see #getMinimumSize() + * @see #getPreferredSize() + * @see LayoutManager + */ + public Dimension getMaximumSize() + { + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + /** + * Returns the preferred horizontal alignment of this component. The value + * returned will be between {@link #LEFT_ALIGNMENT} and + * {@link #RIGHT_ALIGNMENT}, inclusive. + * + * @return the preferred horizontal alignment of this component + */ + public float getAlignmentX() + { + return CENTER_ALIGNMENT; + } + + /** + * Returns the preferred vertical alignment of this component. The value + * returned will be between {@link #TOP_ALIGNMENT} and + * {@link #BOTTOM_ALIGNMENT}, inclusive. + * + * @return the preferred vertical alignment of this component + */ + public float getAlignmentY() + { + return CENTER_ALIGNMENT; + } + + /** + * Calls the layout manager to re-layout the component. This is called + * during validation of a container in most cases. + * + * @see #validate() + * @see LayoutManager + */ + public void doLayout() + { + layout (); + } + + /** + * Calls the layout manager to re-layout the component. This is called + * during validation of a container in most cases. + * + * @deprecated use {@link #doLayout()} instead + */ + public void layout() + { + // Nothing to do unless we're a container. + } + + /** + * Called to ensure that the layout for this component is valid. This is + * usually called on containers. + * + * @see #invalidate() + * @see #doLayout() + * @see LayoutManager + * @see Container#validate() + */ + public void validate() + { + valid = true; + } + + /** + * Invalidates this component and all of its parent components. This will + * cause them to have their layout redone. This is called frequently, so + * make it fast. + */ + public void invalidate() + { + valid = false; + prefSize = null; + minSize = null; + if (parent != null && parent.valid) + parent.invalidate(); + } + + /** + * Returns a graphics object for this component. Returns null + * if this component is not currently displayed on the screen. + * + * @return a graphics object for this component + * @see #paint(Graphics) + */ + public Graphics getGraphics() + { + if (peer != null) + { + Graphics gfx = peer.getGraphics(); + if (gfx != null) + return gfx; + // create graphics for lightweight: + Container parent = getParent(); + if (parent != null) + { + gfx = parent.getGraphics(); + Rectangle bounds = getBounds(); + gfx.setClip(bounds); + gfx.translate(bounds.x, bounds.y); + return gfx; + } + } + return null; + } + + /** + * Returns the font metrics for the specified font in this component. + * + * @param font the font to retrieve metrics for + * @return the font metrics for the specified font + * @throws NullPointerException if font is null + * @see #getFont() + * @see Toolkit#getFontMetrics(Font) + */ + public FontMetrics getFontMetrics(Font font) + { + return peer == null ? getToolkit().getFontMetrics(font) + : peer.getFontMetrics(font); + } + + /** + * Sets the cursor for this component to the specified cursor. The cursor + * is displayed when the point is contained by the component, and the + * component is visible, displayable, and enabled. This is inherited by + * subcomponents unless they set their own cursor. + * + * @param cursor the new cursor for this component + * @see #isEnabled() + * @see #isShowing() + * @see #getCursor() + * @see #contains(int, int) + * @see Toolkit#createCustomCursor(Image, Point, String) + */ + public void setCursor(Cursor cursor) + { + this.cursor = cursor; + if (peer != null) + peer.setCursor(cursor); + } + + /** + * Returns the cursor for this component. If not set, this is inherited + * from the parent, or from Cursor.getDefaultCursor(). + * + * @return the cursor for this component + */ + public Cursor getCursor() + { + if (cursor != null) + return cursor; + return parent != null ? parent.getCursor() : Cursor.getDefaultCursor(); + } + + /** + * Tests if the cursor was explicitly set, or just inherited from the parent. + * + * @return true if the cursor has been set + * @since 1.4 + */ + public boolean isCursorSet() + { + return cursor != null; + } + + /** + * Paints this component on the screen. The clipping region in the graphics + * context will indicate the region that requires painting. This is called + * whenever the component first shows, or needs to be repaired because + * something was temporarily drawn on top. It is not necessary for + * subclasses to call super.paint(g). Components with no area + * are not painted. + * + * @param g the graphics context for this paint job + * @see #update(Graphics) + */ + public void paint(Graphics g) + { + // Paint the heavyweight peer + if (!isLightweight() && peer != null) + peer.paint(g); + } + + /** + * Updates this component. This is called in response to + * repaint. This method fills the component with the + * background color, then sets the foreground color of the specified + * graphics context to the foreground color of this component and calls + * the paint() method. The coordinates of the graphics are + * relative to this component. Subclasses should call either + * super.update(g) or paint(g). + * + * @param g the graphics context for this update + * + * @see #paint(Graphics) + * @see #repaint() + */ + public void update(Graphics g) + { + if (!isLightweight()) + { + Rectangle clip = g.getClipBounds(); + if (clip == null) + g.clearRect(0, 0, width, height); + else + g.clearRect(clip.x, clip.y, clip.width, clip.height); + } + + paint(g); + } + + /** + * Paints this entire component, including any sub-components. + * + * @param g the graphics context for this paint job + * + * @see #paint(Graphics) + */ + public void paintAll(Graphics g) + { + if (! visible) + return; + paint(g); + } + + /** + * Repaint this entire component. The update() method + * on this component will be called as soon as possible. + * + * @see #update(Graphics) + * @see #repaint(long, int, int, int, int) + */ + public void repaint() + { + repaint(0, 0, 0, width, height); + } + + /** + * Repaint this entire component. The update() method on this + * component will be called in approximate the specified number of + * milliseconds. + * + * @param tm milliseconds before this component should be repainted + * @see #paint(Graphics) + * @see #repaint(long, int, int, int, int) + */ + public void repaint(long tm) + { + repaint(tm, 0, 0, width, height); + } + + /** + * Repaints the specified rectangular region within this component. The + * update method on this component will be called as soon as + * possible. The coordinates are relative to this component. + * + * @param x the X coordinate of the upper left of the region to repaint + * @param y the Y coordinate of the upper left of the region to repaint + * @param w the width of the region to repaint + * @param h the height of the region to repaint + * @see #update(Graphics) + * @see #repaint(long, int, int, int, int) + */ + public void repaint(int x, int y, int w, int h) + { + repaint(0, x, y, w, h); + } + + /** + * Repaints the specified rectangular region within this component. The + * update method on this component will be called in + * approximately the specified number of milliseconds. The coordinates + * are relative to this component. + * + * @param tm milliseconds before this component should be repainted + * @param x the X coordinate of the upper left of the region to repaint + * @param y the Y coordinate of the upper left of the region to repaint + * @param width the width of the region to repaint + * @param height the height of the region to repaint + * @see #update(Graphics) + */ + public void repaint(long tm, int x, int y, int width, int height) + { + // Handle lightweight repainting by forwarding to native parent + if (isLightweight() && parent != null) + { + if (parent != null) + parent.repaint(tm, x + getX(), y + getY(), width, height); + } + else if (peer != null) + peer.repaint(tm, x, y, width, height); + } + + /** + * Prints this component. This method is provided so that printing can be + * done in a different manner from painting. However, the implementation + * in this class simply calls the paint() method. + * + * @param g the graphics context of the print device + * + * @see #paint(Graphics) + */ + public void print(Graphics g) + { + paint(g); + } + + /** + * Prints this component, including all sub-components. This method is + * provided so that printing can be done in a different manner from + * painting. However, the implementation in this class simply calls the + * paintAll() method. + * + * @param g the graphics context of the print device + * + * @see #paintAll(Graphics) + */ + public void printAll(Graphics g) + { + paintAll(g); + } + + /** + * Called when an image has changed so that this component is repainted. + * This incrementally draws an image as more bits are available, when + * possible. Incremental drawing is enabled if the system property + * awt.image.incrementalDraw is not present or is true, in which + * case the redraw rate is set to 100ms or the value of the system property + * awt.image.redrawrate. + * + *

The coordinate system used depends on the particular flags. + * + * @param img the image that has been updated + * @param flags tlags as specified in ImageObserver + * @param x the X coordinate + * @param y the Y coordinate + * @param w the width + * @param h the height + * @return false if the image is completely loaded, loading has been + * aborted, or an error has occurred. true if more updates are + * required. + * @see ImageObserver + * @see Graphics#drawImage(Image, int, int, Color, ImageObserver) + * @see Graphics#drawImage(Image, int, int, ImageObserver) + * @see Graphics#drawImage(Image, int, int, int, int, Color, ImageObserver) + * @see Graphics#drawImage(Image, int, int, int, int, ImageObserver) + * @see ImageObserver#imageUpdate(Image, int, int, int, int, int) + */ + public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h) + { + if ((flags & (FRAMEBITS | ALLBITS)) != 0) + repaint (); + else if ((flags & SOMEBITS) != 0) + { + if (incrementalDraw) + { + if (redrawRate != null) + { + long tm = redrawRate.longValue(); + if (tm < 0) + tm = 0; + repaint (tm); + } + else + repaint (100); + } + } + return (flags & (ALLBITS | ABORT | ERROR)) == 0; + } + + /** + * Creates an image from the specified producer. + * + * @param producer the image procedure to create the image from + * @return the resulting image + */ + public Image createImage(ImageProducer producer) + { + // Sun allows producer to be null. + if (peer != null) + return peer.createImage(producer); + else + return getToolkit().createImage(producer); + } + + /** + * Creates an image with the specified width and height for use in + * double buffering. Headless environments do not support images. + * + * @param width the width of the image + * @param height the height of the image + * @return the requested image, or null if it is not supported + */ + public Image createImage (int width, int height) + { + Image returnValue = null; + if (!GraphicsEnvironment.isHeadless ()) + { + if (isLightweight () && parent != null) + returnValue = parent.createImage (width, height); + else if (peer != null) + returnValue = peer.createImage (width, height); + } + return returnValue; + } + + /** + * Creates an image with the specified width and height for use in + * double buffering. Headless environments do not support images. + * + * @param width the width of the image + * @param height the height of the image + * @return the requested image, or null if it is not supported + * @since 1.4 + */ + public VolatileImage createVolatileImage(int width, int height) + { + if (GraphicsEnvironment.isHeadless()) + return null; + GraphicsConfiguration config = getGraphicsConfiguration(); + return config == null ? null + : config.createCompatibleVolatileImage(width, height); + } + + /** + * Creates an image with the specified width and height for use in + * double buffering. Headless environments do not support images. The image + * will support the specified capabilities. + * + * @param width the width of the image + * @param height the height of the image + * @param caps the requested capabilities + * @return the requested image, or null if it is not supported + * @throws AWTException if a buffer with the capabilities cannot be created + * @since 1.4 + */ + public VolatileImage createVolatileImage(int width, int height, + ImageCapabilities caps) + throws AWTException + { + if (GraphicsEnvironment.isHeadless()) + return null; + GraphicsConfiguration config = getGraphicsConfiguration(); + return config == null ? null + : config.createCompatibleVolatileImage(width, height, caps); + } + + /** + * Prepares the specified image for rendering on this component. + * + * @param image the image to prepare for rendering + * @param observer the observer to notify of image preparation status + * @return true if the image is already fully prepared + * @throws NullPointerException if image is null + */ + public boolean prepareImage(Image image, ImageObserver observer) + { + return prepareImage(image, image.getWidth(observer), + image.getHeight(observer), observer); + } + + /** + * Prepares the specified image for rendering on this component at the + * specified scaled width and height + * + * @param image the image to prepare for rendering + * @param width the scaled width of the image + * @param height the scaled height of the image + * @param observer the observer to notify of image preparation status + * @return true if the image is already fully prepared + */ + public boolean prepareImage(Image image, int width, int height, + ImageObserver observer) + { + if (peer != null) + return peer.prepareImage(image, width, height, observer); + else + return getToolkit().prepareImage(image, width, height, observer); + } + + /** + * Returns the status of the loading of the specified image. The value + * returned will be those flags defined in ImageObserver. + * + * @param image the image to check on + * @param observer the observer to notify of image loading progress + * @return the image observer flags indicating the status of the load + * @see #prepareImage(Image, int, int, ImageObserver) + * @see Toolkit#checkImage(Image, int, int, ImageObserver) + * @throws NullPointerException if image is null + */ + public int checkImage(Image image, ImageObserver observer) + { + return checkImage(image, -1, -1, observer); + } + + /** + * Returns the status of the loading of the specified image. The value + * returned will be those flags defined in ImageObserver. + * + * @param image the image to check on + * @param width the scaled image width + * @param height the scaled image height + * @param observer the observer to notify of image loading progress + * @return the image observer flags indicating the status of the load + * @see #prepareImage(Image, int, int, ImageObserver) + * @see Toolkit#checkImage(Image, int, int, ImageObserver) + */ + public int checkImage(Image image, int width, int height, + ImageObserver observer) + { + if (peer != null) + return peer.checkImage(image, width, height, observer); + return getToolkit().checkImage(image, width, height, observer); + } + + /** + * Sets whether paint messages delivered by the operating system should be + * ignored. This does not affect messages from AWT, except for those + * triggered by OS messages. Setting this to true can allow faster + * performance in full-screen mode or page-flipping. + * + * @param ignoreRepaint the new setting for ignoring repaint events + * @see #getIgnoreRepaint() + * @see BufferStrategy + * @see GraphicsDevice#setFullScreenWindow(Window) + * @since 1.4 + */ + public void setIgnoreRepaint(boolean ignoreRepaint) + { + this.ignoreRepaint = ignoreRepaint; + } + + /** + * Test whether paint events from the operating system are ignored. + * + * @return the status of ignoring paint events + * @see #setIgnoreRepaint(boolean) + * @since 1.4 + */ + public boolean getIgnoreRepaint() + { + return ignoreRepaint; + } + + /** + * Tests whether or not the specified point is contained within this + * component. Coordinates are relative to this component. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is within this component + * @see #getComponentAt(int, int) + */ + public boolean contains(int x, int y) + { + return inside (x, y); + } + + /** + * Tests whether or not the specified point is contained within this + * component. Coordinates are relative to this component. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is within this component + * @deprecated use {@link #contains(int, int)} instead + */ + public boolean inside(int x, int y) + { + return x >= 0 && y >= 0 && x < width && y < height; + } + + /** + * Tests whether or not the specified point is contained within this + * component. Coordinates are relative to this component. + * + * @param p the point to test + * @return true if the point is within this component + * @throws NullPointerException if p is null + * @see #getComponentAt(Point) + * @since 1.1 + */ + public boolean contains(Point p) + { + return contains (p.x, p.y); + } + + /** + * Returns the component occupying the position (x,y). This will either + * be this component, an immediate child component, or null + * if neither of the first two occupies the specified location. + * + * @param x the X coordinate to search for components at + * @param y the Y coordinate to search for components at + * @return the component at the specified location, or null + * @see #contains(int, int) + */ + public Component getComponentAt(int x, int y) + { + return locate (x, y); + } + + /** + * Returns the component occupying the position (x,y). This will either + * be this component, an immediate child component, or null + * if neither of the first two occupies the specified location. + * + * @param x the X coordinate to search for components at + * @param y the Y coordinate to search for components at + * @return the component at the specified location, or null + * @deprecated use {@link #getComponentAt(int, int)} instead + */ + public Component locate(int x, int y) + { + return contains (x, y) ? this : null; + } + + /** + * Returns the component occupying the position (x,y). This will either + * be this component, an immediate child component, or null + * if neither of the first two occupies the specified location. + * + * @param p the point to search for components at + * @return the component at the specified location, or null + * @throws NullPointerException if p is null + * @see #contains(Point) + * @since 1.1 + */ + public Component getComponentAt(Point p) + { + return getComponentAt (p.x, p.y); + } + + /** + * AWT 1.0 event delivery. + * + * Deliver an AWT 1.0 event to this Component. This method simply + * calls {@link #postEvent}. + * + * @param e the event to deliver + * @deprecated use {@link #dispatchEvent (AWTEvent)} instead + */ + public void deliverEvent (Event e) + { + postEvent (e); + } + + /** + * Forwards AWT events to processEvent() if:

+ * + * @param e the event to dispatch + */ + public final void dispatchEvent(AWTEvent e) + { + // Some subclasses in the AWT package need to override this behavior, + // hence the use of dispatchEventImpl(). + dispatchEventImpl(e); + if (peer != null && ! e.consumed) + peer.handleEvent(e); + } + + /** + * AWT 1.0 event handler. + * + * This method simply calls handleEvent and returns the result. + * + * @param e the event to handle + * @return true if the event was handled, false otherwise + * @deprecated use {@link #dispatchEvent(AWTEvent)} instead + */ + public boolean postEvent (Event e) + { + boolean handled = handleEvent (e); + + if (!handled && getParent() != null) + // FIXME: need to translate event coordinates to parent's + // coordinate space. + handled = getParent ().postEvent (e); + + return handled; + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see ComponentEvent + * @see #removeComponentListener(ComponentListener) + * @see #getComponentListeners() + * @since 1.1 + */ + public synchronized void addComponentListener(ComponentListener listener) + { + componentListener = AWTEventMulticaster.add(componentListener, listener); + if (componentListener != null) + enableEvents(AWTEvent.COMPONENT_EVENT_MASK); + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see ComponentEvent + * @see #addComponentListener(ComponentListener) + * @see #getComponentListeners() + * @since 1.1 + */ + public synchronized void removeComponentListener(ComponentListener listener) + { + componentListener = AWTEventMulticaster.remove(componentListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addComponentListener(ComponentListener) + * @see #removeComponentListener(ComponentListener) + * @since 1.4 + */ + public synchronized ComponentListener[] getComponentListeners() + { + return (ComponentListener[]) + AWTEventMulticaster.getListeners(componentListener, + ComponentListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see FocusEvent + * @see #removeFocusListener(FocusListener) + * @see #getFocusListeners() + * @since 1.1 + */ + public synchronized void addFocusListener(FocusListener listener) + { + focusListener = AWTEventMulticaster.add(focusListener, listener); + if (focusListener != null) + enableEvents(AWTEvent.FOCUS_EVENT_MASK); + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see FocusEvent + * @see #addFocusListener(FocusListener) + * @see #getFocusListeners() + * @since 1.1 + */ + public synchronized void removeFocusListener(FocusListener listener) + { + focusListener = AWTEventMulticaster.remove(focusListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addFocusListener(FocusListener) + * @see #removeFocusListener(FocusListener) + * @since 1.4 + */ + public synchronized FocusListener[] getFocusListeners() + { + return (FocusListener[]) + AWTEventMulticaster.getListeners(focusListener, FocusListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see HierarchyEvent + * @see #removeHierarchyListener(HierarchyListener) + * @see #getHierarchyListeners() + * @since 1.3 + */ + public synchronized void addHierarchyListener(HierarchyListener listener) + { + hierarchyListener = AWTEventMulticaster.add(hierarchyListener, listener); + if (hierarchyListener != null) + enableEvents(AWTEvent.HIERARCHY_EVENT_MASK); + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see HierarchyEvent + * @see #addHierarchyListener(HierarchyListener) + * @see #getHierarchyListeners() + * @since 1.3 + */ + public synchronized void removeHierarchyListener(HierarchyListener listener) + { + hierarchyListener = AWTEventMulticaster.remove(hierarchyListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addHierarchyListener(HierarchyListener) + * @see #removeHierarchyListener(HierarchyListener) + * @since 1.4 + */ + public synchronized HierarchyListener[] getHierarchyListeners() + { + return (HierarchyListener[]) + AWTEventMulticaster.getListeners(hierarchyListener, + HierarchyListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see HierarchyEvent + * @see #removeHierarchyBoundsListener(HierarchyBoundsListener) + * @see #getHierarchyBoundsListeners() + * @since 1.3 + */ + public synchronized void + addHierarchyBoundsListener(HierarchyBoundsListener listener) + { + hierarchyBoundsListener = + AWTEventMulticaster.add(hierarchyBoundsListener, listener); + if (hierarchyBoundsListener != null) + enableEvents(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK); + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see HierarchyEvent + * @see #addHierarchyBoundsListener(HierarchyBoundsListener) + * @see #getHierarchyBoundsListeners() + * @since 1.3 + */ + public synchronized void + removeHierarchyBoundsListener(HierarchyBoundsListener listener) + { + hierarchyBoundsListener = + AWTEventMulticaster.remove(hierarchyBoundsListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addHierarchyBoundsListener(HierarchyBoundsListener) + * @see #removeHierarchyBoundsListener(HierarchyBoundsListener) + * @since 1.4 + */ + public synchronized HierarchyBoundsListener[] getHierarchyBoundsListeners() + { + return (HierarchyBoundsListener[]) + AWTEventMulticaster.getListeners(hierarchyBoundsListener, + HierarchyBoundsListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see KeyEvent + * @see #removeKeyListener(KeyListener) + * @see #getKeyListeners() + * @since 1.1 + */ + public synchronized void addKeyListener(KeyListener listener) + { + keyListener = AWTEventMulticaster.add(keyListener, listener); + if (keyListener != null) + enableEvents(AWTEvent.KEY_EVENT_MASK); + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see KeyEvent + * @see #addKeyListener(KeyListener) + * @see #getKeyListeners() + * @since 1.1 + */ + public synchronized void removeKeyListener(KeyListener listener) + { + keyListener = AWTEventMulticaster.remove(keyListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addKeyListener(KeyListener) + * @see #removeKeyListener(KeyListener) + * @since 1.4 + */ + public synchronized KeyListener[] getKeyListeners() + { + return (KeyListener[]) + AWTEventMulticaster.getListeners(keyListener, KeyListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see MouseEvent + * @see #removeMouseListener(MouseListener) + * @see #getMouseListeners() + * @since 1.1 + */ + public synchronized void addMouseListener(MouseListener listener) + { + mouseListener = AWTEventMulticaster.add(mouseListener, listener); + if (mouseListener != null) + enableEvents(AWTEvent.MOUSE_EVENT_MASK); + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see MouseEvent + * @see #addMouseListener(MouseListener) + * @see #getMouseListeners() + * @since 1.1 + */ + public synchronized void removeMouseListener(MouseListener listener) + { + mouseListener = AWTEventMulticaster.remove(mouseListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addMouseListener(MouseListener) + * @see #removeMouseListener(MouseListener) + * @since 1.4 + */ + public synchronized MouseListener[] getMouseListeners() + { + return (MouseListener[]) + AWTEventMulticaster.getListeners(mouseListener, MouseListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see MouseEvent + * @see #removeMouseMotionListener(MouseMotionListener) + * @see #getMouseMotionListeners() + * @since 1.1 + */ + public synchronized void addMouseMotionListener(MouseMotionListener listener) + { + mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener, listener); + if (mouseMotionListener != null) + enableEvents(AWTEvent.MOUSE_EVENT_MASK); + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see MouseEvent + * @see #addMouseMotionListener(MouseMotionListener) + * @see #getMouseMotionListeners() + * @since 1.1 + */ + public synchronized void removeMouseMotionListener(MouseMotionListener listener) + { + mouseMotionListener = AWTEventMulticaster.remove(mouseMotionListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addMouseMotionListener(MouseMotionListener) + * @see #removeMouseMotionListener(MouseMotionListener) + * @since 1.4 + */ + public synchronized MouseMotionListener[] getMouseMotionListeners() + { + return (MouseMotionListener[]) + AWTEventMulticaster.getListeners(mouseMotionListener, + MouseMotionListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see MouseEvent + * @see MouseWheelEvent + * @see #removeMouseWheelListener(MouseWheelListener) + * @see #getMouseWheelListeners() + * @since 1.4 + */ + public synchronized void addMouseWheelListener(MouseWheelListener listener) + { + mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener, listener); + if (mouseWheelListener != null) + enableEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK); + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see MouseEvent + * @see MouseWheelEvent + * @see #addMouseWheelListener(MouseWheelListener) + * @see #getMouseWheelListeners() + * @since 1.4 + */ + public synchronized void removeMouseWheelListener(MouseWheelListener listener) + { + mouseWheelListener = AWTEventMulticaster.remove(mouseWheelListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addMouseWheelListener(MouseWheelListener) + * @see #removeMouseWheelListener(MouseWheelListener) + * @since 1.4 + */ + public synchronized MouseWheelListener[] getMouseWheelListeners() + { + return (MouseWheelListener[]) + AWTEventMulticaster.getListeners(mouseWheelListener, + MouseWheelListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see InputMethodEvent + * @see #removeInputMethodListener(InputMethodListener) + * @see #getInputMethodListeners() + * @see #getInputMethodRequests() + * @since 1.2 + */ + public synchronized void addInputMethodListener(InputMethodListener listener) + { + inputMethodListener = AWTEventMulticaster.add(inputMethodListener, listener); + if (inputMethodListener != null) + enableEvents(AWTEvent.INPUT_METHOD_EVENT_MASK); + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see InputMethodEvent + * @see #addInputMethodListener(InputMethodListener) + * @see #getInputMethodRequests() + * @since 1.2 + */ + public synchronized void removeInputMethodListener(InputMethodListener listener) + { + inputMethodListener = AWTEventMulticaster.remove(inputMethodListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addInputMethodListener(InputMethodListener) + * @see #removeInputMethodListener(InputMethodListener) + * @since 1.4 + */ + public synchronized InputMethodListener[] getInputMethodListeners() + { + return (InputMethodListener[]) + AWTEventMulticaster.getListeners(inputMethodListener, + InputMethodListener.class); + } + + /** + * Returns all registered EventListers of the given listenerType. + * + * @param listenerType the class of listeners to filter + * @return an array of registered listeners + * @see #getComponentListeners() + * @see #getFocusListeners() + * @see #getHierarchyListeners() + * @see #getHierarchyBoundsListeners() + * @see #getKeyListeners() + * @see #getMouseListeners() + * @see #getMouseMotionListeners() + * @see #getMouseWheelListeners() + * @see #getInputMethodListeners() + * @see #getPropertyChangeListeners() + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + if (listenerType == ComponentListener.class) + return getComponentListeners(); + if (listenerType == FocusListener.class) + return getFocusListeners(); + if (listenerType == HierarchyListener.class) + return getHierarchyListeners(); + if (listenerType == HierarchyBoundsListener.class) + return getHierarchyBoundsListeners(); + if (listenerType == KeyListener.class) + return getKeyListeners(); + if (listenerType == MouseListener.class) + return getMouseListeners(); + if (listenerType == MouseMotionListener.class) + return getMouseMotionListeners(); + if (listenerType == MouseWheelListener.class) + return getMouseWheelListeners(); + if (listenerType == InputMethodListener.class) + return getInputMethodListeners(); + if (listenerType == PropertyChangeListener.class) + return getPropertyChangeListeners(); + return (EventListener[]) Array.newInstance(listenerType, 0); + } + + /** + * Returns the input method request handler, for subclasses which support + * on-the-spot text input. By default, input methods are handled by AWT, + * and this returns null. + * + * @return the input method handler, null by default + * @since 1.2 + */ + public InputMethodRequests getInputMethodRequests() + { + return null; + } + + /** + * Gets the input context of this component, which is inherited from the + * parent unless this is overridden. + * + * @return the text input context + * @since 1.2 + */ + public InputContext getInputContext() + { + return parent == null ? null : parent.getInputContext(); + } + + /** + * Enables the specified events. The events to enable are specified + * by OR-ing together the desired masks from AWTEvent. + * + *

Events are enabled by default when a listener is attached to the + * component for that event type. This method can be used by subclasses + * to ensure the delivery of a specified event regardless of whether + * or not a listener is attached. + * + * @param eventsToEnable the desired events to enable + * @see #processEvent(AWTEvent) + * @see #disableEvents(long) + * @see AWTEvent + * @since 1.1 + */ + protected final void enableEvents(long eventsToEnable) + { + eventMask |= eventsToEnable; + // TODO: Unlike Sun's implementation, I think we should try and + // enable/disable events at the peer (gtk/X) level. This will avoid + // clogging the event pipeline with useless mousemove events that + // we arn't interested in, etc. This will involve extending the peer + // interface, but thats okay because the peer interfaces have been + // deprecated for a long time, and no longer feature in the + // API specification at all. + if (isLightweight() && parent != null) + parent.enableEvents(eventsToEnable); + else if (peer != null) + peer.setEventMask(eventMask); + } + + /** + * Disables the specified events. The events to disable are specified + * by OR-ing together the desired masks from AWTEvent. + * + * @param eventsToDisable the desired events to disable + * @see #enableEvents(long) + * @since 1.1 + */ + protected final void disableEvents(long eventsToDisable) + { + eventMask &= ~eventsToDisable; + // forward new event mask to peer? + } + + /** + * This is called by the EventQueue if two events with the same event id + * and owner component are queued. Returns a new combined event, or null if + * no combining is done. The coelesced events are currently mouse moves + * (intermediate ones are discarded) and paint events (a merged paint is + * created in place of the two events). + * + * @param existingEvent the event on the queue + * @param newEvent the new event that might be entered on the queue + * @return null if both events are kept, or the replacement coelesced event + */ + protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) + { + switch (existingEvent.id) + { + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + // Just drop the old (intermediate) event and return the new one. + return newEvent; + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + return coalescePaintEvents((PaintEvent) existingEvent, + (PaintEvent) newEvent); + default: + return null; + } + } + + /** + * Processes the specified event. In this class, this method simply + * calls one of the more specific event handlers. + * + * @param e the event to process + * @throws NullPointerException if e is null + * @see #processComponentEvent(ComponentEvent) + * @see #processFocusEvent(FocusEvent) + * @see #processKeyEvent(KeyEvent) + * @see #processMouseEvent(MouseEvent) + * @see #processMouseMotionEvent(MouseEvent) + * @see #processInputMethodEvent(InputMethodEvent) + * @see #processHierarchyEvent(HierarchyEvent) + * @see #processMouseWheelEvent(MouseWheelEvent) + * @since 1.1 + */ + protected void processEvent(AWTEvent e) + { + /* Note: the order of these if statements are + important. Subclasses must be checked first. Eg. MouseEvent + must be checked before ComponentEvent, since a MouseEvent + object is also an instance of a ComponentEvent. */ + + if (e instanceof FocusEvent) + processFocusEvent((FocusEvent) e); + else if (e instanceof MouseWheelEvent) + processMouseWheelEvent((MouseWheelEvent) e); + else if (e instanceof MouseEvent) + { + if (e.id == MouseEvent.MOUSE_MOVED + || e.id == MouseEvent.MOUSE_DRAGGED) + processMouseMotionEvent((MouseEvent) e); + else + processMouseEvent((MouseEvent) e); + } + else if (e instanceof KeyEvent) + processKeyEvent((KeyEvent) e); + else if (e instanceof InputMethodEvent) + processInputMethodEvent((InputMethodEvent) e); + else if (e instanceof ComponentEvent) + processComponentEvent((ComponentEvent) e); + else if (e instanceof HierarchyEvent) + { + if (e.id == HierarchyEvent.HIERARCHY_CHANGED) + processHierarchyEvent((HierarchyEvent) e); + else + processHierarchyBoundsEvent((HierarchyEvent) e); + } + } + + /** + * Called when a component event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the ComponentEvent to process + * @throws NullPointerException if e is null + * @see ComponentListener + * @see #addComponentListener(ComponentListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processComponentEvent(ComponentEvent e) + { + if (componentListener == null) + return; + switch (e.id) + { + case ComponentEvent.COMPONENT_HIDDEN: + componentListener.componentHidden(e); + break; + case ComponentEvent.COMPONENT_MOVED: + componentListener.componentMoved(e); + break; + case ComponentEvent.COMPONENT_RESIZED: + componentListener.componentResized(e); + break; + case ComponentEvent.COMPONENT_SHOWN: + componentListener.componentShown(e); + break; + } + } + + /** + * Called when a focus event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the FocusEvent to process + * @throws NullPointerException if e is null + * @see FocusListener + * @see #addFocusListener(FocusListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processFocusEvent(FocusEvent e) + { + if (focusListener == null) + return; + + switch (e.id) + { + case FocusEvent.FOCUS_GAINED: + focusListener.focusGained(e); + break; + case FocusEvent.FOCUS_LOST: + focusListener.focusLost(e); + break; + } + } + + /** + * Called when a key event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the KeyEvent to process + * @throws NullPointerException if e is null + * @see KeyListener + * @see #addKeyListener(KeyListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processKeyEvent(KeyEvent e) + { + if (keyListener == null) + return; + switch (e.id) + { + case KeyEvent.KEY_PRESSED: + keyListener.keyPressed(e); + break; + case KeyEvent.KEY_RELEASED: + keyListener.keyReleased(e); + break; + case KeyEvent.KEY_TYPED: + keyListener.keyTyped(e); + break; + } + } + + /** + * Called when a regular mouse event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the MouseEvent to process + * @throws NullPointerException if e is null + * @see MouseListener + * @see #addMouseListener(MouseListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processMouseEvent(MouseEvent e) + { + if (mouseListener == null) + return; + switch (e.id) + { + case MouseEvent.MOUSE_CLICKED: + mouseListener.mouseClicked(e); + break; + case MouseEvent.MOUSE_ENTERED: + mouseListener.mouseEntered(e); + break; + case MouseEvent.MOUSE_EXITED: + mouseListener.mouseExited(e); + break; + case MouseEvent.MOUSE_PRESSED: + mouseListener.mousePressed(e); + break; + case MouseEvent.MOUSE_RELEASED: + mouseListener.mouseReleased(e); + break; + } + e.consume(); + } + + /** + * Called when a mouse motion event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the MouseMotionEvent to process + * @throws NullPointerException if e is null + * @see MouseMotionListener + * @see #addMouseMotionListener(MouseMotionListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processMouseMotionEvent(MouseEvent e) + { + if (mouseMotionListener == null) + return; + switch (e.id) + { + case MouseEvent.MOUSE_DRAGGED: + mouseMotionListener.mouseDragged(e); + break; + case MouseEvent.MOUSE_MOVED: + mouseMotionListener.mouseMoved(e); + break; + } + e.consume(); + } + + /** + * Called when a mouse wheel event is dispatched and component events are + * enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the MouseWheelEvent to process + * @throws NullPointerException if e is null + * @see MouseWheelListener + * @see #addMouseWheelListener(MouseWheelListener) + * @see #enableEvents(long) + * @since 1.4 + */ + protected void processMouseWheelEvent(MouseWheelEvent e) + { + if (mouseWheelListener != null + && e.id == MouseEvent.MOUSE_WHEEL) + { + mouseWheelListener.mouseWheelMoved(e); + e.consume(); + } + } + + /** + * Called when an input method event is dispatched and component events are + * enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the InputMethodEvent to process + * @throws NullPointerException if e is null + * @see InputMethodListener + * @see #addInputMethodListener(InputMethodListener) + * @see #enableEvents(long) + * @since 1.2 + */ + protected void processInputMethodEvent(InputMethodEvent e) + { + if (inputMethodListener == null) + return; + switch (e.id) + { + case InputMethodEvent.CARET_POSITION_CHANGED: + inputMethodListener.caretPositionChanged(e); + break; + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + inputMethodListener.inputMethodTextChanged(e); + break; + } + } + + /** + * Called when a hierarchy change event is dispatched and component events + * are enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the HierarchyEvent to process + * @throws NullPointerException if e is null + * @see HierarchyListener + * @see #addHierarchyListener(HierarchyListener) + * @see #enableEvents(long) + * @since 1.3 + */ + protected void processHierarchyEvent(HierarchyEvent e) + { + if (hierarchyListener == null) + return; + if (e.id == HierarchyEvent.HIERARCHY_CHANGED) + hierarchyListener.hierarchyChanged(e); + } + + /** + * Called when a hierarchy bounds event is dispatched and component events + * are enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the HierarchyEvent to process + * @throws NullPointerException if e is null + * @see HierarchyBoundsListener + * @see #addHierarchyBoundsListener(HierarchyBoundsListener) + * @see #enableEvents(long) + * @since 1.3 + */ + protected void processHierarchyBoundsEvent(HierarchyEvent e) + { + if (hierarchyBoundsListener == null) + return; + switch (e.id) + { + case HierarchyEvent.ANCESTOR_MOVED: + hierarchyBoundsListener.ancestorMoved(e); + break; + case HierarchyEvent.ANCESTOR_RESIZED: + hierarchyBoundsListener.ancestorResized(e); + break; + } + } + + /** + * AWT 1.0 event handler. + * + * This method calls one of the event-specific handler methods. For + * example for key events, either {@link #keyDown(Event,int)} + * or {@link #keyUp(Event,int)} is called. A derived + * component can override one of these event-specific methods if it + * only needs to handle certain event types. Otherwise it can + * override handleEvent itself and handle any event. + * + * @param evt the event to handle + * @return true if the event was handled, false otherwise + * @deprecated use {@link #processEvent(AWTEvent)} instead + */ + public boolean handleEvent (Event evt) + { + switch (evt.id) + { + // Handle key events. + case Event.KEY_ACTION: + case Event.KEY_PRESS: + return keyDown (evt, evt.key); + case Event.KEY_ACTION_RELEASE: + case Event.KEY_RELEASE: + return keyUp (evt, evt.key); + + // Handle mouse events. + case Event.MOUSE_DOWN: + return mouseDown (evt, evt.x, evt.y); + case Event.MOUSE_UP: + return mouseUp (evt, evt.x, evt.y); + case Event.MOUSE_MOVE: + return mouseMove (evt, evt.x, evt.y); + case Event.MOUSE_DRAG: + return mouseDrag (evt, evt.x, evt.y); + case Event.MOUSE_ENTER: + return mouseEnter (evt, evt.x, evt.y); + case Event.MOUSE_EXIT: + return mouseExit (evt, evt.x, evt.y); + + // Handle focus events. + case Event.GOT_FOCUS: + return gotFocus (evt, evt.arg); + case Event.LOST_FOCUS: + return lostFocus (evt, evt.arg); + + // Handle action event. + case Event.ACTION_EVENT: + return action (evt, evt.arg); + } + // Unknown event. + return false; + } + + /** + * AWT 1.0 MOUSE_DOWN event handler. This method is meant to be + * overridden by components providing their own MOUSE_DOWN handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseDown(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_DRAG event handler. This method is meant to be + * overridden by components providing their own MOUSE_DRAG handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseMotionEvent(MouseEvent)} instead + */ + public boolean mouseDrag(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_UP event handler. This method is meant to be + * overridden by components providing their own MOUSE_UP handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseUp(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_MOVE event handler. This method is meant to be + * overridden by components providing their own MOUSE_MOVE handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseMotionEvent(MouseEvent)} instead + */ + public boolean mouseMove(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_ENTER event handler. This method is meant to be + * overridden by components providing their own MOUSE_ENTER handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseEnter(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_EXIT event handler. This method is meant to be + * overridden by components providing their own MOUSE_EXIT handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseExit(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 KEY_PRESS and KEY_ACTION event handler. This method is + * meant to be overridden by components providing their own key + * press handler. The default implementation simply returns false. + * + * @param evt the event to handle + * @param key the key pressed, ignored + * @return false + * @deprecated use {@link #processKeyEvent(KeyEvent)} instead + */ + public boolean keyDown(Event evt, int key) + { + return false; + } + + /** + * AWT 1.0 KEY_RELEASE and KEY_ACTION_RELEASE event handler. This + * method is meant to be overridden by components providing their + * own key release handler. The default implementation simply + * returns false. + * + * @param evt the event to handle + * @param key the key pressed, ignored + * @return false + * @deprecated use {@link #processKeyEvent(KeyEvent)} instead + */ + public boolean keyUp(Event evt, int key) + { + return false; + } + + /** + * AWT 1.0 ACTION_EVENT event handler. This method is meant to be + * overridden by components providing their own action event + * handler. The default implementation simply returns false. + * + * @param evt the event to handle + * @param what the object acted on, ignored + * @return false + * @deprecated in classes which support actions, use + * processActionEvent(ActionEvent) instead + */ + public boolean action(Event evt, Object what) + { + return false; + } + + /** + * Called to inform this component it has been added to a container. + * A native peer - if any - is created at this time. This method is + * called automatically by the AWT system and should not be called by + * user level code. + * + * @see #isDisplayable() + * @see #removeNotify() + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit().createComponent(this); + /* Now that all the children has gotten their peers, we should + have the event mask needed for this component and its + lightweight subcomponents. */ + peer.setEventMask(eventMask); + /* We do not invalidate here, but rather leave that job up to + the peer. For efficiency, the peer can choose not to + invalidate if it is happy with the current dimensions, + etc. */ + } + + /** + * Called to inform this component is has been removed from its + * container. Its native peer - if any - is destroyed at this time. + * This method is called automatically by the AWT system and should + * not be called by user level code. + * + * @see #isDisplayable() + * @see #addNotify() + */ + public void removeNotify() + { + // We null our peer field before disposing of it, such that if we're + // not the event dispatch thread and the dispatch thread is awoken by + // the dispose call, there will be no race checking the peer's null + // status. + + ComponentPeer tmp = peer; + peer = null; + if (tmp != null) + tmp.dispose(); + } + + /** + * AWT 1.0 GOT_FOCUS event handler. This method is meant to be + * overridden by components providing their own GOT_FOCUS handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param what the Object focused, ignored + * @return false + * @deprecated use {@link #processFocusEvent(FocusEvent)} instead + */ + public boolean gotFocus(Event evt, Object what) + { + return false; + } + + /** + * AWT 1.0 LOST_FOCUS event handler. This method is meant to be + * overridden by components providing their own LOST_FOCUS handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param what the Object focused, ignored + * @return false + * @deprecated use {@link #processFocusEvent(FocusEvent)} instead + */ + public boolean lostFocus(Event evt, Object what) + { + return false; + } + + /** + * Tests whether or not this component is in the group that can be + * traversed using the keyboard traversal mechanism (such as the TAB key). + * + * @return true if the component is traversed via the TAB key + * @see #setFocusable(boolean) + * @since 1.1 + * @deprecated use {@link #isFocusable()} instead + */ + public boolean isFocusTraversable() + { + return enabled && visible && (peer == null || isLightweight() || peer.isFocusTraversable()); + } + + /** + * Tests if this component can receive focus. + * + * @return true if this component can receive focus + * @since 1.4 + */ + public boolean isFocusable() + { + return focusable; + } + + /** + * Specify whether this component can receive focus. This method also + * sets the {@link #isFocusTraversableOverridden} field to 1, which + * appears to be the undocumented way {@link + * DefaultFocusTraversalPolicy#accept(Component)} determines whether to + * respect the {@link #isFocusable()} method of the component. + * + * @param focusable the new focusable status + * @since 1.4 + */ + public void setFocusable(boolean focusable) + { + firePropertyChange("focusable", this.focusable, focusable); + this.focusable = focusable; + this.isFocusTraversableOverridden = 1; + } + + /** + * Sets the focus traversal keys for one of the three focus + * traversal directions supported by Components: + * {@link KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS}, + * {@link KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS}, or + * {@link KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS}. Normally, the + * default values should match the operating system's native + * choices. To disable a given traversal, use + * Collections.EMPTY_SET. The event dispatcher will + * consume PRESSED, RELEASED, and TYPED events for the specified + * key, although focus can only transfer on PRESSED or RELEASED. + * + *

The defaults are: + * + * + * + * + * + * + * + * + * + * + *
IdentifierMeaningDefault
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYSNormal forward traversalTAB on KEY_PRESSED, Ctrl-TAB on KEY_PRESSED
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYSNormal backward traversalShift-TAB on KEY_PRESSED, Ctrl-Shift-TAB on KEY_PRESSED
KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYSGo up a traversal cycleNone
+ * + * If keystrokes is null, this component's focus traversal key set + * is inherited from one of its ancestors. If none of its ancestors + * has its own set of focus traversal keys, the focus traversal keys + * are set to the defaults retrieved from the current + * KeyboardFocusManager. If not null, the set must contain only + * AWTKeyStrokes that are not already focus keys and are not + * KEY_TYPED events. + * + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or + * UP_CYCLE_TRAVERSAL_KEYS + * @param keystrokes a set of keys, or null + * @throws IllegalArgumentException if id or keystrokes is invalid + * @see #getFocusTraversalKeys(int) + * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS + * @since 1.4 + */ + public void setFocusTraversalKeys(int id, Set keystrokes) + { + if (keystrokes == null) + { + Container parent = getParent (); + + while (parent != null) + { + if (parent.areFocusTraversalKeysSet (id)) + { + keystrokes = parent.getFocusTraversalKeys (id); + break; + } + parent = parent.getParent (); + } + + if (keystrokes == null) + keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). + getDefaultFocusTraversalKeys (id); + } + + Set sa; + Set sb; + String name; + switch (id) + { + case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + name = "forwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + name = "backwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + name = "upCycleFocusTraversalKeys"; + break; + default: + throw new IllegalArgumentException (); + } + + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + + while (--i >= 0) + { + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) + || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) + throw new IllegalArgumentException (); + } + + if (focusTraversalKeys == null) + focusTraversalKeys = new Set[3]; + + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (name, focusTraversalKeys[id], keystrokes); + + focusTraversalKeys[id] = keystrokes; + } + + /** + * Returns the set of keys for a given focus traversal action, as + * defined in setFocusTraversalKeys. If not set, this + * is inherited from the parent component, which may have gotten it + * from the KeyboardFocusManager. + * + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * or UP_CYCLE_TRAVERSAL_KEYS + * + * @return set of traversal keys + * + * @throws IllegalArgumentException if id is invalid + * + * @see #setFocusTraversalKeys (int, Set) + * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS + * + * @since 1.4 + */ + public Set getFocusTraversalKeys (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException(); + + Set s = null; + + if (focusTraversalKeys != null) + s = focusTraversalKeys[id]; + + if (s == null && parent != null) + s = parent.getFocusTraversalKeys (id); + + return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() + .getDefaultFocusTraversalKeys(id)) : s; + } + + /** + * Tests whether the focus traversal keys for a given action are explicitly + * set or inherited. + * + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * or UP_CYCLE_TRAVERSAL_KEYS + * @return true if that set is explicitly specified + * @throws IllegalArgumentException if id is invalid + * @see #getFocusTraversalKeys (int) + * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS + * @since 1.4 + */ + public boolean areFocusTraversalKeysSet (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + return focusTraversalKeys != null && focusTraversalKeys[id] != null; + } + + /** + * Enable or disable focus traversal keys on this Component. If + * they are, then the keyboard focus manager consumes and acts on + * key press and release events that trigger focus traversal, and + * discards the corresponding key typed events. If focus traversal + * keys are disabled, then all key events that would otherwise + * trigger focus traversal are sent to this Component. + * + * @param focusTraversalKeysEnabled the new value of the flag + * @see #getFocusTraversalKeysEnabled () + * @see #setFocusTraversalKeys (int, Set) + * @see #getFocusTraversalKeys (int) + * @since 1.4 + */ + public void setFocusTraversalKeysEnabled (boolean focusTraversalKeysEnabled) + { + firePropertyChange ("focusTraversalKeysEnabled", + this.focusTraversalKeysEnabled, + focusTraversalKeysEnabled); + this.focusTraversalKeysEnabled = focusTraversalKeysEnabled; + } + + /** + * Check whether or not focus traversal keys are enabled on this + * Component. If they are, then the keyboard focus manager consumes + * and acts on key press and release events that trigger focus + * traversal, and discards the corresponding key typed events. If + * focus traversal keys are disabled, then all key events that would + * otherwise trigger focus traversal are sent to this Component. + * + * @return true if focus traversal keys are enabled + * @see #setFocusTraversalKeysEnabled (boolean) + * @see #setFocusTraversalKeys (int, Set) + * @see #getFocusTraversalKeys (int) + * @since 1.4 + */ + public boolean getFocusTraversalKeysEnabled () + { + return focusTraversalKeysEnabled; + } + + /** + * Request that this Component be given the keyboard input focus and + * that its top-level ancestor become the focused Window. + * + * For the request to be granted, the Component must be focusable, + * displayable and showing and the top-level Window to which it + * belongs must be focusable. If the request is initially denied on + * the basis that the top-level Window is not focusable, the request + * will be remembered and granted when the Window does become + * focused. + * + * Never assume that this Component is the focus owner until it + * receives a FOCUS_GAINED event. + * + * The behaviour of this method is platform-dependent. + * {@link #requestFocusInWindow()} should be used instead. + * + * @see #requestFocusInWindow () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + */ + public void requestFocus () + { + if (isDisplayable () + && isShowing () + && isFocusable ()) + { + synchronized (getTreeLock ()) + { + // Find this Component's top-level ancestor. + Container parent = getParent (); + + while (parent != null + && !(parent instanceof Window)) + parent = parent.getParent (); + + Window toplevel = (Window) parent; + if (toplevel.isFocusableWindow ()) + { + if (peer != null && !isLightweight()) + // This call will cause a FOCUS_GAINED event to be + // posted to the system event queue if the native + // windowing system grants the focus request. + peer.requestFocus (); + else + { + // Either our peer hasn't been created yet or we're a + // lightweight component. In either case we want to + // post a FOCUS_GAINED event. + EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + synchronized (eq) + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + Component currentFocusOwner = manager.getGlobalPermanentFocusOwner (); + if (currentFocusOwner != null) + { + eq.postEvent (new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, + false, this)); + eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, false, + currentFocusOwner)); + } + else + eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, false)); + } + } + } + else + pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED); + } + } + } + + /** + * Request that this Component be given the keyboard input focus and + * that its top-level ancestor become the focused Window. + * + * For the request to be granted, the Component must be focusable, + * displayable and showing and the top-level Window to which it + * belongs must be focusable. If the request is initially denied on + * the basis that the top-level Window is not focusable, the request + * will be remembered and granted when the Window does become + * focused. + * + * Never assume that this Component is the focus owner until it + * receives a FOCUS_GAINED event. + * + * The behaviour of this method is platform-dependent. + * {@link #requestFocusInWindow()} should be used instead. + * + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. This method is meant to be called by derived + * lightweight Components that want to avoid unnecessary repainting + * when they know a given focus transfer need only be temporary. + * + * @param temporary true if the focus request is temporary + * @return true if the request has a chance of success + * @see #requestFocusInWindow () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + * @since 1.4 + */ + protected boolean requestFocus (boolean temporary) + { + if (isDisplayable () + && isShowing () + && isFocusable ()) + { + synchronized (getTreeLock ()) + { + // Find this Component's top-level ancestor. + Container parent = getParent (); + + while (parent != null + && !(parent instanceof Window)) + parent = parent.getParent (); + + Window toplevel = (Window) parent; + if (toplevel.isFocusableWindow ()) + { + if (peer != null && !isLightweight()) + // This call will cause a FOCUS_GAINED event to be + // posted to the system event queue if the native + // windowing system grants the focus request. + peer.requestFocus (); + else + { + // Either our peer hasn't been created yet or we're a + // lightweight component. In either case we want to + // post a FOCUS_GAINED event. + EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + synchronized (eq) + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + Component currentFocusOwner = manager.getGlobalPermanentFocusOwner (); + if (currentFocusOwner != null) + { + eq.postEvent (new FocusEvent(currentFocusOwner, + FocusEvent.FOCUS_LOST, + temporary, this)); + eq.postEvent (new FocusEvent(this, + FocusEvent.FOCUS_GAINED, + temporary, + currentFocusOwner)); + } + else + eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary)); + } + } + } + else + // FIXME: need to add a focus listener to our top-level + // ancestor, so that we can post this event when it becomes + // the focused window. + pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary); + } + } + // Always return true. + return true; + } + + /** + * Request that this component be given the keyboard input focus, if + * its top-level ancestor is the currently focused Window. A + * FOCUS_GAINED event will be fired if and only if this + * request is successful. To be successful, the component must be + * displayable, showing, and focusable, and its ancestor top-level + * Window must be focused. + * + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. + * + * @return true if the request has a chance of success + * @see #requestFocus () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + * @since 1.4 + */ + public boolean requestFocusInWindow () + { + return requestFocusInWindow (false); + } + + /** + * Request that this component be given the keyboard input focus, if + * its top-level ancestor is the currently focused Window. A + * FOCUS_GAINED event will be fired if and only if this + * request is successful. To be successful, the component must be + * displayable, showing, and focusable, and its ancestor top-level + * Window must be focused. + * + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. This method is meant to be called by derived + * lightweight Components that want to avoid unnecessary repainting + * when they know a given focus transfer need only be temporary. + * + * @param temporary true if the focus request is temporary + * @return true if the request has a chance of success + * @see #requestFocus () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + * @since 1.4 + */ + protected boolean requestFocusInWindow (boolean temporary) + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + Window focusedWindow = manager.getFocusedWindow (); + + if (isDisplayable () + && isShowing () + && isFocusable ()) + { + if (focusedWindow != null) + { + synchronized (getTreeLock ()) + { + Container parent = getParent (); + + while (parent != null + && !(parent instanceof Window)) + parent = parent.getParent (); + + Window toplevel = (Window) parent; + + // Check if top-level ancestor is currently focused window. + if (focusedWindow == toplevel) + { + if (peer != null + && !isLightweight() + && !(this instanceof Window)) + // This call will cause a FOCUS_GAINED event to be + // posted to the system event queue if the native + // windowing system grants the focus request. + peer.requestFocus (); + else + { + // Either our peer hasn't been created yet or we're a + // lightweight component. In either case we want to + // post a FOCUS_GAINED event. + EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + synchronized (eq) + { + Component currentFocusOwner = manager.getGlobalPermanentFocusOwner (); + if (currentFocusOwner != null) + { + eq.postEvent (new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, + temporary, this)); + eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary, + currentFocusOwner)); + } + else + eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary)); + } + } + } + else + return false; + } + } + + return true; + } + return false; + } + + /** + * Transfers focus to the next component in the focus traversal + * order, as though this were the current focus owner. + * + * @see #requestFocus() + * @since 1.1 + */ + public void transferFocus () + { + nextFocus (); + } + + /** + * Returns the root container that owns the focus cycle where this + * component resides. A focus cycle root is in two cycles, one as + * the ancestor, and one as the focusable element; this call always + * returns the ancestor. + * + * @return the ancestor container that owns the focus cycle + * @since 1.4 + */ + public Container getFocusCycleRootAncestor () + { + if (this instanceof Window + && ((Container) this).isFocusCycleRoot ()) + return (Container) this; + + Container parent = getParent (); + + while (parent != null + && !parent.isFocusCycleRoot ()) + parent = parent.getParent (); + + return parent; + } + + /** + * Tests if the container is the ancestor of the focus cycle that + * this component belongs to. + * + * @param c the container to test + * @return true if c is the focus cycle root + * @since 1.4 + */ + public boolean isFocusCycleRoot (Container c) + { + return c == getFocusCycleRootAncestor (); + } + + /** + * AWT 1.0 focus event processor. Transfers focus to the next + * component in the focus traversal order, as though this were the + * current focus owner. + * + * @deprecated use {@link #transferFocus ()} instead + */ + public void nextFocus () + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + manager.focusNextComponent (this); + } + + /** + * Transfers focus to the previous component in the focus traversal + * order, as though this were the current focus owner. + * + * @see #requestFocus () + * @since 1.4 + */ + public void transferFocusBackward () + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + manager.focusPreviousComponent (this); + } + + /** + * Transfers focus to the focus cycle root of this component. + * However, if this is a Window, the default focus owner in the + * window in the current focus cycle is focused instead. + * + * @see #requestFocus() + * @see #isFocusCycleRoot(Container) + * @since 1.4 + */ + public void transferFocusUpCycle () + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + manager.upFocusCycle (this); + } + + /** + * Tests if this component is the focus owner. Use {@link + * #isFocusOwner ()} instead. + * + * @return true if this component owns focus + * @since 1.2 + */ + public boolean hasFocus () + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + Component focusOwner = manager.getFocusOwner (); + + return this == focusOwner; + } + + /** + * Tests if this component is the focus owner. + * + * @return true if this component owns focus + * @since 1.4 + */ + public boolean isFocusOwner() + { + return hasFocus (); + } + + /** + * Adds the specified popup menu to this component. + * + * @param popup the popup menu to be added + * + * @see #remove(MenuComponent) + * + * @since 1.1 + */ + public synchronized void add(PopupMenu popup) + { + if (popups == null) + popups = new Vector(); + popups.add(popup); + + if (popup.parent != null) + popup.parent.remove(popup); + popup.parent = this; + if (peer != null) + popup.addNotify(); + } + + /** + * Removes the specified popup menu from this component. + * + * @param popup the popup menu to remove + * @see #add(PopupMenu) + * @since 1.1 + */ + public synchronized void remove(MenuComponent popup) + { + if (popups != null) + popups.remove(popup); + } + + /** + * Returns a debugging string representing this component. The string may + * be empty but not null. + * + * @return a string representing this component + */ + protected String paramString() + { + StringBuffer param = new StringBuffer(); + String name = getName(); + if (name != null) + param.append(name).append(","); + param.append(x).append(",").append(y).append(",").append(width) + .append("x").append(height); + if (! isValid()) + param.append(",invalid"); + if (! isVisible()) + param.append(",invisible"); + if (! isEnabled()) + param.append(",disabled"); + if (! isOpaque()) + param.append(",translucent"); + if (isDoubleBuffered()) + param.append(",doublebuffered"); + return param.toString(); + } + + /** + * Returns a string representation of this component. This is implemented + * as getClass().getName() + '[' + paramString() + ']'. + * + * @return a string representation of this component + */ + public String toString() + { + return getClass().getName() + '[' + paramString() + ']'; + } + + /** + * Prints a listing of this component to System.out. + * + * @see #list(PrintStream) + */ + public void list() + { + list(System.out, 0); + } + + /** + * Prints a listing of this component to the specified print stream. + * + * @param out the PrintStream to print to + */ + public void list(PrintStream out) + { + list(out, 0); + } + + /** + * Prints a listing of this component to the specified print stream, + * starting at the specified indentation point. + * + * @param out the PrintStream to print to + * @param indent the indentation point + */ + public void list(PrintStream out, int indent) + { + for (int i = 0; i < indent; ++i) + out.print(' '); + out.println(toString()); + } + + /** + * Prints a listing of this component to the specified print writer. + * + * @param out the PrintWrinter to print to + * @since 1.1 + */ + public void list(PrintWriter out) + { + list(out, 0); + } + + /** + * Prints a listing of this component to the specified print writer, + * starting at the specified indentation point. + * + * @param out the PrintWriter to print to + * @param indent the indentation point + * @since 1.1 + */ + public void list(PrintWriter out, int indent) + { + for (int i = 0; i < indent; ++i) + out.print(' '); + out.println(toString()); + } + + /** + * Adds the specified property listener to this component. This is harmless + * if the listener is null, but if the listener has already been registered, + * it will now be registered twice. The property listener ignores inherited + * properties. Recognized properties include:
+ *

+ * + * @param listener the new listener to add + * @see #removePropertyChangeListener(PropertyChangeListener) + * @see #getPropertyChangeListeners() + * @see #addPropertyChangeListener(String, PropertyChangeListener) + * @since 1.1 + */ + public void addPropertyChangeListener(PropertyChangeListener listener) + { + if (changeSupport == null) + changeSupport = new PropertyChangeSupport(this); + changeSupport.addPropertyChangeListener(listener); + } + + /** + * Removes the specified property listener from the component. This is + * harmless if the listener was not previously registered. + * + * @param listener the listener to remove + * @see #addPropertyChangeListener(PropertyChangeListener) + * @see #getPropertyChangeListeners() + * @see #removePropertyChangeListener(String, PropertyChangeListener) + * @since 1.1 + */ + public void removePropertyChangeListener(PropertyChangeListener listener) + { + if (changeSupport != null) + changeSupport.removePropertyChangeListener(listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addPropertyChangeListener(PropertyChangeListener) + * @see #removePropertyChangeListener(PropertyChangeListener) + * @see #getPropertyChangeListeners(String) + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return changeSupport == null ? new PropertyChangeListener[0] + : changeSupport.getPropertyChangeListeners(); + } + + /** + * Adds the specified property listener to this component. This is harmless + * if the listener is null, but if the listener has already been registered, + * it will now be registered twice. The property listener ignores inherited + * properties. The listener is keyed to a single property. Recognized + * properties include:
+ * + * + * @param propertyName the property name to filter on + * @param listener the new listener to add + * @see #removePropertyChangeListener(String, PropertyChangeListener) + * @see #getPropertyChangeListeners(String) + * @see #addPropertyChangeListener(PropertyChangeListener) + * @since 1.1 + */ + public void addPropertyChangeListener(String propertyName, + PropertyChangeListener listener) + { + if (changeSupport == null) + changeSupport = new PropertyChangeSupport(this); + changeSupport.addPropertyChangeListener(propertyName, listener); + } + + /** + * Removes the specified property listener on a particular property from + * the component. This is harmless if the listener was not previously + * registered. + * + * @param propertyName the property name to filter on + * @param listener the listener to remove + * @see #addPropertyChangeListener(String, PropertyChangeListener) + * @see #getPropertyChangeListeners(String) + * @see #removePropertyChangeListener(PropertyChangeListener) + * @since 1.1 + */ + public void removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) + { + if (changeSupport != null) + changeSupport.removePropertyChangeListener(propertyName, listener); + } + + /** + * Returns an array of all specified listeners on the named property that + * are registered on this component. + * + * @return an array of listeners + * @see #addPropertyChangeListener(String, PropertyChangeListener) + * @see #removePropertyChangeListener(String, PropertyChangeListener) + * @see #getPropertyChangeListeners() + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners(String property) + { + return changeSupport == null ? new PropertyChangeListener[0] + : changeSupport.getPropertyChangeListeners(property); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(String propertyName, Object oldValue, + Object newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(String propertyName, boolean oldValue, + boolean newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(String propertyName, int oldValue, + int newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Sets the text layout orientation of this component. New components default + * to UNKNOWN (which behaves like LEFT_TO_RIGHT). This method affects only + * the current component, while + * {@link #applyComponentOrientation(ComponentOrientation)} affects the + * entire hierarchy. + * + * @param o the new orientation + * @throws NullPointerException if o is null + * @see #getComponentOrientation() + */ + public void setComponentOrientation(ComponentOrientation o) + { + if (o == null) + throw new NullPointerException(); + ComponentOrientation oldOrientation = orientation; + orientation = o; + firePropertyChange("componentOrientation", oldOrientation, o); + } + + /** + * Determines the text layout orientation used by this component. + * + * @return the component orientation + * @see #setComponentOrientation(ComponentOrientation) + */ + public ComponentOrientation getComponentOrientation() + { + return orientation; + } + + /** + * Sets the text layout orientation of this component. New components default + * to UNKNOWN (which behaves like LEFT_TO_RIGHT). This method affects the + * entire hierarchy, while + * {@link #setComponentOrientation(ComponentOrientation)} affects only the + * current component. + * + * @param o the new orientation + * @throws NullPointerException if o is null + * @see #getComponentOrientation() + * @since 1.4 + */ + public void applyComponentOrientation(ComponentOrientation o) + { + setComponentOrientation(o); + } + + /** + * Returns the accessibility framework context of this class. Component is + * not accessible, so the default implementation returns null. Subclasses + * must override this behavior, and return an appropriate subclass of + * {@link AccessibleAWTComponent}. + * + * @return the accessibility context + */ + public AccessibleContext getAccessibleContext() + { + return null; + } + + + // Helper methods; some are package visible for use by subclasses. + + /** + * Subclasses should override this to return unique component names like + * "menuitem0". + * + * @return the generated name for this component + */ + String generateName() + { + // Component is abstract. + return null; + } + + /** + * Sets the peer for this component. + * + * @param peer the new peer + */ + final void setPeer(ComponentPeer peer) + { + this.peer = peer; + } + + /** + * Implementation method that allows classes such as Canvas and Window to + * override the graphics configuration without violating the published API. + * + * @return the graphics configuration + */ + GraphicsConfiguration getGraphicsConfigurationImpl() + { + if (peer != null) + { + GraphicsConfiguration config = peer.getGraphicsConfiguration(); + if (config != null) + return config; + } + + if (parent != null) + return parent.getGraphicsConfiguration(); + + return null; + } + + /** + * Translate an AWT 1.1 event ({@link AWTEvent}) into an AWT 1.0 + * event ({@link Event}). + * + * @param e an AWT 1.1 event to translate + * + * @return an AWT 1.0 event representing e + */ + static Event translateEvent (AWTEvent e) + { + Component target = (Component) e.getSource (); + Event translated = null; + + if (e instanceof InputEvent) + { + InputEvent ie = (InputEvent) e; + long when = ie.getWhen (); + + int oldID = 0; + int id = e.getID (); + + int oldMods = 0; + int mods = ie.getModifiersEx (); + + if ((mods & InputEvent.BUTTON2_DOWN_MASK) != 0) + oldMods |= Event.META_MASK; + else if ((mods & InputEvent.BUTTON3_DOWN_MASK) != 0) + oldMods |= Event.ALT_MASK; + + if ((mods & InputEvent.SHIFT_DOWN_MASK) != 0) + oldMods |= Event.SHIFT_MASK; + + if ((mods & InputEvent.CTRL_DOWN_MASK) != 0) + oldMods |= Event.CTRL_MASK; + + if ((mods & InputEvent.META_DOWN_MASK) != 0) + oldMods |= Event.META_MASK; + + if ((mods & InputEvent.ALT_DOWN_MASK) != 0) + oldMods |= Event.ALT_MASK; + + if (e instanceof MouseEvent) + { + if (id == MouseEvent.MOUSE_PRESSED) + oldID = Event.MOUSE_DOWN; + else if (id == MouseEvent.MOUSE_RELEASED) + oldID = Event.MOUSE_UP; + else if (id == MouseEvent.MOUSE_MOVED) + oldID = Event.MOUSE_MOVE; + else if (id == MouseEvent.MOUSE_DRAGGED) + oldID = Event.MOUSE_DRAG; + else if (id == MouseEvent.MOUSE_ENTERED) + oldID = Event.MOUSE_ENTER; + else if (id == MouseEvent.MOUSE_EXITED) + oldID = Event.MOUSE_EXIT; + else + // No analogous AWT 1.0 mouse event. + return null; + + MouseEvent me = (MouseEvent) e; + + translated = new Event (target, when, oldID, + me.getX (), me.getY (), 0, oldMods); + } + else if (e instanceof KeyEvent) + { + if (id == KeyEvent.KEY_PRESSED) + oldID = Event.KEY_PRESS; + else if (e.getID () == KeyEvent.KEY_RELEASED) + oldID = Event.KEY_RELEASE; + else + // No analogous AWT 1.0 key event. + return null; + + int oldKey = 0; + int newKey = ((KeyEvent) e).getKeyCode (); + switch (newKey) + { + case KeyEvent.VK_BACK_SPACE: + oldKey = Event.BACK_SPACE; + break; + case KeyEvent.VK_CAPS_LOCK: + oldKey = Event.CAPS_LOCK; + break; + case KeyEvent.VK_DELETE: + oldKey = Event.DELETE; + break; + case KeyEvent.VK_DOWN: + case KeyEvent.VK_KP_DOWN: + oldKey = Event.DOWN; + break; + case KeyEvent.VK_END: + oldKey = Event.END; + break; + case KeyEvent.VK_ENTER: + oldKey = Event.ENTER; + break; + case KeyEvent.VK_ESCAPE: + oldKey = Event.ESCAPE; + break; + case KeyEvent.VK_F1: + oldKey = Event.F1; + break; + case KeyEvent.VK_F10: + oldKey = Event.F10; + break; + case KeyEvent.VK_F11: + oldKey = Event.F11; + break; + case KeyEvent.VK_F12: + oldKey = Event.F12; + break; + case KeyEvent.VK_F2: + oldKey = Event.F2; + break; + case KeyEvent.VK_F3: + oldKey = Event.F3; + break; + case KeyEvent.VK_F4: + oldKey = Event.F4; + break; + case KeyEvent.VK_F5: + oldKey = Event.F5; + break; + case KeyEvent.VK_F6: + oldKey = Event.F6; + break; + case KeyEvent.VK_F7: + oldKey = Event.F7; + break; + case KeyEvent.VK_F8: + oldKey = Event.F8; + break; + case KeyEvent.VK_F9: + oldKey = Event.F9; + break; + case KeyEvent.VK_HOME: + oldKey = Event.HOME; + break; + case KeyEvent.VK_INSERT: + oldKey = Event.INSERT; + break; + case KeyEvent.VK_LEFT: + case KeyEvent.VK_KP_LEFT: + oldKey = Event.LEFT; + break; + case KeyEvent.VK_NUM_LOCK: + oldKey = Event.NUM_LOCK; + break; + case KeyEvent.VK_PAUSE: + oldKey = Event.PAUSE; + break; + case KeyEvent.VK_PAGE_DOWN: + oldKey = Event.PGDN; + break; + case KeyEvent.VK_PAGE_UP: + oldKey = Event.PGUP; + break; + case KeyEvent.VK_PRINTSCREEN: + oldKey = Event.PRINT_SCREEN; + break; + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_KP_RIGHT: + oldKey = Event.RIGHT; + break; + case KeyEvent.VK_SCROLL_LOCK: + oldKey = Event.SCROLL_LOCK; + break; + case KeyEvent.VK_TAB: + oldKey = Event.TAB; + break; + case KeyEvent.VK_UP: + case KeyEvent.VK_KP_UP: + oldKey = Event.UP; + break; + default: + oldKey = newKey; + } + + translated = new Event (target, when, oldID, + 0, 0, oldKey, oldMods); + } + } + else if (e instanceof ActionEvent) + translated = new Event (target, Event.ACTION_EVENT, + ((ActionEvent) e).getActionCommand ()); + + return translated; + } + + /** + * Implementation of dispatchEvent. Allows trusted package classes + * to dispatch additional events first. This implementation first + * translates e to an AWT 1.0 event and sends the + * result to {@link #postEvent}. If the AWT 1.0 event is not + * handled, and events of type e are enabled for this + * component, e is passed on to {@link #processEvent}. + * + * @param e the event to dispatch + */ + + void dispatchEventImpl (AWTEvent e) + { + Event oldEvent = translateEvent (e); + + if (oldEvent != null) + postEvent (oldEvent); + + if (eventTypeEnabled (e.id)) + { + // the trick we use to communicate between dispatch and redispatch + // is to have KeyboardFocusManager.redispatch synchronize on the + // object itself. we then do not redispatch to KeyboardFocusManager + // if we are already holding the lock. + if (! Thread.holdsLock(e)) + { + switch (e.id) + { + case WindowEvent.WINDOW_GAINED_FOCUS: + case WindowEvent.WINDOW_LOST_FOCUS: + case KeyEvent.KEY_PRESSED: + case KeyEvent.KEY_RELEASED: + case KeyEvent.KEY_TYPED: + case FocusEvent.FOCUS_GAINED: + case FocusEvent.FOCUS_LOST: + if (KeyboardFocusManager + .getCurrentKeyboardFocusManager() + .dispatchEvent(e)) + return; + case MouseEvent.MOUSE_PRESSED: + if (isLightweight()) + requestFocus(); + break; + } + } + processEvent (e); + } + } + + /** + * Tells whether or not an event type is enabled. + */ + boolean eventTypeEnabled (int type) + { + if (type > AWTEvent.RESERVED_ID_MAX) + return true; + + switch (type) + { + case ComponentEvent.COMPONENT_HIDDEN: + case ComponentEvent.COMPONENT_MOVED: + case ComponentEvent.COMPONENT_RESIZED: + case ComponentEvent.COMPONENT_SHOWN: + return (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0); + + case KeyEvent.KEY_PRESSED: + case KeyEvent.KEY_RELEASED: + case KeyEvent.KEY_TYPED: + return (keyListener != null + || (eventMask & AWTEvent.KEY_EVENT_MASK) != 0); + + case MouseEvent.MOUSE_CLICKED: + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + return (mouseListener != null + || mouseMotionListener != null + || (eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0); + + case FocusEvent.FOCUS_GAINED: + case FocusEvent.FOCUS_LOST: + return (focusListener != null + || (eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0); + + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + case InputMethodEvent.CARET_POSITION_CHANGED: + return (inputMethodListener != null + || (eventMask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0); + + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + return (eventMask & AWTEvent.PAINT_EVENT_MASK) != 0; + + default: + return false; + } + } + + /** + * Coalesce paint events. Current heuristic is: Merge if the union of + * areas is less than twice that of the sum of the areas. The X server + * tend to create a lot of paint events that are adjacent but not + * overlapping. + * + *
+   * +------+
+   * |      +-----+  ...will be merged
+   * |      |     |
+   * |      |     |
+   * +------+     |
+   *        +-----+
+   *
+   * +---------------+--+
+   * |               |  |  ...will not be merged
+   * +---------------+  |
+   *                 |  |
+   *                 |  |
+   *                 |  |
+   *                 |  |
+   *                 |  |
+   *                 +--+
+   * 
+ * + * @param queuedEvent the first paint event + * @param newEvent the second paint event + * @return the combined paint event, or null + */ + private PaintEvent coalescePaintEvents(PaintEvent queuedEvent, + PaintEvent newEvent) + { + Rectangle r1 = queuedEvent.getUpdateRect(); + Rectangle r2 = newEvent.getUpdateRect(); + Rectangle union = r1.union(r2); + + int r1a = r1.width * r1.height; + int r2a = r2.width * r2.height; + int ua = union.width * union.height; + + if (ua > (r1a+r2a)*2) + return null; + /* The 2 factor should maybe be reconsidered. Perhaps 3/2 + would be better? */ + + newEvent.setUpdateRect(union); + return newEvent; + } + + /** + * This method is used to implement transferFocus(). CHILD is the child + * making the request. This is overridden by Container; when called for an + * ordinary component there is no child and so we always return null. + * + * FIXME: is this still needed, in light of focus traversal policies? + * + * @param child the component making the request + * @return the next component to focus on + */ + Component findNextFocusComponent(Component child) + { + return null; + } + + /** + * Deserializes this component. This regenerates all serializable listeners + * which were registered originally. + * + * @param s the stream to read from + * @throws ClassNotFoundException if deserialization fails + * @throws IOException if the stream fails + */ + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject(); + String key = (String) s.readObject(); + while (key != null) + { + Object listener = s.readObject(); + if ("componentL".equals(key)) + addComponentListener((ComponentListener) listener); + else if ("focusL".equals(key)) + addFocusListener((FocusListener) listener); + else if ("keyL".equals(key)) + addKeyListener((KeyListener) listener); + else if ("mouseL".equals(key)) + addMouseListener((MouseListener) listener); + else if ("mouseMotionL".equals(key)) + addMouseMotionListener((MouseMotionListener) listener); + else if ("inputMethodL".equals(key)) + addInputMethodListener((InputMethodListener) listener); + else if ("hierarchyL".equals(key)) + addHierarchyListener((HierarchyListener) listener); + else if ("hierarchyBoundsL".equals(key)) + addHierarchyBoundsListener((HierarchyBoundsListener) listener); + else if ("mouseWheelL".equals(key)) + addMouseWheelListener((MouseWheelListener) listener); + key = (String) s.readObject(); + } + } + + /** + * Serializes this component. This ignores all listeners which do not + * implement Serializable, but includes those that do. + * + * @param s the stream to write to + * @throws IOException if the stream fails + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + AWTEventMulticaster.save(s, "componentL", componentListener); + AWTEventMulticaster.save(s, "focusL", focusListener); + AWTEventMulticaster.save(s, "keyL", keyListener); + AWTEventMulticaster.save(s, "mouseL", mouseListener); + AWTEventMulticaster.save(s, "mouseMotionL", mouseMotionListener); + AWTEventMulticaster.save(s, "inputMethodL", inputMethodListener); + AWTEventMulticaster.save(s, "hierarchyL", hierarchyListener); + AWTEventMulticaster.save(s, "hierarchyBoundsL", hierarchyBoundsListener); + AWTEventMulticaster.save(s, "mouseWheelL", mouseWheelListener); + s.writeObject(null); + } + + + // Nested classes. + + /** + * This class provides accessibility support for subclasses of container. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ + protected abstract class AccessibleAWTComponent extends AccessibleContext + implements Serializable, AccessibleComponent + { + /** + * Compatible with JDK 1.3+. + */ + private static final long serialVersionUID = 642321655757800191L; + + /** + * Converts show/hide events to PropertyChange events, and is registered + * as a component listener on this component. + * + * @serial the component handler + */ + protected ComponentListener accessibleAWTComponentHandler + = new AccessibleAWTComponentHandler(); + + /** + * Converts focus events to PropertyChange events, and is registered + * as a focus listener on this component. + * + * @serial the focus handler + */ + protected FocusListener accessibleAWTFocusHandler + = new AccessibleAWTFocusHandler(); + + /** + * The default constructor. + */ + protected AccessibleAWTComponent() + { + Component.this.addComponentListener(accessibleAWTComponentHandler); + Component.this.addFocusListener(accessibleAWTFocusHandler); + } + + /** + * Adds a global property change listener to the accessible component. + * + * @param l the listener to add + * @see #ACCESSIBLE_NAME_PROPERTY + * @see #ACCESSIBLE_DESCRIPTION_PROPERTY + * @see #ACCESSIBLE_STATE_PROPERTY + * @see #ACCESSIBLE_VALUE_PROPERTY + * @see #ACCESSIBLE_SELECTION_PROPERTY + * @see #ACCESSIBLE_TEXT_PROPERTY + * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY + */ + public void addPropertyChangeListener(PropertyChangeListener l) + { + Component.this.addPropertyChangeListener(l); + super.addPropertyChangeListener(l); + } + + /** + * Removes a global property change listener from this accessible + * component. + * + * @param l the listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener l) + { + Component.this.removePropertyChangeListener(l); + super.removePropertyChangeListener(l); + } + + /** + * Returns the accessible name of this component. It is almost always + * wrong to return getName(), since it is not localized. In fact, for + * things like buttons, this should be the text of the button, not the + * name of the object. The tooltip text might also be appropriate. + * + * @return the name + * @see #setAccessibleName(String) + */ + public String getAccessibleName() + { + return accessibleName == null ? getName() : accessibleName; + } + + /** + * Returns a brief description of this accessible context. This should + * be localized. + * + * @return a description of this component + * @see #setAccessibleDescription(String) + */ + public String getAccessibleDescription() + { + return accessibleDescription; + } + + /** + * Returns the role of this component. + * + * @return the accessible role + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.AWT_COMPONENT; + } + + /** + * Returns a state set describing this component's state. + * + * @return a new state set + * @see AccessibleState + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet s = new AccessibleStateSet(); + if (Component.this.isEnabled()) + s.add(AccessibleState.ENABLED); + if (isFocusable()) + s.add(AccessibleState.FOCUSABLE); + if (isFocusOwner()) + s.add(AccessibleState.FOCUSED); + if (isOpaque()) + s.add(AccessibleState.OPAQUE); + if (Component.this.isShowing()) + s.add(AccessibleState.SHOWING); + if (Component.this.isVisible()) + s.add(AccessibleState.VISIBLE); + return s; + } + + /** + * Returns the parent of this component, if it is accessible. + * + * @return the accessible parent + */ + public Accessible getAccessibleParent() + { + if (accessibleParent == null) + { + Container parent = getParent(); + accessibleParent = parent instanceof Accessible + ? (Accessible) parent : null; + } + return accessibleParent; + } + + /** + * Returns the index of this component in its accessible parent. + * + * @return the index, or -1 if the parent is not accessible + * @see #getAccessibleParent() + */ + public int getAccessibleIndexInParent() + { + if (getAccessibleParent() == null) + return -1; + AccessibleContext context + = ((Component) accessibleParent).getAccessibleContext(); + if (context == null) + return -1; + for (int i = context.getAccessibleChildrenCount(); --i >= 0; ) + if (context.getAccessibleChild(i) == Component.this) + return i; + return -1; + } + + /** + * Returns the number of children of this component which implement + * Accessible. Subclasses must override this if they can have children. + * + * @return the number of accessible children, default 0 + */ + public int getAccessibleChildrenCount() + { + return 0; + } + + /** + * Returns the ith accessible child. Subclasses must override this if + * they can have children. + * + * @return the ith accessible child, or null + * @see #getAccessibleChildrenCount() + */ + public Accessible getAccessibleChild(int i) + { + return null; + } + + /** + * Returns the locale of this component. + * + * @return the locale + * @throws IllegalComponentStateException if the locale is unknown + */ + public Locale getLocale() + { + return Component.this.getLocale(); + } + + /** + * Returns this, since it is an accessible component. + * + * @return the accessible component + */ + public AccessibleComponent getAccessibleComponent() + { + return this; + } + + /** + * Gets the background color. + * + * @return the background color + * @see #setBackground(Color) + */ + public Color getBackground() + { + return Component.this.getBackground(); + } + + /** + * Sets the background color. + * + * @param c the background color + * @see #getBackground() + * @see #isOpaque() + */ + public void setBackground(Color c) + { + Component.this.setBackground(c); + } + + /** + * Gets the foreground color. + * + * @return the foreground color + * @see #setForeground(Color) + */ + public Color getForeground() + { + return Component.this.getForeground(); + } + + /** + * Sets the foreground color. + * + * @param c the foreground color + * @see #getForeground() + */ + public void setForeground(Color c) + { + Component.this.setForeground(c); + } + + /** + * Gets the cursor. + * + * @return the cursor + * @see #setCursor(Cursor) + */ + public Cursor getCursor() + { + return Component.this.getCursor(); + } + + /** + * Sets the cursor. + * + * @param cursor the cursor + * @see #getCursor() + */ + public void setCursor(Cursor cursor) + { + Component.this.setCursor(cursor); + } + + /** + * Gets the font. + * + * @return the font + * @see #setFont(Font) + */ + public Font getFont() + { + return Component.this.getFont(); + } + + /** + * Sets the font. + * + * @param f the font + * @see #getFont() + */ + public void setFont(Font f) + { + Component.this.setFont(f); + } + + /** + * Gets the font metrics for a font. + * + * @param f the font to look up + * @return its metrics + * @throws NullPointerException if f is null + * @see #getFont() + */ + public FontMetrics getFontMetrics(Font f) + { + return Component.this.getFontMetrics(f); + } + + /** + * Tests if the component is enabled. + * + * @return true if the component is enabled + * @see #setEnabled(boolean) + * @see #getAccessibleStateSet() + * @see AccessibleState#ENABLED + */ + public boolean isEnabled() + { + return Component.this.isEnabled(); + } + + /** + * Set whether the component is enabled. + * + * @param b the new enabled status + * @see #isEnabled() + */ + public void setEnabled(boolean b) + { + Component.this.setEnabled(b); + } + + /** + * Test whether the component is visible (not necesarily showing). + * + * @return true if it is visible + * @see #setVisible(boolean) + * @see #getAccessibleStateSet() + * @see AccessibleState#VISIBLE + */ + public boolean isVisible() + { + return Component.this.isVisible(); + } + + /** + * Sets the visibility of this component. + * + * @param b the desired visibility + * @see #isVisible() + */ + public void setVisible(boolean b) + { + Component.this.setVisible(b); + } + + /** + * Tests if the component is showing. + * + * @return true if this is showing + */ + public boolean isShowing() + { + return Component.this.isShowing(); + } + + /** + * Tests if the point is contained in this component. + * + * @param p the point to check + * @return true if it is contained + * @throws NullPointerException if p is null + */ + public boolean contains(Point p) + { + return Component.this.contains(p.x, p.y); + } + + /** + * Returns the location of this object on the screen, or null if it is + * not showing. + * + * @return the location relative to screen coordinates, if showing + * @see #getBounds() + * @see #getLocation() + */ + public Point getLocationOnScreen() + { + return Component.this.isShowing() ? Component.this.getLocationOnScreen() + : null; + } + + /** + * Returns the location of this object relative to its parent's coordinate + * system, or null if it is not showing. + * + * @return the location + * @see #getBounds() + * @see #getLocationOnScreen() + */ + public Point getLocation() + { + return Component.this.isShowing() ? Component.this.getLocation() : null; + } + + /** + * Sets the location of this relative to its parent's coordinate system. + * + * @param p the location + * @throws NullPointerException if p is null + * @see #getLocation() + */ + public void setLocation(Point p) + { + Component.this.setLocation(p.x, p.y); + } + + /** + * Gets the bounds of this component, or null if it is not on screen. + * + * @return the bounds + * @see #contains(Point) + * @see #setBounds(Rectangle) + */ + public Rectangle getBounds() + { + return Component.this.isShowing() ? Component.this.getBounds() : null; + } + + /** + * Sets the bounds of this component. + * + * @param r the bounds + * @throws NullPointerException if r is null + * @see #getBounds() + */ + public void setBounds(Rectangle r) + { + Component.this.setBounds(r.x, r.y, r.width, r.height); + } + + /** + * Gets the size of this component, or null if it is not showing. + * + * @return the size + * @see #setSize(Dimension) + */ + public Dimension getSize() + { + return Component.this.isShowing() ? Component.this.getSize() : null; + } + + /** + * Sets the size of this component. + * + * @param d the size + * @throws NullPointerException if d is null + * @see #getSize() + */ + public void setSize(Dimension d) + { + Component.this.setSize(d.width, d.height); + } + + /** + * Returns the Accessible child at a point relative to the coordinate + * system of this component, if one exists, or null. Since components + * have no children, subclasses must override this to get anything besides + * null. + * + * @param p the point to check + * @return the accessible child at that point + * @throws NullPointerException if p is null + */ + public Accessible getAccessibleAt(Point p) + { + return null; + } + + /** + * Tests whether this component can accept focus. + * + * @return true if this is focus traversable + * @see #getAccessibleStateSet () + * @see AccessibleState#FOCUSABLE + * @see AccessibleState#FOCUSED + */ + public boolean isFocusTraversable () + { + return Component.this.isFocusTraversable (); + } + + /** + * Requests focus for this component. + * + * @see #isFocusTraversable () + */ + public void requestFocus () + { + Component.this.requestFocus (); + } + + /** + * Adds a focus listener. + * + * @param l the listener to add + */ + public void addFocusListener(FocusListener l) + { + Component.this.addFocusListener(l); + } + + /** + * Removes a focus listener. + * + * @param l the listener to remove + */ + public void removeFocusListener(FocusListener l) + { + Component.this.removeFocusListener(l); + } + + /** + * Converts component changes into property changes. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ + protected class AccessibleAWTComponentHandler implements ComponentListener + { + /** + * Default constructor. + */ + protected AccessibleAWTComponentHandler() + { + } + + /** + * Convert a component hidden to a property change. + * + * @param e the event to convert + */ + public void componentHidden(ComponentEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, AccessibleState.VISIBLE, null); + } + + /** + * Convert a component shown to a property change. + * + * @param e the event to convert + */ + public void componentShown(ComponentEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.VISIBLE); + } + + /** + * Moving a component does not affect properties. + * + * @param e ignored + */ + public void componentMoved(ComponentEvent e) + { + } + + /** + * Resizing a component does not affect properties. + * + * @param e ignored + */ + public void componentResized(ComponentEvent e) + { + } + } // class AccessibleAWTComponentHandler + + /** + * Converts focus changes into property changes. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ + protected class AccessibleAWTFocusHandler implements FocusListener + { + /** + * Default constructor. + */ + protected AccessibleAWTFocusHandler() + { + } + + /** + * Convert a focus gained to a property change. + * + * @param e the event to convert + */ + public void focusGained(FocusEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.FOCUSED); + } + + /** + * Convert a focus lost to a property change. + * + * @param e the event to convert + */ + public void focusLost(FocusEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, AccessibleState.FOCUSED, null); + } + } // class AccessibleAWTComponentHandler + } // class AccessibleAWTComponent + + /** + * This class provides support for blitting offscreen surfaces to a + * component. + * + * @see BufferStrategy + * + * @since 1.4 + */ + protected class BltBufferStrategy extends BufferStrategy + { + /** + * The capabilities of the image buffer. + */ + protected BufferCapabilities caps; + + /** + * The back buffers used in this strategy. + */ + protected VolatileImage[] backBuffers; + + /** + * Whether or not the image buffer resources are allocated and + * ready to be drawn into. + */ + protected boolean validatedContents; + + /** + * The width of the back buffers. + */ + protected int width; + + /** + * The height of the back buffers. + */ + protected int height; + + /** + * The front buffer. + */ + private VolatileImage frontBuffer; + + /** + * Creates a blitting buffer strategy. + * + * @param numBuffers the number of buffers, including the front + * buffer + * @param caps the capabilities of this strategy + */ + protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) + { + this.caps = caps; + createBackBuffers(numBuffers - 1); + width = getWidth(); + height = getHeight(); + } + + /** + * Initializes the backBuffers field with an array of numBuffers + * VolatileImages. + * + * @param numBuffers the number of backbuffers to create + */ + protected void createBackBuffers(int numBuffers) + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + backBuffers = new VolatileImage[numBuffers]; + + for (int i = 0; i < numBuffers; i++) + backBuffers[i] = c.createCompatibleVolatileImage(width, height); + } + + /** + * Retrieves the capabilities of this buffer strategy. + * + * @return the capabilities of this buffer strategy + */ + public BufferCapabilities getCapabilities() + { + return caps; + } + + /** + * Retrieves a graphics object that can be used to draw into this + * strategy's image buffer. + * + * @return a graphics object + */ + public Graphics getDrawGraphics() + { + // Return the backmost buffer's graphics. + return backBuffers[0].getGraphics(); + } + + /** + * Bring the contents of the back buffer to the front buffer. + */ + public void show() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + // draw the front buffer. + getGraphics().drawImage(backBuffers[backBuffers.length - 1], + width, height, null); + + BufferCapabilities.FlipContents f = getCapabilities().getFlipContents(); + + // blit the back buffers. + for (int i = backBuffers.length - 1; i > 0 ; i--) + backBuffers[i] = backBuffers[i - 1]; + + // create new backmost buffer. + if (f == BufferCapabilities.FlipContents.UNDEFINED) + backBuffers[0] = c.createCompatibleVolatileImage(width, height); + + // create new backmost buffer and clear it to the background + // color. + if (f == BufferCapabilities.FlipContents.BACKGROUND) + { + backBuffers[0] = c.createCompatibleVolatileImage(width, height); + backBuffers[0].getGraphics().clearRect(0, 0, width, height); + } + + // FIXME: set the backmost buffer to the prior contents of the + // front buffer. How do we retrieve the contents of the front + // buffer? + // + // if (f == BufferCapabilities.FlipContents.PRIOR) + + // set the backmost buffer to a copy of the new front buffer. + if (f == BufferCapabilities.FlipContents.COPIED) + backBuffers[0] = backBuffers[backBuffers.length - 1]; + } + + /** + * Re-create the image buffer resources if they've been lost. + */ + protected void revalidate() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + for (int i = 0; i < backBuffers.length; i++) + { + int result = backBuffers[i].validate(c); + if (result == VolatileImage.IMAGE_INCOMPATIBLE) + backBuffers[i] = c.createCompatibleVolatileImage(width, height); + } + validatedContents = true; + } + + /** + * Returns whether or not the image buffer resources have been + * lost. + * + * @return true if the resources have been lost, false otherwise + */ + public boolean contentsLost() + { + for (int i = 0; i < backBuffers.length; i++) + { + if (backBuffers[i].contentsLost()) + { + validatedContents = false; + return true; + } + } + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return false; + } + + /** + * Returns whether or not the image buffer resources have been + * restored. + * + * @return true if the resources have been restored, false + * otherwise + */ + public boolean contentsRestored() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + boolean imageRestored = false; + + for (int i = 0; i < backBuffers.length; i++) + { + int result = backBuffers[i].validate(c); + if (result == VolatileImage.IMAGE_RESTORED) + imageRestored = true; + else if (result == VolatileImage.IMAGE_INCOMPATIBLE) + return false; + } + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return imageRestored; + } + } + + /** + * This class provides support for flipping component buffers. It + * can only be used on Canvases and Windows. + * + * @since 1.4 + */ + protected class FlipBufferStrategy extends BufferStrategy + { + /** + * The number of buffers. + */ + protected int numBuffers; + + /** + * The capabilities of this buffering strategy. + */ + protected BufferCapabilities caps; + + /** + * An Image reference to the drawing buffer. + */ + protected Image drawBuffer; + + /** + * A VolatileImage reference to the drawing buffer. + */ + protected VolatileImage drawVBuffer; + + /** + * Whether or not the image buffer resources are allocated and + * ready to be drawn into. + */ + protected boolean validatedContents; + + /** + * The width of the back buffer. + */ + private int width; + + /** + * The height of the back buffer. + */ + private int height; + + /** + * Creates a flipping buffer strategy. The only supported + * strategy for FlipBufferStrategy itself is a double-buffer page + * flipping strategy. It forms the basis for more complex derived + * strategies. + * + * @param numBuffers the number of buffers + * @param caps the capabilities of this buffering strategy + * + * @throws AWTException if the requested + * number-of-buffers/capabilities combination is not supported + */ + protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) + throws AWTException + { + this.caps = caps; + width = getWidth(); + height = getHeight(); + + if (numBuffers > 1) + createBuffers(numBuffers, caps); + else + { + drawVBuffer = peer.createVolatileImage(width, height); + drawBuffer = drawVBuffer; + } + } + + /** + * Creates a multi-buffer flipping strategy. The number of + * buffers must be greater than one and the buffer capabilities + * must specify page flipping. + * + * @param numBuffers the number of flipping buffers; must be + * greater than one + * @param caps the buffering capabilities; caps.isPageFlipping() + * must return true + * + * @throws IllegalArgumentException if numBuffers is not greater + * than one or if the page flipping capability is not requested + * + * @throws AWTException if the requested flipping strategy is not + * supported + */ + protected void createBuffers(int numBuffers, BufferCapabilities caps) + throws AWTException + { + if (numBuffers <= 1) + throw new IllegalArgumentException("FlipBufferStrategy.createBuffers:" + + " numBuffers must be greater than" + + " one."); + + if (!caps.isPageFlipping()) + throw new IllegalArgumentException("FlipBufferStrategy.createBuffers:" + + " flipping must be a specified" + + " capability."); + + peer.createBuffers(numBuffers, caps); + } + + /** + * Return a direct reference to the back buffer image. + * + * @return a direct reference to the back buffer image. + */ + protected Image getBackBuffer() + { + return peer.getBackBuffer(); + } + + /** + * Perform a flip operation to transfer the contents of the back + * buffer to the front buffer. + */ + protected void flip(BufferCapabilities.FlipContents flipAction) + { + peer.flip(flipAction); + } + + /** + * Release the back buffer's resources. + */ + protected void destroyBuffers() + { + peer.destroyBuffers(); + } + + /** + * Retrieves the capabilities of this buffer strategy. + * + * @return the capabilities of this buffer strategy + */ + public BufferCapabilities getCapabilities() + { + return caps; + } + + /** + * Retrieves a graphics object that can be used to draw into this + * strategy's image buffer. + * + * @return a graphics object + */ + public Graphics getDrawGraphics() + { + return drawVBuffer.getGraphics(); + } + + /** + * Re-create the image buffer resources if they've been lost. + */ + protected void revalidate() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + if (drawVBuffer.validate(c) == VolatileImage.IMAGE_INCOMPATIBLE) + drawVBuffer = peer.createVolatileImage(width, height); + validatedContents = true; + } + + /** + * Returns whether or not the image buffer resources have been + * lost. + * + * @return true if the resources have been lost, false otherwise + */ + public boolean contentsLost() + { + if (drawVBuffer.contentsLost()) + { + validatedContents = false; + return true; + } + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return false; + } + + /** + * Returns whether or not the image buffer resources have been + * restored. + * + * @return true if the resources have been restored, false + * otherwise + */ + public boolean contentsRestored() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + int result = drawVBuffer.validate(c); + + boolean imageRestored = false; + + if (result == VolatileImage.IMAGE_RESTORED) + imageRestored = true; + else if (result == VolatileImage.IMAGE_INCOMPATIBLE) + return false; + + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return imageRestored; + } + + /** + * Bring the contents of the back buffer to the front buffer. + */ + public void show() + { + flip(caps.getFlipContents()); + } + } +} diff --git a/libjava/classpath/java/awt/ComponentOrientation.java b/libjava/classpath/java/awt/ComponentOrientation.java new file mode 100644 index 0000000..69b14c7 --- /dev/null +++ b/libjava/classpath/java/awt/ComponentOrientation.java @@ -0,0 +1,215 @@ +/* ComponentOrientation.java -- describes a component's orientation + Copyright (C) 2000, 2001, 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 java.awt; + +import java.io.Serializable; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * This class is used to differentiate different orientations for text layout. + * It controls whether text flows left-to-right or right-to-left, and whether + * lines are horizontal or vertical, as in this table:
+ *
+ * LT      RT      TL      TR
+ * A B C   C B A   A D G   G D A
+ * D E F   F E D   B E H   H E B
+ * G H I   I H G   C F I   I F C
+ * 
+ * LT languages are most common (left-to-right lines, top-to-bottom). + * This includes Western European languages, and optionally includes Japanese, + * Chinese, and Korean. RT languages (right-to-left lines, + * top-to-bottom) are mainly middle eastern, such as Hebrew and Arabic. + * TR languages flow top-to-bottom in a line, right-to-left, and are + * the basis of Japanese, Chinese, and Korean. Finally, TL languages + * flow top-to-bottom in a line, left-to-right, as in Mongolian. + * + *

This is a pretty poor excuse for a type-safe enum, since it is not + * guaranteed that orientation objects are unique (thanks to serialization), + * yet there is no equals() method. You would be wise to compare the output + * of isHorizontal() and isLeftToRight() rather than comparing objects with + * ==, especially since more constants may be added in the future. + * + * @author Bryce McKinlay (bryce@albatross.co.nz) + * @since 1.0 + * @status updated to 1.4 + */ +public final class ComponentOrientation implements Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4113291392143563828L; + + /** Constant for unknown orientation. */ + private static final int UNKNOWN_ID = 1; + + /** Constant for horizontal line orientation. */ + private static final int HORIZONTAL_ID = 2; + + /** Constant for left-to-right orientation. */ + private static final int LEFT_TO_RIGHT_ID = 4; + + /** + * Items run left to right, and lines flow top to bottom. Examples: English, + * French. + */ + public static final ComponentOrientation LEFT_TO_RIGHT + = new ComponentOrientation(HORIZONTAL_ID | LEFT_TO_RIGHT_ID); + + /** + * Items run right to left, and lines flow top to bottom. Examples: Arabic, + * Hebrew. + */ + public static final ComponentOrientation RIGHT_TO_LEFT + = new ComponentOrientation(HORIZONTAL_ID); + + /** + * The orientation is unknown for the locale. For backwards compatibility, + * this behaves like LEFT_TO_RIGHT in the instance methods. + */ + public static final ComponentOrientation UNKNOWN + = new ComponentOrientation(UNKNOWN_ID | HORIZONTAL_ID | LEFT_TO_RIGHT_ID); + + /** + * The orientation of this object; bitwise-or of unknown (1), horizontal (2), + * and left-to-right (4). + * + * @serial the orientation + */ + private final int orientation; + + /** + * Construct a given orientation. + * + * @param orientation the orientation + */ + private ComponentOrientation(int orientation) + { + this.orientation = orientation; + } + + /** + * Returns true if the lines are horizontal, in which case lines flow + * top-to-bottom. For example, English, Hebrew. Counterexamples: Japanese, + * Chinese, Korean, Mongolian. + * + * @return true if this orientation has horizontal lines + */ + public boolean isHorizontal() + { + return (orientation & HORIZONTAL_ID) != 0; + } + + /** + * If isHorizontal() returns true, then this determines whether items in + * the line flow left-to-right. If isHorizontal() returns false, items in + * a line flow top-to-bottom, and this determines if lines flow + * left-to-right. + * + * @return true if this orientation flows left-to-right + */ + public boolean isLeftToRight() + { + return (orientation & LEFT_TO_RIGHT_ID) != 0; + } + + /** + * Gets an orientation appropriate for the locale. + * + * @param locale the locale + * @return the orientation for that locale + * @throws NullPointerException if locale is null + */ + public static ComponentOrientation getOrientation(Locale locale) + { + // Based on iterating over all languages defined in JDK 1.4, this behavior + // matches Sun's. However, it makes me wonder if any non-horizontal + // orientations even exist, as it sure contradicts their documentation. + String language = locale.getLanguage(); + if ("ar".equals(language) || "fa".equals(language) || "iw".equals(language) + || "ur".equals(language)) + return RIGHT_TO_LEFT; + return LEFT_TO_RIGHT; + } + + /** + * Gets an orientation from a resource bundle. This tries the following: + * + *

+ * + * @param bdl the bundle to use + * @return the orientation + * @throws NullPointerException if bdl is null + * @deprecated use {@link #getOrientation(Locale)} instead + */ + public static ComponentOrientation getOrientation(ResourceBundle bdl) + { + ComponentOrientation r; + try + { + r = (ComponentOrientation) bdl.getObject("Orientation"); + if (r != null) + return r; + } + catch (MissingResourceException ignored) + { + } + catch (ClassCastException ignored) + { + } + try + { + r = getOrientation(bdl.getLocale()); + if (r != null) + return r; + } + catch (Exception ignored) + { + } + return getOrientation(Locale.getDefault()); + } +} // class ComponentOrientation diff --git a/libjava/classpath/java/awt/Composite.java b/libjava/classpath/java/awt/Composite.java new file mode 100644 index 0000000..ca3abe4 --- /dev/null +++ b/libjava/classpath/java/awt/Composite.java @@ -0,0 +1,73 @@ +/* Composite.java -- graphics formed from composite layers + 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 java.awt; + +import java.awt.image.ColorModel; + +/** + * This interface is for graphics which are formed as composites of others. + * It combines {@link Graphics2D} shapes according to defined rules to form + * the new image. Implementations of this interface must be immutable, because + * they are not cloned when a Graphics2D container is cloned. + * + *

Since this can expose pixels to untrusted code, there is a security + * check on custom objects, readDisplayPixels, to prevent leaking + * restricted information graphically. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see AlphaComposite + * @see CompositeContext + * @see Graphics2D#setComposite(Composite) + * @since 1.2 + * @status updated to 1.4 + */ +public interface Composite +{ + /** + * Create a context state for performing the compositing operation. Several + * contexts may exist for this object, in a multi-threaded environment. + * + * @param srcColorModel the color model of the source + * @param dstColorModel the color model of the destination + * @param hints hints for choosing between rendering alternatives + */ + CompositeContext createContext(ColorModel srcColorModel, + ColorModel dstColorModel, + RenderingHints hints); +} // interface Composite diff --git a/libjava/classpath/java/awt/CompositeContext.java b/libjava/classpath/java/awt/CompositeContext.java new file mode 100644 index 0000000..018a270 --- /dev/null +++ b/libjava/classpath/java/awt/CompositeContext.java @@ -0,0 +1,71 @@ +/* Composite.java -- the context for compositing graphics layers + 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 java.awt; + +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +/** + * This interface provides an optimized environment for compositing graphics. + * Several such contexts may exist for a given Composite object. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Composite + * @since 1.2 + * @status updated to 1.4 + */ +public interface CompositeContext +{ + /** + * Release resources allocated for the compositing. + */ + void dispose(); + + /** + * Compose the two source images into the composite image. The destination + * can be the same as one of the two inputs, and the destination must be + * compatible with the ColorModel chosen in {@link Composite#createContext}. + * + * @param src the lower image source in compositing + * @param dstIn the upper image source in compositing + * @param dstOut the destination for the composite + * @see Composite + */ + void compose(Raster src, Raster dstIn, WritableRaster dstOut); +} // interface CompositeContext diff --git a/libjava/classpath/java/awt/Container.java b/libjava/classpath/java/awt/Container.java new file mode 100644 index 0000000..303d13b --- /dev/null +++ b/libjava/classpath/java/awt/Container.java @@ -0,0 +1,2026 @@ +/* Container.java -- parent container class in AWT + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ContainerPeer; +import java.awt.peer.LightweightPeer; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.util.Collections; +import java.util.EventListener; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.accessibility.Accessible; +import javax.swing.SwingUtilities; + +/** + * A generic window toolkit object that acts as a container for other objects. + * Components are tracked in a list, and new elements are at the end of the + * list or bottom of the stacking order. + * + * @author original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * + * @since 1.0 + * + * @status still missing 1.4 support + */ +public class Container extends Component +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 4613797578919906343L; + + /* Serialized fields from the serialization spec. */ + int ncomponents; + Component[] component; + LayoutManager layoutMgr; + + LightweightDispatcher dispatcher; + + Dimension maxSize; + + /** + * @since 1.4 + */ + boolean focusCycleRoot; + + int containerSerializedDataVersion; + + /* Anything else is non-serializable, and should be declared "transient". */ + transient ContainerListener containerListener; + transient PropertyChangeSupport changeSupport; + + /** The focus traversal policy that determines how focus is + transferred between this Container and its children. */ + private FocusTraversalPolicy focusTraversalPolicy; + + /** + * The focus traversal keys, if not inherited from the parent or default + * keyboard manager. These sets will contain only AWTKeyStrokes that + * represent press and release events to use as focus control. + * + * @see #getFocusTraversalKeys(int) + * @see #setFocusTraversalKeys(int, Set) + * @since 1.4 + */ + transient Set[] focusTraversalKeys; + + /** + * Default constructor for subclasses. + */ + public Container() + { + } + + /** + * Returns the number of components in this container. + * + * @return The number of components in this container. + */ + public int getComponentCount() + { + return countComponents (); + } + + /** + * Returns the number of components in this container. + * + * @return The number of components in this container. + * + * @deprecated use {@link #getComponentCount()} instead + */ + public int countComponents() + { + return ncomponents; + } + + /** + * Returns the component at the specified index. + * + * @param n The index of the component to retrieve. + * + * @return The requested component. + * + * @throws ArrayIndexOutOfBoundsException If the specified index is invalid + */ + public Component getComponent(int n) + { + synchronized (getTreeLock ()) + { + if (n < 0 || n >= ncomponents) + throw new ArrayIndexOutOfBoundsException("no such component"); + + return component[n]; + } + } + + /** + * Returns an array of the components in this container. + * + * @return The components in this container. + */ + public Component[] getComponents() + { + synchronized (getTreeLock ()) + { + Component[] result = new Component[ncomponents]; + + if (ncomponents > 0) + System.arraycopy(component, 0, result, 0, ncomponents); + + return result; + } + } + + /** + * Swaps the components at position i and j, in the container. + */ + + protected void swapComponents (int i, int j) + { + synchronized (getTreeLock ()) + { + if (i < 0 + || i >= component.length + || j < 0 + || j >= component.length) + throw new ArrayIndexOutOfBoundsException (); + Component tmp = component[i]; + component[i] = component[j]; + component[j] = tmp; + } + } + + /** + * Returns the insets for this container, which is the space used for + * borders, the margin, etc. + * + * @return The insets for this container. + */ + public Insets getInsets() + { + return insets (); + } + + /** + * Returns the insets for this container, which is the space used for + * borders, the margin, etc. + * + * @return The insets for this container. + * @deprecated use {@link #getInsets()} instead + */ + public Insets insets() + { + if (peer == null) + return new Insets (0, 0, 0, 0); + + return ((ContainerPeer) peer).getInsets (); + } + + /** + * Adds the specified component to this container at the end of the + * component list. + * + * @param comp The component to add to the container. + * + * @return The same component that was added. + */ + public Component add(Component comp) + { + addImpl(comp, null, -1); + return comp; + } + + /** + * Adds the specified component to the container at the end of the + * component list. This method should not be used. Instead, use + * add(Component, Object). + * + * @param name The name of the component to be added. + * @param comp The component to be added. + * + * @return The same component that was added. + * + * @see #add(Component,Object) + */ + public Component add(String name, Component comp) + { + addImpl(comp, name, -1); + return comp; + } + + /** + * Adds the specified component to this container at the specified index + * in the component list. + * + * @param comp The component to be added. + * @param index The index in the component list to insert this child + * at, or -1 to add at the end of the list. + * + * @return The same component that was added. + * + * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. + */ + public Component add(Component comp, int index) + { + addImpl(comp, null, index); + return comp; + } + + /** + * Adds the specified component to this container at the end of the + * component list. The layout manager will use the specified constraints + * when laying out this component. + * + * @param comp The component to be added to this container. + * @param constraints The layout constraints for this component. + */ + public void add(Component comp, Object constraints) + { + addImpl(comp, constraints, -1); + } + + /** + * Adds the specified component to this container at the specified index + * in the component list. The layout manager will use the specified + * constraints when layout out this component. + * + * @param comp The component to be added. + * @param constraints The layout constraints for this component. + * @param index The index in the component list to insert this child + * at, or -1 to add at the end of the list. + * + * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. + */ + public void add(Component comp, Object constraints, int index) + { + addImpl(comp, constraints, index); + } + + /** + * This method is called by all the add() methods to perform + * the actual adding of the component. Subclasses who wish to perform + * their own processing when a component is added should override this + * method. Any subclass doing this must call the superclass version of + * this method in order to ensure proper functioning of the container. + * + * @param comp The component to be added. + * @param constraints The layout constraints for this component, or + * null if there are no constraints. + * @param index The index in the component list to insert this child + * at, or -1 to add at the end of the list. + * + * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. + */ + protected void addImpl(Component comp, Object constraints, int index) + { + synchronized (getTreeLock ()) + { + if (index > ncomponents + || (index < 0 && index != -1) + || comp instanceof Window + || (comp instanceof Container + && ((Container) comp).isAncestorOf(this))) + throw new IllegalArgumentException(); + + // Reparent component, and make sure component is instantiated if + // we are. + if (comp.parent != null) + comp.parent.remove(comp); + comp.parent = this; + if (peer != null) + { + if (comp.isLightweight ()) + { + enableEvents (comp.eventMask); + if (!isLightweight ()) + enableEvents (AWTEvent.PAINT_EVENT_MASK); + } + } + + invalidate(); + + if (component == null) + component = new Component[4]; // FIXME, better initial size? + + // This isn't the most efficient implementation. We could do less + // copying when growing the array. It probably doesn't matter. + if (ncomponents >= component.length) + { + int nl = component.length * 2; + Component[] c = new Component[nl]; + System.arraycopy(component, 0, c, 0, ncomponents); + component = c; + } + + if (index == -1) + component[ncomponents++] = comp; + else + { + System.arraycopy(component, index, component, index + 1, + ncomponents - index); + component[index] = comp; + ++ncomponents; + } + + // Notify the layout manager. + if (layoutMgr != null) + { + if (layoutMgr instanceof LayoutManager2) + { + LayoutManager2 lm2 = (LayoutManager2) layoutMgr; + lm2.addLayoutComponent(comp, constraints); + } + else if (constraints instanceof String) + layoutMgr.addLayoutComponent((String) constraints, comp); + else + layoutMgr.addLayoutComponent(null, comp); + } + + if (isShowing ()) + { + // Post event to notify of adding the component. + ContainerEvent ce = new ContainerEvent(this, + ContainerEvent.COMPONENT_ADDED, + comp); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + } + + /** + * Removes the component at the specified index from this container. + * + * @param index The index of the component to remove. + */ + public void remove(int index) + { + synchronized (getTreeLock ()) + { + Component r = component[index]; + + r.removeNotify(); + + System.arraycopy(component, index + 1, component, index, + ncomponents - index - 1); + component[--ncomponents] = null; + + invalidate(); + + if (layoutMgr != null) + layoutMgr.removeLayoutComponent(r); + + r.parent = null; + + if (isShowing ()) + { + // Post event to notify of removing the component. + ContainerEvent ce = new ContainerEvent(this, + ContainerEvent.COMPONENT_REMOVED, + r); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + } + + /** + * Removes the specified component from this container. + * + * @param comp The component to remove from this container. + */ + public void remove(Component comp) + { + synchronized (getTreeLock ()) + { + for (int i = 0; i < ncomponents; ++i) + { + if (component[i] == comp) + { + remove(i); + break; + } + } + } + } + + /** + * Removes all components from this container. + */ + public void removeAll() + { + synchronized (getTreeLock ()) + { + while (ncomponents > 0) + remove(0); + } + } + + /** + * Returns the current layout manager for this container. + * + * @return The layout manager for this container. + */ + public LayoutManager getLayout() + { + return layoutMgr; + } + + /** + * Sets the layout manager for this container to the specified layout + * manager. + * + * @param mgr The new layout manager for this container. + */ + public void setLayout(LayoutManager mgr) + { + layoutMgr = mgr; + invalidate(); + } + + /** + * Layout the components in this container. + */ + public void doLayout() + { + layout (); + } + + /** + * Layout the components in this container. + * + * @deprecated use {@link #doLayout()} instead + */ + public void layout() + { + if (layoutMgr != null) + layoutMgr.layoutContainer (this); + } + + /** + * Invalidates this container to indicate that it (and all parent + * containers) need to be laid out. + */ + public void invalidate() + { + super.invalidate(); + } + + /** + * Re-lays out the components in this container. + */ + public void validate() + { + synchronized (getTreeLock ()) + { + if (! isValid() && peer != null) + { + validateTree(); + } + } + } + + /** + * Recursively invalidates the container tree. + */ + void invalidateTree() + { + for (int i = 0; i < ncomponents; i++) + { + Component comp = component[i]; + comp.invalidate(); + if (comp instanceof Container) + ((Container) comp).invalidateTree(); + } + } + + /** + * Recursively validates the container tree, recomputing any invalid + * layouts. + */ + protected void validateTree() + { + if (valid) + return; + + ContainerPeer cPeer = null; + if (peer != null && ! (peer instanceof LightweightPeer)) + { + cPeer = (ContainerPeer) peer; + cPeer.beginValidate(); + } + + for (int i = 0; i < ncomponents; ++i) + { + Component comp = component[i]; + + if (comp.getPeer () == null) + comp.addNotify(); + } + + doLayout (); + for (int i = 0; i < ncomponents; ++i) + { + Component comp = component[i]; + + if (! comp.isValid()) + { + if (comp instanceof Container) + { + ((Container) comp).validateTree(); + } + else + { + component[i].validate(); + } + } + } + + /* children will call invalidate() when they are layed out. It + is therefore important that valid is not set to true + until after the children have been layed out. */ + valid = true; + + if (cPeer != null) + cPeer.endValidate(); + } + + public void setFont(Font f) + { + super.setFont(f); + // FIXME: Although it might make more sense to invalidate only + // those children whose font == null, Sun invalidates all children. + // So we'll do the same. + invalidateTree(); + } + + /** + * Returns the preferred size of this container. + * + * @return The preferred size of this container. + */ + public Dimension getPreferredSize() + { + return preferredSize (); + } + + /** + * Returns the preferred size of this container. + * + * @return The preferred size of this container. + * + * @deprecated use {@link #getPreferredSize()} instead + */ + public Dimension preferredSize() + { + if (layoutMgr != null) + return layoutMgr.preferredLayoutSize (this); + else + return super.preferredSize (); + } + + /** + * Returns the minimum size of this container. + * + * @return The minimum size of this container. + */ + public Dimension getMinimumSize() + { + return minimumSize (); + } + + /** + * Returns the minimum size of this container. + * + * @return The minimum size of this container. + * + * @deprecated use {@link #getMinimumSize()} instead + */ + public Dimension minimumSize() + { + if (layoutMgr != null) + return layoutMgr.minimumLayoutSize (this); + else + return super.minimumSize (); + } + + /** + * Returns the maximum size of this container. + * + * @return The maximum size of this container. + */ + public Dimension getMaximumSize() + { + if (layoutMgr != null && layoutMgr instanceof LayoutManager2) + { + LayoutManager2 lm2 = (LayoutManager2) layoutMgr; + return lm2.maximumLayoutSize(this); + } + else + return super.getMaximumSize(); + } + + /** + * Returns the preferred alignment along the X axis. This is a value + * between 0 and 1 where 0 represents alignment flush left and + * 1 means alignment flush right, and 0.5 means centered. + * + * @return The preferred alignment along the X axis. + */ + public float getAlignmentX() + { + if (layoutMgr instanceof LayoutManager2) + { + LayoutManager2 lm2 = (LayoutManager2) layoutMgr; + return lm2.getLayoutAlignmentX(this); + } + else + return super.getAlignmentX(); + } + + /** + * Returns the preferred alignment along the Y axis. This is a value + * between 0 and 1 where 0 represents alignment flush top and + * 1 means alignment flush bottom, and 0.5 means centered. + * + * @return The preferred alignment along the Y axis. + */ + public float getAlignmentY() + { + if (layoutMgr instanceof LayoutManager2) + { + LayoutManager2 lm2 = (LayoutManager2) layoutMgr; + return lm2.getLayoutAlignmentY(this); + } + else + return super.getAlignmentY(); + } + + /** + * Paints this container. The implementation of this method in this + * class forwards to any lightweight components in this container. If + * this method is subclassed, this method should still be invoked as + * a superclass method so that lightweight components are properly + * drawn. + * + * @param g The graphics context for this paint job. + */ + public void paint(Graphics g) + { + if (!isShowing()) + return; + // Paint self first. + super.paint(g); + // Visit heavyweights as well, in case they were + // erased when we cleared the background for this container. + visitChildren(g, GfxPaintVisitor.INSTANCE, false); + } + + /** + * Updates this container. The implementation of this method in this + * class forwards to any lightweight components in this container. If + * this method is subclassed, this method should still be invoked as + * a superclass method so that lightweight components are properly + * drawn. + * + * @param g The graphics context for this update. + */ + public void update(Graphics g) + { + super.update(g); + } + + /** + * Prints this container. The implementation of this method in this + * class forwards to any lightweight components in this container. If + * this method is subclassed, this method should still be invoked as + * a superclass method so that lightweight components are properly + * drawn. + * + * @param g The graphics context for this print job. + */ + public void print(Graphics g) + { + super.print(g); + visitChildren(g, GfxPrintVisitor.INSTANCE, true); + } + + /** + * Paints all of the components in this container. + * + * @param g The graphics context for this paint job. + */ + public void paintComponents(Graphics g) + { + super.paint(g); + visitChildren(g, GfxPaintAllVisitor.INSTANCE, true); + } + + /** + * Prints all of the components in this container. + * + * @param g The graphics context for this print job. + */ + public void printComponents(Graphics g) + { + super.paint(g); + visitChildren(g, GfxPrintAllVisitor.INSTANCE, true); + } + + /** + * Adds the specified container listener to this object's list of + * container listeners. + * + * @param listener The listener to add. + */ + public synchronized void addContainerListener(ContainerListener listener) + { + containerListener = AWTEventMulticaster.add(containerListener, listener); + } + + /** + * Removes the specified container listener from this object's list of + * container listeners. + * + * @param listener The listener to remove. + */ + public synchronized void removeContainerListener(ContainerListener listener) + { + containerListener = AWTEventMulticaster.remove(containerListener, listener); + } + + /** + * @since 1.4 + */ + public synchronized ContainerListener[] getContainerListeners() + { + return (ContainerListener[]) + AWTEventMulticaster.getListeners(containerListener, + ContainerListener.class); + } + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this Container. FooListeners are registered using the addFooListener + * method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements @see java.util.EventListener. + * + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + if (listenerType == ContainerListener.class) + return getContainerListeners(); + return super.getListeners(listenerType); + } + + /** + * Processes the specified event. This method calls + * processContainerEvent() if this method is a + * ContainerEvent, otherwise it calls the superclass + * method. + * + * @param e The event to be processed. + */ + protected void processEvent(AWTEvent e) + { + if (e instanceof ContainerEvent) + processContainerEvent((ContainerEvent) e); + else + super.processEvent(e); + } + + /** + * Called when a container event occurs if container events are enabled. + * This method calls any registered listeners. + * + * @param e The event that occurred. + */ + protected void processContainerEvent(ContainerEvent e) + { + if (containerListener == null) + return; + switch (e.id) + { + case ContainerEvent.COMPONENT_ADDED: + containerListener.componentAdded(e); + break; + + case ContainerEvent.COMPONENT_REMOVED: + containerListener.componentRemoved(e); + break; + } + } + + /** + * AWT 1.0 event processor. + * + * @param e The event that occurred. + * + * @deprecated use {@link #dispatchEvent(AWTEvent)} instead + */ + public void deliverEvent(Event e) + { + if (!handleEvent (e)) + { + synchronized (getTreeLock ()) + { + Component parent = getParent (); + + if (parent != null) + parent.deliverEvent (e); + } + } + } + + /** + * Returns the component located at the specified point. This is done + * by checking whether or not a child component claims to contain this + * point. The first child component that does is returned. If no + * child component claims the point, the container itself is returned, + * unless the point does not exist within this container, in which + * case null is returned. + * + * @param x The X coordinate of the point. + * @param y The Y coordinate of the point. + * + * @return The component containing the specified point, or + * null if there is no such point. + */ + public Component getComponentAt(int x, int y) + { + return locate (x, y); + } + + /** + * Returns the component located at the specified point. This is done + * by checking whether or not a child component claims to contain this + * point. The first child component that does is returned. If no + * child component claims the point, the container itself is returned, + * unless the point does not exist within this container, in which + * case null is returned. + * + * @param x The x position of the point to return the component at. + * @param y The y position of the point to return the component at. + * + * @return The component containing the specified point, or null + * if there is no such point. + * + * @deprecated use {@link #getComponentAt(int, int)} instead + */ + public Component locate(int x, int y) + { + synchronized (getTreeLock ()) + { + if (!contains (x, y)) + return null; + for (int i = 0; i < ncomponents; ++i) + { + // Ignore invisible children... + if (!component[i].isVisible ()) + continue; + + int x2 = x - component[i].x; + int y2 = y - component[i].y; + if (component[i].contains (x2, y2)) + return component[i]; + } + return this; + } + } + + /** + * Returns the component located at the specified point. This is done + * by checking whether or not a child component claims to contain this + * point. The first child component that does is returned. If no + * child component claims the point, the container itself is returned, + * unless the point does not exist within this container, in which + * case null is returned. + * + * @param p The point to return the component at. + * @return The component containing the specified point, or null + * if there is no such point. + */ + public Component getComponentAt(Point p) + { + return getComponentAt (p.x, p.y); + } + + public Component findComponentAt(int x, int y) + { + synchronized (getTreeLock ()) + { + if (! contains(x, y)) + return null; + + for (int i = 0; i < ncomponents; ++i) + { + // Ignore invisible children... + if (!component[i].isVisible()) + continue; + + int x2 = x - component[i].x; + int y2 = y - component[i].y; + // We don't do the contains() check right away because + // findComponentAt would redundantly do it first thing. + if (component[i] instanceof Container) + { + Container k = (Container) component[i]; + Component r = k.findComponentAt(x2, y2); + if (r != null) + return r; + } + else if (component[i].contains(x2, y2)) + return component[i]; + } + + return this; + } + } + + public Component findComponentAt(Point p) + { + return findComponentAt(p.x, p.y); + } + + /** + * Called when this container is added to another container to inform it + * to create its peer. Peers for any child components will also be + * created. + */ + public void addNotify() + { + super.addNotify(); + addNotifyContainerChildren(); + } + + /** + * Called when this container is removed from its parent container to + * inform it to destroy its peer. This causes the peers of all child + * component to be destroyed as well. + */ + public void removeNotify() + { + synchronized (getTreeLock ()) + { + for (int i = 0; i < ncomponents; ++i) + component[i].removeNotify(); + super.removeNotify(); + } + } + + /** + * Tests whether or not the specified component is contained within + * this components subtree. + * + * @param comp The component to test. + * + * @return true if this container is an ancestor of the + * specified component, false otherwise. + */ + public boolean isAncestorOf(Component comp) + { + synchronized (getTreeLock ()) + { + while (true) + { + if (comp == null) + return false; + if (comp == this) + return true; + comp = comp.getParent(); + } + } + } + + /** + * Returns a string representing the state of this container for + * debugging purposes. + * + * @return A string representing the state of this container. + */ + protected String paramString() + { + if (layoutMgr == null) + return super.paramString(); + + StringBuffer sb = new StringBuffer(); + sb.append(super.paramString()); + sb.append(",layout="); + sb.append(layoutMgr.getClass().getName()); + return sb.toString(); + } + + /** + * Writes a listing of this container to the specified stream starting + * at the specified indentation point. + * + * @param out The PrintStream to write to. + * @param indent The indentation point. + */ + public void list(PrintStream out, int indent) + { + synchronized (getTreeLock ()) + { + super.list(out, indent); + for (int i = 0; i < ncomponents; ++i) + component[i].list(out, indent + 2); + } + } + + /** + * Writes a listing of this container to the specified stream starting + * at the specified indentation point. + * + * @param out The PrintWriter to write to. + * @param indent The indentation point. + */ + public void list(PrintWriter out, int indent) + { + synchronized (getTreeLock ()) + { + super.list(out, indent); + for (int i = 0; i < ncomponents; ++i) + component[i].list(out, indent + 2); + } + } + + /** + * Sets the focus traversal keys for a given traversal operation for this + * Container. + * + * @exception IllegalArgumentException If id is not one of + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, + * or if keystrokes contains null, or if any Object in keystrokes is not an + * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any + * keystroke already maps to another focus traversal operation for this + * Container. + * + * @since 1.4 + */ + public void setFocusTraversalKeys(int id, Set keystrokes) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + if (keystrokes == null) + { + Container parent = getParent (); + + while (parent != null) + { + if (parent.areFocusTraversalKeysSet (id)) + { + keystrokes = parent.getFocusTraversalKeys (id); + break; + } + parent = parent.getParent (); + } + + if (keystrokes == null) + keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). + getDefaultFocusTraversalKeys (id); + } + + Set sa; + Set sb; + Set sc; + String name; + switch (id) + { + case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + name = "forwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + name = "backwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + name = "upCycleFocusTraversalKeys"; + break; + case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + name = "downCycleFocusTraversalKeys"; + break; + default: + throw new IllegalArgumentException (); + } + + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + + while (--i >= 0) + { + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) || sc.contains (o) + || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) + throw new IllegalArgumentException (); + } + + if (focusTraversalKeys == null) + focusTraversalKeys = new Set[3]; + + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (name, focusTraversalKeys[id], keystrokes); + + focusTraversalKeys[id] = keystrokes; + } + + /** + * Returns the Set of focus traversal keys for a given traversal operation for + * this Container. + * + * @exception IllegalArgumentException If id is not one of + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. + * + * @since 1.4 + */ + public Set getFocusTraversalKeys (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + Set s = null; + + if (focusTraversalKeys != null) + s = focusTraversalKeys[id]; + + if (s == null && parent != null) + s = parent.getFocusTraversalKeys (id); + + return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() + .getDefaultFocusTraversalKeys(id)) : s; + } + + /** + * Returns whether the Set of focus traversal keys for the given focus + * traversal operation has been explicitly defined for this Container. + * If this method returns false, this Container is inheriting the Set from + * an ancestor, or from the current KeyboardFocusManager. + * + * @exception IllegalArgumentException If id is not one of + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. + * + * @since 1.4 + */ + public boolean areFocusTraversalKeysSet (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + return focusTraversalKeys != null && focusTraversalKeys[id] != null; + } + + /** + * Check whether the given Container is the focus cycle root of this + * Container's focus traversal cycle. If this Container is a focus + * cycle root itself, then it will be in two different focus cycles + * -- it's own, and that of its ancestor focus cycle root's. In + * that case, if c is either of those containers, this + * method will return true. + * + * @param c the candidate Container + * + * @return true if c is the focus cycle root of the focus traversal + * cycle to which this Container belongs, false otherwise + * + * @since 1.4 + */ + public boolean isFocusCycleRoot (Container c) + { + if (this == c + && isFocusCycleRoot ()) + return true; + + Container ancestor = getFocusCycleRootAncestor (); + + if (c == ancestor) + return true; + + return false; + } + + /** + * If this Container is a focus cycle root, set the focus traversal + * policy that determines the focus traversal order for its + * children. If non-null, this policy will be inherited by all + * inferior focus cycle roots. If policy is null, this + * Container will inherit its policy from the closest ancestor focus + * cycle root that's had its policy set. + * + * @param policy the new focus traversal policy for this Container or null + * + * @since 1.4 + */ + public void setFocusTraversalPolicy (FocusTraversalPolicy policy) + { + focusTraversalPolicy = policy; + } + + /** + * Return the focus traversal policy that determines the focus + * traversal order for this Container's children. This method + * returns null if this Container is not a focus cycle root. If the + * focus traversal policy has not been set explicitly, then this + * method will return an ancestor focus cycle root's policy instead. + * + * @return this Container's focus traversal policy or null + * + * @since 1.4 + */ + public FocusTraversalPolicy getFocusTraversalPolicy () + { + if (!isFocusCycleRoot ()) + return null; + + if (focusTraversalPolicy == null) + { + Container ancestor = getFocusCycleRootAncestor (); + + if (ancestor != this) + return ancestor.getFocusTraversalPolicy (); + else + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + return manager.getDefaultFocusTraversalPolicy (); + } + } + else + return focusTraversalPolicy; + } + + /** + * Check whether this Container's focus traversal policy has been + * explicitly set. If it has not, then this Container will inherit + * its focus traversal policy from one of its ancestor focus cycle + * roots. + * + * @return true if focus traversal policy is set, false otherwise + */ + public boolean isFocusTraversalPolicySet () + { + return focusTraversalPolicy == null; + } + + /** + * Set whether or not this Container is the root of a focus + * traversal cycle. This Container's focus traversal policy + * determines the order of focus traversal. Some policies prevent + * the focus from being transferred between two traversal cycles + * until an up or down traversal operation is performed. In that + * case, normal traversal (not up or down) is limited to this + * Container and all of this Container's descendents that are not + * descendents of inferior focus cycle roots. In the default case + * however, ContainerOrderFocusTraversalPolicy is in effect, and it + * supports implicit down-cycle traversal operations. + * + * @param focusCycleRoot true if this is a focus cycle root, false otherwise + * + * @since 1.4 + */ + public void setFocusCycleRoot (boolean focusCycleRoot) + { + this.focusCycleRoot = focusCycleRoot; + } + + /** + * Check whether this Container is a focus cycle root. + * + * @return true if this is a focus cycle root, false otherwise + * + * @since 1.4 + */ + public boolean isFocusCycleRoot () + { + return focusCycleRoot; + } + + /** + * Transfer focus down one focus traversal cycle. If this Container + * is a focus cycle root, then its default component becomes the + * focus owner, and this Container becomes the current focus cycle + * root. No traversal will occur if this Container is not a focus + * cycle root. + * + * @since 1.4 + */ + public void transferFocusDownCycle () + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + manager.downFocusCycle (this); + } + + /** + * Sets the ComponentOrientation property of this container and all components + * contained within it. + * + * @exception NullPointerException If orientation is null + * + * @since 1.4 + */ + public void applyComponentOrientation (ComponentOrientation orientation) + { + if (orientation == null) + throw new NullPointerException (); + } + + public void addPropertyChangeListener (PropertyChangeListener listener) + { + if (listener == null) + return; + + if (changeSupport == null) + changeSupport = new PropertyChangeSupport (this); + + changeSupport.addPropertyChangeListener (listener); + } + + public void addPropertyChangeListener (String name, + PropertyChangeListener listener) + { + if (listener == null) + return; + + if (changeSupport == null) + changeSupport = new PropertyChangeSupport (this); + + changeSupport.addPropertyChangeListener (name, listener); + } + + // Hidden helper methods. + + /** + * Perform a graphics operation on the children of this container. + * For each applicable child, the visitChild() method will be called + * to perform the graphics operation. + * + * @param gfx The graphics object that will be used to derive new + * graphics objects for the children. + * + * @param visitor Object encapsulating the graphics operation that + * should be performed. + * + * @param lightweightOnly If true, only lightweight components will + * be visited. + */ + private void visitChildren(Graphics gfx, GfxVisitor visitor, + boolean lightweightOnly) + { + synchronized (getTreeLock ()) + { + for (int i = ncomponents - 1; i >= 0; --i) + { + Component comp = component[i]; + // If we're visiting heavyweights as well, + // don't recurse into Containers here. This avoids + // painting the same nested child multiple times. + boolean applicable = comp.isVisible() + && (comp.isLightweight() + || !lightweightOnly && ! (comp instanceof Container)); + + if (applicable) + visitChild(gfx, visitor, comp); + } + } + } + + /** + * Perform a graphics operation on a child. A translated and clipped + * graphics object will be created, and the visit() method of the + * visitor will be called to perform the operation. + * + * @param gfx The graphics object that will be used to derive new + * graphics objects for the child. + * + * @param visitor Object encapsulating the graphics operation that + * should be performed. + * + * @param comp The child component that should be visited. + */ + private void visitChild(Graphics gfx, GfxVisitor visitor, + Component comp) + { + Rectangle bounds = comp.getBounds(); + Rectangle oldClip = gfx.getClipBounds(); + if (oldClip == null) + oldClip = bounds; + + Rectangle clip = oldClip.intersection(bounds); + + if (clip.isEmpty()) return; + + boolean clipped = false; + boolean translated = false; + try + { + gfx.setClip(clip.x, clip.y, clip.width, clip.height); + clipped = true; + gfx.translate(bounds.x, bounds.y); + translated = true; + visitor.visit(comp, gfx); + } + finally + { + if (translated) + gfx.translate (-bounds.x, -bounds.y); + if (clipped) + gfx.setClip (oldClip.x, oldClip.y, oldClip.width, oldClip.height); + } + } + + void dispatchEventImpl(AWTEvent e) + { + // Give lightweight dispatcher a chance to handle it. + if (eventTypeEnabled (e.id) + && dispatcher != null + && dispatcher.handleEvent (e)) + return; + + if ((e.id <= ContainerEvent.CONTAINER_LAST + && e.id >= ContainerEvent.CONTAINER_FIRST) + && (containerListener != null + || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); + } + + // This is used to implement Component.transferFocus. + Component findNextFocusComponent(Component child) + { + synchronized (getTreeLock ()) + { + int start, end; + if (child != null) + { + for (start = 0; start < ncomponents; ++start) + { + if (component[start] == child) + break; + } + end = start; + // This special case lets us be sure to terminate. + if (end == 0) + end = ncomponents; + ++start; + } + else + { + start = 0; + end = ncomponents; + } + + for (int j = start; j != end; ++j) + { + if (j >= ncomponents) + { + // The JCL says that we should wrap here. However, that + // seems wrong. To me it seems that focus order should be + // global within in given window. So instead if we reach + // the end we try to look in our parent, if we have one. + if (parent != null) + return parent.findNextFocusComponent(this); + j -= ncomponents; + } + if (component[j] instanceof Container) + { + Component c = component[j]; + c = c.findNextFocusComponent(null); + if (c != null) + return c; + } + else if (component[j].isFocusTraversable()) + return component[j]; + } + + return null; + } + } + + private void addNotifyContainerChildren() + { + synchronized (getTreeLock ()) + { + for (int i = ncomponents; --i >= 0; ) + { + component[i].addNotify(); + if (component[i].isLightweight ()) + { + + // If we're not lightweight, and we just got a lightweight + // child, we need a lightweight dispatcher to feed it events. + if (! this.isLightweight()) + { + if (dispatcher == null) + dispatcher = new LightweightDispatcher (this); + } + + + enableEvents(component[i].eventMask); + if (peer != null && !isLightweight ()) + enableEvents (AWTEvent.PAINT_EVENT_MASK); + } + } + } + } + + /** + * Deserialize this Container: + *

    + *
  1. Read from the stream the default serializable fields.
  2. + *
  3. Read a list of serializable ContainerListeners as optional + * data. If the list is null, no listeners will be registered.
  4. + *
  5. Read this Container's FocusTraversalPolicy as optional data. + * If this is null, then this Container will use a + * DefaultFocusTraversalPolicy.
  6. + *
+ * + * @param s the stream to read from + * @throws ClassNotFoundException if deserialization fails + * @throws IOException if the stream fails + */ + private void readObject (ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject (); + String key = (String) s.readObject (); + while (key != null) + { + Object object = s.readObject (); + if ("containerL".equals (key)) + addContainerListener((ContainerListener) object); + // FIXME: under what key is the focus traversal policy stored? + else if ("focusTraversalPolicy".equals (key)) + setFocusTraversalPolicy ((FocusTraversalPolicy) object); + + key = (String) s.readObject(); + } + } + + /** + * Serialize this Container: + *
    + *
  1. Write to the stream the default serializable fields.
  2. + *
  3. Write the list of serializable ContainerListeners as optional + * data.
  4. + *
  5. Write this Container's FocusTraversalPolicy as optional data.
  6. + *
+ * + * @param s the stream to write to + * @throws IOException if the stream fails + */ + private void writeObject (ObjectOutputStream s) throws IOException + { + s.defaultWriteObject (); + AWTEventMulticaster.save (s, "containerL", containerListener); + if (focusTraversalPolicy instanceof Serializable) + s.writeObject (focusTraversalPolicy); + else + s.writeObject (null); + } + + // Nested classes. + + /* The following classes are used in concert with the + visitChildren() method to implement all the graphics operations + that requires traversal of the containment hierarchy. */ + + abstract static class GfxVisitor + { + public abstract void visit(Component c, Graphics gfx); + } + + static class GfxPaintVisitor extends GfxVisitor + { + public static final GfxVisitor INSTANCE = new GfxPaintVisitor(); + + public void visit(Component c, Graphics gfx) + { + c.paint(gfx); + } + } + + static class GfxPrintVisitor extends GfxVisitor + { + public static final GfxVisitor INSTANCE = new GfxPrintVisitor(); + + public void visit(Component c, Graphics gfx) + { + c.print(gfx); + } + } + + static class GfxPaintAllVisitor extends GfxVisitor + { + public static final GfxVisitor INSTANCE = new GfxPaintAllVisitor(); + + public void visit(Component c, Graphics gfx) + { + c.paintAll(gfx); + } + } + + static class GfxPrintAllVisitor extends GfxVisitor + { + public static final GfxVisitor INSTANCE = new GfxPrintAllVisitor(); + + public void visit(Component c, Graphics gfx) + { + c.printAll(gfx); + } + } + + /** + * This class provides accessibility support for subclasses of container. + * + * @author Eric Blake (ebb9@email.byu.edu) + * + * @since 1.3 + */ + protected class AccessibleAWTContainer extends AccessibleAWTComponent + { + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 5081320404842566097L; + + /** + * The handler to fire PropertyChange when children are added or removed. + * + * @serial the handler for property changes + */ + protected ContainerListener accessibleContainerHandler + = new AccessibleContainerHandler(); + + /** + * The default constructor. + */ + protected AccessibleAWTContainer() + { + Container.this.addContainerListener(accessibleContainerHandler); + } + + /** + * Return the number of accessible children of the containing accessible + * object (at most the total number of its children). + * + * @return the number of accessible children + */ + public int getAccessibleChildrenCount() + { + synchronized (getTreeLock ()) + { + int count = 0; + int i = component == null ? 0 : component.length; + while (--i >= 0) + if (component[i] instanceof Accessible) + count++; + return count; + } + } + + /** + * Return the nth accessible child of the containing accessible object. + * + * @param i the child to grab, zero-based + * @return the accessible child, or null + */ + public Accessible getAccessibleChild(int i) + { + synchronized (getTreeLock ()) + { + if (component == null) + return null; + int index = -1; + while (i >= 0 && ++index < component.length) + if (component[index] instanceof Accessible) + i--; + if (i < 0) + return (Accessible) component[index]; + return null; + } + } + + /** + * Return the accessible child located at point (in the parent's + * coordinates), if one exists. + * + * @param p the point to look at + * + * @return an accessible object at that point, or null + * + * @throws NullPointerException if p is null + */ + public Accessible getAccessibleAt(Point p) + { + Component c = getComponentAt(p.x, p.y); + return c != Container.this && c instanceof Accessible ? (Accessible) c + : null; + } + + /** + * This class fires a PropertyChange listener, if registered, + * when children are added or removed from the enclosing accessible object. + * + * @author Eric Blake (ebb9@email.byu.edu) + * + * @since 1.3 + */ + protected class AccessibleContainerHandler implements ContainerListener + { + /** + * Default constructor. + */ + protected AccessibleContainerHandler() + { + } + + /** + * Fired when a component is added; forwards to the PropertyChange + * listener. + * + * @param e the container event for adding + */ + public void componentAdded(ContainerEvent e) + { + AccessibleAWTContainer.this.firePropertyChange + (ACCESSIBLE_CHILD_PROPERTY, null, e.getChild()); + } + + /** + * Fired when a component is removed; forwards to the PropertyChange + * listener. + * + * @param e the container event for removing + */ + public void componentRemoved(ContainerEvent e) + { + AccessibleAWTContainer.this.firePropertyChange + (ACCESSIBLE_CHILD_PROPERTY, e.getChild(), null); + } + } // class AccessibleContainerHandler + } // class AccessibleAWTContainer +} // class Container + +/** + * There is a helper class implied from stack traces called + * LightweightDispatcher, but since it is not part of the public API, + * rather than mimic it exactly we write something which does "roughly + * the same thing". + */ + +class LightweightDispatcher implements Serializable +{ + private static final long serialVersionUID = 5184291520170872969L; + private Container nativeContainer; + private Cursor nativeCursor; + private long eventMask; + + private transient Component mouseEventTarget; + private transient Component pressedComponent; + private transient Component lastComponentEntered; + private transient Component tempComponent; + private transient int pressCount; + + LightweightDispatcher(Container c) + { + nativeContainer = c; + } + + void acquireComponentForMouseEvent(MouseEvent me) + { + int x = me.getX (); + int y = me.getY (); + + // Find the candidate which should receive this event. + Component parent = nativeContainer; + Component candidate = null; + Point p = me.getPoint(); + while (candidate == null && parent != null) + { + candidate = + SwingUtilities.getDeepestComponentAt(parent, p.x, p.y); + if (candidate == null || (candidate.eventMask & me.getID()) == 0) + { + candidate = null; + p = SwingUtilities.convertPoint(parent, p.x, p.y, parent.parent); + parent = parent.parent; + } + } + + // If the only candidate we found was the native container itself, + // don't dispatch any event at all. We only care about the lightweight + // children here. + if (candidate == nativeContainer) + candidate = null; + + // If our candidate is new, inform the old target we're leaving. + if (lastComponentEntered != null + && lastComponentEntered.isShowing() + && lastComponentEntered != candidate) + { + // Old candidate could have been removed from + // the nativeContainer so we check first. + if (SwingUtilities.isDescendingFrom(lastComponentEntered, nativeContainer)) + { + Point tp = + SwingUtilities.convertPoint(nativeContainer, + x, y, lastComponentEntered); + MouseEvent exited = new MouseEvent (lastComponentEntered, + MouseEvent.MOUSE_EXITED, + me.getWhen (), + me.getModifiersEx (), + tp.x, tp.y, + me.getClickCount (), + me.isPopupTrigger (), + me.getButton ()); + tempComponent = lastComponentEntered; + lastComponentEntered = null; + tempComponent.dispatchEvent(exited); + } + lastComponentEntered = null; + } + // If we have a candidate, maybe enter it. + if (candidate != null) + { + mouseEventTarget = candidate; + if (candidate.isLightweight() + && candidate.isShowing() + && candidate != nativeContainer + && candidate != lastComponentEntered) + { + lastComponentEntered = mouseEventTarget; + Point cp = SwingUtilities.convertPoint(nativeContainer, + x, y, lastComponentEntered); + MouseEvent entered = new MouseEvent (lastComponentEntered, + MouseEvent.MOUSE_ENTERED, + me.getWhen (), + me.getModifiersEx (), + cp.x, cp.y, + me.getClickCount (), + me.isPopupTrigger (), + me.getButton ()); + lastComponentEntered.dispatchEvent (entered); + } + } + + if (me.getID() == MouseEvent.MOUSE_RELEASED + || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0 + || me.getID() == MouseEvent.MOUSE_DRAGGED) + // If any of the following events occur while a button is held down, + // they should be dispatched to the same component to which the + // original MOUSE_PRESSED event was dispatched: + // - MOUSE_RELEASED + // - MOUSE_PRESSED: another button pressed while the first is held down + // - MOUSE_DRAGGED + if (SwingUtilities.isDescendingFrom(pressedComponent, nativeContainer)) + mouseEventTarget = pressedComponent; + else if (me.getID() == MouseEvent.MOUSE_CLICKED) + { + // Don't dispatch CLICKED events whose target is not the same as the + // target for the original PRESSED event. + if (candidate != pressedComponent) + mouseEventTarget = null; + else if (pressCount == 0) + pressedComponent = null; + } + } + + boolean handleEvent(AWTEvent e) + { + if (e instanceof MouseEvent) + { + MouseEvent me = (MouseEvent) e; + + acquireComponentForMouseEvent(me); + + // Avoid dispatching ENTERED and EXITED events twice. + if (mouseEventTarget != null + && mouseEventTarget.isShowing() + && e.getID() != MouseEvent.MOUSE_ENTERED + && e.getID() != MouseEvent.MOUSE_EXITED) + { + MouseEvent newEvt = + SwingUtilities.convertMouseEvent(nativeContainer, me, + mouseEventTarget); + mouseEventTarget.dispatchEvent(newEvt); + + switch (e.getID()) + { + case MouseEvent.MOUSE_PRESSED: + if (pressCount++ == 0) + pressedComponent = mouseEventTarget; + break; + + case MouseEvent.MOUSE_RELEASED: + // Clear our memory of the original PRESSED event, only if + // we're not expecting a CLICKED event after this. If + // there is a CLICKED event after this, it will do clean up. + if (--pressCount == 0 + && mouseEventTarget != pressedComponent) + pressedComponent = null; + break; + } + if (newEvt.isConsumed()) + e.consume(); + } + } + + return e.isConsumed(); + } + +} // class LightweightDispatcher diff --git a/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java b/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java new file mode 100644 index 0000000..152482c --- /dev/null +++ b/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java @@ -0,0 +1,413 @@ +/* ContainerOrderFocusTraversalPolicy.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 java.awt; + +import java.io.Serializable; + +/** + * ContainerOrderFocusTraversalPolicy defines a focus traversal order + * based on the order in which Components were packed in a Container. + * This policy performs a pre-order traversal of the Component + * hierarchy starting from a given focus cycle root. Portions of the + * hierarchy that are not visible and displayable are skipped. + * + * By default, this policy transfers focus down-cycle implicitly. + * That is, if a forward traversal is requested on a focus cycle root + * and the focus cycle root has focusable children, the focus will + * automatically be transfered down to the lower focus cycle. + * + * The default implementation of accept accepts only Components that + * are visible, displayable, enabled and focusable. Derived classes + * can override these acceptance criteria by overriding accept. + * + * @author Michael Koch + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + * @since 1.4 + */ +public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy + implements Serializable +{ + /** + * Compatible to JDK 1.4+ + */ + static final long serialVersionUID = 486933713763926351L; + + /** + * True if implicit down cycling is enabled. + */ + private boolean implicitDownCycleTraversal = true; + + /** + * Creates the ContainerOrderFocusTraversalPolicy object. + */ + public ContainerOrderFocusTraversalPolicy () + { + // Nothing to do here + } + + /** + * Returns the Component that should receive the focus after current. + * root must be a focus cycle root of current. + * + * @param root a focus cycle root of current + * @param current a (possibly indirect) child of root, or root itself + * + * @return the next Component in the focus traversal order for root, + * or null if no acceptable Component exists. + * + * @exception IllegalArgumentException If root is not a focus cycle + * root of current, or if either root or current is null. + */ + public Component getComponentAfter (Container root, Component current) + { + if (root == null) + throw new IllegalArgumentException ("focus cycle root is null"); + if (current == null) + throw new IllegalArgumentException ("current component is null"); + + if (!root.isFocusCycleRoot ()) + throw new IllegalArgumentException ("root is not a focus cycle root"); + + Container ancestor = current.getFocusCycleRootAncestor (); + Container prevAncestor = ancestor; + while (ancestor != root) + { + ancestor = current.getFocusCycleRootAncestor (); + if (ancestor == prevAncestor) + { + // We've reached the top focus cycle root ancestor. Check + // if it is root. + if (ancestor != root) + throw new IllegalArgumentException ("the given container is not" + + " a focus cycle root of the" + + " current component"); + else + break; + } + prevAncestor = ancestor; + } + + // FIXME: is this the right thing to do here? It moves the context + // for traversal up one focus traversal cycle. We'll need a test + // for this. + if ((Component) root == current) + root = current.getFocusCycleRootAncestor (); + + // Check if we've reached the top of the component hierarchy. If + // so then we want to loop around to the first component in the + // focus traversal cycle. + if (current instanceof Window) + return getFirstComponent ((Container) current); + + Container parent = current.getParent (); + + synchronized (parent.getTreeLock ()) + { + Component[] components = parent.getComponents (); + int componentIndex = 0; + int numComponents = parent.getComponentCount (); + + // Find component's index. + for (int i = 0; i < numComponents; i++) + { + if (components[i] == current) + componentIndex = i; + } + + // Search forward for the next acceptable component. + for (int i = componentIndex + 1; i < numComponents; i++) + { + if (accept (components[i])) + return components[i]; + + if (components[i] instanceof Container) + { + Component result = getFirstComponent ((Container) components[i]); + + if (result != null + && implicitDownCycleTraversal) + return result; + } + } + + // No focusable components after current in its Container. So go + // to the next Component after current's Container (parent). + Component result = getComponentAfter (root, parent); + + return result; + } + } + + /** + * Returns the Component that should receive the focus before + * current. root must be a focus cycle + * root of current. + * + * @param root a focus cycle root of current + * @param current a (possibly indirect) child of root, or root itself + * + * @return the previous Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * + * @exception IllegalArgumentException If root is not a focus cycle + * root of current, or if either root or current is null. + */ + public Component getComponentBefore (Container root, Component current) + { + if (root == null) + throw new IllegalArgumentException ("focus cycle root is null"); + if (current == null) + throw new IllegalArgumentException ("current component is null"); + + if (!root.isFocusCycleRoot ()) + throw new IllegalArgumentException ("root is not a focus cycle root"); + + Container ancestor = current.getFocusCycleRootAncestor (); + Container prevAncestor = ancestor; + while (ancestor != root) + { + ancestor = current.getFocusCycleRootAncestor (); + if (ancestor == prevAncestor) + { + // We've reached the top focus cycle root ancestor. Check + // if it is root. + if (ancestor != root) + throw new IllegalArgumentException ("the given container is not" + + " a focus cycle root of the" + + " current component"); + else + break; + } + prevAncestor = ancestor; + } + + // FIXME: is this the right thing to do here? It moves the context + // for traversal up one focus traversal cycle. We'll need a test + // for this. + if ((Component) root == current) + root = current.getFocusCycleRootAncestor (); + + // Check if we've reached the top of the component hierarchy. If + // so then we want to loop around to the last component in the + // focus traversal cycle. + if (current instanceof Window) + return getLastComponent ((Container) current); + + Container parent = current.getParent (); + + synchronized (parent.getTreeLock ()) + { + Component[] components = parent.getComponents (); + int componentIndex = 0; + int numComponents = parent.getComponentCount (); + + // Find component's index. + for (int i = 0; i < numComponents; i++) + { + if (components[i] == current) + componentIndex = i; + } + + // Search backward for the next acceptable component. + for (int i = componentIndex - 1; i >= 0; i--) + { + if (accept (components[i])) + return components[i]; + + if (components[i] instanceof Container) + { + Component result = getLastComponent ((Container) components[i]); + + if (result != null) + return result; + } + } + + // No focusable components before current in its Container. So go + // to the previous Component before current's Container (parent). + Component result = getComponentBefore (root, parent); + + return result; + } + } + + /** + * Returns the first Component of root that should receive the focus. + * + * @param root a focus cycle root + * + * @return the first Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * + * @exception IllegalArgumentException If root is null. + */ + public Component getFirstComponent(Container root) + { + if (root == null) + throw new IllegalArgumentException (); + + if (!root.isVisible () + || !root.isDisplayable ()) + return null; + + if (accept (root)) + return root; + + Component[] componentArray = root.getComponents (); + + for (int i = 0; i < componentArray.length; i++) + { + Component component = componentArray [i]; + + if (accept (component)) + return component; + + if (component instanceof Container) + { + Component result = getFirstComponent ((Container) component); + + if (result != null) + return result; + } + } + + return null; + } + + /** + * Returns the last Component of root that should receive the focus. + * + * @param root a focus cycle root + * + * @return the last Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * + * @exception IllegalArgumentException If root is null. + */ + public Component getLastComponent (Container root) + { + if (root == null) + throw new IllegalArgumentException (); + + if (!root.isVisible () + || !root.isDisplayable ()) + return null; + + if (accept (root)) + return root; + + Component[] componentArray = root.getComponents (); + + for (int i = componentArray.length - 1; i >= 0; i--) + { + Component component = componentArray [i]; + + if (accept (component)) + return component; + + if (component instanceof Container) + { + Component result = getLastComponent ((Container) component); + + if (result != null) + return result; + } + } + + return null; + } + + /** + * Returns the default Component of root that should receive the focus. + * + * @param root a focus cycle root + * + * @return the default Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * + * @exception IllegalArgumentException If root is null. + */ + public Component getDefaultComponent (Container root) + { + return getFirstComponent (root); + } + + /** + * Set whether or not implicit down cycling is enabled. If it is, + * then initiating a forward focus traversal operation onto a focus + * cycle root, the focus will be implicitly transferred into the + * root container's focus cycle. + * + * @param value the setting for implicit down cycling + */ + public void setImplicitDownCycleTraversal (boolean value) + { + implicitDownCycleTraversal = value; + } + + /** + * Check whether or not implicit down cycling is enabled. If it is, + * then initiating a forward focus traversal operation onto a focus + * cycle root, the focus will be implicitly transferred into the + * root container's focus cycle. + * + * @return true if the focus will be transferred down-cycle + * implicitly + */ + public boolean getImplicitDownCycleTraversal () + { + return implicitDownCycleTraversal; + } + + /** + * Check whether the given Component is an acceptable target for the + * keyboard input focus. + * + * @param current the Component to check + * + * @return true if current is acceptable, false otherwise + */ + protected boolean accept (Component current) + { + return (current.visible + && current.isDisplayable () + && current.enabled + && current.focusable); + } +} diff --git a/libjava/classpath/java/awt/Cursor.java b/libjava/classpath/java/awt/Cursor.java new file mode 100644 index 0000000..48a63f0 --- /dev/null +++ b/libjava/classpath/java/awt/Cursor.java @@ -0,0 +1,224 @@ +/* Copyright (C) 1999, 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 java.awt; + +/** + * This class represents various predefined cursor types. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Cursor implements java.io.Serializable +{ + static final long serialVersionUID = 8028237497568985504L; + + /** + * Constant for the system default cursor type + */ + public static final int DEFAULT_CURSOR = 0; + + /** + * Constant for a cross-hair cursor. + */ + public static final int CROSSHAIR_CURSOR = 1; + + /** + * Constant for a cursor over a text field. + */ + public static final int TEXT_CURSOR = 2; + + /** + * Constant for a cursor to display while waiting for an action to complete. + */ + public static final int WAIT_CURSOR = 3; + + /** + * Cursor used over SW corner of window decorations. + */ + public static final int SW_RESIZE_CURSOR = 4; + + /** + * Cursor used over SE corner of window decorations. + */ + public static final int SE_RESIZE_CURSOR = 5; + + /** + * Cursor used over NW corner of window decorations. + */ + public static final int NW_RESIZE_CURSOR = 6; + + /** + * Cursor used over NE corner of window decorations. + */ + public static final int NE_RESIZE_CURSOR = 7; + + /** + * Cursor used over N edge of window decorations. + */ + public static final int N_RESIZE_CURSOR = 8; + + /** + * Cursor used over S edge of window decorations. + */ + public static final int S_RESIZE_CURSOR = 9; + + /** + * Cursor used over W edge of window decorations. + */ + public static final int W_RESIZE_CURSOR = 10; + + /** + * Cursor used over E edge of window decorations. + */ + public static final int E_RESIZE_CURSOR = 11; + + /** + * Constant for a hand cursor. + */ + public static final int HAND_CURSOR = 12; + + /** + * Constant for a cursor used during window move operations. + */ + public static final int MOVE_CURSOR = 13; + + public static final int CUSTOM_CURSOR = 0xFFFFFFFF; + + private static final int PREDEFINED_COUNT = 14; + + protected static Cursor[] predefined = new Cursor[PREDEFINED_COUNT]; + protected String name; + + /** + * @serial The numeric id of this cursor. + */ + int type; + + /** + * Initializes a new instance of Cursor with the specified + * type. + * + * @param type The cursor type. + * + * @exception IllegalArgumentException If the specified cursor type is invalid + */ + public Cursor(int type) + { + if (type < 0 || type >= PREDEFINED_COUNT) + throw new IllegalArgumentException ("invalid cursor " + type); + + this.type = type; + // FIXME: lookup and set name? + } + + /** This constructor is used internally only. + * Application code should call Toolkit.createCustomCursor(). + */ + protected Cursor(String name) + { + this.name = name; + this.type = CUSTOM_CURSOR; + } + + /** + * Returns an instance of Cursor for one of the specified + * predetermined types. + * + * @param type The type contant from this class. + * + * @return The requested predefined cursor. + * + * @exception IllegalArgumentException If the constant is not one of the + * predefined cursor type constants from this class. + */ + public static Cursor getPredefinedCursor(int type) + { + if (type < 0 || type >= PREDEFINED_COUNT) + throw new IllegalArgumentException ("invalid cursor " + type); + if (predefined[type] == null) + predefined[type] = new Cursor(type); + return predefined[type]; + } + + /** + * Retrieves the system specific custom Cursor named Cursor names are, + * for example: "Invalid.16x16". + * + * @exception AWTException + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public static Cursor getSystemCustomCursor(String name) + throws AWTException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); + + // FIXME + return null; + } + + /** + * Returns an instance of the system default cursor type. + * + * @return The system default cursor. + */ + public static Cursor getDefaultCursor() + { + return getPredefinedCursor(DEFAULT_CURSOR); + } + + /** + * Returns the numeric type identifier for this cursor. + * + * @return The cursor id. + */ + public int getType() + { + return type; + } + + public String getName() + { + return name; + } + + public String toString() + { + return (this.getClass() + "[" + getName() + "]"); + } +} diff --git a/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java b/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java new file mode 100644 index 0000000..46b56d3 --- /dev/null +++ b/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java @@ -0,0 +1,109 @@ +/* DefaultFocusTraversalPolicy.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 java.awt; + +/** + * DefaultFocusTraversalPolicy is the default focus traversal policy + * used by Containers. + * + * This policy sharpens ContainerOrderFocusTraversalPolicy's + * acceptance criteria, to reject those Components that have + * unfocusable peers. Despite this extra strictness, this policy will + * always accept a Component that has explicitly been set focusable by + * any means. + * + * This AWT implementation assumes that the peers of the following + * Components are not focusable: Canvas, Panel, Label, ScrollPane, + * Scrollbar, Window, and any lightweight Component. + * + * A Component's focusability is independent of the focusability of + * its peer. + * + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + * @since 1.4 + */ +public class DefaultFocusTraversalPolicy + extends ContainerOrderFocusTraversalPolicy +{ + /** + * Construct a default focus traversal policy. + */ + public DefaultFocusTraversalPolicy () + { + } + + /** + * Check whether a given Component would be acceptable as a focus + * owner. The Component must be displayable, visible and enabled to + * be acceptable. If the Component's focus traversability has been + * overridden, by overriding Component.isFocusTraversable or + * Component.isFocusable, or by calling Component.setFocusable, then + * the Component will be accepted if it is focusable. If the + * Component uses the default focus traversable behaviour, then + * comp will always be rejected if it is a Canvas, + * Panel, Label, ScrollPane, Scrollbar, Window or lightweight + * Component. + * + * @param comp the Component to check + * + * @return true if the Component is an acceptable target for + * keyboard input focus, false otherwise + */ + protected boolean accept (Component comp) + { + if (comp.visible + && comp.isDisplayable () + && comp.enabled) + { + if (comp.isFocusTraversableOverridden != 0 + && (comp.isFocusTraversable () || comp.isFocusable())) + return true; + + if (!(comp instanceof Canvas + || comp instanceof Panel + || comp instanceof Label + || comp instanceof ScrollPane + || comp instanceof Scrollbar + || comp instanceof Window + || comp.isLightweight ())) + return true; + } + return false; + } +} diff --git a/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java b/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java new file mode 100644 index 0000000..f53cc5e --- /dev/null +++ b/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java @@ -0,0 +1,536 @@ +/* DefaultKeyboardFocusManager.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +// FIXME: finish documentation +public class DefaultKeyboardFocusManager extends KeyboardFocusManager +{ + /** + * This class models a request to delay the dispatch of events that + * arrive after a certain time, until a certain component becomes + * the focus owner. + */ + private class EventDelayRequest implements Comparable + { + /** A {@link java.util.List} of {@link java.awt.event.KeyEvent}s + that are being delayed, pending this request's {@link + Component} receiving the keyboard focus. */ + private LinkedList enqueuedKeyEvents = new LinkedList (); + + /** An event timestamp. All events that arrive after this time + should be queued in the {@link #enqueuedKeyEvents} {@link + java.util.List}. */ + public long timestamp; + /** When this {@link Component} becomes focused, all events + between this EventDelayRequest and the next one in will be + dispatched from {@link #enqueuedKeyEvents}. */ + public Component focusedComp; + + /** + * Construct a new EventDelayRequest. + * + * @param timestamp events that arrive after this time will be + * delayed + * @param focusedComp the Component that needs to receive focus + * before events are dispatched + */ + public EventDelayRequest (long timestamp, Component focusedComp) + { + this.timestamp = timestamp; + this.focusedComp = focusedComp; + } + + public int compareTo (Object o) + { + if (!(o instanceof EventDelayRequest)) + throw new ClassCastException (); + + EventDelayRequest request = (EventDelayRequest) o; + + if (request.timestamp < timestamp) + return -1; + else if (request.timestamp == timestamp) + return 0; + else + return 1; + } + + public boolean equals (Object o) + { + if (!(o instanceof EventDelayRequest) || o == null) + return false; + + EventDelayRequest request = (EventDelayRequest) o; + + return (request.timestamp == timestamp + && request.focusedComp == focusedComp); + } + + public void enqueueEvent (KeyEvent e) + { + KeyEvent last = (KeyEvent) enqueuedKeyEvents.getLast (); + if (last != null && e.getWhen () < last.getWhen ()) + throw new RuntimeException ("KeyEvents enqueued out-of-order"); + + if (e.getWhen () <= timestamp) + throw new RuntimeException ("KeyEvents enqueued before starting timestamp"); + + enqueuedKeyEvents.add (e); + } + + public void dispatchEvents () + { + int size = enqueuedKeyEvents.size (); + for (int i = 0; i < size; i++) + { + KeyEvent e = (KeyEvent) enqueuedKeyEvents.remove (0); + dispatchKeyEvent (e); + } + } + + public void discardEvents () + { + enqueuedKeyEvents.clear (); + } + } + + /** + * This flag indicates for which focus traversal key release event we + * possibly wait, before letting any more KEY_TYPED events through. + */ + private AWTKeyStroke waitForKeyStroke = null; + + /** The {@link java.util.SortedSet} of current {@link + #EventDelayRequest}s. */ + private SortedSet delayRequests = new TreeSet (); + + public DefaultKeyboardFocusManager () + { + } + + public boolean dispatchEvent (AWTEvent e) + { + if (e instanceof WindowEvent) + { + Window target = (Window) e.getSource (); + + if (e.id == WindowEvent.WINDOW_ACTIVATED) + setGlobalActiveWindow (target); + else if (e.id == WindowEvent.WINDOW_GAINED_FOCUS) + setGlobalFocusedWindow (target); + else if (e.id != WindowEvent.WINDOW_LOST_FOCUS + && e.id != WindowEvent.WINDOW_DEACTIVATED) + return false; + + redispatchEvent(target, e); + return true; + } + else if (e instanceof FocusEvent) + { + Component target = (Component) e.getSource (); + + if (e.id == FocusEvent.FOCUS_GAINED) + { + if (! (target instanceof Window)) + { + if (((FocusEvent) e).isTemporary ()) + setGlobalFocusOwner (target); + else + setGlobalPermanentFocusOwner (target); + } + + // Keep track of this window's focus owner. + + // Find the target Component's top-level ancestor. target + // may be a window. + Container parent = target.getParent (); + + while (parent != null + && !(parent instanceof Window)) + parent = parent.getParent (); + + // If the parent is null and target is not a window, then target is an + // unanchored component and so we don't want to set the focus owner. + if (! (parent == null && ! (target instanceof Window))) + { + Window toplevel = parent == null ? + (Window) target : (Window) parent; + + Component focusOwner = getFocusOwner (); + if (focusOwner != null + && ! (focusOwner instanceof Window)) + toplevel.setFocusOwner (focusOwner); + } + } + else if (e.id == FocusEvent.FOCUS_LOST) + { + if (((FocusEvent) e).isTemporary ()) + setGlobalFocusOwner (null); + else + setGlobalPermanentFocusOwner (null); + } + + redispatchEvent(target, e); + + return true; + } + else if (e instanceof KeyEvent) + { + // Loop through all registered KeyEventDispatchers, giving + // each a chance to handle this event. + Iterator i = getKeyEventDispatchers().iterator(); + + while (i.hasNext ()) + { + KeyEventDispatcher dispatcher = (KeyEventDispatcher) i.next (); + if (dispatcher.dispatchKeyEvent ((KeyEvent) e)) + return true; + } + + // processKeyEvent checks if this event represents a focus + // traversal key stroke. + Component focusOwner = getGlobalPermanentFocusOwner (); + + if (focusOwner != null) + processKeyEvent (focusOwner, (KeyEvent) e); + + if (e.isConsumed ()) + return true; + + if (enqueueKeyEvent ((KeyEvent) e)) + // This event was enqueued for dispatch at a later time. + return true; + else + // This event wasn't handled by any of the registered + // KeyEventDispatchers, and wasn't enqueued for dispatch + // later, so send it to the default dispatcher. + return dispatchKeyEvent ((KeyEvent) e); + } + + return false; + } + + private boolean enqueueKeyEvent (KeyEvent e) + { + Iterator i = delayRequests.iterator (); + boolean oneEnqueued = false; + while (i.hasNext ()) + { + EventDelayRequest request = (EventDelayRequest) i.next (); + if (e.getWhen () > request.timestamp) + { + request.enqueueEvent (e); + oneEnqueued = true; + } + } + return oneEnqueued; + } + + public boolean dispatchKeyEvent (KeyEvent e) + { + Component focusOwner = getGlobalPermanentFocusOwner (); + + if (focusOwner != null) + redispatchEvent(focusOwner, e); + + // Loop through all registered KeyEventPostProcessors, giving + // each a chance to process this event. + Iterator i = getKeyEventPostProcessors().iterator(); + + while (i.hasNext ()) + { + KeyEventPostProcessor processor = (KeyEventPostProcessor) i.next (); + if (processor.postProcessKeyEvent ((KeyEvent) e)) + return true; + } + + // The event hasn't been consumed yet. Check if it is an + // MenuShortcut. + if (postProcessKeyEvent (e)) + return true; + + // Always return true. + return true; + } + + public boolean postProcessKeyEvent (KeyEvent e) + { + // Check if this event represents a menu shortcut. + + // MenuShortcuts are activated by Ctrl- KeyEvents, only on KEY_PRESSED. + int modifiers = e.getModifiersEx (); + if (e.getID() == KeyEvent.KEY_PRESSED + && (modifiers & KeyEvent.CTRL_DOWN_MASK) != 0) + { + Window focusedWindow = getGlobalFocusedWindow (); + if (focusedWindow instanceof Frame) + { + MenuBar menubar = ((Frame) focusedWindow).getMenuBar (); + + if (menubar != null) + { + // If there's a menubar, loop through all menu items, + // checking whether each one has a shortcut, and if + // so, whether this key event should activate it. + int numMenus = menubar.getMenuCount (); + + for (int i = 0; i < numMenus; i++) + { + Menu menu = menubar.getMenu (i); + int numItems = menu.getItemCount (); + + for (int j = 0; j < numItems; j++) + { + MenuItem item = menu.getItem (j); + MenuShortcut shortcut = item.getShortcut (); + + if (item.isEnabled() && shortcut != null) + { + // Dispatch a new ActionEvent if: + // + // a) this is a Shift- KeyEvent, and the + // shortcut requires the Shift modifier + // + // or, b) this is not a Shift- KeyEvent, and the + // shortcut does not require the Shift + // modifier. + if (shortcut.getKey () == e.getKeyCode () + && ((shortcut.usesShiftModifier () + && (modifiers & KeyEvent.SHIFT_DOWN_MASK) != 0) + || (! shortcut.usesShiftModifier () + && (modifiers & KeyEvent.SHIFT_DOWN_MASK) == 0))) + { + item.dispatchEvent (new ActionEvent (item, + ActionEvent.ACTION_PERFORMED, + item.getActionCommand (), + modifiers)); + // The event was dispatched. + return true; + } + } + } + } + } + } + } + return false; + } + + public void processKeyEvent (Component comp, KeyEvent e) + { + AWTKeyStroke eventKeystroke = AWTKeyStroke.getAWTKeyStrokeForEvent (e); + // For every focus traversal keystroke, we need to also consume + // the other two key event types for the same key (e.g. if + // KEY_PRESSED TAB is a focus traversal keystroke, we also need to + // consume KEY_RELEASED and KEY_TYPED TAB key events). + // consuming KEY_RELEASED is easy, because their keyCodes matches + // the KEY_PRESSED event. Consuming the intermediate KEY_TYPED is + // very difficult because their is no clean way that we can know + // which KEY_TYPED belongs to a focusTraversalKey and which not. + // To address this problem we swallow every KEY_TYPE between the + // KEY_PRESSED event that matches a focusTraversalKey and the + // corresponding KEY_RELEASED. + AWTKeyStroke oppositeKeystroke = AWTKeyStroke.getAWTKeyStroke (e.getKeyCode (), + e.getModifiersEx (), + !(e.id == KeyEvent.KEY_RELEASED)); + + // Here we check if we are currently waiting for a KEY_RELEASED and + // swallow all KeyEvents that are to be delivered in between. This + // should only be the KEY_TYPED events that correspond to the + // focusTraversalKey's KEY_PRESSED event + if (waitForKeyStroke != null) + { + if (eventKeystroke.equals(waitForKeyStroke)) + // release this lock + waitForKeyStroke = null; + + // as long as we are waiting for the KEY_RELEASED, we swallow every + // KeyEvent, including the KEY_RELEASED + e.consume(); + return; + } + + Set forwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + Set backwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + Set upKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + Set downKeystrokes = null; + if (comp instanceof Container) + downKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + + if (forwardKeystrokes.contains (eventKeystroke)) + { + waitForKeyStroke = oppositeKeystroke; + focusNextComponent (comp); + e.consume (); + } + else if (backwardKeystrokes.contains (eventKeystroke)) + { + waitForKeyStroke = oppositeKeystroke; + focusPreviousComponent (comp); + e.consume (); + } + else if (upKeystrokes.contains (eventKeystroke)) + { + waitForKeyStroke = oppositeKeystroke; + upFocusCycle (comp); + e.consume (); + } + else if (comp instanceof Container + && downKeystrokes.contains (eventKeystroke)) + { + waitForKeyStroke = oppositeKeystroke; + downFocusCycle ((Container) comp); + e.consume (); + } + } + + protected void enqueueKeyEvents (long after, Component untilFocused) + { + delayRequests.add (new EventDelayRequest (after, untilFocused)); + } + + protected void dequeueKeyEvents (long after, Component untilFocused) + { + // FIXME: need synchronization on delayRequests and enqueuedKeyEvents. + + // Remove the KeyEvent with the oldest timestamp, which should be + // the first element in the SortedSet. + if (after < 0) + { + int size = delayRequests.size (); + if (size > 0) + delayRequests.remove (delayRequests.first ()); + } + else + { + EventDelayRequest template = new EventDelayRequest (after, untilFocused); + if (delayRequests.contains (template)) + { + EventDelayRequest actual = (EventDelayRequest) delayRequests.tailSet (template).first (); + delayRequests.remove (actual); + actual.dispatchEvents (); + } + } + } + + protected void discardKeyEvents (Component comp) + { + // FIXME: need synchronization on delayRequests and enqueuedKeyEvents. + + Iterator i = delayRequests.iterator (); + + while (i.hasNext ()) + { + EventDelayRequest request = (EventDelayRequest) i.next (); + + if (request.focusedComp == comp + || (comp instanceof Container + && ((Container) comp).isAncestorOf (request.focusedComp))) + request.discardEvents (); + } + } + + public void focusPreviousComponent (Component comp) + { + Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp; + Container focusCycleRoot = focusComp.getFocusCycleRootAncestor (); + FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy (); + + Component previous = policy.getComponentBefore (focusCycleRoot, focusComp); + if (previous != null) + previous.requestFocusInWindow (); + } + + public void focusNextComponent (Component comp) + { + Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp; + Container focusCycleRoot = focusComp.getFocusCycleRootAncestor (); + FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy (); + + Component next = policy.getComponentAfter (focusCycleRoot, focusComp); + if (next != null) + next.requestFocusInWindow (); + } + + public void upFocusCycle (Component comp) + { + Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp; + Container focusCycleRoot = focusComp.getFocusCycleRootAncestor (); + + if (focusCycleRoot instanceof Window) + { + FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy (); + Component defaultComponent = policy.getDefaultComponent (focusCycleRoot); + if (defaultComponent != null) + defaultComponent.requestFocusInWindow (); + } + else + { + Container parentFocusCycleRoot = focusCycleRoot.getFocusCycleRootAncestor (); + + focusCycleRoot.requestFocusInWindow (); + setGlobalCurrentFocusCycleRoot (parentFocusCycleRoot); + } + } + + public void downFocusCycle (Container cont) + { + if (cont == null) + return; + + if (cont.isFocusCycleRoot (cont)) + { + FocusTraversalPolicy policy = cont.getFocusTraversalPolicy (); + Component defaultComponent = policy.getDefaultComponent (cont); + if (defaultComponent != null) + defaultComponent.requestFocusInWindow (); + setGlobalCurrentFocusCycleRoot (cont); + } + } +} // class DefaultKeyboardFocusManager diff --git a/libjava/classpath/java/awt/Dialog.java b/libjava/classpath/java/awt/Dialog.java new file mode 100644 index 0000000..d3eb975 --- /dev/null +++ b/libjava/classpath/java/awt/Dialog.java @@ -0,0 +1,553 @@ +/* Dialog.java -- An AWT dialog box + Copyright (C) 1999, 2000, 2001, 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 java.awt; + +import java.awt.peer.DialogPeer; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * A dialog box widget class. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class Dialog extends Window +{ + +/* + * Static Variables + */ + +// Serialization constant +private static final long serialVersionUID = 5920926903803293709L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial Indicates whether or not this dialog box is modal. + */ +private boolean modal; + +/** + * @serial Indicates whether or not this dialog box is resizable. + */ +private boolean resizable = true; + +/** + * @serial The title string for this dialog box, which can be + * null. + */ +private String title; + +/** + * This field indicates whether the dialog is undecorated or not. + */ +private boolean undecorated = false; + +/** + * Indicates that we are blocked for modality in show + */ +private boolean blocked = false; + +/** + * Secondary EventQueue to handle AWT events while + * we are blocked for modality in show + */ +private EventQueue eq2 = null; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of Dialog with the specified + * parent, that is resizable and not modal, and which has no title. + * + * @param parent The parent frame of this dialog box. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null. This exception is always + * thrown when GraphicsEnvironment.isHeadless() returns true. + */ +public +Dialog(Frame parent) +{ + this(parent, "", false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Dialog with the specified + * parent and modality, that is resizable and which has no title. + * + * @param parent The parent frame of this dialog box. + * @param modal true if this dialog box is modal, + * false otherwise. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null. This exception is always + * thrown when GraphicsEnvironment.isHeadless() returns true. + */ +public +Dialog(Frame parent, boolean modal) +{ + this(parent, "", modal); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Dialog with the specified + * parent, that is resizable and not modal, and which has the specified + * title. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null. This exception is always + * thrown when GraphicsEnvironment.isHeadless() returns true. + */ +public +Dialog(Frame parent, String title) +{ + this(parent, title, false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Dialog with the specified, + * parent, title, and modality, that is resizable. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal true if this dialog box is modal, + * false otherwise. + * + * @exception IllegalArgumentException If owner is null or + * GraphicsEnvironment.isHeadless() returns true. + */ +public +Dialog(Frame parent, String title, boolean modal) +{ + this (parent, title, modal, parent.getGraphicsConfiguration ()); +} + +/** + * Initializes a new instance of Dialog with the specified, + * parent, title, modality and GraphicsConfiguration, + * that is resizable. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal true if this dialog box is modal, + * false otherwise. + * @param gc The GraphicsConfiguration object to use. + * + * @exception IllegalArgumentException If owner is null, the + * GraphicsConfiguration is not a screen device or + * GraphicsEnvironment.isHeadless() returns true. + * + * @since 1.4 + */ +public +Dialog (Frame parent, String title, boolean modal, GraphicsConfiguration gc) +{ + super (parent, gc); + + // A null title is equivalent to an empty title + this.title = (title != null) ? title : ""; + this.modal = modal; + visible = false; + + setLayout(new BorderLayout()); +} + +/** + * Initializes a new instance of Dialog with the specified, + * parent, that is resizable. + * + * @exception IllegalArgumentException If parent is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + * + * @since 1.2 + */ +public +Dialog (Dialog owner) +{ + this (owner, "", false, owner.getGraphicsConfiguration ()); +} + +/** + * Initializes a new instance of Dialog with the specified, + * parent and title, that is resizable. + * + * @exception IllegalArgumentException If parent is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + * + * @since 1.2 + */ +public +Dialog (Dialog owner, String title) +{ + this (owner, title, false, owner.getGraphicsConfiguration ()); +} + +/** + * Initializes a new instance of Dialog with the specified, + * parent, title and modality, that is resizable. + * + * @exception IllegalArgumentException If parent is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + * + * @since 1.2 + */ +public +Dialog (Dialog owner, String title, boolean modal) +{ + this (owner, title, modal, owner.getGraphicsConfiguration ()); +} + +/** + * Initializes a new instance of Dialog with the specified, + * parent, title, modality and GraphicsConfiguration, + * that is resizable. + * + * @exception IllegalArgumentException If parent is null, the + * GraphicsConfiguration is not a screen device or + * GraphicsEnvironment.isHeadless() returns true. + * + * @since 1.4 + */ +public +Dialog (Dialog parent, String title, boolean modal, GraphicsConfiguration gc) +{ + super (parent, parent.getGraphicsConfiguration ()); + + // A null title is equivalent to an empty title + this.title = (title != null) ? title : ""; + this.modal = modal; + visible = false; + + setLayout (new BorderLayout ()); +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the title of this dialog box. + * + * @return The title of this dialog box. + */ +public String +getTitle() +{ + return(title); +} + +/*************************************************************************/ + +/** + * Sets the title of this dialog box to the specified string. + * + * @param title The new title. + */ +public synchronized void +setTitle(String title) +{ + // A null title is equivalent to an empty title + this.title = (title != null) ? title : ""; + + if (peer != null) + { + DialogPeer d = (DialogPeer) peer; + d.setTitle (title); + } +} + +/*************************************************************************/ + +/** + * Tests whether or not this dialog box is modal. + * + * @return true if this dialog box is modal, + * false otherwise. + */ +public boolean +isModal() +{ + return(modal); +} + +/*************************************************************************/ + +/** + * Changes the modality of this dialog box. This can only be done before + * the peer is created. + * + * @param modal true to make this dialog box modal, + * false to make it non-modal. + */ +public void +setModal(boolean modal) +{ + this.modal = modal; +} + +/*************************************************************************/ + +/** + * Tests whether or not this dialog box is resizable. + * + * @return true if this dialog is resizable, false, + * otherwise. + */ +public boolean +isResizable() +{ + return(resizable); +} + +/*************************************************************************/ + +/** + * Changes the resizability of this dialog box. + * + * @param resizable true to make this dialog resizable, + * false to make it non-resizable. + */ +public synchronized void +setResizable(boolean resizable) +{ + this.resizable = resizable; + if (peer != null) + { + DialogPeer d = (DialogPeer) peer; + d.setResizable (resizable); + } +} + +/*************************************************************************/ + +/** + * Creates this object's native peer. + */ +public synchronized void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createDialog (this); + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Makes this dialog visible and brings it to the front. + * If the dialog is modal and is not already visible, this call will not + * return until the dialog is hidden by someone calling hide or dispose. + * If this is the event dispatching thread we must ensure that another event + * thread runs while the one which invoked this method is blocked. + */ +public synchronized void +show() +{ + super.show(); + + if (isModal()) + { + // If already shown (and blocked) just return + if (blocked) + return; + + /* If show is called in the dispatch thread for a modal dialog it will + block so we must run another thread so the events keep being + dispatched.*/ + if (EventQueue.isDispatchThread ()) + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + eq2 = new EventQueue (); + eq.push (eq2); + } + + try + { + blocked = true; + wait (); + blocked = false; + } + catch (InterruptedException e) + { + blocked = false; + } + + if (eq2 != null) + { + eq2.pop (); + eq2 = null; + } + } +} + +/*************************************************************************/ + +/** + * Hides the Dialog and then + * causes show() to return if it is currently blocked. + */ + +public synchronized void +hide () +{ + if (blocked) + { + notifyAll (); + } + + super.hide(); +} + +/*************************************************************************/ + +/** + * Disposes the Dialog and then causes show() to return + * if it is currently blocked. + */ + +public synchronized void +dispose () +{ + if (blocked) + { + notifyAll (); + } + + super.dispose(); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this component. + * + * @return A debugging string for this component. + */ +protected String +paramString() +{ + return ("title+" + title + ",modal=" + modal + + ",resizable=" + resizable + "," + super.paramString()); +} + + /** + * Returns whether this frame is undecorated or not. + * + * @since 1.4 + */ + public boolean isUndecorated () + { + return undecorated; + } + + /** + * Disables or enables decorations for this frame. This method can only be + * called while the frame is not displayable. + * + * @exception IllegalComponentStateException If this frame is displayable. + * + * @since 1.4 + */ + public void setUndecorated (boolean undecorated) + { + if (isDisplayable ()) + throw new IllegalComponentStateException (); + + this.undecorated = undecorated; + } + + protected class AccessibleAWTDialog extends AccessibleAWTWindow + { + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.DIALOG; + } + + public AccessibleStateSet getAccessibleState() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (isResizable()) + states.add(AccessibleState.RESIZABLE); + if (isModal()) + states.add(AccessibleState.MODAL); + return states; + } + } + + /** + * Gets the AccessibleContext associated with this Dialog. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTDialog(); + return accessibleContext; + } + +} // class Dialog + diff --git a/libjava/classpath/java/awt/Dimension.java b/libjava/classpath/java/awt/Dimension.java new file mode 100644 index 0000000..4c1a07b --- /dev/null +++ b/libjava/classpath/java/awt/Dimension.java @@ -0,0 +1,234 @@ +/* Dimension.java -- represents a 2-dimensional span + Copyright (C) 1999, 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 java.awt; + +import java.awt.geom.Dimension2D; +import java.io.Serializable; + +/** + * This class holds a width and height value pair. This is used in plenty + * of windowing classes, but also has geometric meaning. + * + *

It is valid for a dimension to have negative width or height; but it + * is considered to have no area. Therefore, the behavior in various methods + * is undefined in such a case. + * + *

There are some public fields; if you mess with them in an inconsistent + * manner, it is your own fault when you get invalid results. Also, this + * class is not threadsafe. + * + * @author Per Bothner (bothner@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Component + * @see LayoutManager + * @since 1.0 + * @status updated to 1.14 + */ +public class Dimension extends Dimension2D implements Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 4723952579491349524L; + + /** + * The width of this object. + * + * @see #getSize() + * @see #setSize(double, double) + * @serial the width + */ + public int width; + + /** + * The height of this object. + * + * @see #getSize() + * @see #setSize(double, double) + * @serial the height + */ + public int height; + + /** + * Create a new Dimension with a width and height of zero. + */ + public Dimension() + { + } + + /** + * Create a new Dimension with width and height identical to that of the + * specified dimension. + * + * @param d the Dimension to copy + * @throws NullPointerException if d is null + */ + public Dimension(Dimension d) + { + width = d.width; + height = d.height; + } + + /** + * Create a new Dimension with the specified width and height. + * + * @param w the width of this object + * @param h the height of this object + */ + public Dimension(int w, int h) + { + width = w; + height = h; + } + + /** + * Gets the width of this dimension. + * + * @return the width, as a double + */ + public double getWidth() + { + return width; + } + + /** + * Gets the height of this dimension. + * + * @return the height, as a double + */ + public double getHeight() + { + return height; + } + + /** + * Sets the size of this dimension. The values are rounded to int. + * + * @param w the new width + * @param h the new height + * @since 1.2 + */ + public void setSize(double w, double h) + { + width = (int) w; + height = (int) h; + } + + /** + * Returns the size of this dimension. A pretty useless method, as this is + * already a dimension. + * + * @return a copy of this dimension + * @see #setSize(Dimension) + * @since 1.1 + */ + public Dimension getSize() + { + return new Dimension(width, height); + } + + /** + * Sets the width and height of this object to match that of the + * specified object. + * + * @param d the Dimension to get the new width and height from + * @throws NullPointerException if d is null + * @see #getSize() + * @since 1.1 + */ + public void setSize(Dimension d) + { + width = d.width; + height = d.height; + } + + /** + * Sets the width and height of this object to the specified values. + * + * @param w the new width value + * @param h the new height value + */ + public void setSize(int w, int h) + { + width = w; + height = h; + } + + /** + * Tests this object for equality against the specified object. This will + * be true if and only if the specified object is an instance of + * Dimension2D, and has the same width and height. + * + * @param obj the object to test against + * @return true if the object is equal to this + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Dimension)) + return false; + Dimension dim = (Dimension) obj; + return height == dim.height && width == dim.width; + } + + /** + * Return the hashcode for this object. It is not documented, but appears + * to be ((width + height) * (width + height + 1) / 2) + width. + * + * @return the hashcode + */ + public int hashCode() + { + // Reverse engineering this was fun! + return (width + height) * (width + height + 1) / 2 + width; + } + + /** + * Returns a string representation of this object. The format is: + * getClass().getName() + "[width=" + width + ",height=" + height + * + ']'. + * + * @return a string representation of this object + */ + public String toString() + { + return getClass().getName() + + "[width=" + width + ",height=" + height + ']'; + } +} // class Dimension diff --git a/libjava/classpath/java/awt/DisplayMode.java b/libjava/classpath/java/awt/DisplayMode.java new file mode 100644 index 0000000..d41d4a8 --- /dev/null +++ b/libjava/classpath/java/awt/DisplayMode.java @@ -0,0 +1,164 @@ +/* DisplayMode.java -- a description of display mode configurations + Copyright (C) 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 java.awt; + +/** + * This encapsulates information about the display mode for a graphics + * device configuration. They are device dependent, and may not always be + * available. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see GraphicsDevice + * @since 1.4 + * @status updated to 1.4 + */ +public final class DisplayMode +{ + /** + * Value of the bit depth if multiple depths are supported. + * + * @see #getBitDepth() + */ + public static final int BIT_DEPTH_MULTI = -1; + + /** + * Value of an unknown refresh rate. + * + * @see #getRefreshRate() + */ + public static final int REFRESH_RATE_UNKNOWN = 0; + + /** The width. */ + private final int width; + + /** The height. */ + private final int height; + + /** The bit depth. */ + private final int bitDepth; + + /** The refresh rate. */ + private final int refreshRate; + + /** + * Create a mode with the given parameters. + * + * @param width the width + * @param height the height + * @param bitDepth the bitDepth + * @param refreshRate the refreshRate + * @see #BIT_DEPTH_MULTI + * @see #REFRESH_RATE_UNKNOWN + */ + public DisplayMode(int width, int height, int bitDepth, int refreshRate) + { + this.width = width; + this.height = height; + this.bitDepth = bitDepth; + this.refreshRate = refreshRate; + } + + /** + * Returns the height, in pixels. + * + * @return the height + */ + public int getHeight() + { + return height; + } + + /** + * Returns the width, in pixels. + * + * @return the width + */ + public int getWidth() + { + return width; + } + + /** + * Returns the bit depth, in bits per pixel. This may be BIT_DEPTH_MULTI. + * + * @return the bit depth + * @see #BIT_DEPTH_MULTI + */ + public int getBitDepth() + { + return bitDepth; + } + + /** + * Returns the refresh rate, in hertz. This may be REFRESH_RATE_UNKNOWN. + * + * @return the refresh rate + * @see #REFRESH_RATE_UNKNOWN + */ + public int getRefreshRate() + { + return refreshRate; + } + + /** + * Test for equality. This returns true for two modes with identical + * parameters. + * + * @param dm The display mode to compare to + * + * @return true if it is equal + */ + public boolean equals (DisplayMode dm) + { + return (width == dm.width + && height == dm.height + && bitDepth == dm.bitDepth + && refreshRate == dm.refreshRate); + } + + /** + * Returns a hash code for the display mode. + * + * @return the hash code + */ + public int hashCode() + { + return width + height + bitDepth + refreshRate; + } +} // class DisplayMode diff --git a/libjava/classpath/java/awt/Event.java b/libjava/classpath/java/awt/Event.java new file mode 100644 index 0000000..648139c --- /dev/null +++ b/libjava/classpath/java/awt/Event.java @@ -0,0 +1,185 @@ +/* Copyright (C) 1999, 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 java.awt; + +/** + * 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. + */ + +public class Event implements java.io.Serializable +{ + static final long serialVersionUID = 5488922509400504703L; + + public static final int SHIFT_MASK = 1; + public static final int CTRL_MASK = 2; + public static final int META_MASK = 4; + public static final int ALT_MASK = 8; + + public static final int ACTION_EVENT = 1001; + public static final int BACK_SPACE = 8; + public static final int CAPS_LOCK = 1022; + public static final int DELETE = 127; + public static final int DOWN = 1005; + public static final int END = 1001; + public static final int ENTER = 10; + public static final int ESCAPE = 27; + public static final int F1 = 1008; + public static final int F10 = 1017; + public static final int F11 = 1018; + public static final int F12 = 1019; + public static final int F2 = 1009; + public static final int F3 = 1010; + public static final int F4 = 1011; + public static final int F5 = 1012; + public static final int F6 = 1013; + public static final int F7 = 1014; + public static final int F8 = 1015; + public static final int F9 = 1016; + public static final int GOT_FOCUS = 1004; + public static final int HOME = 1000; + public static final int INSERT = 1025; + public static final int KEY_ACTION = 403; + public static final int KEY_ACTION_RELEASE = 404; + public static final int KEY_PRESS = 401; + public static final int KEY_RELEASE = 402; + public static final int LEFT = 1006; + public static final int LIST_DESELECT = 702; + public static final int LIST_SELECT = 701; + public static final int LOAD_FILE = 1002; + public static final int LOST_FOCUS = 1005; + public static final int MOUSE_DOWN = 501; + public static final int MOUSE_DRAG = 506; + public static final int MOUSE_ENTER = 504; + public static final int MOUSE_EXIT = 505; + public static final int MOUSE_MOVE = 503; + public static final int MOUSE_UP = 502; + public static final int NUM_LOCK = 1023; + public static final int PAUSE = 1024; + public static final int PGDN = 1003; + public static final int PGUP = 1002; + public static final int PRINT_SCREEN = 1020; + public static final int RIGHT = 1007; + public static final int SAVE_FILE = 1003; + public static final int SCROLL_ABSOLUTE = 605; + public static final int SCROLL_BEGIN = 606; + public static final int SCROLL_END = 607; + public static final int SCROLL_LINE_DOWN = 602; + public static final int SCROLL_LINE_UP = 601; + public static final int SCROLL_LOCK = 1021; + public static final int SCROLL_PAGE_DOWN = 604; + public static final int SCROLL_PAGE_UP = 603; + public static final int TAB = 9; + public static final int UP = 1004; + public static final int WINDOW_DEICONIFY = 204; + public static final int WINDOW_DESTROY = 201; + public static final int WINDOW_EXPOSE = 202; + public static final int WINDOW_ICONIFY = 203; + public static final int WINDOW_MOVED = 205; + + public Object arg; + public int clickCount; + boolean consumed; // Required by serialization spec. + public Event evt; + public int id; + public int key; + public int modifiers; + public Object target; + public long when; + public int x; + public int y; + + public Event (Object target, int id, Object arg) + { + this.id = id; + this.target = target; + this.arg = arg; + } + + public Event (Object target, long when, int id, int x, int y, int key, + int modifiers) + { + this.target = target; + this.when = when; + this.id = id; + this.x = x; + this.y = y; + this.key = key; + this.modifiers = modifiers; + } + + public Event (Object target, long when, int id, int x, int y, int key, + int modifiers, Object arg) + { + this (target, when, id, x, y, key, modifiers); + this.arg = arg; + } + + public boolean controlDown () + { + return ((modifiers & CTRL_MASK) == 0 ? false : true); + } + + public boolean metaDown () + { + return ((modifiers & META_MASK) == 0 ? false : true); + } + + protected String paramString () + { + return "id=" + id + ",x=" + x + ",y=" + y + + ",target=" + target + ",arg=" + arg; + } + + public boolean shiftDown() + { + return ((modifiers & SHIFT_MASK) == 0 ? false : true); + } + + public String toString() + { + return getClass().getName() + "[" + paramString() + "]"; + } + + public void translate (int x, int y) + { + this.x += x; + this.y += y; + } +} diff --git a/libjava/classpath/java/awt/EventDispatchThread.java b/libjava/classpath/java/awt/EventDispatchThread.java new file mode 100644 index 0000000..a64cdae --- /dev/null +++ b/libjava/classpath/java/awt/EventDispatchThread.java @@ -0,0 +1,94 @@ +/* EventDispatchThread.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 java.awt; + +/** + * @author Bryce McKinlay + * @status believed complete, but untested. + */ +class EventDispatchThread extends Thread +{ + private static int dispatchThreadNum; + + private EventQueue queue; + + EventDispatchThread(EventQueue queue) + { + super(); + setName("AWT-EventQueue-" + ++dispatchThreadNum); + this.queue = queue; + setPriority(NORM_PRIORITY + 1); + } + + public void run() + { + while (true) + { + try + { + AWTEvent evt = queue.getNextEvent(); + + KeyboardFocusManager manager; + manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + // Try to dispatch this event to the current keyboard focus + // manager. It will dispatch all FocusEvents, all + // WindowEvents related to focus, and all KeyEvents, + // returning true. Otherwise, it returns false and we + // dispatch the event normally. + if (!manager.dispatchEvent (evt)) + queue.dispatchEvent(evt); + } + catch (ThreadDeath death) + { + // If someone wants to kill us, let them. + return; + } + catch (InterruptedException ie) + { + // We are interrupted when we should finish executing + return; + } + catch (Throwable x) + { + System.err.println("Exception during event dispatch:"); + x.printStackTrace(System.err); + } + } + } +} diff --git a/libjava/classpath/java/awt/EventQueue.java b/libjava/classpath/java/awt/EventQueue.java new file mode 100644 index 0000000..a8b0078 --- /dev/null +++ b/libjava/classpath/java/awt/EventQueue.java @@ -0,0 +1,552 @@ +/* EventQueue.java -- + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.awt.ClasspathToolkit; + +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.InvocationEvent; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.EmptyStackException; + +/* Written using on-line Java 2 Platform Standard Edition v1.3 API + * Specification, as well as "The Java Class Libraries", 2nd edition + * (Addison-Wesley, 1998). + * Status: Believed complete, but untested. + */ + +/** + * This class manages a queue of AWTEvent objects that + * are posted to it. The AWT system uses only one event queue for all + * events. + * + * @author Bryce McKinlay + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class EventQueue +{ + private static final int INITIAL_QUEUE_DEPTH = 8; + private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH]; + + private int next_in = 0; // Index where next event will be added to queue + private int next_out = 0; // Index of next event to be removed from queue + + private EventQueue next; + private EventQueue prev; + private AWTEvent currentEvent; + private long lastWhen = System.currentTimeMillis(); + + private EventDispatchThread dispatchThread = new EventDispatchThread(this); + private boolean shutdown = false; + + private long lastNativeQueueAccess = 0; + private long humanLatencyThreshold = 100; + + synchronized void setShutdown (boolean b) + { + shutdown = b; + } + + synchronized boolean isShutdown () + { + if (shutdown) + return true; + + // This is the exact self-shutdown condition specified in J2SE: + // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html + + if (peekEvent() == null + && ((ClasspathToolkit) Toolkit.getDefaultToolkit()).nativeQueueEmpty()) + { + Frame[] frames = Frame.getFrames(); + for (int i = 0; i < frames.length; ++i) + if (frames[i].isDisplayable()) + return false; + return true; + } + return false; + } + + /** + * Initializes a new instance of EventQueue. + */ + public EventQueue() + { + } + + /** + * Returns the next event in the queue. This method will block until + * an event is available or until the thread is interrupted. + * + * @return The next event in the queue. + * + * @exception InterruptedException If this thread is interrupted while + * waiting for an event to be posted to the queue. + */ + public synchronized AWTEvent getNextEvent() + throws InterruptedException + { + if (next != null) + return next.getNextEvent(); + + ClasspathToolkit tk = ((ClasspathToolkit) Toolkit.getDefaultToolkit()); + long curr = System.currentTimeMillis(); + + if (! tk.nativeQueueEmpty() && + (curr - lastNativeQueueAccess > humanLatencyThreshold)) + { + tk.iterateNativeQueue(this, false); + lastNativeQueueAccess = curr; + } + + while (next_in == next_out) + { + // Only the EventDispatchThread associated with the top of the stack is + // allowed to get events from the native source; everyone else just + // waits on the head of the queue. + + if (isDispatchThread()) + { + // We are not allowed to return null from this method, yet it + // is possible that we actually have run out of native events + // in the enclosing while() loop, and none of the native events + // happened to cause AWT events. We therefore ought to check + // the isShutdown() condition here, before risking a "native + // wait". If we check it before entering this function we may + // wait forever for events after the shutdown condition has + // arisen. + + if (isShutdown()) + throw new InterruptedException(); + + tk.iterateNativeQueue(this, true); + lastNativeQueueAccess = System.currentTimeMillis(); + } + else + { + try + { + wait(); + } + catch (InterruptedException ie) + { + } + } + } + + AWTEvent res = queue[next_out]; + + if (++next_out == queue.length) + next_out = 0; + return res; + } + + /** + * Returns the next event in the queue without removing it from the queue. + * This method will block until an event is available or until the thread + * is interrupted. + * + * @return The next event in the queue. + * @specnote Does not block. Returns null if there are no events on the + * queue. + */ + public synchronized AWTEvent peekEvent() + { + if (next != null) + return next.peekEvent(); + + if (next_in != next_out) + return queue[next_out]; + else + return null; + } + + /** + * Returns the next event in the queue that has the specified id + * without removing it from the queue. + * This method will block until an event is available or until the thread + * is interrupted. + * + * @param id The event id to return. + * + * @return The next event in the queue. + * + * @specnote Does not block. Returns null if there are no matching events + * on the queue. + */ + public synchronized AWTEvent peekEvent(int id) + { + if (next != null) + return next.peekEvent(id); + + int i = next_out; + while (i != next_in) + { + AWTEvent qevt = queue[i]; + if (qevt.id == id) + return qevt; + } + return null; + } + + /** + * Posts a new event to the queue. + * + * @param evt The event to post to the queue. + * + * @exception NullPointerException If event is null. + */ + public synchronized void postEvent(AWTEvent evt) + { + if (evt == null) + throw new NullPointerException(); + + if (next != null) + { + next.postEvent(evt); + return; + } + + /* Check for any events already on the queue with the same source + and ID. */ + int i = next_out; + while (i != next_in) + { + AWTEvent qevt = queue[i]; + Object src; + if (qevt.id == evt.id + && (src = qevt.getSource()) == evt.getSource() + && src instanceof Component) + { + /* If there are, call coalesceEvents on the source component + to see if they can be combined. */ + Component srccmp = (Component) src; + AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt); + if (coalesced_evt != null) + { + /* Yes. Replace the existing event with the combined event. */ + queue[i] = coalesced_evt; + return; + } + break; + } + if (++i == queue.length) + i = 0; + } + + queue[next_in] = evt; + if (++next_in == queue.length) + next_in = 0; + + if (next_in == next_out) + { + /* Queue is full. Extend it. */ + AWTEvent[] oldQueue = queue; + queue = new AWTEvent[queue.length * 2]; + + int len = oldQueue.length - next_out; + System.arraycopy(oldQueue, next_out, queue, 0, len); + if (next_out != 0) + System.arraycopy(oldQueue, 0, queue, len, next_out); + + next_out = 0; + next_in = oldQueue.length; + } + + if (dispatchThread == null || !dispatchThread.isAlive()) + { + dispatchThread = new EventDispatchThread(this); + dispatchThread.start(); + } + + // Window events might represent the closing of a window, which + // might cause the end of the dispatch thread's life, so we'll wake + // it up here to give it a chance to check for shutdown. + + if (!isDispatchThread() + || (evt.getID() == WindowEvent.WINDOW_CLOSED) + || (evt.getID() == WindowEvent.WINDOW_CLOSING)) + ((ClasspathToolkit) Toolkit.getDefaultToolkit()).wakeNativeQueue(); + + notify(); + } + + /** + * Causes runnable to have its run method called in the dispatch thread of the + * EventQueue. This will happen after all pending events are processed. The + * call blocks until this has happened. This method will throw an Error if + * called from the event dispatcher thread. + * + * @exception InterruptedException If another thread has interrupted + * this thread. + * @exception InvocationTargetException If an exception is thrown when running + * runnable. + * + * @since 1.2 + */ + public static void invokeAndWait(Runnable runnable) + throws InterruptedException, InvocationTargetException + { + if (isDispatchThread ()) + throw new Error("Can't call invokeAndWait from event dispatch thread"); + + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + Thread current = Thread.currentThread(); + + InvocationEvent ie = + new InvocationEvent(eq, runnable, current, true); + + synchronized (current) + { + eq.postEvent(ie); + current.wait(); + } + + Exception exception; + + if ((exception = ie.getException()) != null) + throw new InvocationTargetException(exception); + } + + /** + * This arranges for runnable to have its run method called in the + * dispatch thread of the EventQueue. This will happen after all + * pending events are processed. + * + * @since 1.2 + */ + public static void invokeLater(Runnable runnable) + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + + InvocationEvent ie = + new InvocationEvent(eq, runnable, null, false); + + eq.postEvent(ie); + } + + /** + * Return true if the current thread is the current AWT event dispatch + * thread. + */ + public static boolean isDispatchThread() + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + + /* Find last EventQueue in chain */ + while (eq.next != null) + eq = eq.next; + + return (Thread.currentThread() == eq.dispatchThread); + } + + /** + * Return the event currently being dispatched by the event + * dispatch thread. If the current thread is not the event + * dispatch thread, this method returns null. + * + * @since 1.4 + */ + public static AWTEvent getCurrentEvent() + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + Thread ct = Thread.currentThread(); + + /* Find out if this thread is the dispatch thread for any of the + EventQueues in the chain */ + while (ct != eq.dispatchThread) + { + // Try next EventQueue, if any + if (eq.next == null) + return null; // Not an event dispatch thread + eq = eq.next; + } + + return eq.currentEvent; + } + + /** + * Allows a custom EventQueue implementation to replace this one. + * All pending events are transferred to the new queue. Calls to postEvent, + * getNextEvent, and peekEvent and others are forwarded to the pushed queue + * until it is removed with a pop(). + * + * @exception NullPointerException if newEventQueue is null. + */ + public synchronized void push(EventQueue newEventQueue) + { + if (newEventQueue == null) + throw new NullPointerException (); + + /* Make sure we are at the top of the stack because callers can + only get a reference to the one at the bottom using + Toolkit.getDefaultToolkit().getSystemEventQueue() */ + if (next != null) + { + next.push (newEventQueue); + return; + } + + /* Make sure we have a live dispatch thread to drive the queue */ + if (dispatchThread == null) + dispatchThread = new EventDispatchThread(this); + + int i = next_out; + while (i != next_in) + { + newEventQueue.postEvent(queue[i]); + next_out = i; + if (++i == queue.length) + i = 0; + } + + next = newEventQueue; + newEventQueue.prev = this; + } + + /** Transfer any pending events from this queue back to the parent queue that + * was previously push()ed. Event dispatch from this queue is suspended. + * + * @exception EmptyStackException If no previous push was made on this + * EventQueue. + */ + protected void pop() throws EmptyStackException + { + if (prev == null) + throw new EmptyStackException(); + + /* The order is important here, we must get the prev lock first, + or deadlock could occur as callers usually get here following + prev's next pointer, and thus obtain prev's lock before trying + to get this lock. */ + synchronized (prev) + { + prev.next = next; + if (next != null) + next.prev = prev; + + synchronized (this) + { + int i = next_out; + while (i != next_in) + { + prev.postEvent(queue[i]); + next_out = i; + if (++i == queue.length) + i = 0; + } + // Empty the queue so it can be reused + next_in = 0; + next_out = 0; + + ((ClasspathToolkit) Toolkit.getDefaultToolkit()).wakeNativeQueue(); + setShutdown(true); + dispatchThread = null; + this.notifyAll(); + } + } + } + + /** + * Dispatches an event. The manner in which the event is dispatched depends + * upon the type of the event and the type of the event's source object. + * + * @exception NullPointerException If event is null. + */ + protected void dispatchEvent(AWTEvent evt) + { + currentEvent = evt; + + if (evt instanceof InputEvent) + lastWhen = ((InputEvent) evt).getWhen(); + else if (evt instanceof ActionEvent) + lastWhen = ((ActionEvent) evt).getWhen(); + else if (evt instanceof InvocationEvent) + lastWhen = ((InvocationEvent) evt).getWhen(); + + if (evt instanceof ActiveEvent) + { + ActiveEvent active_evt = (ActiveEvent) evt; + active_evt.dispatch(); + } + else + { + Object source = evt.getSource(); + + if (source instanceof Component) + { + Component srccmp = (Component) source; + srccmp.dispatchEvent(evt); + } + else if (source instanceof MenuComponent) + { + MenuComponent srccmp = (MenuComponent) source; + srccmp.dispatchEvent(evt); + } + } + } + + /** + * Returns the timestamp of the most recent event that had a timestamp, or + * the initialization time of the event queue if no events have been fired. + * At present, only InputEvents, ActionEvents, + * InputMethodEvents, and InvocationEvents have + * timestamps, but this may be added to other events in future versions. + * If this is called by the event dispatching thread, it can be any + * (sequential) value, but to other threads, the safest bet is to return + * System.currentTimeMillis(). + * + * @return the most recent timestamp + * @see InputEvent#getWhen() + * @see ActionEvent#getWhen() + * @see InvocationEvent#getWhen() + * @see InputMethodEvent#getWhen() + * @since 1.4 + */ + public static long getMostRecentEventTime() + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + if (Thread.currentThread() != eq.dispatchThread) + return System.currentTimeMillis(); + return eq.lastWhen; + } +} diff --git a/libjava/classpath/java/awt/FileDialog.java b/libjava/classpath/java/awt/FileDialog.java new file mode 100644 index 0000000..7f2723e --- /dev/null +++ b/libjava/classpath/java/awt/FileDialog.java @@ -0,0 +1,318 @@ +/* FileDialog.java -- A filename selection dialog box + Copyright (C) 1999, 2000, 2001, 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 java.awt; + +import java.awt.peer.FileDialogPeer; +import java.io.FilenameFilter; +import java.io.Serializable; + +/** + * This class implements a file selection dialog box widget. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class FileDialog extends Dialog implements Serializable +{ + +/* + * Static Variables + */ + +/** + * Indicates that the purpose of the dialog is for opening a file. + */ +public static final int LOAD = 0; + +/** + * Indicates that the purpose of the dialog is for saving a file. + */ +public static final int SAVE = 1; + +// Serialization constant +private static final long serialVersionUID = 5035145889651310422L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The directory for this file dialog. + */ +private String dir; + +/** + * @serial The filename for this file dialog + */ +private String file; + +/** + * @serial The filter for selecting filenames to display + */ +private FilenameFilter filter; + +/** + * @serial The mode of this dialog, either LOAD or + * SAVE. + */ +private int mode; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of FileDialog with the + * specified parent. This dialog will have no title and will be for + * loading a file. + * + * @param parent The parent frame for this dialog. + */ +public +FileDialog(Frame parent) +{ + this(parent, "", LOAD); +} + +/*************************************************************************/ + +/** + * Initialized a new instance of FileDialog with the + * specified parent and title. This dialog will be for opening a file. + * + * @param parent The parent frame for this dialog. + * @param title The title for this dialog. + */ +public +FileDialog(Frame parent, String title) +{ + this(parent, title, LOAD); +} + +/*************************************************************************/ + +/** + * Initialized a new instance of FileDialog with the + * specified parent, title, and mode. + * + * @param parent The parent frame for this dialog. + * @param title The title for this dialog. + * @param mode The mode of the dialog, either LOAD or + * SAVE. + * + * @exception IllegalArgumentException If an illegal file dialog mode + * is supplied. + */ +public +FileDialog(Frame parent, String title, int mode) +{ + super(parent, title, true); + + if ((mode != LOAD) && (mode != SAVE)) + throw new IllegalArgumentException ( + "Mode argument must be either LOAD or SAVE"); + + setMode (mode); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the mode of this dialog, either LOAD or + * SAVE. + * + * @return The mode of this dialog. + */ +public int +getMode() +{ + return(mode); +} + +/*************************************************************************/ + +/** + * Sets the mode of this dialog to either LOAD or + * SAVE. This method is only effective before the native + * peer is created. + * + * @param mode The new mode of this file dialog. + * + * @exception IllegalArgumentException If an illegal file dialog mode + * is supplied. + */ +public void +setMode(int mode) +{ + if ((mode != LOAD) && (mode != SAVE)) + throw new IllegalArgumentException("Bad mode: " + mode); + + this.mode = mode; +} + +/*************************************************************************/ + +/** + * Returns the directory for this file dialog. + * + * @return The directory for this file dialog. + */ +public String +getDirectory() +{ + return(dir); +} + +/*************************************************************************/ + +/** + * Sets the directory for this file dialog. + * + * @param dir The new directory for this file dialog. + */ +public synchronized void +setDirectory(String dir) +{ + this.dir = dir; + if (peer != null) + { + FileDialogPeer f = (FileDialogPeer) peer; + f.setDirectory (dir); + } +} + +/*************************************************************************/ + +/** + * Returns the file that is selected in this dialog. + * + * @return The file that is selected in this dialog. + */ +public String +getFile() +{ + return(file); +} + +/*************************************************************************/ + +/** + * Sets the selected file for this dialog. + * + * @param file The selected file for this dialog. + */ +public synchronized void +setFile(String file) +{ + this.file = file; + if (peer != null) + { + FileDialogPeer f = (FileDialogPeer) peer; + f.setFile (file); + } +} + +/*************************************************************************/ + +/** + * Returns the filename filter being used by this dialog. + * + * @return The filename filter being used by this dialog. + */ +public FilenameFilter +getFilenameFilter() +{ + return(filter); +} + +/*************************************************************************/ + +/** + * Sets the filename filter used by this dialog. + * + * @param filter The new filename filter for this file dialog box. + */ +public synchronized void +setFilenameFilter(FilenameFilter filter) +{ + this.filter = filter; + if (peer != null) + { + FileDialogPeer f = (FileDialogPeer) peer; + f.setFilenameFilter (filter); + } +} + +/*************************************************************************/ + +/** + * Creates the native peer for this file dialog box. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createFileDialog (this); + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +protected String +paramString() +{ + return ("dir=" + dir + ",file=" + file + + ",mode=" + mode + "," + super.paramString()); +} + +} // class FileDialog + diff --git a/libjava/classpath/java/awt/FlowLayout.java b/libjava/classpath/java/awt/FlowLayout.java new file mode 100644 index 0000000..4674990 --- /dev/null +++ b/libjava/classpath/java/awt/FlowLayout.java @@ -0,0 +1,364 @@ +/* FlowLayout.java -- Grid-based layout engine + Copyright (C) 1999, 2000, 2001, 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 java.awt; + +import java.io.Serializable; + +/** This class implements a flow-based layout. Components are laid + * out in order from left to right. When a component cannot be placed + * without horizontal clipping, a new row is started. This class + * supports horizontal and vertical gaps. These are used for spacing + * between components. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class FlowLayout implements LayoutManager, Serializable +{ + /** Constant that specifies left alignment. */ + public static final int LEFT = 0; + /** Constant that specifies center alignment. */ + public static final int CENTER = 1; + /** Constant that specifies right alignment. */ + public static final int RIGHT = 2; + + /** Constant that specifies alignment to leading edge of container's + * orientation. */ + public static final int LEADING = 3; + /** Constant that specifies alignment to trailing edge of container's + * orientation. */ + public static final int TRAILING = 4; + + // Serialization constant + private static final long serialVersionUID = -7262534875583282631L; + + /** + * Add a new component to the layout. This particular implementation + * does nothing. + * + * @param name the name + * @param comp the component + */ + public void addLayoutComponent (String name, Component comp) + { + // Nothing. + } + + /** + * Returns the current justification value for this object. + * + * @return The current justification value for this object. + */ + public int getAlignment () + { + return align; + } + + /** + * Returns the horizontal gap between components. + * + * @return The horizontal gap between components. + */ + public int getHgap () + { + return hgap; + } + + /** + * Returns the vertical gap between lines of components. + * + * @return The vertical gap between lines of components. + */ + public int getVgap () + { + return vgap; + } + + /** + * Initializes a new instance of FlowLayout with a center + * justification and a default horizontal and vertical gap of 5. + */ + public FlowLayout () + { + this (CENTER, 5, 5); + } + + /** + * Initializes a new instance of FlowLayout with the specified + * justification and a default horizontal and vertical gap of 5. + * + * @param align The justification setting, which should be one of the + * contants in this class. + */ + public FlowLayout (int align) + { + this (align, 5, 5); + } + + /** + * Initializes a new instance of FlowLayout with the specified + * justification and gap values + * @param align Alignment + * @param hgap The horizontal gap + * @param vgap The vertical gap + * @exception IllegalArgumentException If either gap is negative + */ + public FlowLayout (int align, int hgap, int vgap) + { + // Use methods to set fields so that we can have all the checking + // in one place. + setVgap (vgap); + setHgap (hgap); + setAlignment (align); + } + + /** Lay out the container's components based on current settings. + * @param parent The parent container + */ + public void layoutContainer (Container parent) + { + synchronized (parent.getTreeLock ()) + { + int num = parent.getComponentCount (); + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + Dimension d = parent.getSize (); + Insets ins = parent.getInsets (); + + ComponentOrientation orient = parent.getComponentOrientation (); + boolean left_to_right = orient.isLeftToRight (); + + int y = ins.top + vgap; + int i = 0; + while (i < num) + { + // Find the components which go in the current row. + int new_w = ins.left + hgap + ins.right; + int new_h = 0; + int j; + boolean found_one = false; + for (j = i; j < num; ++j) + { + // Skip invisible items. + if (! comps[j].visible) + continue; + + Dimension c = comps[j].getPreferredSize (); + + int next_w = new_w + hgap + c.width; + if (next_w <= d.width || ! found_one) + { + new_w = next_w; + new_h = Math.max (new_h, c.height); + found_one = true; + } + else + { + // Must start a new row, and we already found an item + break; + } + } + + // Set the location of each component for this row. + int x; + + int myalign = align; + if (align == LEADING) + myalign = left_to_right ? LEFT : RIGHT; + else if (align == TRAILING) + myalign = left_to_right ? RIGHT : LEFT; + + if (myalign == LEFT) + x = ins.left + hgap; + else if (myalign == CENTER) + x = ins.left + (d.width - new_w) / 2 + hgap; + else + x = ins.left + (d.width - new_w) + hgap; + + for (int k = i; k < j; ++k) + { + if (comps[k].visible) + { + Dimension c = comps[k].getPreferredSize (); + comps[k].setBounds (x, y + (new_h - c.height) / 2, + c.width, c.height); + x += c.width + hgap; + } + } + + // Advance to next row. + i = j; + y += new_h + vgap; + } + } + } + + /** + * Returns the minimum layout size for the specified container using + * this layout. + * @param cont The parent container + * @return The minimum layout size. + */ + public Dimension minimumLayoutSize (Container cont) + { + return getSize (cont, true); + } + + /** + * Returns the preferred layout size for the specified container using + * this layout. + * @param cont The parent container + * @return The preferred layout size. + */ + public Dimension preferredLayoutSize (Container cont) + { + return getSize (cont, false); + } + + /** Remove the indicated component from this layout manager. + * This particular implementation does nothing. + * @param comp The component to remove + */ + public void removeLayoutComponent (Component comp) + { + // Nothing. + } + + /** + * Sets the justification value for this object to the specified value. + * + * @param align The new justification value for this object, which must + * be one of the constants in this class. + */ + public void setAlignment (int align) + { + if (align != LEFT && align != RIGHT && align != CENTER + && align != LEADING && align != TRAILING) + throw new IllegalArgumentException ("invalid alignment: " + align); + this.align = align; + } + + /** + * Sets the horizontal gap between components to the specified value. + * + * @param hgap The new horizontal gap between components. + */ + public void setHgap (int hgap) + { + if (hgap < 0) + throw new IllegalArgumentException ("horizontal gap must be nonnegative"); + this.hgap = hgap; + } + + /** + * Sets the vertical gap between lines of components to the specified value. + * + * @param vgap The new vertical gap. + */ + public void setVgap (int vgap) + { + if (vgap < 0) + throw new IllegalArgumentException ("vertical gap must be nonnegative"); + this.vgap = vgap; + } + + /** Return String description of this object. + * @return A string representation of this object. + */ + public String toString () + { + return ("[" + getClass ().getName () + ",hgap=" + hgap + ",vgap=" + vgap + + ",align=" + align + "]"); + } + + // This method is used to compute the various sizes. + private Dimension getSize (Container parent, boolean is_min) + { + synchronized (parent.getTreeLock ()) + { + int w, h, num = parent.getComponentCount (); + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + w = 0; + h = 0; + for (int i = 0; i < num; ++i) + { + if (! comps[i].visible) + continue; + + // FIXME: can we just directly read the fields in Component? + // Or will that not work with subclassing? + Dimension d; + + if (is_min) + d = comps[i].getMinimumSize (); + else + d = comps[i].getPreferredSize (); + + w += d.width; + h = Math.max (d.height, h); + } + + Insets ins = parent.getInsets (); + + w += (num + 1) * hgap + ins.left + ins.right; + h += 2 * vgap + ins.top + ins.bottom; + + return new Dimension (w, h); + } + } + + /** + * @serial The justification alignment of the lines of components, which + * will be one of the constants defined in this class. + */ + private int align; + + /** + * @serial The horizontal gap between components. + */ + private int hgap; + + /** + * @serial The vertical gap between lines of components. + */ + private int vgap; +} diff --git a/libjava/classpath/java/awt/FocusTraversalPolicy.java b/libjava/classpath/java/awt/FocusTraversalPolicy.java new file mode 100644 index 0000000..a7f1558 --- /dev/null +++ b/libjava/classpath/java/awt/FocusTraversalPolicy.java @@ -0,0 +1,103 @@ +/* FocusTraversalPolicy.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 java.awt; + +/** + * @since 1.4 + */ +public abstract class FocusTraversalPolicy +{ + /** + * Creates a FocusTraversalPolicy object. + */ + public FocusTraversalPolicy() + { + // Do nothing in here. + } + + /** + * Returns the Component that should receive the focus after a Component. + * + * @exception IllegalArgumentException If root or current is null, + * or if root is not a focus cycle root of current. + */ + public abstract Component getComponentAfter(Container root, + Component current); + + /** + * Returns the Component that should receive the focus before a Component. + * + * @exception IllegalArgumentException If root or current is null, + * or if root is not a focus cycle root of current. + */ + public abstract Component getComponentBefore(Container root, + Component current); + + /** + * Returns the first Component in the traversal cycle. + * + * @exception IllegalArgumentException If root is null. + */ + public abstract Component getFirstComponent(Container root); + + /** + * Returns the last Component in the traversal cycle. + * + * @exception IllegalArgumentException If root is null. + */ + public abstract Component getLastComponent(Container root); + + /** + * Returns the default Component to focus. + * + * @exception IllegalArgumentException If root is null. + */ + public abstract Component getDefaultComponent(Container root); + + /** + * Returns the Component that should receive the focus when a Window is made + * visible for the first time. + * + * @exception IllegalArgumentException If window is null. + */ + public Component getInitialComponent(Window window) + { + return getDefaultComponent(window); + } +} // class FocusTraversalPolicy diff --git a/libjava/classpath/java/awt/Font.java b/libjava/classpath/java/awt/Font.java new file mode 100644 index 0000000..30961ab --- /dev/null +++ b/libjava/classpath/java/awt/Font.java @@ -0,0 +1,1336 @@ +/* Font.java -- Font object + Copyright (C) 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 java.awt; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.peer.ClasspathFontPeer; + +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.peer.FontPeer; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.text.AttributedCharacterIterator; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * This class represents a windowing system font. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @author Graydon Hoare (graydon@redhat.com) + */ +public class Font implements Serializable +{ + +/* + * Static Variables + */ + +/** + * Constant indicating a "plain" font. + */ +public static final int PLAIN = 0; + +/** + * Constant indicating a "bold" font. + */ +public static final int BOLD = 1; + +/** + * Constant indicating an "italic" font. + */ +public static final int ITALIC = 2; + +/** + * Constant indicating the baseline mode characteristic of Roman. + */ +public static final int ROMAN_BASELINE = 0; + +/** + * Constant indicating the baseline mode characteristic of Chinese. + */ +public static final int CENTER_BASELINE = 1; + +/** + * Constant indicating the baseline mode characteristic of Devanigri. + */ +public static final int HANGING_BASELINE = 2; + + + /** + * Indicates to createFont that the supplied font data + * is in TrueType format. + * + *

Specification Note: The Sun JavaDoc for J2SE 1.4 does + * not indicate whether this value also subsumes OpenType. OpenType + * is essentially the same format as TrueType, but allows to define + * glyph shapes in the same way as PostScript, using cubic bezier + * curves. + * + * @since 1.3 + */ + public static final int TRUETYPE_FONT = 0; + + + /** + * A flag for layoutGlyphVector, indicating that the + * orientation of a text run is from left to right. + * + * @since 1.4 + */ + public static final int LAYOUT_LEFT_TO_RIGHT = 0; + + + /** + * A flag for layoutGlyphVector, indicating that the + * orientation of a text run is from right to left. + * + * @since 1.4 + */ + public static final int LAYOUT_RIGHT_TO_LEFT = 1; + + + /** + * A flag for layoutGlyphVector, indicating that the + * text does not contain valid characters before the + * start position. If this flag is set, + * layoutGlyphVector does not examine the text before + * start, even if this would be necessary to select the + * correct glyphs (e.g., for Arabic text). + * + * @since 1.4 + */ + public static final int LAYOUT_NO_START_CONTEXT = 2; + + + /** + * A flag for layoutGlyphVector, indicating that the + * text does not contain valid characters after the + * limit position. If this flag is set, + * layoutGlyphVector does not examine the text after + * limit, even if this would be necessary to select the + * correct glyphs (e.g., for Arabic text). + * + * @since 1.4 + */ + public static final int LAYOUT_NO_LIMIT_CONTEXT = 4; + + /** + * The logical name of this font. + * + * @since 1.0 + */ + protected String name; + + /** + * The size of this font in pixels. + * + * @since 1.0 + */ + protected int size; + + /** + * The style of this font -- PLAIN, BOLD, ITALIC or BOLD+ITALIC. + * + * @since 1.0 + */ + protected int style; + +// Serialization constant +private static final long serialVersionUID = -4206021311591459213L; + + + // The ClasspathToolkit-provided peer which implements this font + private ClasspathFontPeer peer; + +/*************************************************************************/ + +/* + * Static Methods + */ + +/** + * Creates a Font object from the specified string, which + * is in one of the following formats: + *

+ *

+ *

+ * The style should be one of BOLD, ITALIC, or BOLDITALIC. The default + * style if none is specified is PLAIN. The default size if none + * is specified is 12. + * + * @param fontspec a string specifying the required font (null + * permitted, interpreted as 'Dialog-PLAIN-12'). + * + * @return A font. + */ + public static Font decode (String fontspec) +{ + if (fontspec == null) + fontspec = "Dialog-PLAIN-12"; + String name = null; + int style = PLAIN; + int size = 12; + + StringTokenizer st = new StringTokenizer(fontspec, "- "); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (name == null) + { + name = token; + continue; + } + + if (token.toUpperCase().equals("BOLD")) + { + style = BOLD; + continue; + } + if (token.toUpperCase().equals("ITALIC")) + { + style = ITALIC; + continue; + } + if (token.toUpperCase().equals("BOLDITALIC")) + { + style = BOLD | ITALIC; + continue; + } + + int tokenval = 0; + try + { + tokenval = Integer.parseInt(token); + } + catch(NumberFormatException e) + { + // Ignored. + } + + if (tokenval != 0) + size = tokenval; + } + + HashMap attrs = new HashMap(); + ClasspathFontPeer.copyStyleToAttrs (style, attrs); + ClasspathFontPeer.copySizeToAttrs (size, attrs); + + return getFontFromToolkit (name, attrs); +} + + /* These methods delegate to the toolkit. */ + + protected static ClasspathToolkit tk () + { + return (ClasspathToolkit)(Toolkit.getDefaultToolkit ()); + } + + /* Every factory method in Font should eventually call this. */ + protected static Font getFontFromToolkit (String name, Map attribs) + { + return tk ().getFont (name, attribs); + } + + /* Every Font constructor should eventually call this. */ + protected static ClasspathFontPeer getPeerFromToolkit (String name, Map attrs) + { + return tk ().getClasspathFontPeer (name, attrs); + } + + +/*************************************************************************/ + +/** + * Returns a Font object from the passed property name. + * + * @param propname The name of the system property. + * @param defval Value to use if the property is not found. + * + * @return The requested font, or default if the property + * not exist or is malformed. + */ + public static Font getFont (String propname, Font defval) +{ + String propval = System.getProperty(propname); + if (propval != null) + return decode (propval); + return defval; +} + +/*************************************************************************/ + +/** + * Returns a Font object from the passed property name. + * + * @param propname The name of the system property. + * + * @return The requested font, or null if the property + * not exist or is malformed. + */ + public static Font getFont (String propname) +{ + return getFont (propname, (Font)null); +} + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of Font with the specified + * attributes. + * + * @param name The name of the font. + * @param style The font style. + * @param size The font point size. + */ + + public Font (String name, int style, int size) + { + HashMap attrs = new HashMap(); + ClasspathFontPeer.copyStyleToAttrs (style, attrs); + ClasspathFontPeer.copySizeToAttrs (size, attrs); + this.peer = getPeerFromToolkit (name, attrs); + } + + public Font (Map attrs) + { + this(null, attrs); + } + + /* This extra constructor is here to permit ClasspathToolkit and to build + a font with a "logical name" as well as attrs. */ + public Font (String name, Map attrs) + { + // If attrs is null, setting it to an empty HashMap will give this + // Font default attributes. + if (attrs == null) + attrs = new HashMap(); + this.peer = getPeerFromToolkit (name, attrs); + } + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the logical name of the font. A logical name is the name the + * font was constructed with. It may be the name of a logical font (one + * of 6 required names in all java environments) or it may be a face + * name. + * + * @return The logical name of the font. + * + * @see #getFamily() + * @see #getFontName() + */ + public String getName () +{ + return peer.getName (this); +} + +/*************************************************************************/ + +/** + * Returns the style of the font. + * + * @return The font style. + */ + public int getSize () +{ + return (int) peer.getSize (this); +} + + public float getSize2D () +{ + return peer.getSize (this); +} + +/*************************************************************************/ + +/** + * Tests whether or not this is a plain font. This will be true if + * and only if neither the bold nor the italics style is set. + * + * @return true if this is a plain font, false + * otherwise. + */ + public boolean isPlain () +{ + return peer.isPlain (this); +} + +/*************************************************************************/ + +/** + * Tests whether or not this font is bold. + * + * @return true if this font is bold, false + * otherwise. + */ + public boolean isBold () +{ + return peer.isBold (this); +} + +/*************************************************************************/ + +/** + * Tests whether or not this font is italic. + * + * @return true if this font is italic, false + * otherwise. + */ + public boolean isItalic () +{ + return peer.isItalic (this); +} + +/*************************************************************************/ + +/** + * Returns the family name of this font. A family name describes a design + * or "brand name" (such as Helvetica or Palatino). It is less specific + * than a font face name (such as Helvetica Bold). + * + * @return A string containing the font family name. + * + * @since 1.2 + * + * @see #getName() + * @see #getFontName() + * @see GraphicsEnvironment#getAvailableFontFamilyNames() + */ + public String getFamily () +{ + return peer.getFamily (this); +} + +/** + * Returns integer code representing the sum of style flags of this font, a + * combination of either {@link #PLAIN}, {@link #BOLD}, or {@link #ITALIC}. + * + * @return code representing the style of this font. + * + * @see #isPlain() + * @see #isBold() + * @see #isItalic() + */ + public int getStyle () +{ + return peer.getStyle (this); +} + +/** + * Checks if specified character maps to a glyph in this font. + * + * @param c The character to check. + * + * @return Whether the character has a corresponding glyph in this font. + * + * @since 1.2 + */ + public boolean canDisplay (char c) +{ + return peer.canDisplay (this, c); +} + +/** + * Checks how much of a given string can be mapped to glyphs in + * this font. + * + * @param s The string to check. + * + * @return The index of the first character in s which cannot + * be converted to a glyph by this font, or -1 if all + * characters can be mapped to glyphs. + * + * @since 1.2 + */ + public int canDisplayUpTo (String s) +{ + return peer.canDisplayUpTo (this, new StringCharacterIterator (s), + 0, s.length () - 1); +} + +/** + * Checks how much of a given sequence of text can be mapped to glyphs in + * this font. + * + * @param text Array containing the text to check. + * @param start Position of first character to check in text. + * @param limit Position of last character to check in text. + * + * @return The index of the first character in the indicated range which + * cannot be converted to a glyph by this font, or -1 if all + * characters can be mapped to glyphs. + * + * @since 1.2 + * + * @throws IndexOutOfBoundsException if the range [start, limit] is + * invalid in text. + */ + public int canDisplayUpTo (char[] text, int start, int limit) +{ + return peer.canDisplayUpTo + (this, new StringCharacterIterator (new String (text)), start, limit); +} + +/** + * Checks how much of a given sequence of text can be mapped to glyphs in + * this font. + * + * @param i Iterator over the text to check. + * @param start Position of first character to check in i. + * @param limit Position of last character to check in i. + * + * @return The index of the first character in the indicated range which + * cannot be converted to a glyph by this font, or -1 if all + * characters can be mapped to glyphs. + * + * @since 1.2 + * + * @throws IndexOutOfBoundsException if the range [start, limit] is + * invalid in i. + */ + public int canDisplayUpTo (CharacterIterator i, int start, int limit) +{ + return peer.canDisplayUpTo (this, i, start, limit); +} + +/** + * Creates a new font with point size 1 and {@link #PLAIN} style, + * reading font data from the provided input stream. The resulting font + * can have further fonts derived from it using its + * deriveFont method. + * + * @param fontFormat Integer code indicating the format the font data is + * in.Currently this can only be {@link #TRUETYPE_FONT}. + * @param is {@link InputStream} from which font data will be read. This + * stream is not closed after font data is extracted. + * + * @return A new {@link Font} of the format indicated. + * + * @throws IllegalArgumentException if fontType is not + * recognized. + * @throws FontFormatException if data in InputStream is not of format + * indicated. + * @throws IOException if insufficient data is present on InputStream. + * + * @since 1.3 + */ + public static Font createFont (int fontFormat, InputStream is) + throws FontFormatException, IOException +{ + return tk().createFont (fontFormat, is); +} + +/** + * Maps characters to glyphs in a one-to-one relationship, returning a new + * {@link GlyphVector} with a mapped glyph for each input character. This + * sort of mapping is often sufficient for some scripts such as Roman, but + * is inappropriate for scripts with special shaping or contextual layout + * requirements such as Arabic, Indic, Hebrew or Thai. + * + * @param ctx The rendering context used for precise glyph placement. + * @param str The string to convert to Glyphs. + * + * @return A new {@link GlyphVector} containing glyphs mapped from str, + * through the font's cmap table. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + */ + public GlyphVector createGlyphVector (FontRenderContext ctx, String str) +{ + return peer.createGlyphVector (this, ctx, new StringCharacterIterator (str)); +} + +/** + * Maps characters to glyphs in a one-to-one relationship, returning a new + * {@link GlyphVector} with a mapped glyph for each input character. This + * sort of mapping is often sufficient for some scripts such as Roman, but + * is inappropriate for scripts with special shaping or contextual layout + * requirements such as Arabic, Indic, Hebrew or Thai. + * + * @param ctx The rendering context used for precise glyph placement. + * @param i Iterator over the text to convert to glyphs. + * + * @return A new {@link GlyphVector} containing glyphs mapped from str, + * through the font's cmap table. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + */ + public GlyphVector createGlyphVector (FontRenderContext ctx, CharacterIterator i) +{ + return peer.createGlyphVector (this, ctx, i); +} + +/** + * Maps characters to glyphs in a one-to-one relationship, returning a new + * {@link GlyphVector} with a mapped glyph for each input character. This + * sort of mapping is often sufficient for some scripts such as Roman, but + * is inappropriate for scripts with special shaping or contextual layout + * requirements such as Arabic, Indic, Hebrew or Thai. + * + * @param ctx The rendering context used for precise glyph placement. + * @param chars Array of characters to convert to glyphs. + * + * @return A new {@link GlyphVector} containing glyphs mapped from str, + * through the font's cmap table. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + */ + public GlyphVector createGlyphVector (FontRenderContext ctx, char[] chars) +{ + return peer.createGlyphVector + (this, ctx, new StringCharacterIterator (new String (chars))); +} + +/** + * Extracts a sequence of glyphs from a font, returning a new {@link + * GlyphVector} with a mapped glyph for each input glyph code. + * + * @param ctx The rendering context used for precise glyph placement. + * @param glyphCodes Array of characters to convert to glyphs. + * + * @return A new {@link GlyphVector} containing glyphs mapped from str, + * through the font's cmap table. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + * + * @specnote This method is documented to perform character-to-glyph + * conversions, in the Sun documentation, but its second parameter name is + * "glyphCodes" and it is not clear to me why it would exist if its + * purpose was to transport character codes inside integers. I assume it + * is mis-documented in the Sun documentation. + */ + + public GlyphVector createGlyphVector (FontRenderContext ctx, int[] glyphCodes) +{ + return peer.createGlyphVector (this, ctx, glyphCodes); +} + +/** + * Produces a new {@link Font} based on the current font, adjusted to a + * new size and style. + * + * @param style The style of the newly created font. + * @param size The size of the newly created font. + * + * @return A clone of the current font, with the specified size and style. + * + * @since 1.2 + */ + public Font deriveFont (int style, float size) +{ + return peer.deriveFont (this, style, size); +} + +/** + * Produces a new {@link Font} based on the current font, adjusted to a + * new size. + * + * @param size The size of the newly created font. + * + * @return A clone of the current font, with the specified size. + * + * @since 1.2 + */ + public Font deriveFont (float size) +{ + return peer.deriveFont (this, size); +} + +/** + * Produces a new {@link Font} based on the current font, adjusted to a + * new style. + * + * @param style The style of the newly created font. + * + * @return A clone of the current font, with the specified style. + * + * @since 1.2 + */ + public Font deriveFont (int style) +{ + return peer.deriveFont (this, style); +} + +/** + * Produces a new {@link Font} based on the current font, adjusted to a + * new style and subjected to a new affine transformation. + * + * @param style The style of the newly created font. + * @param a The transformation to apply. + * + * @return A clone of the current font, with the specified style and + * transform. + * + * @throws IllegalArgumentException If transformation is + * null. + * + * @since 1.2 + */ + public Font deriveFont (int style, AffineTransform a) +{ + if (a == null) + throw new IllegalArgumentException ("Affine transformation is null"); + + return peer.deriveFont (this, style, a); +} + +/** + * Produces a new {@link Font} based on the current font, subjected + * to a new affine transformation. + * + * @param a The transformation to apply. + * + * @return A clone of the current font, with the specified transform. + * + * @throws IllegalArgumentException If transformation is + * null. + * + * @since 1.2 + */ + public Font deriveFont (AffineTransform a) +{ + if (a == null) + throw new IllegalArgumentException ("Affine transformation is null"); + + return peer.deriveFont (this, a); +} + +/** + * Produces a new {@link Font} based on the current font, adjusted to a + * new set of attributes. + * + * @param attributes Attributes of the newly created font. + * + * @return A clone of the current font, with the specified attributes. + * + * @since 1.2 + */ + public Font deriveFont (Map attributes) +{ + return peer.deriveFont (this, attributes); +} + +/** + * Returns a map of chracter attributes which this font currently has set. + * + * @return A map of chracter attributes which this font currently has set. + * + * @see #getAvailableAttributes() + * @see java.text.AttributedCharacterIterator.Attribute + * @see java.awt.font.TextAttribute + */ + public Map getAttributes () +{ + return peer.getAttributes (this); +} + +/** + * Returns an array of chracter attribute keys which this font understands. + * + * @return An array of chracter attribute keys which this font understands. + * + * @see #getAttributes() + * @see java.text.AttributedCharacterIterator.Attribute + * @see java.awt.font.TextAttribute + */ + public AttributedCharacterIterator.Attribute[] getAvailableAttributes() +{ + return peer.getAvailableAttributes (this); +} + +/** + * Returns a baseline code (one of {@link #ROMAN_BASELINE}, {@link + * #CENTER_BASELINE} or {@link #HANGING_BASELINE}) indicating which baseline + * this font will measure baseline offsets for, when presenting glyph + * metrics for a given character. + * + * Baseline offsets describe the position of a glyph relative to an + * invisible line drawn under, through the center of, or over a line of + * rendered text, respectively. Different scripts use different baseline + * modes, so clients should not assume all baseline offsets in a glyph + * vector are from a common baseline. + * + * @param c The character code to select a baseline mode for. + * + * @return The baseline mode which would be used in a glyph associated + * with the provided character. + * + * @since 1.2 + * + * @see LineMetrics#getBaselineOffsets() + */ + public byte getBaselineFor (char c) +{ + return peer.getBaselineFor (this, c); +} + +/** + * Returns the family name of this font. A family name describes a + * typographic style (such as Helvetica or Palatino). It is more specific + * than a logical font name (such as Sans Serif) but less specific than a + * font face name (such as Helvetica Bold). + * + * @param lc The locale in which to describe the name of the font family. + * + * @return A string containing the font family name, localized for the + * provided locale. + * + * @since 1.2 + * + * @see #getName() + * @see #getFontName() + * @see GraphicsEnvironment#getAvailableFontFamilyNames() + * @see Locale + */ + public String getFamily (Locale lc) +{ + return peer.getFamily (this, lc); +} + +/** + * Returns a font appropriate for the given attribute set. + * + * @param attributes The attributes required for the new font. + * + * @return A new Font with the given attributes. + * + * @since 1.2 + * + * @see java.awt.font.TextAttribute + */ + public static Font getFont (Map attributes) +{ + return getFontFromToolkit (null, attributes); +} + +/** + * Returns the font face name of the font. A font face name describes a + * specific variant of a font family (such as Helvetica Bold). It is more + * specific than both a font family name (such as Helvetica) and a logical + * font name (such as Sans Serif). + * + * @return The font face name of the font. + * + * @since 1.2 + * + * @see #getName() + * @see #getFamily() + */ + public String getFontName () +{ + return peer.getFontName (this); +} + +/** + * Returns the font face name of the font. A font face name describes a + * specific variant of a font family (such as Helvetica Bold). It is more + * specific than both a font family name (such as Helvetica). + * + * @param lc The locale in which to describe the name of the font face. + * + * @return A string containing the font face name, localized for the + * provided locale. + * + * @since 1.2 + * + * @see #getName() + * @see #getFamily() + */ + public String getFontName (Locale lc) +{ + return peer.getFontName (this, lc); +} + +/** + * Returns the italic angle of this font, a measurement of its slant when + * style is {@link #ITALIC}. The precise meaning is the inverse slope of a + * caret line which "best measures" the font's italic posture. + * + * @return The italic angle. + * + * @see java.awt.font.TextAttribute#POSTURE + */ + public float getItalicAngle () +{ + return peer.getItalicAngle (this); +} + +/** + * Returns a {@link LineMetrics} object constructed with the specified + * text and {@link FontRenderContext}. + * + * @param text The string to calculate metrics from. + * @param begin Index of first character in text to measure. + * @param limit Index of last character in text to measure. + * @param rc Context for calculating precise glyph placement and hints. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in text. + */ + public LineMetrics getLineMetrics(String text, int begin, + int limit, FontRenderContext rc) +{ + return peer.getLineMetrics (this, new StringCharacterIterator (text), + begin, limit, rc); +} + +/** + * Returns a {@link LineMetrics} object constructed with the specified + * text and {@link FontRenderContext}. + * + * @param chars The string to calculate metrics from. + * @param begin Index of first character in text to measure. + * @param limit Index of last character in text to measure. + * @param rc Context for calculating precise glyph placement and hints. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in chars. + */ + public LineMetrics getLineMetrics(char[] chars, int begin, + int limit, FontRenderContext rc) +{ + return peer.getLineMetrics (this, new StringCharacterIterator (new String(chars)), + begin, limit, rc); +} + +/** + * Returns a {@link LineMetrics} object constructed with the specified + * text and {@link FontRenderContext}. + * + * @param ci The string to calculate metrics from. + * @param begin Index of first character in text to measure. + * @param limit Index of last character in text to measure. + * @param rc Context for calculating precise glyph placement and hints. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in ci. + */ + public LineMetrics getLineMetrics (CharacterIterator ci, int begin, + int limit, FontRenderContext rc) +{ + return peer.getLineMetrics (this, ci, begin, limit, rc); +} + +/** + * Returns the maximal bounding box of all the bounding boxes in this + * font, when the font's bounding boxes are evaluated in a given {@link + * FontRenderContext} + * + * @param rc Context in which to evaluate bounding boxes. + * + * @return The maximal bounding box. + */ + public Rectangle2D getMaxCharBounds (FontRenderContext rc) +{ + return peer.getMaxCharBounds (this, rc); +} + +/** + * Returns the glyph code this font uses to represent missing glyphs. This + * code will be present in glyph vectors when the font was unable to + * locate a glyph to represent a particular character code. + * + * @return The missing glyph code. + * + * @since 1.2 + */ + public int getMissingGlyphCode () +{ + return peer.getMissingGlyphCode (this); +} + +/** + * Returns the overall number of glyphs in this font. This number is one + * more than the greatest glyph code used in any glyph vectors this font + * produces. In other words, glyph codes are taken from the range + * [ 0, getNumGlyphs() - 1 ]. + * + * @return The number of glyphs in this font. + * + * @since 1.2 + */ + public int getNumGlyphs () +{ + return peer.getMissingGlyphCode (this); +} + +/** + * Returns the PostScript Name of this font. + * + * @return The PostScript Name of this font. + * + * @since 1.2 + * + * @see #getName() + * @see #getFamily() + * @see #getFontName() + */ + public String getPSName () +{ + return peer.getPostScriptName (this); +} + +/** + * Returns the logical bounds of the specified string when rendered with this + * font in the specified {@link FontRenderContext}. This box will include the + * glyph origin, ascent, advance, height, and leading, but may not include all + * diacritics or accents. To get the complete visual bounding box of all the + * glyphs in a run of text, use the {@link TextLayout#getBounds} method of + * {@link TextLayout}. + * + * @param str The string to measure. + * @param frc The context in which to make the precise glyph measurements. + * + * @return A bounding box covering the logical bounds of the specified text. + * + * @see #createGlyphVector(FontRenderContext, String) + */ + public Rectangle2D getStringBounds (String str, FontRenderContext frc) +{ + return getStringBounds (str, 0, str.length () - 1, frc); +} + +/** + * Returns the logical bounds of the specified string when rendered with this + * font in the specified {@link FontRenderContext}. This box will include the + * glyph origin, ascent, advance, height, and leading, but may not include all + * diacritics or accents. To get the complete visual bounding box of all the + * glyphs in a run of text, use the {@link TextLayout#getBounds} method of + * {@link TextLayout}. + * + * @param str The string to measure. + * @param begin Index of the first character in str to measure. + * @param limit Index of the last character in str to measure. + * @param frc The context in which to make the precise glyph measurements. + * + * @return A bounding box covering the logical bounds of the specified text. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in str. + * + * @since 1.2 + * + * @see #createGlyphVector(FontRenderContext, String) + */ + public Rectangle2D getStringBounds (String str, int begin, + int limit, FontRenderContext frc) +{ + return peer.getStringBounds (this, new StringCharacterIterator(str), begin, limit, frc); +} + +/** + * Returns the logical bounds of the specified string when rendered with this + * font in the specified {@link FontRenderContext}. This box will include the + * glyph origin, ascent, advance, height, and leading, but may not include all + * diacritics or accents. To get the complete visual bounding box of all the + * glyphs in a run of text, use the {@link TextLayout#getBounds} method of + * {@link TextLayout}. + * + * @param ci The text to measure. + * @param begin Index of the first character in ci to measure. + * @param limit Index of the last character in ci to measure. + * @param frc The context in which to make the precise glyph measurements. + * + * @return A bounding box covering the logical bounds of the specified text. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in ci. + * + * @since 1.2 + * + * @see #createGlyphVector(FontRenderContext, CharacterIterator) + */ + public Rectangle2D getStringBounds (CharacterIterator ci, int begin, + int limit, FontRenderContext frc) +{ + return peer.getStringBounds (this, ci, begin, limit, frc); +} + +/** + * Returns the logical bounds of the specified string when rendered with this + * font in the specified {@link FontRenderContext}. This box will include the + * glyph origin, ascent, advance, height, and leading, but may not include all + * diacritics or accents. To get the complete visual bounding box of all the + * glyphs in a run of text, use the {@link TextLayout#getBounds} method of + * {@link TextLayout}. + * + * @param chars The text to measure. + * @param begin Index of the first character in ci to measure. + * @param limit Index of the last character in ci to measure. + * @param frc The context in which to make the precise glyph measurements. + * + * @return A bounding box covering the logical bounds of the specified text. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in chars. + * + * @since 1.2 + * + * @see #createGlyphVector(FontRenderContext, char[]) + */ + public Rectangle2D getStringBounds (char[] chars, int begin, + int limit, FontRenderContext frc) +{ + return peer.getStringBounds (this, new StringCharacterIterator (new String (chars)), + begin, limit, frc); +} + +/** + * Returns a copy of the affine transformation this font is currently + * subject to, if any. + * + * @return The current transformation. + */ + public AffineTransform getTransform () +{ + return peer.getTransform (this); +} + +/** + * Indicates whether this font's line metrics are uniform. A font may be + * composed of several "subfonts", each covering a different code range, + * and each with their own line metrics. A font with no subfonts, or + * subfonts with identical line metrics, is said to have "uniform" line + * metrics. + * + * @return Whether this font has uniform line metrics. + * + * @see LineMetrics + * @see #getLineMetrics(String, FontRenderContext) + */ + public boolean hasUniformLineMetrics () +{ + return peer.hasUniformLineMetrics (this); +} + +/** + * Indicates whether this font is subject to a non-identity affine + * transformation. + * + * @return true iff the font has a non-identity affine + * transformation applied to it. + */ + public boolean isTransformed () +{ + return peer.isTransformed (this); +} + +/** + * Produces a glyph vector representing a full layout fo the specified + * text in this font. Full layouts may include complex shaping and + * reordering operations, for scripts such as Arabic or Hindi. + * + * Bidirectional (bidi) layout is not performed in this method; text + * should have its bidi direction specified with one of the flags {@link + * #LAYOUT_LEFT_TO_RIGHT} or {@link #LAYOUT_RIGHT_TO_LEFT}. + * + * Some types of layout (notably Arabic glyph shaping) may examine context + * characters beyond the bounds of the indicated range, in order to select + * an appropriate shape. The flags {@link #LAYOUT_NO_START_CONTEXT} and + * {@link #LAYOUT_NO_LIMIT_CONTEXT} can be provided to prevent these extra + * context areas from being examined, for instance if they contain invalid + * characters. + * + * @param frc Context in which to perform the layout. + * @param chars Text to perform layout on. + * @param start Index of first character to perform layout on. + * @param limit Index of last character to perform layout on. + * @param flags Combination of flags controlling layout. + * + * @return A new {@link GlyphVector} representing the specified text. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in chars. + */ + public GlyphVector layoutGlyphVector (FontRenderContext frc, + char[] chars, int start, + int limit, int flags) +{ + return peer.layoutGlyphVector (this, frc, chars, start, limit, flags); +} + + +/** + * Returns a native peer object for this font. + * + * @return A native peer object for this font. + * + * @deprecated + */ + public FontPeer getPeer () +{ + return peer; +} + + +/** + * Returns a hash value for this font. + * + * @return A hash for this font. + */ + public int hashCode() +{ + return this.toString().hashCode(); +} + + +/** + * Tests whether or not the specified object is equal to this font. This + * will be true if and only if: + *

+ *

+ * + * @return true if the specified object is equal to this + * object, false otherwise. + */ +public boolean +equals(Object obj) +{ + if (obj == null) + return(false); + + if (!(obj instanceof Font)) + return(false); + + Font f = (Font)obj; + + return (f.getName ().equals (this.getName ()) && + f.getFamily ().equals (this.getFamily ()) && + f.getFontName ().equals (this.getFontName ()) && + f.getTransform ().equals (this.getTransform ()) && + f.getSize() == this.getSize() && + f.getStyle() == this.getStyle()); +} + +/*************************************************************************/ + +/** + * Returns a string representation of this font. + * + * @return A string representation of this font. + */ +public String +toString() +{ + String styleString = ""; + + switch (getStyle ()) + { + case 0: + styleString = "plain"; + break; + case 1: + styleString = "bold"; + break; + case 2: + styleString = "italic"; + break; + default: + styleString = "unknown"; + } + + return getClass ().getName () + + "[family=" + getFamily () + + ",name=" + getFontName () + + ",style=" + styleString + + ",size=" + getSize () + "]"; +} + + + /** + * Determines the line metrics for a run of text. + * + * @param str the text run to be measured. + * + * @param frc the font rendering parameters that are used for the + * measurement. The exact placement and size of text slightly + * depends on device-specific characteristics, for instance + * the device resolution or anti-aliasing. For this reason, + * the returned measurement 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. + * + * @see java.awt.Graphics2D#getFontRenderContext() + */ + public LineMetrics getLineMetrics(String str, FontRenderContext frc) + { + return getLineMetrics (str, 0, str.length () - 1, frc); + } + +} // class Font + diff --git a/libjava/classpath/java/awt/FontFormatException.java b/libjava/classpath/java/awt/FontFormatException.java new file mode 100644 index 0000000..6ec8757 --- /dev/null +++ b/libjava/classpath/java/awt/FontFormatException.java @@ -0,0 +1,65 @@ +/* FontFormatException.java -- the specified font is bad + 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 java.awt; + +/** + * Thrown when a specified font is bad. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Font + * @since 1.3 + * @status updated to 1.4 + */ +public class FontFormatException extends Exception +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = -4481290147811361272L; + + /** + * Create a new instance with the specified detailed error message. + * + * @param message the detailed error message + */ + public FontFormatException(String message) + { + super(message); + } +} // class FontFormatException diff --git a/libjava/classpath/java/awt/FontMetrics.java b/libjava/classpath/java/awt/FontMetrics.java new file mode 100644 index 0000000..e702a62 --- /dev/null +++ b/libjava/classpath/java/awt/FontMetrics.java @@ -0,0 +1,425 @@ +/* FontMetrics.java -- Information about about a fonts display characteristics + Copyright (C) 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 java.awt; + +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.geom.Rectangle2D; +import java.text.CharacterIterator; + +// FIXME: I leave many methods basically unimplemented. This +// should be reviewed. + +/** + * This class returns information about the display characteristics of + * a font. It is abstract, and concrete subclasses should implement at + * least the following methods: + * + * + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class FontMetrics implements java.io.Serializable +{ + // Serialization constant. + private static final long serialVersionUID = 1681126225205050147L; + + /** + * This is the font for which metrics will be returned. + */ + protected Font font; + + /** + * Initializes a new instance of FontMetrics for the + * specified font. + * + * @param font The font to return metric information for. + */ + protected FontMetrics(Font font) + { + this.font = font; + } + + /** + * Returns the font that this object is creating metric information fo. + * + * @return The font for this object. + */ + public Font getFont() + { + return font; + } + + /** + * Returns the leading, or spacing between lines, for this font. + * + * @return The font leading. + */ + public int getLeading() + { + return 0; + } + + /** + * Returns the ascent of the font, which is the distance from the base + * to the top of the majority of characters in the set. Some characters + * can exceed this value however. + * + * @return The font ascent. + */ + public int getAscent() + { + return 1; + } + + /** + * Returns the descent of the font, which is the distance from the base + * to the bottom of the majority of characters in the set. Some characters + * can exceed this value however. + * + * @return The font descent. + */ + public int getDescent() + { + return 1; + } + + /** + * Returns the height of a line in this font. This will be the sum + * of the leading, the ascent, and the descent. + * + * @return The height of the font. + */ + public int getHeight() + { + return getAscent() + getDescent() + getLeading(); + } + + /** + * Returns the maximum ascent value. This is the maximum distance any + * character in the font rised above the baseline. + * + * @return The maximum ascent for this font. + */ + public int getMaxAscent() + { + return getAscent(); + } + + /** + * Returns the maximum descent value. This is the maximum distance any + * character in the font extends below the baseline. + * + * @return The maximum descent for this font. + */ + public int getMaxDescent() + { + return getMaxDecent(); + } + + /** + * Returns the maximum descent value. This is the maximum distance any + * character in the font extends below the baseline. + * + * @return The maximum descent for this font. + * + * @deprecated This method is deprecated in favor of + * getMaxDescent(). + */ + public int getMaxDecent() + { + return getDescent(); + } + + /** + * Returns the width of the widest character in the font. + * + * @return The width of the widest character in the font. + */ + public int getMaxAdvance() + { + return -1; + } + + /** + * Returns the width of the specified character. + * + * @param ch The character to return the width of. + * + * @return The width of the specified character. + */ + public int charWidth(int ch) + { + return charWidth((char) ch); + } + + /** + * Returns the width of the specified character. + * + * @param ch The character to return the width of. + * + * @return The width of the specified character. + */ + public int charWidth(char ch) + { + return 1; + } + + /** + * Returns the total width of the specified string + * + * @param str The string to return the width of. + * + * @return The width of the string. + */ + public int stringWidth(String str) + { + char[] buf = new char[str.length()]; + str.getChars(0, str.length(), buf, 0); + + return charsWidth(buf, 0, buf.length); + } + + /** + * Returns the total width of the specified character array. + * + * @param buf The character array containing the data. + * @param offset The offset into the array to start calculating from. + * @param len The total number of bytes to process. + * + * @return The width of the requested characters. + */ + public int charsWidth(char[] buf, int offset, int len) + { + int total_width = 0; + for (int i = offset; i < len; i++) + total_width += charWidth(buf[i]); + return total_width; + } + + /** + * Returns the total width of the specified byte array. + * + * @param buf The byte array containing the data. + * @param offset The offset into the array to start calculating from. + * @param len The total number of bytes to process. + * + * @return The width of the requested characters. + */ + public int bytesWidth(byte[] buf, int offset, int len) + { + int total_width = 0; + for (int i = offset; i < len; i++) + total_width = charWidth((char) buf[i]); + + return total_width; + } + + /** + * Returns the widths of the first 256 characters in the font. + * + * @return The widths of the first 256 characters in the font. + */ + public int[] getWidths() + { + int[] result = new int[256]; + for (char i = 0; i < 256; i++) + result[i] = charWidth(i); + return result; + } + + /** + * Returns a string representation of this object. + * + * @return A string representation of this object. + */ + public String toString() + { + return (this.getClass() + "[font=" + font + ",ascent=" + getAscent() + + ",descent=" + getDescent() + ",height=" + getHeight() + "]"); + } + + // Generic FontRenderContext used when getLineMetrics is called with a + // plain Graphics object. + private static final FontRenderContext gRC = new FontRenderContext(null, + false, + false); + + /** + * Returns a {@link LineMetrics} object constructed with the + * specified text and the {@link FontRenderContext} of the Graphics + * object when it is an instance of Graphics2D or a generic + * FontRenderContext with a null transform, not anti-aliased and not + * using fractional metrics. + * + * @param text The string to calculate metrics from. + * @param g The Graphics object that will be used. + * + * @return A new {@link LineMetrics} object. + */ + public LineMetrics getLineMetrics(String text, Graphics g) + { + return getLineMetrics(text, 0, text.length(), g); + } + + /** + * Returns a {@link LineMetrics} object constructed with the + * specified text and the {@link FontRenderContext} of the Graphics + * object when it is an instance of Graphics2D or a generic + * FontRenderContext with a null transform, not anti-aliased and not + * using fractional metrics. + * + * @param text The string to calculate metrics from. + * @param begin Index of first character in text to measure. + * @param limit Index of last character in text to measure. + * @param g The Graphics object that will be used. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in text. + */ + public LineMetrics getLineMetrics(String text, int begin, int limit, + Graphics g) + { + FontRenderContext rc; + if (g instanceof Graphics2D) + rc = ((Graphics2D) g).getFontRenderContext(); + else + rc = gRC; + return font.getLineMetrics(text, begin, limit, rc); + } + + /** + * Returns a {@link LineMetrics} object constructed with the + * specified text and the {@link FontRenderContext} of the Graphics + * object when it is an instance of Graphics2D or a generic + * FontRenderContext with a null transform, not anti-aliased and not + * using fractional metrics. + * + * @param chars The string to calculate metrics from. + * @param begin Index of first character in text to measure. + * @param limit Index of last character in text to measure. + * @param g The Graphics object that will be used. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in text. + */ + public LineMetrics getLineMetrics(char[] chars, int begin, int limit, + Graphics g) + { + FontRenderContext rc; + if (g instanceof Graphics2D) + rc = ((Graphics2D) g).getFontRenderContext(); + else + rc = gRC; + return font.getLineMetrics(chars, begin, limit, rc); + } + + /** + * Returns a {@link LineMetrics} object constructed with the + * specified text and the {@link FontRenderContext} of the Graphics + * object when it is an instance of Graphics2D or a generic + * FontRenderContext with a null transform, not anti-aliased and not + * using fractional metrics. + * + * @param ci An iterator over the string to calculate metrics from. + * @param begin Index of first character in text to measure. + * @param limit Index of last character in text to measure. + * @param g The Graphics object that will be used. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in text. + */ + public LineMetrics getLineMetrics(CharacterIterator ci, int begin, + int limit, Graphics g) + { + FontRenderContext rc; + if (g instanceof Graphics2D) + rc = ((Graphics2D) g).getFontRenderContext(); + else + rc = gRC; + return font.getLineMetrics(ci, begin, limit, rc); + } + + public Rectangle2D getStringBounds(String str, Graphics context) + { + return font.getStringBounds(str, getFontRenderContext(context)); + } + + public Rectangle2D getStringBounds(String str, int beginIndex, int limit, + Graphics context) + { + return font.getStringBounds(str, beginIndex, limit, + getFontRenderContext(context)); + } + + public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, + Graphics context) + { + return font.getStringBounds(chars, beginIndex, limit, + getFontRenderContext(context)); + } + + public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, + int limit, Graphics context) + { + return font.getStringBounds(ci, beginIndex, limit, + getFontRenderContext(context)); + } + + private FontRenderContext getFontRenderContext(Graphics context) + { + if (context instanceof Graphics2D) + return ((Graphics2D) context).getFontRenderContext(); + + return gRC; + } +} diff --git a/libjava/classpath/java/awt/Frame.java b/libjava/classpath/java/awt/Frame.java new file mode 100644 index 0000000..0cb97f8 --- /dev/null +++ b/libjava/classpath/java/awt/Frame.java @@ -0,0 +1,649 @@ +/* Frame.java -- AWT toplevel window + Copyright (C) 1999, 2000, 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 java.awt; + +import java.awt.peer.FramePeer; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Vector; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * This class is a top-level window with a title bar and window + * decorations. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Frame extends Window implements MenuContainer +{ +/** + * Constant for the default cursor. + * @deprecated Replaced by Cursor.DEFAULT_CURSOR instead. + */ +public static final int DEFAULT_CURSOR = Cursor.DEFAULT_CURSOR; + +/** + * Constant for a cross-hair cursor. + * @deprecated Use Cursor.CROSSHAIR_CURSOR instead. + */ +public static final int CROSSHAIR_CURSOR = Cursor.CROSSHAIR_CURSOR; + +/** + * Constant for a cursor over a text field. + * @deprecated Use Cursor.TEXT_CURSOR instead. + */ +public static final int TEXT_CURSOR = Cursor.TEXT_CURSOR; + +/** + * Constant for a cursor to display while waiting for an action to complete. + * @deprecated Use Cursor.WAIT_CURSOR. + */ +public static final int WAIT_CURSOR = Cursor.WAIT_CURSOR; + +/** + * Cursor used over SW corner of window decorations. + * @deprecated Use Cursor.SW_RESIZE_CURSOR instead. + */ +public static final int SW_RESIZE_CURSOR = Cursor.SW_RESIZE_CURSOR; + +/** + * Cursor used over SE corner of window decorations. + * @deprecated Use Cursor.SE_RESIZE_CURSOR instead. + */ +public static final int SE_RESIZE_CURSOR = Cursor.SE_RESIZE_CURSOR; + +/** + * Cursor used over NW corner of window decorations. + * @deprecated Use Cursor.NW_RESIZE_CURSOR instead. + */ +public static final int NW_RESIZE_CURSOR = Cursor.NW_RESIZE_CURSOR; + +/** + * Cursor used over NE corner of window decorations. + * @deprecated Use Cursor.NE_RESIZE_CURSOR instead. + */ +public static final int NE_RESIZE_CURSOR = Cursor.NE_RESIZE_CURSOR; + +/** + * Cursor used over N edge of window decorations. + * @deprecated Use Cursor.N_RESIZE_CURSOR instead. + */ +public static final int N_RESIZE_CURSOR = Cursor.N_RESIZE_CURSOR; + +/** + * Cursor used over S edge of window decorations. + * @deprecated Use Cursor.S_RESIZE_CURSOR instead. + */ +public static final int S_RESIZE_CURSOR = Cursor.S_RESIZE_CURSOR; + +/** + * Cursor used over E edge of window decorations. + * @deprecated Use Cursor.E_RESIZE_CURSOR instead. + */ +public static final int E_RESIZE_CURSOR = Cursor.E_RESIZE_CURSOR; + +/** + * Cursor used over W edge of window decorations. + * @deprecated Use Cursor.W_RESIZE_CURSOR instead. + */ +public static final int W_RESIZE_CURSOR = Cursor.W_RESIZE_CURSOR; + +/** + * Constant for a hand cursor. + * @deprecated Use Cursor.HAND_CURSOR instead. + */ +public static final int HAND_CURSOR = Cursor.HAND_CURSOR; + +/** + * Constant for a cursor used during window move operations. + * @deprecated Use Cursor.MOVE_CURSOR instead. + */ +public static final int MOVE_CURSOR = Cursor.MOVE_CURSOR; + +public static final int ICONIFIED = 1; +public static final int MAXIMIZED_BOTH = 6; +public static final int MAXIMIZED_HORIZ = 2; +public static final int MAXIMIZED_VERT = 4; +public static final int NORMAL = 0; + +// Serialization version constant +private static final long serialVersionUID = 2673458971256075116L; + +/** + * @serial The version of the class data being serialized + * // FIXME: what is this value? + */ +private int frameSerializedDataVersion; + +/** + * @serial Image used as the icon when this frame is minimized. + */ +private Image icon; + +/** + * @serial Constant used by the JDK Motif peer set. Not used in + * this implementation. + */ +private boolean mbManagement; + +/** + * @serial The menu bar for this frame. + */ +//private MenuBar menuBar = new MenuBar(); +private MenuBar menuBar; + +/** + * @serial A list of other top-level windows owned by this window. + */ +Vector ownedWindows = new Vector(); + +/** + * @serial Indicates whether or not this frame is resizable. + */ +private boolean resizable = true; + +/** + * @serial The state of this frame. + * // FIXME: What are the values here? + * This is package-private to avoid an accessor method. + */ +int state; + +/** + * @serial The title of the frame. + */ +private String title = ""; + + /** + * Maximized bounds for this frame. + */ + private Rectangle maximizedBounds; + + /** + * This field indicates whether the frame is undecorated or not. + */ + private boolean undecorated = false; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_frame_number; + +/** + * Initializes a new instance of Frame that is not visible + * and has no title. + */ +public +Frame() +{ + this(""); + noteFrame(this); +} + +/** + * Initializes a new instance of Frame that is not visible + * and has the specified title. + * + * @param title The title of this frame. + */ +public +Frame(String title) +{ + super(); + this.title = title; + // Top-level frames are initially invisible. + visible = false; + noteFrame(this); +} + +public +Frame(GraphicsConfiguration gc) +{ + super(gc); + visible = false; + noteFrame(this); +} + +public +Frame(String title, GraphicsConfiguration gc) +{ + super(gc); + setTitle(title); + visible = false; + noteFrame(this); +} + +/** + * Returns this frame's title string. + * + * @return This frame's title string. + */ +public String +getTitle() +{ + return(title); +} + +/* + * Sets this frame's title to the specified value. + * + * @param title The new frame title. + */ +public synchronized void +setTitle(String title) +{ + this.title = title; + if (peer != null) + ((FramePeer) peer).setTitle(title); +} + +/** + * Returns this frame's icon. + * + * @return This frame's icon, or null if this frame does not + * have an icon. + */ +public Image +getIconImage() +{ + return(icon); +} + +/** + * Sets this frame's icon to the specified value. + * + * @icon The new icon for this frame. + */ +public synchronized void +setIconImage(Image icon) +{ + this.icon = icon; + if (peer != null) + ((FramePeer) peer).setIconImage(icon); +} + +/** + * Returns this frame's menu bar. + * + * @return This frame's menu bar, or null if this frame + * does not have a menu bar. + */ +public MenuBar +getMenuBar() +{ + return(menuBar); +} + +/** + * Sets this frame's menu bar. + * + * @param menuBar The new menu bar for this frame. + */ +public synchronized void +setMenuBar(MenuBar menuBar) +{ + if (peer != null) + { + if (this.menuBar != null) + this.menuBar.removeNotify(); + if (menuBar != null) + menuBar.addNotify(); + invalidateTree (); + ((FramePeer) peer).setMenuBar(menuBar); + } + this.menuBar = menuBar; +} + +/** + * Tests whether or not this frame is resizable. This will be + * true by default. + * + * @return true if this frame is resizable, false + * otherwise. + */ +public boolean +isResizable() +{ + return(resizable); +} + +/** + * Sets the resizability of this frame to the specified value. + * + * @param resizable true to make the frame resizable, + * false to make it non-resizable. + */ +public synchronized void +setResizable(boolean resizable) +{ + this.resizable = resizable; + if (peer != null) + ((FramePeer) peer).setResizable(resizable); +} + +/** + * Returns the cursor type of the cursor for this window. This will + * be one of the constants in this class. + * + * @return The cursor type for this frame. + * + * @deprecated Use Component.getCursor() instead. + */ +public int +getCursorType() +{ + return(getCursor().getType()); +} + +/** + * Sets the cursor for this window to the specified type. The specified + * type should be one of the constants in this class. + * + * @param type The cursor type. + * + * @deprecated Use Component.setCursor(Cursor) instead. + */ +public void +setCursor(int type) +{ + setCursor(new Cursor(type)); +} + +/** + * Removes the specified component from this frame's menu. + * + * @param menu The menu component to remove. + */ +public void +remove(MenuComponent menu) +{ + menuBar.remove(menu); +} + +/** + * Notifies this frame that it should create its native peer. + */ +private static void fireDummyEvent() +{ + EventQueue.invokeLater(new Runnable() + { + public void run() + { + // Do nothing here. + } + }); +} + +public void +addNotify() +{ + if (menuBar != null) + menuBar.addNotify(); + if (peer == null) + peer = getToolkit ().createFrame (this); + + // We now know there's a Frame (us) with a live peer, so we can start the + // fundamental queue and dispatch thread, by inserting a dummy event. + if (parent != null && parent.isDisplayable()) + fireDummyEvent(); + + super.addNotify(); +} + +public void removeNotify() +{ + if (menuBar != null) + menuBar.removeNotify(); + super.removeNotify(); + + // By now we've been disconnected from the peer, and the peer set to + // null. This is formally the same as saying "we just became + // un-displayable", so we wake up the event queue with a dummy event to + // see if it's time to shut down. + fireDummyEvent(); +} + + /** + * Returns a debugging string describing this window. + * + * @return A debugging string describing this window. + */ + protected String paramString () + { + String title = getTitle (); + + String resizable = ""; + if (isResizable ()) + resizable = ",resizable"; + + String state = ""; + switch (getState ()) + { + case NORMAL: + state = ",normal"; + break; + case ICONIFIED: + state = ",iconified"; + break; + case MAXIMIZED_BOTH: + state = ",maximized-both"; + break; + case MAXIMIZED_HORIZ: + state = ",maximized-horiz"; + break; + case MAXIMIZED_VERT: + state = ",maximized-vert"; + break; + } + + return super.paramString () + ",title=" + title + resizable + state; + } + +private static ArrayList weakFrames = new ArrayList(); + +private static void noteFrame(Frame f) +{ + weakFrames.add(new WeakReference(f)); +} + +public static Frame[] getFrames() +{ + int n = 0; + synchronized (weakFrames) + { + Iterator i = weakFrames.iterator(); + while (i.hasNext()) + { + WeakReference wr = (WeakReference) i.next(); + if (wr.get() != null) + ++n; + } + if (n == 0) + return new Frame[0]; + else + { + Frame[] frames = new Frame[n]; + n = 0; + i = weakFrames.iterator(); + while (i.hasNext()) + { + WeakReference wr = (WeakReference) i.next(); + if (wr.get() != null) + frames[n++] = (Frame) wr.get(); + } + return frames; + } + } +} + + public void setState (int state) + { + int current_state = getExtendedState (); + + if (state == NORMAL + && (current_state & ICONIFIED) != 0) + setExtendedState (current_state | ICONIFIED); + + if (state == ICONIFIED + && (current_state & ~ICONIFIED) == 0) + setExtendedState (current_state & ~ICONIFIED); + } + + public int getState () + { + /* FIXME: State might have changed in the peer... Must check. */ + + return (state & ICONIFIED) != 0 ? ICONIFIED : NORMAL; + } + + /** + * @since 1.4 + */ + public void setExtendedState (int state) + { + this.state = state; + } + + /** + * @since 1.4 + */ + public int getExtendedState () + { + return state; + } + + /** + * @since 1.4 + */ + public void setMaximizedBounds (Rectangle maximizedBounds) + { + this.maximizedBounds = maximizedBounds; + } + + /** + * Returns the maximized bounds of this frame. + * + * @return the maximized rectangle, may be null. + * + * @since 1.4 + */ + public Rectangle getMaximizedBounds () + { + return maximizedBounds; + } + + /** + * Returns whether this frame is undecorated or not. + * + * @since 1.4 + */ + public boolean isUndecorated () + { + return undecorated; + } + + /** + * Disables or enables decorations for this frame. This method can only be + * called while the frame is not displayable. + * + * @exception IllegalComponentStateException If this frame is displayable. + * + * @since 1.4 + */ + public void setUndecorated (boolean undecorated) + { + if (isDisplayable ()) + throw new IllegalComponentStateException (); + + this.undecorated = undecorated; + } + + /** + * Generate a unique name for this frame. + * + * @return A unique name for this frame. + */ + String generateName () + { + return "frame" + getUniqueLong (); + } + + private static synchronized long getUniqueLong () + { + return next_frame_number++; + } + + protected class AccessibleAWTFrame extends AccessibleAWTWindow + { + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.FRAME; + } + + public AccessibleStateSet getAccessibleState() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (isResizable()) + states.add(AccessibleState.RESIZABLE); + if ((state & ICONIFIED) != 0) + states.add(AccessibleState.ICONIFIED); + return states; + } + } + + /** + * Gets the AccessibleContext associated with this Frame. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTFrame(); + return accessibleContext; + } + +} diff --git a/libjava/classpath/java/awt/GradientPaint.java b/libjava/classpath/java/awt/GradientPaint.java new file mode 100644 index 0000000..74067f4 --- /dev/null +++ b/libjava/classpath/java/awt/GradientPaint.java @@ -0,0 +1,229 @@ +/* GradientPaint.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 java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import gnu.java.awt.GradientPaintContext; + +/** + * A paint object that can be used to color a region by blending two colors. + * Instances of this class are immutable. + */ +public class GradientPaint implements Paint +{ + private final float x1; + private final float y1; + private final Color c1; + private final float x2; + private final float y2; + private final Color c2; + private final boolean cyclic; + + /** + * Creates a new acyclic GradientPaint. + * + * @param x1 the x-coordinate of the anchor point for color 1. + * @param y1 the y-coordinate of the anchor point for color 1. + * @param c1 color 1 (null not permitted). + * @param x2 the x-coordinate of the anchor point for color 2. + * @param y2 the y-coordinate of the anchor point for color 2. + * @param c2 the second color (null not permitted). + */ + public GradientPaint(float x1, float y1, Color c1, + float x2, float y2, Color c2) + { + this(x1, y1, c1, x2, y2, c2, false); + } + + /** + * Creates a new acyclic GradientPaint. + * + * @param p1 anchor point 1 (null not permitted). + * @param c1 color 1 (null not permitted). + * @param p2 anchor point 2 (null not permitted). + * @param c2 color 2 (null not permitted). + */ + public GradientPaint(Point2D p1, Color c1, Point2D p2, Color c2) + { + this((float) p1.getX(), (float) p1.getY(), c1, + (float) p2.getX(), (float) p2.getY(), c2, false); + } + + /** + * Creates a new cyclic or acyclic GradientPaint. + * + * @param x1 the x-coordinate of the anchor point for color 1. + * @param y1 the y-coordinate of the anchor point for color 1. + * @param c1 color 1 (null not permitted). + * @param x2 the x-coordinate of the anchor point for color 2. + * @param y2 the y-coordinate of the anchor point for color 2. + * @param c2 the second color (null not permitted). + * @param cyclic a flag that controls whether the gradient is cyclic or + * acyclic. + */ + public GradientPaint(float x1, float y1, Color c1, + float x2, float y2, Color c2, boolean cyclic) + { + if (c1 == null || c2 == null) + throw new NullPointerException(); + this.x1 = x1; + this.y1 = y1; + this.c1 = c1; + this.x2 = x2; + this.y2 = y2; + this.c2 = c2; + this.cyclic = cyclic; + } + + /** + * Creates a new cyclic or acyclic GradientPaint. + * + * @param p1 anchor point 1 (null not permitted). + * @param c1 color 1 (null not permitted). + * @param p2 anchor point 2 (null not permitted). + * @param c2 color 2 (null not permitted). + * @param cyclic a flag that controls whether the gradient is cyclic or + * acyclic. + */ + public GradientPaint(Point2D p1, Color c1, Point2D p2, Color c2, + boolean cyclic) + { + this((float) p1.getX(), (float) p1.getY(), c1, + (float) p2.getX(), (float) p2.getY(), c2, cyclic); + } + + /** + * Returns a point with the same coordinates as the anchor point for color 1. + * Note that if you modify this point, the GradientPaint remains + * unchanged. + * + * @return A point with the same coordinates as the anchor point for color 1. + */ + public Point2D getPoint1() + { + return new Point2D.Float(x1, y1); + } + + /** + * Returns the first color. + * + * @return The color (never null). + */ + public Color getColor1() + { + return c1; + } + + /** + * Returns a point with the same coordinates as the anchor point for color 2. + * Note that if you modify this point, the GradientPaint remains + * unchanged. + * + * @return A point with the same coordinates as the anchor point for color 2. + */ + public Point2D getPoint2() + { + return new Point2D.Float(x2, y2); + } + + /** + * Returns the second color. + * + * @return The color (never null). + */ + public Color getColor2() + { + return c2; + } + + /** + * Returns true if this GradientPaint instance is + * cyclic, and false otherwise. + * + * @return A boolean. + */ + public boolean isCyclic() + { + return cyclic; + } + + /** + * Returns the {@link PaintContext} used to generate the color pattern. + * + * @param cm the color model, used as a hint (ignored in this + * implementation). + * @param deviceBounds the device space bounding box of the painted area. + * @param userBounds the user space bounding box of the painted area. + * @param xform the transformation from user space to device space. + * @param hints any hints for choosing between rendering alternatives. + * + * @return The context for performing the paint + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + Point2D xp1 = xform.transform(getPoint1(), null); + Point2D xp2 = xform.transform(getPoint2(), null); + return new GradientPaintContext((float) xp1.getX(), (float) xp1.getY(), c1, + (float) xp2.getX(), (float) xp2.getY(), c2, cyclic); + } + + /** + * Returns the transparency code for this GradientPaint instance. + * This is derived from the two {@link Color} objects used in creating this + * object: if both colors are opaque, this method returns + * {@link Transparency#OPAQUE}, otherwise it returns + * {@link Transparency#TRANSLUCENT}. + * + * @return {@link Transparency#OPAQUE} or {@link Transparency#TRANSLUCENT}. + */ + public int getTransparency() + { + if (c1.getAlpha() == 255 && c2.getAlpha() == 255) + return Transparency.OPAQUE; + else + return Transparency.TRANSLUCENT; + } + +} // class GradientPaint diff --git a/libjava/classpath/java/awt/Graphics.java b/libjava/classpath/java/awt/Graphics.java new file mode 100644 index 0000000..ff26190 --- /dev/null +++ b/libjava/classpath/java/awt/Graphics.java @@ -0,0 +1,767 @@ +/* Graphics.java -- Abstract Java drawing class + Copyright (C) 1999, 2000, 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 java.awt; + +import java.awt.image.ImageObserver; +import java.text.AttributedCharacterIterator; + +/** + * This is the abstract superclass of classes for drawing to graphics + * devices such as the screen or printers. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public abstract class Graphics +{ + +/* + * Instance Variables + */ + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Default constructor for subclasses. + */ +protected +Graphics() +{ +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns a copy of this Graphics object. + * + * @return A copy of this object. + */ +public abstract Graphics +create(); + +/*************************************************************************/ + +/** + * Returns a copy of this Graphics object. The origin point + * will be translated to the point (x, y) and the cliping rectangle set + * to the intersection of the clipping rectangle in this object and the + * rectangle specified by the parameters to this method. + * + * @param x The new X coordinate of the clipping region rect. + * @param y The new Y coordinate of the clipping region rect. + * @param width The width of the clipping region intersect rectangle. + * @param height The height of the clipping region intersect rectangle. + * + * @return A copy of this object, modified as specified. + */ +public Graphics +create(int x, int y, int width, int height) +{ + Graphics g = create(); + + g.translate(x, y); + // FIXME: I'm not sure if this will work. Are the old clip rect bounds + // translated above? + g.clipRect(0, 0, width, height); + + return(g); +} + +/*************************************************************************/ + +/** + * Translates this context so that its new origin point is the point + * (x, y). + * + * @param x The new X coordinate of the origin. + * @param y The new Y coordinate of the origin. + */ +public abstract void +translate(int x, int y); + +/*************************************************************************/ + +/** + * Returns the current color for this object. + * + * @return The color for this object. + */ +public abstract Color +getColor(); + +/*************************************************************************/ + +/** + * Sets the current color for this object. + * + * @param color The new color. + */ +public abstract void +setColor(Color color); + +/*************************************************************************/ + +/** + * Sets this context into "paint" mode, where the target pixels are + * completely overwritten when drawn on. + */ +public abstract void +setPaintMode(); + +/*************************************************************************/ + +/** + * Sets this context info "XOR" mode, where the targe pixles are + * XOR-ed when drawn on. + * + * @param color The color to XOR against. + */ +public abstract void +setXORMode(Color color); + +/*************************************************************************/ + +/** + * Returns the current font for this graphics context. + * + * @return The current font. + */ +public abstract Font +getFont(); + +/*************************************************************************/ + +/** + * Sets the font for this graphics context to the specified value. + * + * @param font The new font. + */ +public abstract void +setFont(Font font); + +/*************************************************************************/ + +/** + * Returns the font metrics for the current font. + * + * @return The font metrics for the current font. + */ +public FontMetrics +getFontMetrics() +{ + return(getFontMetrics(getFont())); +} + +/*************************************************************************/ + +/** + * Returns the font metrics for the specified font. + * + * @param font The font to return metrics for. + * + * @return The requested font metrics. + */ +public abstract FontMetrics +getFontMetrics(Font font); + +/*************************************************************************/ + +/** + * Returns the bounding rectangle of the clipping region for this + * graphics context. + * + * @return The bounding rectangle for the clipping region. + */ +public abstract Rectangle +getClipBounds(); + +/*************************************************************************/ + +/** + * Returns the bounding rectangle of the clipping region for this + * graphics context. + * + * @return The bounding rectangle for the clipping region. + * + * @deprecated This method is deprecated in favor of + * getClipBounds(). + */ +public Rectangle +getClipRect() +{ + return(getClipBounds()); +} + +/*************************************************************************/ + +/** + * Sets the clipping region to the intersection of the current clipping + * region and the rectangle determined by the specified parameters. + * + * @param x The X coordinate of the upper left corner of the intersect rect. + * @param y The Y coordinate of the upper left corner of the intersect rect. + * @param width The width of the intersect rect. + * @param height The height of the intersect rect. + */ +public abstract void +clipRect(int x, int y, int width, int height); + +/*************************************************************************/ + +/** + * Sets the clipping region to the rectangle determined by the specified + * parameters. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + */ +public abstract void +setClip(int x, int y, int width, int height); + +/*************************************************************************/ + +/** + * Returns the current clipping region as a Shape object. + * + * @return The clipping region as a Shape. + */ +public abstract Shape +getClip(); + +/*************************************************************************/ + +/** + * Sets the clipping region to the specified Shape. + * + * @param clip The new clipping region. + */ +public abstract void +setClip(Shape clip); + +/*************************************************************************/ + +/** + * Copies the specified rectangle to the specified offset location. + * + * @param x The X coordinate of the upper left corner of the copy rect. + * @param y The Y coordinate of the upper left corner of the copy rect. + * @param width The width of the copy rect. + * @param height The height of the copy rect. + * @param dx The offset from the X value to start drawing. + * @param dy The offset from the Y value to start drawing. + */ +public abstract void +copyArea(int x, int y, int width, int height, int dx, int dy); + +/*************************************************************************/ + +/** + * Draws a line between the two specified points. + * + * @param x1 The X coordinate of the first point. + * @param y1 The Y coordinate of the first point. + * @param x2 The X coordinate of the second point. + * @param y2 The Y coordinate of the second point. + */ +public abstract void +drawLine(int x1, int y1, int x2, int y2); + +/*************************************************************************/ + +/** + * Fills the area bounded by the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the fill rect. + * @param y The Y coordinate of the upper left corner of the fill rect. + * @param width The width of the fill rect. + * @param height The height of the fill rect. + */ +public abstract void +fillRect(int x, int y, int width, int height); + +/*************************************************************************/ + +/** + * Draws the outline of the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the draw rect. + * @param y The Y coordinate of the upper left corner of the draw rect. + * @param width The width of the draw rect. + * @param height The height of the draw rect. + */ +public void +drawRect(int x, int y, int width, int height) +{ + int x1 = x; + int y1 = y; + int x2 = x + width; + int y2 = y + height; + drawLine(x1, y1, x2, y1); + drawLine(x2, y1, x2, y2); + drawLine(x2, y2, x1, y2); + drawLine(x1, y2, x1, y1); +} + +/*************************************************************************/ + +/** + * Clears the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the clear rect. + * @param y The Y coordinate of the upper left corner of the clear rect. + * @param width The width of the clear rect. + * @param height The height of the clear rect. + */ +public abstract void +clearRect(int x, int y, int width, int height); + +/*************************************************************************/ + +/** + * Draws the outline of the specified rectangle with rounded cornders. + * + * @param x The X coordinate of the upper left corner of the draw rect. + * @param y The Y coordinate of the upper left corner of the draw rect. + * @param width The width of the draw rect. + * @param height The height of the draw rect. + * @param arcWidth The width of the corner arcs. + * @param arcHeight The height of the corner arcs. + */ +public abstract void +drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight); + +/*************************************************************************/ + +/** + * Fills the specified rectangle with rounded cornders. + * + * @param x The X coordinate of the upper left corner of the fill rect. + * @param y The Y coordinate of the upper left corner of the fill rect. + * @param width The width of the fill rect. + * @param height The height of the fill rect. + * @param arcWidth The width of the corner arcs. + * @param arcHeight The height of the corner arcs. + */ +public abstract void +fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight); + +/*************************************************************************/ + +public void +draw3DRect(int x, int y, int width, int height, boolean raised) +{ + Color color = getColor(); + Color tl = color.brighter(); + Color br = color.darker(); + + if (!raised) + { + Color tmp = tl; + tl = br; + br = tmp; + } + + int x1 = x; + int y1 = y; + int x2 = x + width; + int y2 = y + height; + + setColor(tl); + drawLine(x1, y1, x2, y1); + drawLine(x1, y2, x1, y1); + setColor(br); + drawLine(x2, y1, x2, y2); + drawLine(x2, y2, x1, y2); + setColor(color); +} + +/** + * Fills the specified rectangle with a 3D effect + * + * @param x The X coordinate of the upper left corner of the fill rect. + * @param y The Y coordinate of the upper left corner of the fill rect. + * @param width The width of the fill rect. + * @param height The height of the fill rect. + * @param raised true if the rectangle appears raised, + * false if it should appear etched. + */ +public void +fill3DRect(int x, int y, int width, int height, boolean raised) +{ + fillRect(x, y, width, height); + draw3DRect(x, y, width-1, height-1, raised); +} + +/*************************************************************************/ + +/** + * Draws an oval that just fits within the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + */ +public abstract void +drawOval(int x, int y, int width, int height); + +/*************************************************************************/ + +/** + * Fills an oval that just fits within the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + */ +public abstract void +fillOval(int x, int y, int width, int height); + +/*************************************************************************/ + +/** + * Draws an arc using the specified bounding rectangle and the specified + * angle parameter. The arc is centered at the center of the rectangle. + * The arc starts at the arcAngle position and extend for arcAngle + * degrees. The degree origin is at the 3 o'clock position. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + * @param arcStart The beginning angle of the arc. + * @param arcAngle The extent of the arc. + */ +public abstract void +drawArc(int x, int y, int width, int height, int arcStart, int arcAngle); + +/*************************************************************************/ + +/** + * Fills the arc define by the specified bounding rectangle and the specified + * angle parameter. The arc is centered at the center of the rectangle. + * The arc starts at the arcAngle position and extend for arcAngle + * degrees. The degree origin is at the 3 o'clock position. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + * @param arcStart The beginning angle of the arc. + * @param arcAngle The extent of the arc. + */ +public abstract void +fillArc(int x, int y, int width, int height, int arcStart, int arcAngle); + +/*************************************************************************/ + +/** + * Draws a series of interconnected lines determined by the arrays + * of corresponding x and y coordinates. + * + * @param xPoints The X coordinate array. + * @param yPoints The Y coordinate array. + * @param npoints The number of points to draw. + */ +public abstract void +drawPolyline(int xPoints[], int yPoints[], int npoints); + +/*************************************************************************/ + +/** + * Draws a series of interconnected lines determined by the arrays + * of corresponding x and y coordinates. The figure is closed if necessary + * by connecting the first and last points. + * + * @param xPoints The X coordinate array. + * @param yPoints The Y coordinate array. + * @param npoints The number of points to draw. + */ +public abstract void +drawPolygon(int xPoints[], int yPoints[], int npoints); + +/*************************************************************************/ + +/** + * Draws the specified polygon. + * + * @param polygon The polygon to draw. + */ +public void +drawPolygon(Polygon polygon) +{ + drawPolygon(polygon.xpoints, polygon.ypoints, polygon.npoints); +} + +/*************************************************************************/ + +/** + * Fills the polygon determined by the arrays + * of corresponding x and y coordinates. + * + * @param xPoints The X coordinate array. + * @param yPoints The Y coordinate array. + * @param npoints The number of points to draw. + */ +public abstract void +fillPolygon(int xPoints[], int yPoints[], int npoints); + +/*************************************************************************/ + +/** + * Fills the specified polygon + * + * @param polygon The polygon to fill. + */ +public void +fillPolygon(Polygon polygon) +{ + fillPolygon(polygon.xpoints, polygon.ypoints, polygon.npoints); +} + +/*************************************************************************/ + +/** + * Draws the specified string starting at the specified point. + * + * @param string The string to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + */ +public abstract void +drawString(String string, int x, int y); + +public abstract void drawString (AttributedCharacterIterator ci, int x, int y); + +/*************************************************************************/ + +/** + * Draws the specified characters starting at the specified point. + * + * @param data The array of characters to draw. + * @param offset The offset into the array to start drawing characters from. + * @param length The number of characters to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + */ +public void +drawChars(char data[], int offset, int length, int x, int y) +{ + drawString(new String(data, offset, length), x, y); +} + +public void +drawBytes(byte[] data, int offset, int length, int x, int y) +{ + String str = new String(data, offset, length); + drawString(str, x, y); +} + +/*************************************************************************/ + +/** + * Draws all of the image that is available and returns. If the image + * is not completely loaded, false is returned and + * the specified iamge observer is notified as more data becomes + * available. + * + * @param image The image to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + * @param observer The image observer to notify as data becomes available. + * + * @return true if all the image data is available, + * false otherwise. + */ +public abstract boolean +drawImage(Image image, int x, int y, ImageObserver observer); + +/*************************************************************************/ + +/** + * Draws all of the image that is available and returns. The image + * is scaled to fit in the specified rectangle. If the image + * is not completely loaded, false is returned and + * the specified iamge observer is notified as more data becomes + * available. + * + * @param image The image to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + * @param width The width of the rectangle to draw in. + * @param height The height of the rectangle to draw in. + * @param observer The image observer to notify as data becomes available. + * + * @return true if all the image data is available, + * false otherwise. + */ +public abstract boolean +drawImage(Image image, int x, int y, int width, int height, + ImageObserver observer); + +/*************************************************************************/ + +/** + * Draws all of the image that is available and returns. If the image + * is not completely loaded, false is returned and + * the specified iamge observer is notified as more data becomes + * available. + * + * @param image The image to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + * @param bgcolor The background color to use for the image. + * @param observer The image observer to notify as data becomes available. + * + * @return true if all the image data is available, + * false otherwise. + */ +public abstract boolean +drawImage(Image image, int x, int y, Color bgcolor, ImageObserver observer); + +/*************************************************************************/ + +/** + * Draws all of the image that is available and returns. The image + * is scaled to fit in the specified rectangle. If the image + * is not completely loaded, false is returned and + * the specified iamge observer is notified as more data becomes + * available. + * + * @param image The image to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + * @param width The width of the rectangle to draw in. + * @param height The height of the rectangle to draw in. + * @param bgcolor The background color to use for the image. + * @param observer The image observer to notify as data becomes available. + * + * @return true if all the image data is available, + * false otherwise. + */ +public abstract boolean +drawImage(Image image, int x, int y, int width, int height, Color bgcolor, + ImageObserver observer); + +/*************************************************************************/ + +/** + * FIXME: Write Javadocs for this when you understand it. + */ +public abstract boolean +drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, + int sx2, int sy2, ImageObserver observer); + +/*************************************************************************/ + +/** + * FIXME: Write Javadocs for this when you understand it. + */ +public abstract boolean +drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, + int sx2, int sy2, Color bgcolor, ImageObserver observer); + +/*************************************************************************/ + +/** + * Free any resources held by this graphics context immediately instead + * of waiting for the object to be garbage collected and finalized. + */ +public abstract void +dispose(); + +/*************************************************************************/ + +/** + * Frees the resources held by this graphics context when it is + * garbage collected. + */ +public void +finalize() +{ + dispose(); +} + +/*************************************************************************/ + +/** + * Returns a string representation of this object. + * + * @return A string representation of this object. + */ +public String +toString() +{ + return getClass ().getName () + "[font=" + getFont () + ",color=" + getColor () + "]"; +} + +public boolean +hitClip(int x, int y, int width, int height) +{ + throw new UnsupportedOperationException("not implemented yet"); +} + +public Rectangle +getClipBounds(Rectangle r) +{ + Rectangle clipBounds = getClipBounds(); + + if (r == null) + return clipBounds; + + r.x = clipBounds.x; + r.y = clipBounds.y; + r.width = clipBounds.width; + r.height = clipBounds.height; + return r; +} + +} // class Graphics + diff --git a/libjava/classpath/java/awt/Graphics2D.java b/libjava/classpath/java/awt/Graphics2D.java new file mode 100644 index 0000000..3faa9dc --- /dev/null +++ b/libjava/classpath/java/awt/Graphics2D.java @@ -0,0 +1,158 @@ +/* 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 java.awt; + +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +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.util.Map; + +/** + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public abstract class Graphics2D extends Graphics +{ + + protected Graphics2D() + { + } + + public void draw3DRect(int x, int y, int width, int height, + boolean raised) + { + super.draw3DRect(x, y, width, height, raised); + } + + public void fill3DRect(int x, int y, int width, int height, + boolean raised) + { + super.fill3DRect(x, y, width, height, raised); + } + + public abstract void draw(Shape shape); + + public abstract boolean drawImage(Image image, AffineTransform xform, + ImageObserver obs); + + public abstract void drawImage(BufferedImage image, + BufferedImageOp op, + int x, + int y); + + public abstract void drawRenderedImage(RenderedImage image, + AffineTransform xform); + + public abstract void drawRenderableImage(RenderableImage image, + AffineTransform xform); + + public abstract void drawString(String text, int x, int y); + + public abstract void drawString(String text, float x, float y); + + public abstract void drawString(AttributedCharacterIterator iterator, + int x, int y); + + public abstract void drawString(AttributedCharacterIterator iterator, + float x, float y); + + // public abstract void drawGlyphVector(GlyphVector g, float x, float y); + + public abstract void fill(Shape shape); + + public abstract boolean hit(Rectangle rect, Shape text, + boolean onStroke); + + public abstract GraphicsConfiguration getDeviceConfiguration(); + + public abstract void setComposite(Composite comp); + + public abstract void setPaint(Paint paint); + + public abstract void setStroke(Stroke stroke); + + public abstract void setRenderingHint(RenderingHints.Key hintKey, + Object hintValue); + + public abstract Object getRenderingHint(RenderingHints.Key hintKey); + + public abstract void setRenderingHints(Map hints); + + public abstract void addRenderingHints(Map hints); + + public abstract RenderingHints getRenderingHints(); + + public abstract void translate(int x, int y); + + public abstract void translate(double tx, double ty); + + public abstract void rotate(double theta); + + public abstract void rotate(double theta, double x, double y); + + public abstract void scale(double scaleX, double scaleY); + + public abstract void shear(double shearX, double shearY); + + public abstract void transform(AffineTransform Tx); + + public abstract void setTransform(AffineTransform Tx); + + public abstract AffineTransform getTransform(); + + public abstract Paint getPaint(); + + public abstract Composite getComposite(); + + public abstract void setBackground(Color color); + + public abstract Color getBackground(); + + public abstract Stroke getStroke(); + + public abstract void clip(Shape s); + + public abstract FontRenderContext getFontRenderContext (); + + public abstract void drawGlyphVector (GlyphVector g, float x, float y); +} diff --git a/libjava/classpath/java/awt/GraphicsConfigTemplate.java b/libjava/classpath/java/awt/GraphicsConfigTemplate.java new file mode 100644 index 0000000..e468883 --- /dev/null +++ b/libjava/classpath/java/awt/GraphicsConfigTemplate.java @@ -0,0 +1,106 @@ +/* GraphicsConfigTemplate.java -- a template for selecting configurations + 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 java.awt; + +import java.io.Serializable; + +/** + * This allows filtering an array of GraphicsConfigurations for the best + * one based on various requirements. The resulting configuration has had + * all non-default attributes set as required to meet or exceed the request. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see GraphicsConfiguration + * @see GraphicsDevice + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class GraphicsConfigTemplate implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -8061369279557787079L; + + /** States that a feature is required to select a configuration. */ + public static final int REQUIRED = 1; + + /** + * States that a feature is preferred, but not required, to select a + * configuration. In the case of multiple valid configurations, the tie + * breaks in favor of the one with the feature. + */ + public static final int PREFERRED = 2; + + /** + * States that a feature is not necessary in the configuration. In the case + * of multiple valid configurations, the tie breaks in favor of the one + * without the feature, to reduce overhead. + */ + public static final int UNNECESSARY = 3; + + /** + * The default constructor. + */ + public GraphicsConfigTemplate() + { + } + + /** + * Returns the "best" match among the array of possible configurations, given + * the criteria of this template. + * + * @param array the array to choose from + * @return the best match + * @throws NullPointerException if array is null + */ + public abstract GraphicsConfiguration getBestConfiguration + (GraphicsConfiguration[] array); + + /** + * Returns true if the given configuration supports all the features required + * by this template. + * + * @param config the configuration to test + * @return true if it is a match + * @throws NullPointerException if config is null + */ + public abstract boolean isGraphicsConfigSupported + (GraphicsConfiguration config); +} // class GraphicsConfigTemplate diff --git a/libjava/classpath/java/awt/GraphicsConfiguration.java b/libjava/classpath/java/awt/GraphicsConfiguration.java new file mode 100644 index 0000000..6dc2779 --- /dev/null +++ b/libjava/classpath/java/awt/GraphicsConfiguration.java @@ -0,0 +1,218 @@ +/* GraphicsConfiguration.java -- describes characteristics of graphics + Copyright (C) 2000, 2001, 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 java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; + +/** + * This class describes the configuration of various graphics devices, such + * as a monitor or printer. Different configurations may exist for the same + * device, according to the different native modes supported. + * + *

Virtual devices are supported (for example, in a multiple screen + * environment, a virtual device covers all screens simultaneously); the + * configuration will have a non-zero relative coordinate system in such + * a case. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Window + * @see Frame + * @see GraphicsEnvironment + * @see GraphicsDevice + * @since 1.0 + * @status updated to 1.4 + */ +public abstract class GraphicsConfiguration +{ + /** + * The default constructor. + * + * @see GraphicsDevice#getConfigurations() + * @see GraphicsDevice#getDefaultConfiguration() + * @see GraphicsDevice#getBestConfiguration(GraphicsConfigTemplate) + * @see Graphics2D#getDeviceConfiguration() + */ + protected GraphicsConfiguration () + { + } + + /** + * Gets the associated device that this configuration describes. + * + * @return the device + */ + public abstract GraphicsDevice getDevice(); + + /** + * Returns a buffered image optimized to this device, so that blitting can + * be supported in the buffered image. + * + * @param w the width of the buffer + * @param h the height of the buffer + * @return the buffered image, or null if none is supported + */ + public abstract BufferedImage createCompatibleImage(int w, int h); + + /** + * Returns a buffered volatile image optimized to this device, so that + * blitting can be supported in the buffered image. Because the buffer is + * volatile, it can be optimized by native graphics accelerators. + * + * @param w the width of the buffer + * @param h the height of the buffer + * @return the buffered image, or null if none is supported + * @see Component#createVolatileImage(int, int) + * @since 1.4 + */ + public abstract VolatileImage createCompatibleVolatileImage(int w, int h); + + /** + * Returns a buffered volatile image optimized to this device, and with the + * given capabilities, so that blitting can be supported in the buffered + * image. Because the buffer is volatile, it can be optimized by native + * graphics accelerators. + * + * @param w the width of the buffer + * @param h the height of the buffer + * @param caps the desired capabilities of the image buffer + * @return the buffered image, or null if none is supported + * @throws AWTException if the capabilities cannot be met + * @since 1.4 + */ + public VolatileImage createCompatibleVolatileImage(int w, int h, + ImageCapabilities caps) + throws AWTException + { + throw new AWTException("not implemented"); + } + + /** + * Returns a buffered image optimized to this device, and with the specified + * transparency, so that blitting can be supported in the buffered image. + * + * @param w the width of the buffer + * @param h the height of the buffer + * @param transparency the transparency of the buffer + * @return the buffered image, or null if none is supported + * @see Transparency#OPAQUE + * @see Transparency#BITMASK + * @see Transparency#TRANSLUCENT + */ + public abstract BufferedImage createCompatibleImage(int w, int h, + int transparency); + + /** + * Gets the color model of the corresponding device. + * + * @return the color model + */ + public abstract ColorModel getColorModel(); + + /** + * Gets a color model for the corresponding device which supports the desired + * transparency level. + * + * @param transparency the transparency of the model + * @return the color model, with transparency + * @see Transparency#OPAQUE + * @see Transparency#BITMASK + * @see Transparency#TRANSLUCENT + */ + public abstract ColorModel getColorModel(int transparency); + + /** + * Returns a transform that maps user coordinates to device coordinates. The + * preferred mapping is about 72 user units to 1 inch (2.54 cm) of physical + * space. This is often the identity transform. The device coordinates have + * the origin at the upper left, with increasing x to the right, and + * increasing y to the bottom. + * + * @return the transformation from user space to device space + * @see #getNormalizingTransform() + */ + public abstract AffineTransform getDefaultTransform(); + + /** + * Returns a transform that maps user coordinates to device coordinates. The + * exact mapping is 72 user units to 1 inch (2.54 cm) of physical space. + * This is often the identity transform. The device coordinates have the + * origin at the upper left, with increasing x to the right, and increasing + * y to the bottom. Note that this is more accurate (and thus, sometimes more + * costly) than the default transform. + * + * @return the normalized transformation from user space to device space + * @see #getDefaultTransform() + */ + public abstract AffineTransform getNormalizingTransform(); + + /** + * Returns the bounds of the configuration, in device coordinates. If this + * is a virtual device (for example, encompassing several screens), the + * bounds may have a non-zero origin. + * + * @return the device bounds + * @since 1.3 + */ + public abstract Rectangle getBounds(); + + /** + * Returns the buffering capabilities of this configuration. + * + * @return the buffer capabilities + * @since 1.4 + */ + public BufferCapabilities getBufferCapabilities() + { + throw new Error("not implemented"); + } + + /** + * Returns the imaging capabilities of this configuration. + * + * @return the image capabilities + * @since 1.4 + */ + public ImageCapabilities getImageCapabilities() + { + throw new Error("not implemented"); + } +} // class GraphicsConfiguration diff --git a/libjava/classpath/java/awt/GraphicsDevice.java b/libjava/classpath/java/awt/GraphicsDevice.java new file mode 100644 index 0000000..95487a2 --- /dev/null +++ b/libjava/classpath/java/awt/GraphicsDevice.java @@ -0,0 +1,292 @@ +/* GraphicsDevice.java -- information about a graphics device + 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 java.awt; + +import java.awt.image.VolatileImage; + +/** + * This describes a graphics device available to the given environment. This + * includes screen and printer devices, and the different configurations for + * each device. Also, this allows you to create virtual devices which operate + * over a multi-screen environment. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see GraphicsEnvironment + * @see GraphicsConfiguration + * @since 1.3 + * @status updated to 1.4 + */ +public abstract class GraphicsDevice +{ + /** Device is a raster screen. */ + public static final int TYPE_RASTER_SCREEN = 0; + + /** Device is a printer. */ + public static final int TYPE_PRINTER = 1; + + /** Device is an image buffer not visible to the user. */ + public static final int TYPE_IMAGE_BUFFER = 2; + + /** The current full-screen window, or null if there is none. */ + private Window full_screen; + + /** + * The bounds of the fullscreen window before it has been switched to full + * screen. + */ + private Rectangle fullScreenOldBounds; + + /** The current display mode, or null if unknown. */ + private DisplayMode mode; + + /** + * The default constructor. + * + * @see GraphicsEnvironment#getScreenDevices() + * @see GraphicsEnvironment#getDefaultScreenDevice() + * @see GraphicsConfiguration#getDevice() + */ + protected GraphicsDevice() + { + } + + /** + * Returns the type of the device. + * + * @return the device type + * @see #TYPE_RASTER_SCREEN + * @see #TYPE_PRINTER + * @see #TYPE_IMAGE_BUFFER + */ + public abstract int getType(); + + /** + * Returns an identification string for the device. This can be + * vendor-specific, and may be useful for debugging. + * + * @return the identification + */ + public abstract String getIDstring(); + + /** + * Return all configurations valid for this device. + * + * @return an array of configurations + */ + public abstract GraphicsConfiguration[] getConfigurations(); + + /** + * Return the default configuration for this device. + * + * @return the default configuration + */ + public abstract GraphicsConfiguration getDefaultConfiguration(); + + /** + * Return the best configuration, according to the criteria in the given + * template. + * + * @param template the template to adjust by + * @return the best configuration + * @throws NullPointerException if template is null + */ + public GraphicsConfiguration getBestConfiguration + (GraphicsConfigTemplate template) + { + return template.getBestConfiguration(getConfigurations()); + } + + /** + * Returns true if the device supports full-screen exclusive mode. The + * default implementation returns true; subclass it if this is not the case. + * + * @return true if full screen support is available + * @since 1.4 + */ + public boolean isFullScreenSupported() + { + return true; + } + + /** + * Toggle the given window between full screen and normal mode. The previous + * full-screen window, if different, is restored; if the given window is + * null, no window will be full screen. If + * isFullScreenSupported() returns true, full screen mode is + * considered to be exclusive, which implies:


+ * If isFullScreenSupported() returns false, full-screen + * exclusive mode is simulated by resizing the window to the size of the + * screen and positioning it at (0,0). This is also what this method does. + * If a device supports real fullscreen mode then it should override this + * method as well as #isFullScreenSupported and #getFullScreenWindow. + * + * @param w the window to toggle + * @see #isFullScreenSupported() + * @see #getFullScreenWindow() + * @see #setDisplayMode(DisplayMode) + * @see Component#enableInputMethods(boolean) + * @since 1.4 + */ + public synchronized void setFullScreenWindow(Window w) + { + // Restore the previous window to normal mode and release the reference. + if (full_screen != null) + { + full_screen.setBounds(fullScreenOldBounds); + } + + full_screen = null; + + // If w != null, make it full-screen. + if (w != null) + { + fullScreenOldBounds = w.getBounds(); + full_screen = w; + DisplayMode dMode = getDisplayMode(); + full_screen.setBounds(0, 0, dMode.getWidth(), dMode.getHeight()); + full_screen.requestFocus(); + full_screen.setLocationRelativeTo(null); + } + } + + /** + * Returns the current full-screen window of the device, or null if no + * window is full-screen. + * + * @return the full-screen window + * @see #setFullScreenWindow(Window) + * @since 1.4 + */ + public Window getFullScreenWindow() + { + return full_screen; + } + + /** + * Returns whether this device supports low-level display changes. This may + * depend on whether full-screen exclusive mode is available. + * + * XXX The default implementation returns false for now. + * + * @return true if display changes are supported + * @see #setDisplayMode(DisplayMode) + * @since 1.4 + */ + public boolean isDisplayChangeSupported() + { + return false; + } + + /** + * Sets the display mode. This may be dependent on the availability of + * full-screen exclusive mode. + * + * @param mode the new mode + * @throws IllegalArgumentException if the new mode is not in getDisplayModes + * @throws UnsupportedOperationException if ! isDisplayChangeSupported() + * @see #getDisplayMode() + * @see #getDisplayModes() + * @see #isDisplayChangeSupported() + * @since 1.4 + */ + public void setDisplayMode(DisplayMode mode) + { + DisplayMode[] array = getDisplayModes(); + if (! isDisplayChangeSupported()) + throw new UnsupportedOperationException(); + int i = array == null ? 0 : array.length; + while (--i >= 0) + if (array[i].equals(mode)) + break; + if (i < 0) + throw new IllegalArgumentException(); + this.mode = mode; + } + + /** + * 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() + { + return mode; + } + + /** + * Return an array of all available display modes. This implementation + * returns a 0-length array, so subclasses must override this. + * + * @return the array of available modes + * @since 1.4 + */ + public DisplayMode[] getDisplayModes() + { + return new DisplayMode[0]; + } + + /** + * Return the number of bytes available in accelerated memory on this + * device. The device may support creation or caching on a first-come, + * first-served basis, depending on the operating system and driver. + * Memory may be a finite resource, and because of multi-threading, you + * are not guaranteed that the result of this method ensures your image + * will successfully be put in accelerated memory. A negative result means + * the memory is unlimited. The default implementation assumes no special + * memory is available, and returns 0. + * + * @return the size of accelerated memory available + * @see VolatileImage#flush() + * @see ImageCapabilities#isAccelerated() + */ + public int getAvailableAcceleratedMemory() + { + return 0; + } +} // class GraphicsDevice diff --git a/libjava/classpath/java/awt/GraphicsEnvironment.java b/libjava/classpath/java/awt/GraphicsEnvironment.java new file mode 100644 index 0000000..a82e7a3 --- /dev/null +++ b/libjava/classpath/java/awt/GraphicsEnvironment.java @@ -0,0 +1,244 @@ +/* GraphicsEnvironment.java -- information about the graphics environment + 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 java.awt; + +import gnu.java.awt.ClasspathToolkit; +import gnu.classpath.SystemProperties; +import java.awt.image.BufferedImage; +import java.util.Locale; + +/** + * This descibes the collection of GraphicsDevice and Font objects available + * on a given platform. The resources might be local or remote, and specify + * the valid configurations for displaying graphics. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see GraphicsDevice + * @see GraphicsConfiguration + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class GraphicsEnvironment +{ + private static GraphicsEnvironment localGraphicsEnvironment; + + /** + * The environment must be obtained from a factory or query method, hence + * this constructor is protected. + */ + protected GraphicsEnvironment() + { + } + + /** + * Returns the local graphics environment. If the java.awt.graphicsenv + * system property is set, it instantiates the specified class, + * otherwise it assume that the awt toolkit is a ClasspathToolkit + * and delegates to it to create the instance. + * + * @return the local environment + */ + public static GraphicsEnvironment getLocalGraphicsEnvironment() + { + if (localGraphicsEnvironment != null) + return localGraphicsEnvironment; + + String graphicsenv = SystemProperties.getProperty("java.awt.graphicsenv", + null); + if (graphicsenv != null) + { + try + { + // We intentionally use the bootstrap class loader. + localGraphicsEnvironment = (GraphicsEnvironment) + Class.forName(graphicsenv).newInstance(); + return localGraphicsEnvironment; + } + catch (Exception x) + { + throw (InternalError) + new InternalError("Unable to instantiate java.awt.graphicsenv") + .initCause(x); + } + } + else + { + ClasspathToolkit tk; + tk = ((ClasspathToolkit) Toolkit.getDefaultToolkit()); + localGraphicsEnvironment = tk.getLocalGraphicsEnvironment(); + return localGraphicsEnvironment; + } + } + + /** + * Check if the local environment is headless, meaning that it does not + * support a display, keyboard, or mouse. Many methods in the Abstract + * Windows Toolkit (java.awt) throw a {@link HeadlessException} if this + * returns true. + * + * This method returns true if the java.awt.headless property is set + * to "true". + * + * @return true if the environment is headless, meaning that graphics are + * unsupported + * @since 1.4 + */ + public static boolean isHeadless() + { + String headless = SystemProperties.getProperty("java.awt.headless", null); + return "true".equalsIgnoreCase(headless); + } + + /** + * Check if the given environment is headless, meaning that it does not + * support a display, keyboard, or mouse. Many methods in the Abstract + * Windows Toolkit (java.awt) throw a {@link HeadlessException} if this + * returns true. This default implementation returns isHeadless(), so + * subclasses need only override it if they differ. + * + * @return true if the environment is headless, meaning that graphics are + * unsupported + * @since 1.4 + */ + public boolean isHeadlessInstance() + { + return isHeadless(); + } + + /** + * Get an array of all the GraphicsDevice objects. + * + * @return the available graphics devices, may be 0 length + * @throws HeadlessException if the environment is headless + */ + public abstract GraphicsDevice[] getScreenDevices(); + + /** + * Get the default screen GraphicsDevice object. + * + * @return the default screen device + * @throws HeadlessException if the environment is headless + */ + public abstract GraphicsDevice getDefaultScreenDevice(); + + /** + * Return a Graphics2D object which will render into the specified image. + * + * @param image the image to render into + * @return the object that renders into the image + */ + public abstract Graphics2D createGraphics(BufferedImage image); + + /** + * Returns an array of the one-point size fonts available in this + * environment. From there, the user can select the font and derive the + * correct one of proper size and attributes, using deriveFont. + * Only one master version of each font appears in this array; if a font + * can be derived from another, it must be created in that way. + * + * @return the array of available fonts + * @see #getAvailableFontFamilyNames() + * @see Font#deriveFont(int, float) + * @since 1.2 + */ + public abstract Font[] getAllFonts(); + + /** + * Returns an array of the font family names available in this environment. + * This allows flexibility in choosing the style of font, while still letting + * the Font class decide its best match. + * + * @return the array of available font families + * @see #getAllFonts() + * @see Font#getFamily() + * @since 1.2 + */ + public abstract String[] getAvailableFontFamilyNames(); + + /** + * Returns an array of the font family names available in this environment, + * localized to the current Locale if l is non-null. This allows + * flexibility in choosing the style of font, while still letting the Font + * class decide its best match. + * + * @param l the locale to use + * @return the array of available font families, localized + * @see #getAllFonts() + * @see Font#getFamily() + * @since 1.2 + */ + public abstract String[] getAvailableFontFamilyNames(Locale l); + + /** + * Returns the point where a window should be centered. You should probably + * also check that the window fits within the screen bounds. The default + * simply returns the center of the maximum window bounds; subclasses should + * override this if native objects (like scrollbars) make that off-centered. + * + * @return the centering point + * @throws HeadlessException if the environment is headless + * @see #getMaximumWindowBounds() + * @since 1.4 + */ + public Point getCenterPoint() + { + Rectangle r = getMaximumWindowBounds(); + return new Point(r.x + r.width / 2, r.y + r.height / 2); + } + + /** + * Returns the maximum bounds for a centered window object. The default + * implementation simply returns the bounds of the default configuration + * of the default screen; subclasses should override this to if native + * objects (like scrollbars) reduce what is truly available. Also, + * subclasses should override this if the window should be centered across + * a multi-screen display. + * + * @return the maximum window bounds + * @throws HeadlessException if the environment is headless + * @see #getCenterPoint() + * @see GraphicsConfiguration#getBounds() + * @see Toolkit#getScreenInsets(GraphicsConfiguration) + * @since 1.4 + */ + public Rectangle getMaximumWindowBounds() + { + return getDefaultScreenDevice().getDefaultConfiguration().getBounds(); + } +} // class GraphicsEnvironment diff --git a/libjava/classpath/java/awt/GridBagConstraints.java b/libjava/classpath/java/awt/GridBagConstraints.java new file mode 100644 index 0000000..8d8b4fa --- /dev/null +++ b/libjava/classpath/java/awt/GridBagConstraints.java @@ -0,0 +1,195 @@ +/* GridBagConstraints.java -- Constraints for GridBag layout manager + Copyright (C) 2000, 2001, 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 java.awt; + +import java.io.Serializable; + +/** + * This specifies the constraints for a component managed by the + * GridBagLayout layout manager. + */ +public class GridBagConstraints implements Cloneable, Serializable +{ + static final long serialVersionUID = -1000070633030801713L; + + /** Fill in both directions. */ + public static final int BOTH = 1; + /** Don't fill. */ + public static final int NONE = 0; + /** Fill horizontally. */ + public static final int HORIZONTAL = 2; + /** Fill vertically. */ + public static final int VERTICAL = 3; + + /** Position in the center. */ + public static final int CENTER = 10; + /** Position to the east. */ + public static final int EAST = 13; + /** Position to the north. */ + public static final int NORTH = 11; + /** Position to the northeast. */ + public static final int NORTHEAST = 12; + /** Position to the northwest. */ + public static final int NORTHWEST = 18; + /** Position to the south. */ + public static final int SOUTH = 15; + /** Position to the southeast. */ + public static final int SOUTHEAST = 14; + /** Position to the southwest. */ + public static final int SOUTHWEST = 16; + /** Position to the west. */ + public static final int WEST = 17; + + /** Occupy all remaining cells except last cell. */ + public static final int RELATIVE = -1; + /** Occupy all remaining cells. */ + public static final int REMAINDER = 0; + + /** + * Position to where the first text line would end. Equals to NORTHEAST for + * horizontal left-to-right orientations. + */ + public static final int FIRST_LINE_END = 24; + + /** + * Position to where the first text line would start. Equals to NORTHWEST for + * horizontal left-to-right orientations. + */ + public static final int FIRST_LINE_START = 23; + + /** + * Position to where the last text line would end. Equals to SOUTHEAST for + * horizontal left-to-right orientations. + */ + public static final int LAST_LINE_END = 26; + + /** + * Position to where the last text line would start. Equals to SOUTHWEST for + * horizontal left-to-right orientations. + */ + public static final int LAST_LINE_START = 25; + + /** + * Position to where a text line would end. Equals to EAST for + * left-to-right orientations. + */ + public static final int LINE_END = 22; + + /** + * Position to where a text line would start. Equals to WEST for + * left-to-right orientations. + */ + public static final int LINE_START = 21; + + /** + * Position to where a page ends. Equals SOUTH for horizontal orientations. + */ + public static final int PAGE_END = 20; + + /** + * Position to where a page starts. Equals NORTH for horizontal orientations. + */ + public static final int PAGE_START = 19; + + public int anchor; + public int fill; + public int gridheight; + public int gridwidth; + public int gridx; + public int gridy; + public Insets insets; + public int ipadx; + public int ipady; + public double weightx; + public double weighty; + + /** Create a copy of this object. */ + public Object clone () + { + try + { + GridBagConstraints g = (GridBagConstraints) super.clone (); + g.insets = (Insets) insets.clone (); + return g; + } + catch (CloneNotSupportedException _) + { + // Can't happen. + return null; + } + } + + /** Create a new GridBagConstraints object with the default + * parameters. */ + public GridBagConstraints () + { + this.anchor = CENTER; + this.fill = NONE; + this.gridx = RELATIVE; + this.gridy = RELATIVE; + this.gridwidth = 1; + this.gridheight = 1; + this.ipadx = 0; + this.ipady = 0; + this.insets = new Insets (0, 0, 0, 0); + this.weightx = 0; + this.weighty = 0; + } + + /** Create a new GridBagConstraints object with the indicated + * parameters. */ + public GridBagConstraints (int gridx, int gridy, + int gridwidth, int gridheight, + double weightx, double weighty, + int anchor, int fill, + Insets insets, int ipadx, int ipady) + { + this.anchor = anchor; + this.fill = fill; + this.gridx = gridx; + this.gridy = gridy; + this.gridwidth = gridwidth; + this.gridheight = gridheight; + this.ipadx = ipadx; + this.ipady = ipady; + this.insets = insets; + this.weightx = weightx; + this.weighty = weighty; + } +} diff --git a/libjava/classpath/java/awt/GridBagLayout.java b/libjava/classpath/java/awt/GridBagLayout.java new file mode 100644 index 0000000..767610c --- /dev/null +++ b/libjava/classpath/java/awt/GridBagLayout.java @@ -0,0 +1,1069 @@ +/* GridBagLayout - Layout manager for components according to GridBagConstraints + 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 java.awt; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @author Jeroen Frijters (jeroen@frijters.net) + */ +public class GridBagLayout + implements Serializable, LayoutManager2 +{ + private static final long serialVersionUID = 8838754796412211005L; + + protected static final int MINSIZE = 1; + protected static final int PREFERREDSIZE = 2; + protected static final int MAXGRIDSIZE = 512; + + // comptable remembers the original contraints given to us. + // internalcomptable is used to keep track of modified constraint values + // that we calculate, particularly when we are given RELATIVE and + // REMAINDER constraints. + // Constraints kept in comptable are never modified, and constraints + // kept in internalcomptable can be modified internally only. + protected Hashtable comptable; + private Hashtable internalcomptable; + protected GridBagLayoutInfo layoutInfo; + protected GridBagConstraints defaultConstraints; + + public double[] columnWeights; + public int[] columnWidths; + public double[] rowWeights; + public int[] rowHeights; + + public GridBagLayout () + { + this.comptable = new Hashtable(); + this.internalcomptable = new Hashtable(); + this.defaultConstraints= new GridBagConstraints(); + } + + /** + * Helper method to calc the sum of a range of elements in an int array. + */ + private int sumIntArray (int[] array, int upto) + { + int result = 0; + + for (int i = 0; i < upto; i++) + result += array [i]; + + return result; + } + + /** + * Helper method to calc the sum of all elements in an int array. + */ + private int sumIntArray (int[] array) + { + return sumIntArray(array, array.length); + } + + /** + * Helper method to calc the sum of all elements in an double array. + */ + private double sumDoubleArray (double[] array) + { + double result = 0; + + for (int i = 0; i < array.length; i++) + result += array [i]; + + return result; + } + + public void addLayoutComponent (String name, Component component) + { + // do nothing here. + } + + public void removeLayoutComponent (Component component) + { + // do nothing here + } + + public void addLayoutComponent (Component component, Object constraints) + { + if (constraints == null) + return; + + if (!(constraints instanceof GridBagConstraints)) + throw new IllegalArgumentException("constraints " + + constraints + + " are not an instance of GridBagConstraints"); + + setConstraints (component, (GridBagConstraints) constraints); + } + + public Dimension preferredLayoutSize (Container parent) + { + if (parent == null) + return new Dimension (0, 0); + + GridBagLayoutInfo li = getLayoutInfo (parent, PREFERREDSIZE); + return getMinSize (parent, li); + } + + public Dimension minimumLayoutSize (Container parent) + { + if (parent == null) + return new Dimension (0, 0); + + GridBagLayoutInfo li = getLayoutInfo (parent, MINSIZE); + return getMinSize (parent, li); + } + + public Dimension maximumLayoutSize (Container target) + { + return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + public void layoutContainer (Container parent) + { + arrangeGrid (parent); + } + + public float getLayoutAlignmentX (Container target) + { + return Component.CENTER_ALIGNMENT; + } + + public float getLayoutAlignmentY (Container target) + { + return Component.CENTER_ALIGNMENT; + } + + public void invalidateLayout (Container target) + { + this.layoutInfo = null; + } + + public void setConstraints (Component component, + GridBagConstraints constraints) + { + GridBagConstraints clone = (GridBagConstraints) constraints.clone(); + + if (clone.gridx < 0) + clone.gridx = GridBagConstraints.RELATIVE; + + if (clone.gridy < 0) + clone.gridy = GridBagConstraints.RELATIVE; + + if (clone.gridwidth == 0) + clone.gridwidth = GridBagConstraints.REMAINDER; + else if (clone.gridwidth < 0 + && clone.gridwidth != GridBagConstraints.REMAINDER + && clone.gridwidth != GridBagConstraints.RELATIVE) + clone.gridwidth = 1; + + if (clone.gridheight == 0) + clone.gridheight = GridBagConstraints.REMAINDER; + else if (clone.gridheight < 0 + && clone.gridheight != GridBagConstraints.REMAINDER + && clone.gridheight != GridBagConstraints.RELATIVE) + clone.gridheight = 1; + + comptable.put (component, clone); + } + + public GridBagConstraints getConstraints (Component component) + { + return (GridBagConstraints) (lookupConstraints (component).clone()); + } + + protected GridBagConstraints lookupConstraints (Component component) + { + GridBagConstraints result = (GridBagConstraints) comptable.get (component); + + if (result == null) + { + setConstraints (component, defaultConstraints); + result = (GridBagConstraints) comptable.get (component); + } + + return result; + } + + private GridBagConstraints lookupInternalConstraints (Component component) + { + GridBagConstraints result = + (GridBagConstraints) internalcomptable.get (component); + + if (result == null) + { + result = (GridBagConstraints) lookupConstraints(component).clone(); + internalcomptable.put (component, result); + } + + return result; + } + + /** + * @since 1.1 + */ + public Point getLayoutOrigin () + { + if (layoutInfo == null) + return new Point (0, 0); + + return new Point (layoutInfo.pos_x, layoutInfo.pos_y); + } + + /** + * @since 1.1 + */ + public int[][] getLayoutDimensions () + { + int[][] result = new int [2][]; + if (layoutInfo == null) + { + result[0] = new int[0]; + result[1] = new int[0]; + + return result; + } + + result [0] = new int [layoutInfo.cols]; + System.arraycopy (layoutInfo.colWidths, 0, result [0], 0, layoutInfo.cols); + result [1] = new int [layoutInfo.rows]; + System.arraycopy (layoutInfo.rowHeights, 0, result [1], 0, layoutInfo.rows); + return result; + } + + public double[][] getLayoutWeights () + { + double[][] result = new double [2][]; + if (layoutInfo == null) + { + result[0] = new double[0]; + result[1] = new double[0]; + + return result; + } + + result [0] = new double [layoutInfo.cols]; + System.arraycopy (layoutInfo.colWeights, 0, result [0], 0, layoutInfo.cols); + result [1] = new double [layoutInfo.rows]; + System.arraycopy (layoutInfo.rowWeights, 0, result [1], 0, layoutInfo.rows); + return result; + } + + /** + * @since 1.1 + */ + public Point location (int x, int y) + { + if (layoutInfo == null) + return new Point (0, 0); + + int col; + int row; + int pixel_x = layoutInfo.pos_x; + int pixel_y = layoutInfo.pos_y; + + for (col = 0; col < layoutInfo.cols; col++) + { + int w = layoutInfo.colWidths [col]; + if (x < pixel_x + w) + break; + + pixel_x += w; + } + + for (row = 0; row < layoutInfo.rows; row++) + { + int h = layoutInfo.rowHeights [row]; + if (y < pixel_y + h) + break; + + pixel_y += h; + } + + return new Point (col, row); + } + + /** + * Obsolete. + */ + protected void AdjustForGravity (GridBagConstraints gbc, Rectangle rect) + { + // FIXME + throw new Error ("Not implemented"); + } + + /** + * Obsolete. + */ + protected void ArrangeGrid (Container parent) + { + Component[] components = parent.getComponents(); + + if (components.length == 0) + return; + + GridBagLayoutInfo info = getLayoutInfo (parent, PREFERREDSIZE); + if (info.cols == 0 && info.rows == 0) + return; + layoutInfo = info; + + // DEBUG + //dumpLayoutInfo (layoutInfo); + + for(int i = 0; i < components.length; i++) + { + Component component = components [i]; + + // If component is not visible we dont have to care about it. + if (!component.isVisible()) + continue; + + GridBagConstraints constraints = + lookupInternalConstraints(component); + + int cellx = sumIntArray(layoutInfo.colWidths, constraints.gridx); + int celly = sumIntArray(layoutInfo.rowHeights, constraints.gridy); + int cellw = sumIntArray(layoutInfo.colWidths, + constraints.gridx + constraints.gridwidth) - cellx; + int cellh = sumIntArray(layoutInfo.rowHeights, + constraints.gridy + constraints.gridheight) - celly; + + Insets insets = constraints.insets; + if (insets != null) + { + cellx += insets.left; + celly += insets.top; + cellw -= insets.left + insets.right; + cellh -= insets.top + insets.bottom; + } + + Dimension dim = component.getPreferredSize(); + + // Note: Documentation says that padding is added on both sides, but + // visual inspection shows that the Sun implementation only adds it + // once, so we do the same. + dim.width += constraints.ipadx; + dim.height += constraints.ipady; + + switch(constraints.fill) + { + case GridBagConstraints.HORIZONTAL: + dim.width = cellw; + break; + case GridBagConstraints.VERTICAL: + dim.height = cellh; + break; + case GridBagConstraints.BOTH: + dim.width = cellw; + dim.height = cellh; + break; + } + + int x; + int y; + + switch(constraints.anchor) + { + case GridBagConstraints.NORTH: + x = cellx + (cellw - dim.width) / 2; + y = celly; + break; + case GridBagConstraints.SOUTH: + x = cellx + (cellw - dim.width) / 2; + y = celly + cellh - dim.height; + break; + case GridBagConstraints.WEST: + x = cellx; + y = celly + (cellh - dim.height) / 2; + break; + case GridBagConstraints.EAST: + x = cellx + cellw - dim.width; + y = celly + (cellh - dim.height) / 2; + break; + case GridBagConstraints.NORTHEAST: + x = cellx + cellw - dim.width; + y = celly; + break; + case GridBagConstraints.NORTHWEST: + x = cellx; + y = celly; + break; + case GridBagConstraints.SOUTHEAST: + x = cellx + cellw - dim.width; + y = celly + cellh - dim.height; + break; + case GridBagConstraints.SOUTHWEST: + x = cellx; + y = celly + cellh - dim.height; + break; + default: + x = cellx + (cellw - dim.width) / 2; + y = celly + (cellh - dim.height) / 2; + break; + } + + component.setBounds(layoutInfo.pos_x + x, layoutInfo.pos_y + y, dim.width, dim.height); + } + + // DEBUG + //dumpLayoutInfo (layoutInfo); + } + + /** + * Obsolete. + */ + protected GridBagLayoutInfo GetLayoutInfo (Container parent, int sizeflag) + { + if (sizeflag != MINSIZE && sizeflag != PREFERREDSIZE) + throw new IllegalArgumentException(); + + Dimension parentDim = parent.getSize (); + Insets parentInsets = parent.getInsets (); + parentDim.width -= parentInsets.left + parentInsets.right; + parentDim.height -= parentInsets.top + parentInsets.bottom; + + int current_y = 0; + int max_x = 0; + int max_y = 0; + + // Guaranteed to contain the last component added to the given row + // or column, whose gridwidth/height is not REMAINDER. + HashMap lastInRow = new HashMap(); + HashMap lastInCol = new HashMap(); + + Component[] components = parent.getComponents(); + + // Components sorted by gridwidths/heights, + // smallest to largest, with REMAINDER and RELATIVE at the end. + // These are useful when determining sizes and weights. + ArrayList sortedByWidth = new ArrayList(components.length); + ArrayList sortedByHeight = new ArrayList(components.length); + + // STEP 1: first we figure out how many rows/columns + for (int i = 0; i < components.length; i++) + { + Component component = components [i]; + + // If component is not visible we dont have to care about it. + if (!component.isVisible()) + continue; + + // When looking up the constraint for the first time, check the + // original unmodified constraint. After the first time, always + // refer to the internal modified constraint. + GridBagConstraints originalConstraints = lookupConstraints (component); + GridBagConstraints constraints = (GridBagConstraints) originalConstraints.clone(); + internalcomptable.put(component, constraints); + + // Cases: + // + // 1. gridy == RELATIVE, gridx == RELATIVE + // + // use y as the row number; check for the next + // available slot at row y + // + // 2. only gridx == RELATIVE + // + // check for the next available slot at row gridy + // + // 3. only gridy == RELATIVE + // + // check for the next available slot at column gridx + // + // 4. neither gridx or gridy == RELATIVE + // + // nothing to check; just add it + + + // cases 1 and 2 + if(constraints.gridx == GridBagConstraints.RELATIVE) + { + if (constraints.gridy == GridBagConstraints.RELATIVE) + constraints.gridy = current_y; + + int x; + + // Check the component that occupies the right-most spot in this + // row. We want to add this component after it. + // If this row is empty, add to the 0 position. + if (!lastInRow.containsKey(new Integer(constraints.gridy))) + x = 0; + else + { + Component lastComponent = (Component) lastInRow.get(new Integer(constraints.gridy)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + x = lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth); + } + + // Determine if this component will fit in the slot vertically. + // If not, bump it over to where it does fit. + for (int y = constraints.gridy + 1; y < constraints.gridy + Math.max(1, constraints.gridheight); y++) + { + if (lastInRow.containsKey(new Integer(y))) + { + Component lastComponent = (Component) lastInRow.get(new Integer(y)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + x = Math.max (x, + lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth)); + } + } + + constraints.gridx = x; + } + // case 3 + else if(constraints.gridy == GridBagConstraints.RELATIVE) + { + int y; + // Check the component that occupies the bottom-most spot in + // this column. We want to add this component below it. + // If this column is empty, add to the 0 position. + if (!lastInCol.containsKey(new Integer(constraints.gridx))) + y = 0; + else + { + Component lastComponent = (Component)lastInCol.get(new Integer(constraints.gridx)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + y = lastConstraints.gridy + Math.max(1, lastConstraints.gridheight); + } + + // Determine if this component will fit in the slot horizontally. + // If not, bump it down to where it does fit. + for (int x = constraints.gridx + 1; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++) + { + if (lastInCol.containsKey(new Integer(x))) + { + Component lastComponent = (Component) lastInCol.get(new Integer(x)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + y = Math.max (y, + lastConstraints.gridy + Math.max(1, lastConstraints.gridheight)); + } + } + + constraints.gridy = y; + } + // case 4: do nothing + + max_x = Math.max(max_x, + constraints.gridx + Math.max(1, constraints.gridwidth)); + max_y = Math.max(max_y, + constraints.gridy + Math.max(1, constraints.gridheight)); + + sortBySpan(component, constraints.gridwidth, sortedByWidth, true); + sortBySpan(component, constraints.gridheight, sortedByHeight, false); + + // Update our reference points for RELATIVE gridx and gridy. + if(constraints.gridwidth == GridBagConstraints.REMAINDER) + { + current_y = constraints.gridy + Math.max(1, constraints.gridheight); + } + else if (constraints.gridwidth != GridBagConstraints.REMAINDER) + { + for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++) + { + if(lastInRow.containsKey(new Integer(y))) + { + Component lastComponent = (Component) lastInRow.get(new Integer(y)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + if (constraints.gridx > lastConstraints.gridx) + { + lastInRow.put(new Integer(y), component); + } + } + else + { + lastInRow.put(new Integer(y), component); + } + } + + for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++) + { + if(lastInCol.containsKey(new Integer(x))) + { + Component lastComponent = (Component) lastInCol.get(new Integer(x)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + if (constraints.gridy > lastConstraints.gridy) + { + lastInCol.put(new Integer(x), component); + } + } + else + { + lastInCol.put(new Integer(x), component); + } + } + } + } // end of STEP 1 + + GridBagLayoutInfo info = new GridBagLayoutInfo(max_x, max_y); + + // Check if column widths and row heights are overridden. + + for (int x = 0; x < max_x; x++) + { + if(columnWidths != null && columnWidths.length > x) + info.colWidths[x] = columnWidths[x]; + if(columnWeights != null && columnWeights.length > x) + info.colWeights[x] = columnWeights[x]; + } + + for (int y = 0; y < max_y; y++) + { + if(rowHeights != null && rowHeights.length > y) + info.rowHeights[y] = rowHeights[y]; + if(rowWeights != null && rowWeights.length > y) + info.rowWeights[y] = rowWeights[y]; + } + + // STEP 2: Fix up any cells with width/height as REMAINDER/RELATIVE. + for (int i = 0; i < components.length; i++) + { + Component component = components [i]; + + // If component is not visible we dont have to care about it. + if (!component.isVisible()) + continue; + + GridBagConstraints constraints = lookupInternalConstraints (component); + + if(constraints.gridwidth == GridBagConstraints.REMAINDER || constraints.gridwidth == GridBagConstraints.RELATIVE) + { + if(constraints.gridwidth == GridBagConstraints.REMAINDER) + { + for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++) + { + if (lastInRow.containsKey(new Integer(y))) + { + Component lastComponent = (Component) lastInRow.get(new Integer(y)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + + if (lastConstraints.gridwidth == GridBagConstraints.RELATIVE) + { + constraints.gridx = max_x - 1; + break; + } + else + { + constraints.gridx = Math.max (constraints.gridx, + lastConstraints.gridx + Math.max (1, lastConstraints.gridwidth)); + } + } + } + constraints.gridwidth = max_x - constraints.gridx; + } + else if (constraints.gridwidth == GridBagConstraints.RELATIVE) + { + constraints.gridwidth = max_x - constraints.gridx - 1; + } + + // Re-sort + sortedByWidth.remove(sortedByWidth.indexOf(component)); + sortBySpan(component, constraints.gridwidth, sortedByWidth, true); + } + + if(constraints.gridheight == GridBagConstraints.REMAINDER || constraints.gridheight == GridBagConstraints.RELATIVE) + { + if(constraints.gridheight == GridBagConstraints.REMAINDER) + { + for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++) + { + if (lastInCol.containsKey(new Integer(x))) + { + Component lastComponent = (Component) lastInRow.get(new Integer(x)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + + if (lastConstraints.gridheight == GridBagConstraints.RELATIVE) + { + constraints.gridy = max_y - 1; + break; + } + else + { + constraints.gridy = Math.max (constraints.gridy, + lastConstraints.gridy + Math.max (1, lastConstraints.gridheight)); + } + } + } + constraints.gridheight = max_y - constraints.gridy; + } + else if (constraints.gridheight == GridBagConstraints.RELATIVE) + { + constraints.gridheight = max_y - constraints.gridy - 1; + } + + // Re-sort + sortedByHeight.remove(sortedByHeight.indexOf(component)); + sortBySpan(component, constraints.gridheight, sortedByHeight, false); + } + } // end of STEP 2 + + // STEP 3: Determine sizes and weights for columns. + for (int i = 0; i < sortedByWidth.size(); i++) + { + Component component = (Component) sortedByWidth.get(i); + + // If component is not visible we dont have to care about it. + if (!component.isVisible()) + continue; + + GridBagConstraints constraints = lookupInternalConstraints (component); + + int width = (sizeflag == PREFERREDSIZE) ? + component.getPreferredSize().width : + component.getMinimumSize().width; + + if(constraints.insets != null) + width += constraints.insets.left + constraints.insets.right; + + width += constraints.ipadx; + + distributeSizeAndWeight(width, + constraints.weightx, + constraints.gridx, + constraints.gridwidth, + info.colWidths, + info.colWeights); + } // end of STEP 3 + + // STEP 4: Determine sizes and weights for rows. + for (int i = 0; i < sortedByHeight.size(); i++) + { + Component component = (Component) sortedByHeight.get(i); + + // If component is not visible we dont have to care about it. + if (!component.isVisible()) + continue; + + GridBagConstraints constraints = lookupInternalConstraints (component); + + int height = (sizeflag == PREFERREDSIZE) ? + component.getPreferredSize().height : + component.getMinimumSize().height; + + if(constraints.insets != null) + height += constraints.insets.top + constraints.insets.bottom; + + height += constraints.ipady; + + distributeSizeAndWeight(height, + constraints.weighty, + constraints.gridy, + constraints.gridheight, + info.rowHeights, + info.rowWeights); + } // end of STEP 4 + + // Adjust cell sizes iff parent size not zero. + if (parentDim.width > 0 && parentDim.height > 0) + { + calcCellSizes (info.colWidths, info.colWeights, parentDim.width); + calcCellSizes (info.rowHeights, info.rowWeights, parentDim.height); + } + + int totalWidth = sumIntArray(info.colWidths); + int totalHeight = sumIntArray(info.rowHeights); + + // Make sure pos_x and pos_y are never negative. + if (totalWidth >= parentDim.width) + info.pos_x = parentInsets.left; + else + info.pos_x = parentInsets.left + (parentDim.width - totalWidth) / 2; + + if (totalHeight >= parentDim.height) + info.pos_y = parentInsets.top; + else + info.pos_y = parentInsets.top + (parentDim.height - totalHeight) / 2; + + // DEBUG + //dumpLayoutInfo (info); + + return info; + } + + /** + * Obsolete. + */ + protected Dimension GetMinSize (Container parent, GridBagLayoutInfo info) + { + if (parent == null || info == null) + return new Dimension (0, 0); + + Insets insets = parent.getInsets(); + int width = sumIntArray (info.colWidths) + insets.left + insets.right; + int height = sumIntArray (info.rowHeights) + insets.top + insets.bottom; + return new Dimension (width, height); + } + + /** + * @since 1.4 + */ + protected Dimension getMinSize (Container parent, GridBagLayoutInfo info) + { + return GetMinSize (parent, info); + } + + /** + * Helper method used by GetLayoutInfo to keep components sorted, either + * by gridwidth or gridheight. + * + * @param component Component to add to the sorted list. + * @param span Either the component's gridwidth or gridheight. + * @param list ArrayList of components, sorted by + * their span. + * @param sortByWidth Flag indicating sorting index. If true, sort by + * width. Otherwise, sort by height. + * FIXME: Use a better sorting algorithm. + */ + private void sortBySpan (Component component, int span, ArrayList list, boolean sortByWidth) + { + if (span == GridBagConstraints.REMAINDER + || span == GridBagConstraints.RELATIVE) + { + // Put all RELATIVE and REMAINDER components at the end. + list.add(component); + } + else + { + int i = 0; + if (list.size() > 0) + { + GridBagConstraints gbc = lookupInternalConstraints((Component) list.get(i)); + int otherspan = sortByWidth ? + gbc.gridwidth : + gbc.gridheight; + while (otherspan != GridBagConstraints.REMAINDER + && otherspan != GridBagConstraints.RELATIVE + && span >= otherspan) + { + i++; + if (i < list.size()) + { + gbc = lookupInternalConstraints((Component) list.get(i)); + otherspan = sortByWidth ? + gbc.gridwidth : + gbc.gridheight; + } + else + break; + } + } + list.add(i, component); + } + } + + /** + * Helper method used by GetLayoutInfo to distribute a component's size + * and weight. + * + * @param size Preferred size of component, with inset and padding + * already added. + * @param weight Weight of component. + * @param start Starting position of component. Either + * constraints.gridx or gridy. + * @param span Span of component. either contraints.gridwidth or + * gridheight. + * @param sizes Sizes of rows or columns. + * @param weights Weights of rows or columns. + */ + private void distributeSizeAndWeight (int size, double weight, + int start, int span, + int[] sizes, double[] weights) + { + if (span == 1) + { + sizes[start] = Math.max(sizes[start], size); + weights[start] = Math.max(weights[start], weight); + } + else + { + int numOccupied = span; + int lastOccupied = -1; + + for(int i = start; i < start + span; i++) + { + if (sizes[i] == 0.0) + numOccupied--; + else + { + size -= sizes[i]; + lastOccupied = i; + } + } + + // A component needs to occupy at least one row. + if(numOccupied == 0) + sizes[start + span - 1] = size; + else if (size > 0) + sizes[lastOccupied] += size; + + calcCellWeights(weight, weights, start, span); + } + } + + /** + * Helper method used by GetLayoutInfo to calculate weight distribution. + * @param weight Weight of component. + * @param weights Weights of rows/columns. + * @param start Starting position of component in grid (gridx/gridy). + * @param span Span of component (gridwidth/gridheight). + */ + private void calcCellWeights (double weight, double[] weights, int start, int span) + { + double totalWeight = 0.0; + for(int k = start; k < start + span; k++) + totalWeight += weights[k]; + + if(weight > totalWeight) + { + if (totalWeight == 0.0) + { + weights[start + span - 1] += weight; + } + else + { + double diff = weight - totalWeight ; + double remaining = diff; + + for(int k = start; k < start + span; k++) + { + double extraWeight = diff * weights[k] / totalWeight; + weights[k] += extraWeight; + remaining -= extraWeight; + } + + if (remaining > 0.0 && weights[start + span - 1] != 0.0) + { + weights[start + span - 1] += remaining; + } + } + } + } + + /** + * Helper method used by GetLayoutInfo to distribute extra space + * based on weight distribution. + * + * @param sizes Sizes of rows/columns. + * @param weights Weights of rows/columns. + * @param range Dimension of container. + */ + private void calcCellSizes (int[] sizes, double[] weights, int range) + { + int totalSize = sumIntArray (sizes); + double totalWeight = sumDoubleArray (weights); + + int diff = range - totalSize; + + if (diff == 0) + return; + + for (int i = 0; i < sizes.length; i++) + { + int newsize = (int) (sizes[i] + (((double) diff) * weights [i] / totalWeight )); + + if (newsize > 0) + sizes[i] = newsize; + } + } + + private void dumpLayoutInfo (GridBagLayoutInfo info) + { + System.out.println ("GridBagLayoutInfo:"); + System.out.println ("cols: " + info.cols + ", rows: " + info.rows); + System.out.print ("colWidths: "); + dumpArray(info.colWidths); + System.out.print ("rowHeights: "); + dumpArray(info.rowHeights); + System.out.print ("colWeights: "); + dumpArray(info.colWeights); + System.out.print ("rowWeights: "); + dumpArray(info.rowWeights); + } + + private void dumpArray(int[] array) + { + String sep = ""; + for(int i = 0; i < array.length; i++) + { + System.out.print(sep); + System.out.print(array[i]); + sep = ", "; + } + System.out.println(); + } + + private void dumpArray(double[] array) + { + String sep = ""; + for(int i = 0; i < array.length; i++) + { + System.out.print(sep); + System.out.print(array[i]); + sep = ", "; + } + System.out.println(); + } + + /** + * @since 1.4 + */ + protected void arrangeGrid (Container parent) + { + ArrangeGrid (parent); + } + + /** + * @since 1.4 + */ + protected GridBagLayoutInfo getLayoutInfo (Container parent, int sizeflag) + { + return GetLayoutInfo (parent, sizeflag); + } + + /** + * @since 1.4 + */ + protected void adjustForGravity (GridBagConstraints gbc, Rectangle rect) + { + AdjustForGravity (gbc, rect); + } +} diff --git a/libjava/classpath/java/awt/GridBagLayoutInfo.java b/libjava/classpath/java/awt/GridBagLayoutInfo.java new file mode 100644 index 0000000..43ba09d --- /dev/null +++ b/libjava/classpath/java/awt/GridBagLayoutInfo.java @@ -0,0 +1,70 @@ +/* GridBagLayoutInfo - + 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 java.awt; + +import java.io.Serializable; + +/** + * @author Michael Koch (konqueror@gmx.de) + */ +class GridBagLayoutInfo implements Serializable +{ + private static final long serialVersionUID = -4899416460737170217L; + + int pos_x; + int pos_y; + int cols; + int rows; + int colWidths[]; + int rowHeights[]; + double colWeights[]; + double rowWeights[]; + + GridBagLayoutInfo (int cols, int rows) + { + this.pos_x = 0; + this.pos_y = 0; + this.cols = cols; + this.rows = rows; + this.colWidths = new int [cols]; + this.rowHeights = new int [rows]; + this.colWeights = new double [cols]; + this.rowWeights = new double [rows]; + } +} diff --git a/libjava/classpath/java/awt/GridLayout.java b/libjava/classpath/java/awt/GridLayout.java new file mode 100644 index 0000000..80d9641 --- /dev/null +++ b/libjava/classpath/java/awt/GridLayout.java @@ -0,0 +1,360 @@ +/* GridLayout.java -- Grid-based layout engine + Copyright (C) 1999, 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 java.awt; + +import java.io.Serializable; + +/** This class implements a grid-based layout scheme. Components are + * all given the same size and are laid out from left to right and top + * to bottom. A GridLayout is configured with a number of rows and a + * number of columns. If both are specified, then the number of + * columns is ignored and is derived from the number of rows and the + * total number of components. If either is zero then that dimension + * is computed based on the actual size of the container. An + * exception is thrown if an attempt is made to set both the number of + * rows and the number of columns to 0. This class also supports + * horizontal and vertical gaps; these are used as spacing between + * cells. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class GridLayout implements LayoutManager, Serializable +{ + static final long serialVersionUID = -7411804673224730901L; + + /** Add a new component to the layout. This particular implementation + * does nothing. + * @param name The name of the component to add. + * @param comp The component to add. + */ + public void addLayoutComponent (String name, Component comp) + { + // Nothing. + } + + /** Return the number of columns in this layout. */ + public int getColumns () + { + return cols; + } + + /** Return the horizontal gap. */ + public int getHgap () + { + return hgap; + } + + /** Return the number of rows in this layout. */ + public int getRows () + { + return rows; + } + + /** Return the vertical gap. */ + public int getVgap () + { + return vgap; + } + + /** Create a new GridLayout with one row and any number + * of columns. Both gaps are set to 0. + */ + public GridLayout () + { + this (1, 0, 0, 0); + } + + /** Create a new GridLayout with the specified number + * of rows and columns. Both gaps are set to 0. Note that the row + * and column settings cannot both be zero. If both the row and + * column values are non-zero, the rows value takes precedence. + * @param rows Number of rows + * @param cols Number of columns + * @exception IllegalArgumentException If rows and columns are both + * 0, or if either are negative + */ + public GridLayout (int rows, int cols) + { + this (rows, cols, 0, 0); + } + + /** Create a new GridLayout with the specified number of rows and + * columns and the specified gaps. + * Note that the row and column settings cannot both be + * zero. If both the row and column values are non-zero, the rows value + * takes precedence. + * @param rows Number of rows + * @param cols Number of columns + * @param hgap The horizontal gap + * @param vgap The vertical gap + * @exception IllegalArgumentException If rows and columns are both + * 0, if either are negative, or if either gap is negative + */ + public GridLayout (int rows, int cols, int hgap, int vgap) + { + if (rows < 0) + throw new IllegalArgumentException ("number of rows cannot be negative"); + if (cols < 0) + throw new IllegalArgumentException ("number of columns cannot be negative"); + if (rows == 0 && cols == 0) + throw new IllegalArgumentException ("both rows and columns cannot be 0"); + if (hgap < 0) + throw new IllegalArgumentException ("horizontal gap must be nonnegative"); + if (vgap < 0) + throw new IllegalArgumentException ("vertical gap must be nonnegative"); + this.rows = rows; + this.cols = cols; + this.hgap = hgap; + this.vgap = vgap; + } + + /** Lay out the container's components based on current settings. + * The free space in the container is divided evenly into the specified + * number of rows and columns in this object. + * @param parent The container to lay out + */ + public void layoutContainer (Container parent) + { + synchronized (parent.getTreeLock ()) + { + int num = parent.ncomponents; + + // There's no point, and handling this would mean adding special + // cases. + if (num == 0) + return; + + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + int real_rows = rows; + int real_cols = cols; + if (real_rows == 0) + real_rows = (num + real_cols - 1) / real_cols; + else + real_cols = (num + real_rows - 1) / real_rows; + + // We might have less than a single row. In this case we expand + // to fill. + if (num < real_cols) + real_cols = num; + + Dimension d = parent.getSize (); + Insets ins = parent.getInsets (); + + // Compute width and height of each cell in the grid. + int tw = d.width - ins.left - ins.right; + tw = (tw - (real_cols - 1) * hgap) / real_cols; + int th = d.height - ins.top - ins.bottom; + th = (th - (real_rows - 1) * vgap) / real_rows; + + // If the cells are too small, still try to do something. + if (tw < 0) + tw = 1; + if (th < 0) + th = 1; + + int x = ins.left; + int y = ins.top; + int i = 0; + int recount = 0; + + while (i < num) + { + comps[i].setBounds (x, y, tw, th); + + ++i; + ++recount; + if (recount == real_cols) + { + recount = 0; + y += vgap + th; + x = ins.left; + } + else + x += hgap + tw; + } + } + } + + /** Get the minimum layout size of the container. + * @param cont The parent container + */ + public Dimension minimumLayoutSize (Container cont) + { + return getSize (cont, true); + } + + /** Get the preferred layout size of the container. + * @param cont The parent container + */ + public Dimension preferredLayoutSize (Container cont) + { + return getSize (cont, false); + } + + /** Remove the indicated component from this layout manager. + * This particular implementation does nothing. + * @param comp The component to remove + */ + public void removeLayoutComponent (Component comp) + { + // Nothing. + } + + /** Set the number of columns. + * @param newCols + * @exception IllegalArgumentException If the number of columns is + * negative, or if the number of columns is zero and the number + * of rows is already 0. + */ + public void setColumns (int newCols) + { + if (newCols < 0) + throw new IllegalArgumentException ("number of columns cannot be negative"); + if (newCols == 0 && rows == 0) + throw new IllegalArgumentException ("number of rows is already 0"); + this.cols = newCols; + } + + /** Set the horizontal gap + * @param hgap The horizontal gap + * @exception IllegalArgumentException If the hgap value is less than zero. + */ + public void setHgap (int hgap) + { + if (hgap < 0) + throw new IllegalArgumentException ("horizontal gap must be nonnegative"); + this.hgap = hgap; + } + + /** Set the number of rows + * @param newRows + * @exception IllegalArgumentException If the number of rows is + * negative, or if the number of rows is zero and the number + * of columns is already 0. + */ + public void setRows (int newRows) + { + if (newRows < 0) + throw new IllegalArgumentException ("number of rows cannot be negative"); + if (newRows == 0 && cols == 0) + throw new IllegalArgumentException ("number of columns is already 0"); + this.rows = newRows; + } + + /** Set the vertical gap. + * @param vgap The vertical gap + * @exception IllegalArgumentException If the vgap value is less than zero. + */ + public void setVgap (int vgap) + { + if (vgap < 0) + throw new IllegalArgumentException ("vertical gap must be nonnegative"); + this.vgap = vgap; + } + + /** Return String description of this object. */ + public String toString () + { + return ("[" + getClass ().getName () + + ",hgap=" + hgap + ",vgap=" + vgap + + ",rows=" + rows + ",cols=" + cols + + "]"); + } + + // This method is used to compute the various sizes. + private Dimension getSize (Container parent, boolean is_min) + { + synchronized (parent.getTreeLock ()) + { + int w = 0, h = 0, num = parent.ncomponents; + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + for (int i = 0; i < num; ++i) + { + Dimension d; + + if (is_min) + d = comps[i].getMinimumSize (); + else + d = comps[i].getPreferredSize (); + + w = Math.max (d.width, w); + h = Math.max (d.height, h); + } + + int real_rows = rows; + int real_cols = cols; + if (real_rows == 0) + real_rows = (num + real_cols - 1) / real_cols; + else + real_cols = (num + real_rows - 1) / real_rows; + + Insets ins = parent.getInsets (); + // We subtract out an extra gap here because the gaps are only + // between cells. + w = ins.left + ins.right + real_cols * (w + hgap) - hgap; + h = ins.top + ins.bottom + real_rows * (h + vgap) - vgap; + return new Dimension (w, h); + } + } + + /** + * @serial The number of columns in the grid. + */ + private int cols; + + /** + * @serial The number of rows in the grid. + */ + private int rows; + + /** + * @serial The horizontal gap between columns + */ + private int hgap; + + /** + * @serial The vertical gap between rows + */ + private int vgap; +} diff --git a/libjava/classpath/java/awt/HeadlessException.java b/libjava/classpath/java/awt/HeadlessException.java new file mode 100644 index 0000000..b180b1d --- /dev/null +++ b/libjava/classpath/java/awt/HeadlessException.java @@ -0,0 +1,72 @@ +/* HeadlessException.java -- operation not possible in headless environment + 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 java.awt; + +/** + * This exception is thrown when code dependent on a keyboard, mouse, or + * display is executed in a headless environment. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public class HeadlessException extends UnsupportedOperationException +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 167183644944358563L; + + /** + * Create a new instance with no detailed error message. + */ + public HeadlessException() + { + } + + /** + * Create a new instance with the specified detailed error message. + * + * @param message the detailed error message + */ + public HeadlessException(String message) + { + super(message); + } +} // class HeadlessException diff --git a/libjava/classpath/java/awt/IllegalComponentStateException.java b/libjava/classpath/java/awt/IllegalComponentStateException.java new file mode 100644 index 0000000..4a47f1d --- /dev/null +++ b/libjava/classpath/java/awt/IllegalComponentStateException.java @@ -0,0 +1,71 @@ +/* IllegalComponentStateException.java -- bad component state + Copyright (C) 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 java.awt; + +/** + * This exception is thrown when the requested operation failed because + * a component was not in the proper state. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class IllegalComponentStateException extends IllegalStateException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -1889339587208144238L; + + /** + * Create a new instance with no detailed error message. + */ + public IllegalComponentStateException() + { + } + + /** + * Create a new instance with the specified detailed error message. + * + * @param message the detailed error message + */ + public IllegalComponentStateException(String message) + { + super(message); + } +} // class IllegalComponentStateException diff --git a/libjava/classpath/java/awt/Image.java b/libjava/classpath/java/awt/Image.java new file mode 100644 index 0000000..b657ad0 --- /dev/null +++ b/libjava/classpath/java/awt/Image.java @@ -0,0 +1,203 @@ +/* Image.java -- superclass for images + Copyright (C) 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 java.awt; + +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.ReplicateScaleFilter; + +/** + * This is the abstract superclass of all image objects in Java. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public abstract class Image +{ + /** + * This variable is returned whenever a property that is not defined + * is requested. + */ + // For debug purposes, this might as well be a unique string. + public static final Object UndefinedProperty + = new String("undefined property"); + + /** + * Constant indicating that the default scaling algorithm should be used. + * + * @since 1.1 + */ + public static final int SCALE_DEFAULT = 1; + + /** + * Constant indicating that a fast scaling algorithm should be used. + * + * @since 1.1 + */ + public static final int SCALE_FAST = 2; + + /** + * Constant indicating that a smooth scaling algorithm should be used. + * + * @since 1.1 + */ + public static final int SCALE_SMOOTH = 4; + + /** + * Constant indicating that the ReplicateScaleFilter class + * algorithm should be used for scaling. + * + * @see ReplicateScaleFilter + * @since 1.1 + */ + public static final int SCALE_REPLICATE = 8; + + /** + * Constant indicating that the area averaging scaling algorithm should be + * used. + * + * @see java.awt.image.AreaAveragingScaleFilter + * @since 1.1 + */ + public static final int SCALE_AREA_AVERAGING = 16; + + /** + * A default constructor for subclasses. + */ + public Image() + { + } + + /** + * Returns the width of the image, or -1 if it is unknown. If the + * image width is unknown, the observer object will be notified when + * the value is known. + * + * @param observer the image observer for this object + * @return the width in pixels + * @see #getHeight(ImageObserver) + */ + public abstract int getWidth(ImageObserver observer); + + /** + * Returns the height of the image, or -1 if it is unknown. If the + * image height is unknown, the observer object will be notified when + * the value is known. + * + * @param observer the image observer for this object + * @return the height in pixels + * @see #getWidth(ImageObserver) + */ + public abstract int getHeight(ImageObserver observer); + + /** + * Returns the image producer object for this object. The producer is the + * object which generates pixels for this image. + * + * @return the image producer for this object + */ + public abstract ImageProducer getSource(); + + /** + * Returns a graphics context object for drawing an off-screen object. + * This method is only valid for off-screen objects. + * + * @return a graphics context object for an off-screen object + * @see Graphics#getcreateImage(int, int) + */ + public abstract Graphics getGraphics(); + + /** + * This method requests a named property for an object. The value of the + * property is returned. The value UndefinedProperty is + * returned if there is no property with the specified name. The value + * null is returned if the properties for the object are + * not yet known. In this case, the specified image observer is notified + * when the properties are known. + * + * @param name the requested property name + * @param observer the image observer for this object + * @return the named property, if available + * @see #UndefinedProperty + */ + public abstract Object getProperty(String name, ImageObserver observer); + + /** + * Scales the image to the requested dimension. A new Image with asynchronous + * loading will be produced according to the hints of the algorithm + * requested. If either the width or height is non-positive, it is adjusted + * to preserve the original aspect ratio. + * + * @param width the width of the scaled image + * @param height the height of the scaled image + * @param flags a value indicating the algorithm to use + * @return the scaled Image object + * @see #SCALE_DEFAULT + * @see #SCALE_FAST + * @see #SCALE_SMOOTH + * @see #SCALE_REPLICATE + * @see #SCALE_AREA_AVERAGING + * @since 1.1 + */ + public Image getScaledInstance(int width, int height, int flags) + { + switch (flags) + { + case SCALE_DEFAULT: + case SCALE_FAST: + case SCALE_REPLICATE: + ImageProducer producer = + new FilteredImageSource(this.getSource(), + new ReplicateScaleFilter(width, height)); + return Toolkit.getDefaultToolkit().createImage(producer); + case SCALE_SMOOTH: + case SCALE_AREA_AVERAGING: + default: + throw new Error("not implemented"); + } + } + + /** + * Flushes (that is, destroys) any resources used for this image. This + * includes the actual image data. + */ + public abstract void flush(); +} // class Image diff --git a/libjava/classpath/java/awt/ImageCapabilities.java b/libjava/classpath/java/awt/ImageCapabilities.java new file mode 100644 index 0000000..2fe71d1 --- /dev/null +++ b/libjava/classpath/java/awt/ImageCapabilities.java @@ -0,0 +1,107 @@ +/* ImageCapabilities.java -- the capabilities of an image buffer + 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 java.awt; + +/** + * This class represents the capabilities of an image buffer. An + * image buffer may be backed by accelerated graphics resources. + * Those resources may or may not be volatile. This class is used to + * describe these image buffer characteristics. + */ +public class ImageCapabilities implements Cloneable +{ + /** + * Whether or not this the image buffer uses accelerated graphics + * resources. + */ + private final boolean accelerated; + + /** + * Create a new image capability descriptor. + * + * @param accelerated true if the image buffer uses accelerated + * graphics resources + */ + public ImageCapabilities(boolean accelerated) + { + this.accelerated = accelerated; + } + + /** + * Returns whether or not the image buffer uses accelerated graphics + * resources. + * + * @return true if the image buffer uses accelerated graphics + * resources; false otherwise + */ + public boolean isAccelerated() + { + return accelerated; + } + + /** + * Returns whether or not the image buffer's resources are volatile, + * meaning that they can be reclaimed by the graphics system at any + * time. + * + * @return true if the image buffer's resources are volatile; false + * otherwise + */ + public boolean isTrueVolatile() + { + return true; + } + + /** + * Clone this image capability descriptor. + * + * @return a clone of this image capability descriptor + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); + } + } +} diff --git a/libjava/classpath/java/awt/Insets.java b/libjava/classpath/java/awt/Insets.java new file mode 100644 index 0000000..7238a34 --- /dev/null +++ b/libjava/classpath/java/awt/Insets.java @@ -0,0 +1,158 @@ +/* Insets.java -- information about a container border + Copyright (C) 1999, 2000, 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 java.awt; + +import java.io.Serializable; + +/** + * This class represents the "margin" or space around a container. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @status + */ +public class Insets implements Cloneable, Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -2272572637695466749L; + + /** + * The gap from the top. + * + * @serial the top inset + */ + public int top; + + /** + * The gap from the left. + * + * @serial the left inset + */ + public int left; + + /** + * The gap from the bottom. + * + * @serial the bottom inset + */ + public int bottom; + + /** + * The gap from the right. + * + * @serial the right inset + */ + public int right; + + /** + * Initializes a new instance of Inset with the specified + * inset values. + * + * @param top the top inset + * @param left the left inset + * @param bottom the bottom inset + * @param right the right inset + */ + public Insets(int top, int left, int bottom, int right) + { + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + + /** + * Tests whether this object is equal to the specified object. The other + * object must be an instance of Insets with identical field values. + * + * @param obj the object to test against + * @return true if the specified object is equal to this one + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Insets)) + return false; + Insets i = (Insets) obj; + return top == i.top && bottom == i.bottom + && left == i.left && right == i.right; + } + + /** + * Returns a hashcode for this instance. The formula is unspecified, but + * appears to be XXX what is it? . + * + * @return the hashcode + */ + public int hashCode() + { + // This can't be right... + return top + bottom + left + right; + } + + /** + * Returns a string representation of this object, which will be non-null. + * The format is unspecified, but appears to be XXX what is it?. + * + * @return a string representation of this object + */ + public String toString() + { + return getClass().getName() + "(top=" + top + ",bottom=" + bottom + + ",left=" + left + ",right=" + right + ')'; + } + + /** + * Returns a copy of this object. + * + * @return a copy of this object + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } +} // class Insets diff --git a/libjava/classpath/java/awt/ItemSelectable.java b/libjava/classpath/java/awt/ItemSelectable.java new file mode 100644 index 0000000..f155f72 --- /dev/null +++ b/libjava/classpath/java/awt/ItemSelectable.java @@ -0,0 +1,75 @@ +/* ItemSelectable.java -- items that can be selected + Copyright (C) 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 java.awt; + +import java.awt.event.ItemListener; + +/** + * This interface is for objects that can have one or more items selected. + * For example, radio buttons. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface ItemSelectable +{ + /** + * Returns the list of objects that are selected in this component. + * + * @return the list of selected objects, or null + */ + Object[] getSelectedObjects(); + + /** + * Adds an item listener to this object. It will receive selection events + * for this object by the user (but not programatically). If listener is + * null, it is ignored. + * + * @param listener the item listener to add + */ + void addItemListener(ItemListener listener); + + /** + * Removes an item listener from this object. + * + * @param listener the item listener to remove + */ + void removeItemListener(ItemListener listener); +} // interface ItemSelectable diff --git a/libjava/classpath/java/awt/JobAttributes.java b/libjava/classpath/java/awt/JobAttributes.java new file mode 100644 index 0000000..2acb3a0 --- /dev/null +++ b/libjava/classpath/java/awt/JobAttributes.java @@ -0,0 +1,500 @@ +/* JobAttributes.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 java.awt; + +/** + * Needs documentation... + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4, lacks documentation + */ +public final class JobAttributes implements Cloneable +{ + public static final class DefaultSelectionType extends AttributeValue + { + private static final String[] NAMES = { "all", "range", "selection" }; + public static final DefaultSelectionType ALL + = new DefaultSelectionType(0); + public static final DefaultSelectionType RANGE + = new DefaultSelectionType(1); + public static final DefaultSelectionType SELECTION + = new DefaultSelectionType(2); + private DefaultSelectionType(int value) + { + super(value, NAMES); + } + } // class DefaultSelectionType + + public static final class DestinationType extends AttributeValue + { + private static final String[] NAMES = { "file", "printer" }; + public static final DestinationType FILE = new DestinationType(0); + public static final DestinationType PRINTER = new DestinationType(1); + private DestinationType(int value) + { + super(value, NAMES); + } + } // class DestinationType + + public static final class DialogType extends AttributeValue + { + private static final String[] NAMES = { "common", "native", "none" }; + public static final DialogType COMMON = new DialogType(0); + public static final DialogType NATIVE = new DialogType(1); + public static final DialogType NONE = new DialogType(2); + private DialogType(int value) + { + super(value, NAMES); + } + } // class DialogType + + public static final class MultipleDocumentHandlingType + extends AttributeValue + { + private static final String[] NAMES = { + "separate-documents-collated-copies", + "separate-documents-uncollated-copies" + }; + public static final MultipleDocumentHandlingType + SEPARATE_DOCUMENTS_COLLATED_COPIES + = new MultipleDocumentHandlingType(0); + public static final MultipleDocumentHandlingType + SEPARATE_DOCUMENTS_UNCOLLATED_COPIES + = new MultipleDocumentHandlingType(1); + private MultipleDocumentHandlingType(int value) + { + super(value, NAMES); + } + } // class MultipleDocumentHandlingType + + public static final class SidesType extends AttributeValue + { + private static final String[] NAMES + = { "one-sided", "two-sided-long-edge", "two-sided-short-edge" }; + public static final SidesType ONE_SIDED = new SidesType(0); + public static final SidesType TWO_SIDED_LONG_EDGE = new SidesType(1); + public static final SidesType TWO_SIDED_SHORT_EDGE = new SidesType(2); + private SidesType(int value) + { + super(value, NAMES); + } + } // class SidesType + + private int copies; + private DefaultSelectionType selection; + private DestinationType destination; + private DialogType dialog; + private String filename; + private int maxPage; + private int minPage; + private MultipleDocumentHandlingType multiple; + private int[][] pageRanges; // null for default value + private int fromPage; // 0 for default value + private int toPage; // 0 for default value + private String printer; + private SidesType sides; + + public JobAttributes() + { + copies = 1; + selection = DefaultSelectionType.ALL; + destination = DestinationType.PRINTER; + dialog = DialogType.NATIVE; + maxPage = Integer.MAX_VALUE; + minPage = 1; + multiple + = MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES; + sides = SidesType.ONE_SIDED; + } + + public JobAttributes(JobAttributes attr) + { + set(attr); + } + + public JobAttributes(int copies, DefaultSelectionType selection, + DestinationType destination, DialogType dialog, + String filename, int max, int min, + MultipleDocumentHandlingType multiple, + int[][] pageRanges, String printer, SidesType sides) + { + if (copies <= 0 || selection == null || destination == null + || dialog == null || max < min || min <= 0 || multiple == null + || sides == null) + throw new IllegalArgumentException(); + this.copies = copies; + this.selection = selection; + this.destination = destination; + this.dialog = dialog; + this.filename = filename; + maxPage = max; + minPage = min; + this.multiple = multiple; + setPageRanges(pageRanges); + this.printer = printer; + this.sides = sides; + } + + public Object clone() + { + return new JobAttributes(this); + } + + public void set(JobAttributes attr) + { + copies = attr.copies; + selection = attr.selection; + destination = attr.destination; + dialog = attr.dialog; + filename = attr.filename; + maxPage = attr.maxPage; + minPage = attr.minPage; + multiple = attr.multiple; + pageRanges = (int[][]) attr.pageRanges.clone(); + printer = attr.printer; + sides = attr.sides; + fromPage = attr.fromPage; + toPage = attr.toPage; + } + + public int getCopies() + { + return copies; + } + + public void setCopies(int copies) + { + if (copies <= 0) + throw new IllegalArgumentException(); + this.copies = copies; + } + + public void setCopiesToDefault() + { + copies = 1; + } + + public DefaultSelectionType getDefaultSelection() + { + return selection; + } + + public void setDefaultSelection(DefaultSelectionType selection) + { + if (selection == null) + throw new IllegalArgumentException(); + this.selection = selection; + } + + public DestinationType getDestination() + { + return destination; + } + + public void setDestination(DestinationType destination) + { + if (destination == null) + throw new IllegalArgumentException(); + this.destination = destination; + } + + public DialogType getDialog() + { + return dialog; + } + + public void setDialog(DialogType dialog) + { + if (dialog == null) + throw new IllegalArgumentException(); + this.dialog = dialog; + } + + public String getFileName() + { + return filename; + } + + public void setFileName(String filename) + { + this.filename = filename; + } + + public int getFromPage() + { + return fromPage != 0 ? fromPage + : pageRanges != null ? pageRanges[0][0] + : toPage != 0 ? toPage : minPage; + } + + public void setFromPage(int fromPage) + { + if (fromPage < minPage || (fromPage > toPage && toPage != 0) + || fromPage > maxPage) + throw new IllegalArgumentException(); + if (pageRanges == null) + this.fromPage = fromPage; + } + + public int getMaxPage() + { + return maxPage; + } + + public void setMaxPage(int maxPage) + { + if (maxPage < minPage) + throw new IllegalArgumentException(); + this.maxPage = maxPage; + if (maxPage < fromPage) + fromPage = maxPage; + if (maxPage < toPage) + toPage = maxPage; + if (pageRanges != null) + { + int i = pageRanges.length - 1; + while (i >= 0 && maxPage < pageRanges[i][1]) + i--; + if (maxPage >= pageRanges[++i][0]) + pageRanges[i++][1] = maxPage; + if (i == 0) + pageRanges = null; + else if (i < pageRanges.length) + { + int[][] tmp = new int[i][]; + System.arraycopy(pageRanges, 0, tmp, 0, i); + pageRanges = tmp; + } + } + } + + public int getMinPage() + { + return minPage; + } + + public void setMinPage(int minPage) + { + if (minPage <= 0 || minPage > maxPage) + throw new IllegalArgumentException(); + this.minPage = minPage; + if (minPage > toPage) + toPage = minPage; + if (minPage > fromPage) + fromPage = minPage; + if (pageRanges != null) + { + int size = pageRanges.length; + int i = 0; + while (i < size && minPage > pageRanges[i][0]) + i++; + if (minPage <= pageRanges[i - 1][1]) + pageRanges[--i][0] = minPage; + if (i == size) + pageRanges = null; + else if (i > 0) + { + int[][] tmp = new int[size - i][]; + System.arraycopy(pageRanges, i, tmp, 0, size - i); + pageRanges = tmp; + } + } + } + + public MultipleDocumentHandlingType getMultipleDocumentHandling() + { + return multiple; + } + + public void setMultipleDocumentHandling + (MultipleDocumentHandlingType multiple) + { + if (multiple == null) + throw new IllegalArgumentException(); + this.multiple = multiple; + } + + public void setMultipleDocumentHandlingToDefault() + { + multiple + = MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES; + } + + public int[][] getPageRanges() + { + if (pageRanges == null) + return new int[][] { { getFromPage(), getToPage() } }; + // Perform a deep clone, so user code cannot affect original arrays. + int i = pageRanges.length; + int[][] result = new int[i][]; + while (--i >= 0) + result[i] = (int[]) pageRanges[i].clone(); + return result; + } + + public void setPageRanges(int[][] pageRanges) + { + int size = pageRanges == null ? 0 : pageRanges.length; + if (size == 0) + throw new IllegalArgumentException(); + while (--size >= 0) + { + int[] range = pageRanges[size]; + if (range == null || range.length != 2 + || range[0] < minPage || range[1] < range[0] || range[1] > maxPage + || (size != 0 && range[0] <= pageRanges[size - 1][1])) + throw new IllegalArgumentException(); + } + size = pageRanges.length; + if (fromPage > 0 && pageRanges[0][0] > fromPage) + fromPage = pageRanges[0][0]; + if (toPage > 0 && pageRanges[size - 1][1] < toPage) + toPage = pageRanges[size - 1][1]; + this.pageRanges = new int[size][]; + while (--size >= 0) + this.pageRanges[size] = (int[]) pageRanges[size].clone(); + } + + public String getPrinter() + { + return printer; + } + + public void setPrinter(String printer) + { + this.printer = printer; + } + + public SidesType getSides() + { + return sides; + } + + public void setSides(SidesType sides) + { + if (sides == null) + throw new IllegalArgumentException(); + this.sides = sides; + } + + public void setSidesToDefault() + { + sides = SidesType.ONE_SIDED; + } + + public int getToPage() + { + return toPage != 0 ? toPage + : pageRanges != null ? pageRanges[pageRanges.length - 1][1] + : fromPage != 0 ? fromPage : maxPage; + } + + public void setToPage(int toPage) + { + if (toPage < minPage || (fromPage > toPage && fromPage != 0) + || toPage > maxPage) + throw new IllegalArgumentException(); + if (pageRanges == null) + this.toPage = toPage; + } + + public boolean equals(Object o) + { + if (this == o) + return true; + if (! (o instanceof JobAttributes)) + return false; + JobAttributes ja = (JobAttributes) o; + if (copies != ja.copies || selection != ja.selection + || destination != ja.destination || dialog != ja.dialog + || ! filename.equals(ja.filename) || maxPage != ja.maxPage + || minPage != ja.minPage || multiple != ja.multiple + || fromPage != ja.fromPage || toPage != ja.toPage + || ! printer.equals(ja.printer) || sides != ja.sides + || (pageRanges == null) != (ja.pageRanges == null)) + return false; + if (pageRanges != ja.pageRanges) + for (int i = pageRanges.length; --i >= 0; ) + if (pageRanges[i][0] != ja.pageRanges[i][0] + || pageRanges[i][1] != ja.pageRanges[i][1]) + return false; + return true; + } + + public int hashCode() + { + int hash = (selection.value << 6) ^ (destination.value << 5) + ^ (dialog.value << 3) ^ (multiple.value << 2) ^ sides.value + ^ (filename == null ? 0 : filename.hashCode()) + ^ (printer == null ? 0 : printer.hashCode()); + // The effect of the above fields on the hashcode match the JDK. However, + // I am unable to reverse engineer the effect of the fields listed below, + // so I am using my own implementation. Note that this still satisfies + // the general contract of hashcode, it just doesn't match the JDK. + hash ^= (copies << 27) ^ (maxPage << 22) ^ (minPage << 17); + if (pageRanges == null) + hash ^= (getFromPage() << 13) ^ (getToPage() << 8); + else + for (int i = pageRanges.length; --i >= 0; ) + hash ^= (pageRanges[i][0] << 13) ^ (pageRanges[i][1] << 8); + return hash; + } + + public String toString() + { + StringBuffer s = new StringBuffer("copies=").append(copies) + .append(",defaultSelection=").append(selection).append(",destination=") + .append(destination).append(",dialog=").append(dialog) + .append(",fileName=").append(filename).append(",fromPage=") + .append(getFromPage()).append(",maxPage=").append(maxPage) + .append(",minPage=").append(minPage) + .append(",multiple-document-handling=").append(multiple) + .append(",page-ranges=["); + if (pageRanges == null) + s.append(minPage).append(':').append(minPage).append(']'); + else + for (int i = 0; i < pageRanges.length; i++) + s.append(pageRanges[i][0]).append(':').append(pageRanges[i][1]) + .append(','); + s.setLength(s.length() - 1); + return s.append("],printer=").append(printer).append(",sides=") + .append(sides).append(",toPage=").append(getToPage()).toString(); + } +} // class JobAttributes diff --git a/libjava/classpath/java/awt/KeyEventDispatcher.java b/libjava/classpath/java/awt/KeyEventDispatcher.java new file mode 100644 index 0000000..3099727 --- /dev/null +++ b/libjava/classpath/java/awt/KeyEventDispatcher.java @@ -0,0 +1,82 @@ +/* KeyEventDispatcher.java -- dispatches key events + 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 java.awt; + +import java.awt.event.KeyEvent; + +/** + * An instance of this interface coordinates with a KeyboardFocusManager to + * target and dispatch all key events. This allows retargeting, consuming, + * changing, or otherwise manipulating the key event before sending it on to + * a target. + * + *

By default, the KeyboardFocusManager is the sink for all key events not + * dispatched by other dispatchers. Therefore, it is unnecessary for the user + * to register the focus manager as a dispatcher. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see KeyboardFocusManager#addKeyEventDispatcher(KeyEventDispatcher) + * @see KeyboardFocusManager#removeKeyEventDispatcher(KeyEventDispatcher) + * @since 1.4 + * @status updated to 1.4 + */ +public interface KeyEventDispatcher +{ + /** + * Called by the KeyboardFocusManager to request that a key event be + * dispatched. The dispatcher is free to retarget the event, consume it, + * dispatch it, or make other changes. This is usually done to allow + * delivery of key events to objects other than the window in focus, such + * as for navigating non-focusable components. If this dispatcher chooses + * to dispatch the event itself, it should call redispatchEvent + * to avoid infinite recursion. + * + *

If the return value is false, the KeyEvent is passed to the next + * dispatcher in the chain, ending with the KeyboardFocusManager. If the + * return value is true, the event has been consumed (although it might + * have been ignored), and no further action will be taken on the event. Be + * sure to check whether the event was consumed before dispatching it + * further. + * + * @param e the key event + * @return true if the event has been consumed + * @see KeyboardFocusManager#redispatchEvent(Component, AWTEvent) + */ + boolean dispatchKeyEvent(KeyEvent e); +} // interface KeyEventDispatcher diff --git a/libjava/classpath/java/awt/KeyEventPostProcessor.java b/libjava/classpath/java/awt/KeyEventPostProcessor.java new file mode 100644 index 0000000..0b39dc2 --- /dev/null +++ b/libjava/classpath/java/awt/KeyEventPostProcessor.java @@ -0,0 +1,81 @@ +/* KeyEventPostProcessor.java -- performs actions after a key event dispatch + 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 java.awt; + +import java.awt.event.KeyEvent; + +/** + * An instance of this interface coordinates with a KeyboardFocusManager to + * target and dispatch all key events that are otherwise unconsumed. This + * allows events which take place when nothing has focus to still operate, + * such as menu keyboard shortcuts. + * + *

By default, the KeyboardFocusManager is the sink for all key events not + * post-processed elsewhere. Therefore, it is unnecessary for the user + * to register the focus manager as a dispatcher. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see KeyboardFocusManager#addKeyEventPostProcessor(KeyEventPostProcessor) + * @see KeyboardFocusManager#removeKeyEventPostProcessor(KeyEventPostProcessor) + * @since 1.4 + * @status updated to 1.4 + */ +public interface KeyEventPostProcessor +{ + /** + * Called by the KeyboardFocusManager to request that a key event be + * post-processed. Typically, the event has already been dispatched and + * handled, unless no object has focus. Thus, this allows global event + * handling for things like menu shortcuts. If this post-processor chooses + * to dispatch the event, it should call redispatchEvent + * to avoid infinite recursion. + * + *

If the return value is false, the KeyEvent is passed to the next + * dispatcher in the chain, ending with the KeyboardFocusManager. If the + * return value is true, the event has been consumed (although it might + * have been ignored), and no further action will be taken on the event. Be + * sure to check whether the event was consumed before dispatching it + * further. + * + * @param e the key event + * @return true if the event has been consumed + * @see KeyboardFocusManager#redispatchEvent(Component, AWTEvent) + */ + boolean postProcessKeyEvent(KeyEvent e); +} // interface KeyEventPostProcessor diff --git a/libjava/classpath/java/awt/KeyboardFocusManager.java b/libjava/classpath/java/awt/KeyboardFocusManager.java new file mode 100644 index 0000000..f646184 --- /dev/null +++ b/libjava/classpath/java/awt/KeyboardFocusManager.java @@ -0,0 +1,1478 @@ +/* KeyboardFocusManager.java -- manage component focusing via the keyboard + Copyright (C) 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 java.awt; + +import java.applet.Applet; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.beans.VetoableChangeSupport; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The KeyboardFocusManager handles the focusing of + * windows for receiving keyboard events. The manager handles + * the dispatch of all FocusEvents and + * KeyEvents, along with WindowEvents + * relating to the focused window. Users can use the manager + * to ascertain the current focus owner and fire events. + *
+ *
+ * The focus owner is the Component that receives + * key events. The focus owner is either the currently focused + * window or a component within this window. + *
+ *
+ * The underlying native windowing system may denote the active + * window or its children with special decorations (e.g. a highlighted + * title bar). The active window is always either a Frame + * or Dialog, and is either the currently focused + * window or its owner. + *
+ *
+ * Applets may be partitioned into different applet contexts, according + * to their code base. In this case, each context has its own + * KeyboardFocusManager, as opposed to the global + * manager maintained by applets which share the same context. + * Each context is insulated from the others, and they don't interact. + * The resulting behaviour, as with context division, depends on the browser + * supporting the applets. Regardless, there can only ever be + * one focused window, one active window and one focus owner + * per ClassLoader. + *
+ *
+ * To support this separation of focus managers, the manager instances + * and the internal state information is grouped by the + * ThreadGroup to which it pertains. With respect to + * applets, each code base has its own ThreadGroup, so the + * isolation of each context is enforced within the manager. + *
+ *
+ * By default, the manager defines TAB and Ctrl+TAB as the + * forward focus traversal keys and Shift+TAB and Ctrl+Shift+TAB + * as the backward focus traversal keys. No up or down cycle + * traversal keys are defined by default. Traversal takes effect + * on the firing of a relevant KEY_PRESSED event. + * However, all other key events related to the use of the + * defined focus traversal key sequence are consumed and not + * dispatched. + *
+ *
+ * These default traversal keys come into effect on all windows + * for which no alternative set of keys is defined. This also + * applies recursively to any child components of such a window, + * which define no traversal keys of their own. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.4 + */ +public abstract class KeyboardFocusManager + implements KeyEventDispatcher, KeyEventPostProcessor +{ + /** Identifies {@link AWTKeyStroke}s that move the focus forward in + the focus cycle. */ + public static final int FORWARD_TRAVERSAL_KEYS = 0; + + /** Identifies {@link AWTKeyStroke}s that move the focus backward in + the focus cycle. */ + public static final int BACKWARD_TRAVERSAL_KEYS = 1; + + /** Identifies {@link AWTKeyStroke}s that move the focus up to the + parent focus cycle root. */ + public static final int UP_CYCLE_TRAVERSAL_KEYS = 2; + + /** Identifies {@link AWTKeyStroke}s that move the focus down to the + child focus cycle root. */ + public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3; + + /** The set of {@link AWTKeyStroke}s that cause focus to be moved to + the next focusable Component in the focus cycle. */ + private static final Set DEFAULT_FORWARD_KEYS; + + /** The set of {@link AWTKeyStroke}s that cause focus to be moved to + the previous focusable Component in the focus cycle. */ + private static final Set DEFAULT_BACKWARD_KEYS; + + /** Populate the DEFAULT_FORWARD_KEYS and DEFAULT_BACKWARD_KEYS + {@link java.util.Set}s. */ + static + { + Set s = new HashSet(); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0)); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, + KeyEvent.CTRL_DOWN_MASK)); + DEFAULT_FORWARD_KEYS = Collections.unmodifiableSet(s); + s = new HashSet(); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, + KeyEvent.SHIFT_DOWN_MASK)); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, + KeyEvent.SHIFT_DOWN_MASK + | KeyEvent.CTRL_DOWN_MASK)); + DEFAULT_BACKWARD_KEYS = Collections.unmodifiableSet(s); + } + + /** The global object {@link java.util.Map}s. */ + + /** For security reasons, {@link java.applet.Applet}s in different + codebases must be insulated from one another. Since {@link + KeyboardFocusManager}s have the ability to return {@link + Component}s from a given {@link java.applet.Applet}, each + codebase must have an independent {@link KeyboardFocusManager}. + Since each codebase has its own {@link ThreadGroup} in which its + {@link Applet}s run, it makes sense to partition {@link + KeyboardFocusManager}s according to {@link + java.lang.ThreadGroup}. Thus, currentKeyboardFocusManagers is a + {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}. */ + private static Map currentKeyboardFocusManagers = new HashMap (); + + /** {@link java.applet.Applet}s in one codebase must not be allowed + to access {@link Component}s in {@link java.applet.Applet}s in + other codebases. To enforce this restriction, we key the + following {@link java.util.Map}s on {@link java.lang.ThreadGroup}s (which + are per-codebase). For example, if {@link + java.lang.ThreadGroup} A calls {@link #setGlobalFocusOwner}, + passing {@link Component} C, currentFocusOwners[A] is assigned + C, and all other currentFocusOwners values are nullified. Then + if {@link java.lang.ThreadGroup} A subsequently calls {@link + #getGlobalFocusOwner}, it will return currentFocusOwners[A], + that is, {@link Component} C. If another {@link + java.lang.ThreadGroup} K calls {@link #getGlobalFocusOwner}, it + will return currentFocusOwners[K], that is, null. + + Since this is a static field, we ensure that there is only one + focused {@link Component} per class loader. */ + private static Map currentFocusOwners = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the {@link Component} that owns the permanent + keyboard focus. @see currentFocusOwners */ + private static Map currentPermanentFocusOwners = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the focused {@link Window}. @see + currentFocusOwners */ + private static Map currentFocusedWindows = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the active {@link Window}. @see + currentFocusOwners */ + private static Map currentActiveWindows = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the focus cycle root {@link Container}. @see + currentFocusOwners */ + private static Map currentFocusCycleRoots = new HashMap (); + + /** The default {@link FocusTraveralPolicy} that focus-managing + {@link Container}s will use to define their initial focus + traversal policy. */ + private FocusTraversalPolicy defaultPolicy; + + /** An array that stores the {@link #FORWARD_TRAVERSAL_KEYS}, {@link + #BACKWARD_TRAVERSAL_KEYS}, {@link #UP_CYCLE_TRAVERSAL_KEYS} and + {@link #DOWN_CYCLE_TRAVERSAL_KEYS} {@link AWTKeyStroke}s {@link + java.util.Set}s. */ + private Set[] defaultFocusKeys = new Set[] + { + DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS, + Collections.EMPTY_SET, Collections.EMPTY_SET + }; + + /** + * A utility class to support the handling of events relating to property changes. + */ + private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport (this); + + /** + * A utility class to support the handling of events relating to vetoable changes. + */ + private final VetoableChangeSupport vetoableChangeSupport = new VetoableChangeSupport (this); + + /** A list of {@link KeyEventDispatcher}s that process {@link + KeyEvent}s before they are processed the default keyboard focus + manager. */ + private final ArrayList keyEventDispatchers = new ArrayList(); + + /** A list of {@link KeyEventPostProcessor}s that process unconsumed + {@link KeyEvent}s. */ + private final ArrayList keyEventPostProcessors = new ArrayList(); + + /** + * Construct a KeyboardFocusManager. + */ + public KeyboardFocusManager () + { + } + + /** + * Retrieve the keyboard focus manager associated with the {@link + * java.lang.ThreadGroup} to which the calling thread belongs. + * + * @return the keyboard focus manager associated with the current + * thread group + */ + public static KeyboardFocusManager getCurrentKeyboardFocusManager () + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + + if (currentKeyboardFocusManagers.get (currentGroup) == null) + setCurrentKeyboardFocusManager (null); + + return (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup); + } + + /** + * Set the keyboard focus manager associated with the {@link + * java.lang.ThreadGroup} to which the calling thread belongs. + * + * @param m the keyboard focus manager for the current thread group + */ + public static void setCurrentKeyboardFocusManager (KeyboardFocusManager m) + { + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission (new AWTPermission ("replaceKeyboardFocusManager")); + + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + KeyboardFocusManager manager; + + if (m == null) + manager = createFocusManager(); + else + manager = m; + + currentKeyboardFocusManagers.put (currentGroup, manager); + } + + /** + * Creates a KeyboardFocusManager. The exact class is determined by the + * system property 'gnu.java.awt.FocusManager'. If this is not set, + * we default to DefaultKeyboardFocusManager. + */ + private static KeyboardFocusManager createFocusManager() + { + String fmClassName = System.getProperty("gnu.java.awt.FocusManager", + "java.awt.DefaultKeyboardFocusManager"); + try + { + Class fmClass = Class.forName(fmClassName); + KeyboardFocusManager fm = (KeyboardFocusManager) fmClass.newInstance(); + return fm; + } + catch (ClassNotFoundException ex) + { + System.err.println("The class " + fmClassName + " cannot be found."); + System.err.println("Check the setting of the system property"); + System.err.println("gnu.java.awt.FocusManager"); + return null; + } + catch (InstantiationException ex) + { + System.err.println("The class " + fmClassName + " cannot be"); + System.err.println("instantiated."); + System.err.println("Check the setting of the system property"); + System.err.println("gnu.java.awt.FocusManager"); + return null; + } + catch (IllegalAccessException ex) + { + System.err.println("The class " + fmClassName + " cannot be"); + System.err.println("accessed."); + System.err.println("Check the setting of the system property"); + System.err.println("gnu.java.awt.FocusManager"); + return null; + } + } + + /** + * Retrieve the {@link Component} that has the keyboard focus, or + * null if the focus owner was not set by a thread in the current + * {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner or null + */ + public Component getFocusOwner () + { + Component owner = (Component) getObject (currentFocusOwners); + if (owner == null) + owner = (Component) getObject (currentPermanentFocusOwners); + return owner; + } + + /** + * Retrieve the {@link Component} that has the keyboard focus, + * regardless of whether or not it was set by a thread in the + * current {@link java.lang.ThreadGroup}. If there is no temporary + * focus owner in effect then this method will return the same value + * as {@link #getGlobalPermanentFocusOwner}. + * + * @return the keyboard focus owner + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Component getGlobalFocusOwner () + { + // Check if there is a temporary focus owner. + Component focusOwner = (Component) getGlobalObject (currentFocusOwners); + + return (focusOwner == null) ? getGlobalPermanentFocusOwner () : focusOwner; + } + + /** + * Set the {@link Component} that will be returned by {@link + * #getFocusOwner} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalFocusOwner}. This + * method does not actually transfer the keyboard focus. + * + * @param owner the Component to return from getFocusOwner and + * getGlobalFocusOwner + * + * @see Component#requestFocus() + * @see Component#requestFocusInWindow() + */ + protected void setGlobalFocusOwner (Component owner) + { + if (owner == null || owner.focusable) + setGlobalObject (currentFocusOwners, owner, "focusOwner"); + } + + /** + * Clear the global focus owner and deliver a FOCUS_LOST event to + * the previously-focused {@link Component}. Until another {@link + * Component} becomes the keyboard focus owner, key events will be + * discarded by top-level windows. + */ + public void clearGlobalFocusOwner () + { + synchronized (currentFocusOwners) + { + Component focusOwner = getGlobalFocusOwner (); + Component permanentFocusOwner = getGlobalPermanentFocusOwner (); + + setGlobalFocusOwner (null); + setGlobalPermanentFocusOwner (null); + + // Inform the old focus owner that it has lost permanent + // focus. + if (focusOwner != null) + { + // We can't cache the event queue, because of + // bootstrapping issues. We need to set the default + // KeyboardFocusManager in EventQueue before the event + // queue is started. + EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + if (focusOwner != permanentFocusOwner) + q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, true)); + else + q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, false)); + } + + if (focusOwner != permanentFocusOwner) + { + EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + q.postEvent (new FocusEvent (permanentFocusOwner, FocusEvent.FOCUS_LOST, false)); + } + } + } + + /** + * Retrieve the {@link Component} that has the permanent keyboard + * focus, or null if the focus owner was not set by a thread in the + * current {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner or null + */ + public Component getPermanentFocusOwner () + { + return (Component) getObject (currentPermanentFocusOwners); + } + + /** + * Retrieve the {@link Component} that has the permanent keyboard + * focus, regardless of whether or not it was set by a thread in the + * current {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Component getGlobalPermanentFocusOwner () + { + return (Component) getGlobalObject (currentPermanentFocusOwners); + } + + /** + * Set the {@link Component} that will be returned by {@link + * #getPermanentFocusOwner} (when it is called from the current + * {@link java.lang.ThreadGroup}) and {@link + * #getGlobalPermanentFocusOwner}. This method does not actually + * transfer the keyboard focus. + * + * @param focusOwner the Component to return from + * getPermanentFocusOwner and getGlobalPermanentFocusOwner + * + * @see Component#requestFocus() + * @see Component#requestFocusInWindow() + */ + protected void setGlobalPermanentFocusOwner (Component focusOwner) + { + if (focusOwner == null || focusOwner.focusable) + setGlobalObject (currentPermanentFocusOwners, focusOwner, + "permanentFocusOwner"); + } + + /** + * Retrieve the {@link Window} that is or contains the keyboard + * focus owner, or null if the focused window was not set by a + * thread in the current {@link java.lang.ThreadGroup}. + * + * @return the focused window or null + */ + public Window getFocusedWindow () + { + return (Window) getObject (currentFocusedWindows); + } + + /** + * Retrieve the {@link Window} that is or contains the focus owner, + * regardless of whether or not the {@link Window} was set focused + * by a thread in the current {@link java.lang.ThreadGroup}. + * + * @return the focused window + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Window getGlobalFocusedWindow () + { + return (Window) getGlobalObject (currentFocusedWindows); + } + + /** + * Set the {@link Window} that will be returned by {@link + * #getFocusedWindow} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalFocusedWindow}. + * This method does not actually cause window to become + * the focused {@link Window}. + * + * @param window the Window to return from getFocusedWindow and + * getGlobalFocusedWindow + */ + protected void setGlobalFocusedWindow (Window window) + { + if (window == null || window.focusable) + setGlobalObject (currentFocusedWindows, window, "focusedWindow"); + } + + /** + * Retrieve the active {@link Window}, or null if the active window + * was not set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the active window or null + */ + public Window getActiveWindow() + { + return (Window) getObject (currentActiveWindows); + } + + /** + * Retrieve the active {@link Window}, regardless of whether or not + * the {@link Window} was made active by a thread in the current + * {@link java.lang.ThreadGroup}. + * + * @return the active window + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Window getGlobalActiveWindow() + { + return (Window) getGlobalObject (currentActiveWindows); + } + + /** + * Set the {@link Window} that will be returned by {@link + * #getActiveWindow} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalActiveWindow}. This + * method does not actually cause window to be made + * active. + * + * @param window the Window to return from getActiveWindow and + * getGlobalActiveWindow + */ + protected void setGlobalActiveWindow(Window window) + { + setGlobalObject (currentActiveWindows, window, "activeWindow"); + } + + /** + * Retrieve the default {@link FocusTraversalPolicy}. + * Focus-managing {@link Container}s use the returned object to + * define their initial focus traversal policy. + * + * @return a non-null default FocusTraversalPolicy object + */ + public FocusTraversalPolicy getDefaultFocusTraversalPolicy () + { + if (defaultPolicy == null) + defaultPolicy = new DefaultFocusTraversalPolicy (); + return defaultPolicy; + } + + /** + * Set the {@link FocusTraversalPolicy} returned by {@link + * #getDefaultFocusTraversalPolicy}. Focus-managing {@link + * Container}s created after this call will use policy as their + * initial focus traversal policy. Existing {@link Container}s' + * focus traversal policies will not be affected by calls to this + * method. + * + * @param policy the FocusTraversalPolicy that will be returned by + * subsequent calls to getDefaultFocusTraversalPolicy + * @throws IllegalArgumentException if policy is null + */ + public void setDefaultFocusTraversalPolicy (FocusTraversalPolicy policy) + { + if (policy == null) + throw new IllegalArgumentException (); + firePropertyChange ("defaultFocusTraversalPolicy", defaultPolicy, policy); + defaultPolicy = policy; + } + + /** + * Set the default {@link java.util.Set} of focus traversal keys for + * one of the focus traversal directions. + * + * @param id focus traversal direction identifier + * @param keystrokes set of AWTKeyStrokes + * + * @see #FORWARD_TRAVERSAL_KEYS + * @see #BACKWARD_TRAVERSAL_KEYS + * @see #UP_CYCLE_TRAVERSAL_KEYS + * @see #DOWN_CYCLE_TRAVERSAL_KEYS + */ + public void setDefaultFocusTraversalKeys (int id, Set keystrokes) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + if (keystrokes == null) + throw new IllegalArgumentException (); + + Set sa; + Set sb; + Set sc; + String type; + switch (id) + { + case FORWARD_TRAVERSAL_KEYS: + sa = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS]; + type = "forwardDefaultFocusTraversalKeys"; + break; + case BACKWARD_TRAVERSAL_KEYS: + sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS]; + type = "backwardDefaultFocusTraversalKeys"; + break; + case UP_CYCLE_TRAVERSAL_KEYS: + sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS]; + type = "upCycleDefaultFocusTraversalKeys"; + break; + case DOWN_CYCLE_TRAVERSAL_KEYS: + sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS]; + type = "downCycleDefaultFocusTraversalKeys"; + break; + default: + throw new IllegalArgumentException (); + } + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + while (--i >= 0) + { + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) || sc.contains (o) + || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) + throw new IllegalArgumentException (); + } + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (type, defaultFocusKeys[id], keystrokes); + defaultFocusKeys[id] = keystrokes; + } + + /** + * Retrieve the default {@link java.util.Set} of focus traversal + * keys for one of the focus traversal directions. + * + * @param id focus traversal direction identifier + * + * @return the default set of AWTKeyStrokes + * + * @see #FORWARD_TRAVERSAL_KEYS + * @see #BACKWARD_TRAVERSAL_KEYS + * @see #UP_CYCLE_TRAVERSAL_KEYS + * @see #DOWN_CYCLE_TRAVERSAL_KEYS + */ + public Set getDefaultFocusTraversalKeys (int id) + { + if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + return defaultFocusKeys[id]; + } + + /** + * Retrieve the current focus cycle root, or null if the focus owner + * was not set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the current focus cycle root or null + */ + public Container getCurrentFocusCycleRoot () + { + return (Container) getObject (currentFocusCycleRoots); + } + + /** + * Retrieve the current focus cycle root, regardless of whether or + * not it was made set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the current focus cycle root + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Container getGlobalCurrentFocusCycleRoot () + { + return (Container) getGlobalObject (currentFocusCycleRoots); + } + + /** + * Set the {@link Container} that will be returned by {@link + * #getCurrentFocusCycleRoot} (when it is called from the current + * {@link java.lang.ThreadGroup}) and {@link + * #getGlobalCurrentFocusCycleRoot}. This method does not actually + * make cycleRoot the current focus cycle root. + * + * @param cycleRoot the focus cycle root to return from + * getCurrentFocusCycleRoot and getGlobalCurrentFocusCycleRoot + */ + public void setGlobalCurrentFocusCycleRoot (Container cycleRoot) + { + setGlobalObject (currentFocusCycleRoots, cycleRoot, "currentFocusCycleRoot"); + } + + /** + * Registers the supplied property change listener for receiving + * events caused by the following property changes: + * + *

+ * + * If the supplied listener is null, nothing occurs. + * + * @param l the new listener to register. + * @see KeyboardFocusManager#addPropertyChangeListener(String, java.beans.PropertyChangeListener) + */ + public void addPropertyChangeListener(PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.addPropertyChangeListener(l); + } + + /** + * Removes the supplied property change listener from the list + * of registered listeners. If the supplied listener is null, + * nothing occurs. + * + * @param l the listener to remove. + */ + public void removePropertyChangeListener(PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.removePropertyChangeListener(l); + } + + /** + * Returns the currently registered property change listeners + * in array form. The returned array is empty if no listeners are + * currently registered. + * + * @return an array of registered property change listeners. + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return propertyChangeSupport.getPropertyChangeListeners(); + } + + /** + * Registers a property change listener for receiving events relating + * to a change to a specified property. The supplied property name can be + * either user-defined or one from the following list of properties + * relevant to this class: + * + * + * + * Nothing occurs if a null listener is supplied. null is regarded as a valid property name. + * + * @param name the name of the property to handle change events for. + * @param l the listener to register for changes to the specified property. + * @see KeyboardFocusManager#addPropertyChangeListener(java.beans.PropertyChangeListener) + */ + public void addPropertyChangeListener(String name, PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.addPropertyChangeListener(name, l); + } + + /** + * Removes the supplied property change listener registered for the + * specified property from the list of registered listeners. If the + * supplied listener is null, nothing occurs. + * + * @param name the name of the property the listener is + * monitoring changes to. + * @param l the listener to remove. + */ + public void removePropertyChangeListener(String name, + PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.removePropertyChangeListener(name, l); + } + + /** + * Returns the currently registered property change listeners + * in array form, which listen for changes to the supplied property. + * The returned array is empty, if no listeners are currently registered + * for events pertaining to the supplied property. + * + * @param name The property the returned listeners monitor for changes. + * @return an array of registered property change listeners which + * listen for changes to the supplied property. + */ + public PropertyChangeListener[] getPropertyChangeListeners(String name) + { + return propertyChangeSupport.getPropertyChangeListeners(name); + } + + /** + * Fires a property change event as a response to a change to + * to the specified property. The event is only fired if a + * change has actually occurred (i.e. o and n are different). + * + * @param name The name of the property to which a change occurred. + * @param o The old value of the property. + * @param n The new value of the property. + */ + protected void firePropertyChange(String name, Object o, Object n) + { + propertyChangeSupport.firePropertyChange(name, o, n); + } + + /** + * Registers a vetoable property change listener for receiving events + * relating to the following properties: + * + * + * + * Nothing occurs if a null listener is supplied. + * + * @param l the listener to register. + * @see KeyboardFocusManager#addVetoableChangeListener(String, java.beans.VetoableChangeListener) + */ + public void addVetoableChangeListener(VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.addVetoableChangeListener(l); + } + + /** + * Removes the supplied vetoable property change listener from + * the list of registered listeners. If the supplied listener + * is null, nothing occurs. + * + * @param l the listener to remove. + */ + public void removeVetoableChangeListener(VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.removeVetoableChangeListener(l); + } + + /** + * Returns the currently registered vetoable property change listeners + * in array form. The returned array is empty if no listeners are + * currently registered. + * + * @return an array of registered vetoable property change listeners. + * @since 1.4 + */ + public VetoableChangeListener[] getVetoableChangeListeners() + { + return vetoableChangeSupport.getVetoableChangeListeners(); + } + + /** + * Registers a vetoable property change listener for receiving events relating + * to a vetoable change to a specified property. The supplied property name can be + * either user-defined or one from the following list of properties + * relevant to this class: + * + * + * + * Nothing occurs if a null listener is supplied. null is regarded as a valid property name. + * + * @param name the name of the property to handle change events for. + * @param l the listener to register for changes to the specified property. + * @see KeyboardFocusManager#addVetoableChangeListener(java.beans.VetoableChangeListener) + */ + public void addVetoableChangeListener(String name, VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.addVetoableChangeListener(name, l); + } + + /** + * Removes the supplied vetoable property change listener registered + * for the specified property from the list of registered listeners. + * If the supplied listener is null, nothing occurs. + * + * @param name the name of the vetoable property the listener is + * monitoring changes to. + * @param l the listener to remove. + */ + public void removeVetoableChangeListener(String name, + VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.removeVetoableChangeListener(name, l); + } + + /** + * Returns the currently registered vetoable property change listeners + * in array form, which listen for changes to the supplied property. + * The returned array is empty, if no listeners are currently registered + * for events pertaining to the supplied property. + * + * @param name The property the returned listeners monitor for changes. + * @return an array of registered property change listeners which + * listen for changes to the supplied property. + * @since 1.4 + */ + public VetoableChangeListener[] getVetoableChangeListeners(String name) + { + return vetoableChangeSupport.getVetoableChangeListeners(name); + } + + /** + * Fires a property change event as a response to a vetoable change to + * to the specified property. The event is only fired if a + * change has actually occurred (i.e. o and n are different). + * In the event that the property change is vetoed, the following + * occurs: + * + *
    + *
  1. + * This method throws a PropertyVetoException to + * the proposed change. + *
  2. + *
  3. + * A new event is fired to reverse the previous change. + *
  4. + *
  5. + * This method again throws a PropertyVetoException + * in response to the reversion. + *
  6. + *
+ * + * @param name The name of the property to which a change occurred. + * @param o The old value of the property. + * @param n The new value of the property. + * @throws PropertyVetoException if one of the listeners vetos + * the change by throwing this exception. + */ + protected void fireVetoableChange(String name, Object o, Object n) + throws PropertyVetoException + { + vetoableChangeSupport.fireVetoableChange(name, o, n); + } + + /** + * Adds a key event dispatcher to the list of registered dispatchers. + * When a key event is fired, each dispatcher's dispatchKeyEvent + * method is called in the order that they were added, prior to the manager + * dispatching the event itself. Notifications halt when one of the + * dispatchers returns true. + *
+ *
+ * The same dispatcher can exist multiple times within the list + * of registered dispatchers, and there is no limit on the length + * of this list. A null dispatcher is simply ignored. + * + * @param dispatcher The dispatcher to register. + */ + public void addKeyEventDispatcher(KeyEventDispatcher dispatcher) + { + if (dispatcher != null) + keyEventDispatchers.add(dispatcher); + } + + /** + * Removes the specified key event dispatcher from the list of + * registered dispatchers. The manager always dispatches events, + * regardless of its existence within the list. The manager + * can be added and removed from the list, as with any other + * dispatcher, but this does not affect its ability to dispatch + * key events. Non-existent and null dispatchers are simply ignored + * by this method. + * + * @param dispatcher The dispatcher to remove. + */ + public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher) + { + keyEventDispatchers.remove(dispatcher); + } + + /** + * Returns the currently registered key event dispatchers in List + * form. At present, this only includes dispatchers explicitly registered + * via the addKeyEventDispatcher() method, but this behaviour + * is subject to change and should not be depended on. The manager itself + * may be a member of the list, but only if explicitly registered. If no + * dispatchers have been registered, the list will be empty. + * + * @return A list of explicitly registered key event dispatchers. + * @see KeyboardFocusManager#addKeyEventDispatcher(java.awt.KeyEventDispatcher) + */ + protected List getKeyEventDispatchers () + { + return (List) keyEventDispatchers.clone (); + } + + /** + * Adds a key event post processor to the list of registered post processors. + * Post processors work in the same way as key event dispatchers, except + * that they are invoked after the manager has dispatched the key event, + * and not prior to this. Each post processor's postProcessKeyEvent + * method is called to see if any post processing needs to be performed. THe + * processors are called in the order in which they were added to the list, + * and notifications continue until one returns true. As with key event + * dispatchers, the manager is implicitly called following this process, + * regardless of whether or not it is present within the list. + *
+ *
+ * The same post processor can exist multiple times within the list + * of registered post processors, and there is no limit on the length + * of this list. A null post processor is simply ignored. + * + * @param postProcessor the post processor to register. + * @see KeyboardFocusManager#addKeyEventDispatcher(java.awt.KeyEventDispatcher) + */ + public void addKeyEventPostProcessor (KeyEventPostProcessor postProcessor) + { + if (postProcessor != null) + keyEventPostProcessors.add (postProcessor); + } + + /** + * Removes the specified key event post processor from the list of + * registered post processors. The manager always post processes events, + * regardless of its existence within the list. The manager + * can be added and removed from the list, as with any other + * post processor, but this does not affect its ability to post process + * key events. Non-existent and null post processors are simply ignored + * by this method. + * + * @param postProcessor the post processor to remove. + */ + public void removeKeyEventPostProcessor (KeyEventPostProcessor postProcessor) + { + keyEventPostProcessors.remove (postProcessor); + } + + /** + * Returns the currently registered key event post processors in List + * form. At present, this only includes post processors explicitly registered + * via the addKeyEventPostProcessor() method, but this behaviour + * is subject to change and should not be depended on. The manager itself + * may be a member of the list, but only if explicitly registered. If no + * post processors have been registered, the list will be empty. + * + * @return A list of explicitly registered key event post processors. + * @see KeyboardFocusManager#addKeyEventPostProcessor(java.awt.KeyEventPostProcessor) + */ + protected List getKeyEventPostProcessors () + { + return (List) keyEventPostProcessors.clone (); + } + + /** + * The AWT event dispatcher uses this method to request that the manager + * handle a particular event. If the manager fails or refuses to + * dispatch the supplied event (this method returns false), the + * AWT event dispatcher will try to dispatch the event itself. + *
+ *
+ * The manager is expected to handle all FocusEvents + * and KeyEvents, and WindowEvents + * relating to the focus. Dispatch is done with regard to the + * the focus owner and the currently focused and active windows. + * In handling the event, the source of the event may be overridden. + *
+ *
+ * The actual dispatching is performed by calling + * redispatchEvent(). This avoids the infinite recursion + * of dispatch requests which may occur if this method is called on + * the target component. + * + * @param e the event to dispatch. + * @return true if the event was dispatched. + * @see KeyboardFocusManager#redispatchEvent(java.awt.Component, java.awt.AWTEvent) + * @see KeyEvent + * @see FocusEvent + * @see WindowEvent + */ + public abstract boolean dispatchEvent (AWTEvent e); + + /** + * Handles redispatching of an event so that recursion of + * dispatch requests does not occur. Event dispatch methods + * within this manager (dispatchEvent()) and + * the key event dispatchers should use this method to handle + * dispatching rather than the dispatch method of the target + * component. + *
+ *
+ * + * This method is not intended for general consumption, and is + * only for the use of the aforementioned classes. + * + * + * @param target the target component to which the event is + * dispatched. + * @param e the event to dispatch. + */ + public final void redispatchEvent (Component target, AWTEvent e) + { + synchronized (e) + { + e.setSource (target); + target.dispatchEvent (e); + } + } + + /** + * Attempts to dispatch key events for which no key event dispatcher + * has so far succeeded. This method is usually called by + * dispatchEvent() following the sending of the key + * event to any registered key event dispatchers. If the key + * event reaches this stage, none of the dispatchers returned + * true. This is, of course, always the case if there are no + * registered dispatchers. + *
+ *
+ * If this method also fails to handle the key event, then + * false is returned to the caller. In the case of + * dispatchEvent(), the calling method may try + * to handle the event itself or simply forward on the + * false result to its caller. When the event is dispatched + * by this method, a true result is propogated through the + * calling methods. + * + * @param e the key event to dispatch. + * @return true if the event was dispatched successfully. + */ + public abstract boolean dispatchKeyEvent (KeyEvent e); + + /** + * Handles the post processing of key events. By default, + * this method will map unhandled key events to appropriate + * MenuShortcuts. The event is consumed + * in the process and the shortcut is activated. This + * method is usually called by dispatchKeyEvent. + * + * @param e the key event to post process. + * @return true by default, as the event was handled. + */ + public abstract boolean postProcessKeyEvent (KeyEvent e); + + /** + * Handles focus traversal operations for key events which + * represent focus traversal keys in relation to the supplied + * component. The supplied component is assumed to have the + * focus, whether it does so or not, and the operation is + * carried out as appropriate, with this in mind. + * + * @param focused the component on which to perform focus traversal, + * on the assumption that this component has the focus. + * @param e the possible focus traversal key event. + */ + public abstract void processKeyEvent (Component focused, KeyEvent e); + + /** + * Delays all key events following the specified timestamp until the + * supplied component has focus. The AWT calls this method when it is + * determined that a focus change may occur within the native windowing + * system. Any key events which occur following the time specified by + * after are delayed until a FOCUS_GAINED event is received + * for the untilFocused component. The manager is responsible for ensuring + * this takes place. + * + * @param after the timestamp beyond which all key events are delayed until + * the supplied component gains focus. + * @param untilFocused the component to wait on gaining focus. + */ + protected abstract void enqueueKeyEvents (long after, Component untilFocused); + + /** + * Removes the key event block specified by the supplied timestamp and component. + * All delayed key events are released for normal dispatching following its + * removal and subsequent key events that would have been blocked are now + * immediately dispatched. If the specified timestamp is below 0, then + * the request with the oldest timestamp is removed. + * + * @param after the timestamp of the key event block to be removed, or a + * value smaller than 0 if the oldest is to be removed. + * @param untilFocused the component of the key event block to be removed. + */ + protected abstract void dequeueKeyEvents (long after, Component untilFocused); + + /** + * Discards all key event blocks relating to focus requirements for + * the supplied component, regardless of timestamp. + * + * @param comp the component of the key event block(s) to be removed. + */ + protected abstract void discardKeyEvents (Component comp); + + /** + * Moves the current focus to the next component following + * comp, based on the current focus traversal policy. By + * default, only visible, displayable, accepted components + * can receive focus. Canvases, Panels, + * Labels, ScrollPanes, Scrollbars, + * Windows and lightweight components are judged + * to be unacceptable by default. See the + * DefaultFocusTraversalPolicy for more details. + * + * @param comp the component prior to the one which will + * become the focus, following execution of this method. + * @see DefaultFocusTraversalPolicy + */ + public abstract void focusNextComponent(Component comp); + + /** + * Moves the current focus to the previous component, prior to + * comp, based on the current focus traversal policy. By + * default, only visible, displayable, accepted components + * can receive focus. Canvases, Panels, + * Labels, ScrollPanes, Scrollbars, + * Windows and lightweight components are judged + * to be unacceptable by default. See the + * DefaultFocusTraversalPolicy for more details. + * + * @param comp the component following the one which will + * become the focus, following execution of this method. + * @see DefaultFocusTraversalPolicy + */ + public abstract void focusPreviousComponent(Component comp); + + /** + * Moves the current focus upwards by one focus cycle. + * Both the current focus owner and current focus cycle root + * become the focus cycle root of the supplied component. + * However, in the case of a Window, the default + * focus component becomes the focus owner and the focus cycle + * root is not changed. + * + * @param comp the component used as part of the focus traversal. + */ + public abstract void upFocusCycle(Component comp); + + /** + * Moves the current focus downwards by one focus cycle. + * If the supplied container is a focus cycle root, then this + * becomes the current focus cycle root and the focus goes + * to the default component of the specified container. + * Nothing happens for non-focus cycle root containers. + * + * @param cont the container used as part of the focus traversal. + */ + public abstract void downFocusCycle(Container cont); + + /** + * Moves the current focus to the next component, based on the + * current focus traversal policy. By default, only visible, + * displayable, accepted component can receive focus. + * Canvases, Panels, + * Labels, ScrollPanes, Scrollbars, + * Windows and lightweight components are judged + * to be unacceptable by default. See the + * DefaultFocusTraversalPolicy for more details. + * + * @see DefaultFocusTraversalPolicy + */ + public final void focusNextComponent() + { + focusNextComponent (null); + } + + /** + * Moves the current focus to the previous component, based on the + * current focus traversal policy. By default, only visible, + * displayable, accepted component can receive focus. + * Canvases, Panels, + * Labels, ScrollPanes, Scrollbars, + * Windows and lightweight components are judged + * to be unacceptable by default. See the + * DefaultFocusTraversalPolicy for more details. + * + * @see DefaultFocusTraversalPolicy + */ + public final void focusPreviousComponent() + { + focusPreviousComponent (null); + } + + /** + * Moves the current focus upwards by one focus cycle, + * so that the new focus owner is the focus cycle root + * of the current owner. The current focus cycle root then + * becomes the focus cycle root of the new focus owner. + * However, in the case of the focus cycle root of the + * current focus owner being a Window, the default + * component of this window becomes the focus owner and the + * focus cycle root is not changed. + */ + public final void upFocusCycle() + { + upFocusCycle (null); + } + + /** + * Moves the current focus downwards by one focus cycle, + * iff the current focus cycle root is a Container. + * Usually, the new focus owner is set to the default component + * of the container and the current focus cycle root is set + * to the current focus owner. Nothing occurs if the current + * focus cycle root is not a container. + */ + public final void downFocusCycle() + { + Component focusOwner = getGlobalFocusOwner (); + if (focusOwner instanceof Container + && ((Container) focusOwner).isFocusCycleRoot ()) + downFocusCycle ((Container) focusOwner); + } + + /** + * Retrieve an object from one of the global object {@link + * java.util.Map}s, if the object was set by the a thread in the + * current {@link java.lang.ThreadGroup}. Otherwise, return null. + * + * @param globalMap one of the global object Maps + * + * @return a global object set by the current ThreadGroup, or null + * + * @see getFocusOwner + * @see getPermanentFocusOwner + * @see getFocusedWindow + * @see getActiveWindow + * @see getCurrentFocusCycleRoot + */ + private Object getObject (Map globalMap) + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + return globalMap.get (currentGroup); + } + + /** + * Retrieve an object from one of the global object {@link + * java.util.Map}s, regardless of whether or not the object was set + * by a thread in the current {@link java.lang.ThreadGroup}. + * + * @param globalMap one of the global object Maps + * + * @return a global object set by the current ThreadGroup, or null + * + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + * + * @see getGlobalFocusOwner + * @see getGlobalPermanentFocusOwner + * @see getGlobalFocusedWindow + * @see getGlobalActiveWindow + * @see getGlobalCurrentFocusCycleRoot + */ + private Object getGlobalObject (Map globalMap) + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + KeyboardFocusManager managerForCallingThread + = (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup); + + if (this != managerForCallingThread) + throw new SecurityException ("Attempted to retrieve an object from a " + + "keyboard focus manager that isn't " + + "associated with the current thread group."); + + synchronized (globalMap) + { + Collection globalObjects = globalMap.values (); + Iterator i = globalObjects.iterator (); + Component globalObject; + + while (i.hasNext ()) + { + globalObject = (Component) i.next (); + if (globalObject != null) + return globalObject; + } + } + + // No Object was found. + return null; + } + + /** + * Set an object in one of the global object {@link java.util.Map}s, + * that will be returned by subsequent calls to getGlobalObject on + * the same {@link java.util.Map}. + * + * @param globalMap one of the global object Maps + * @param newObject the object to set + * @param property the property that will change + * + * @see setGlobalFocusOwner + * @see setGlobalPermanentFocusOwner + * @see setGlobalFocusedWindow + * @see setGlobalActiveWindow + * @see setGlobalCurrentFocusCycleRoot + */ + private void setGlobalObject (Map globalMap, + Object newObject, + String property) + { + synchronized (globalMap) + { + // Save old object. + Object oldObject = getGlobalObject (globalMap); + + // Nullify old object. + Collection threadGroups = globalMap.keySet (); + Iterator i = threadGroups.iterator (); + while (i.hasNext ()) + { + ThreadGroup oldThreadGroup = (ThreadGroup) i.next (); + if (globalMap.get (oldThreadGroup) != null) + { + globalMap.put (oldThreadGroup, null); + // There should only be one object set at a time, so + // we can short circuit. + break; + } + } + + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + firePropertyChange (property, oldObject, newObject); + try + { + fireVetoableChange (property, oldObject, newObject); + // Set new object. + globalMap.put (currentGroup, newObject); + } + catch (PropertyVetoException e) + { + } + } + } +} diff --git a/libjava/classpath/java/awt/Label.java b/libjava/classpath/java/awt/Label.java new file mode 100644 index 0000000..8867fa1 --- /dev/null +++ b/libjava/classpath/java/awt/Label.java @@ -0,0 +1,314 @@ +/* Label.java -- Java label widget + Copyright (C) 1999, 2000, 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 java.awt; + +import java.awt.peer.LabelPeer; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This component is used for displaying simple text strings that cannot + * be edited by the user. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class Label extends Component implements Accessible +{ + +/* + * Static Variables + */ + +/** + * Alignment constant aligning the text to the left of its window. + */ +public static final int LEFT = 0; + +/** + * Alignment constant aligning the text in the center of its window. + */ +public static final int CENTER = 1; + +/** + * Alignment constant aligning the text to the right of its window. + */ +public static final int RIGHT = 2; + +// Serialization version constant: +private static final long serialVersionUID = 3094126758329070636L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial Indicates the alignment of the text within this label's window. + * This is one of the constants in this class. The default value is + * LEFT. + */ +private int alignment; + +/** + * @serial The text displayed in the label + */ +private String text; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of Label with no text. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +Label() +{ + this("", LEFT); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Label with the specified + * text that is aligned to the left. + * + * @param text The text of the label. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +Label(String text) +{ + this(text, LEFT); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Label with the specified + * text and alignment. + * + * @param text The text of the label. + * @param alignment The desired alignment for the text in this label, + * which must be one of LEFT, CENTER, or + * RIGHT. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +Label(String text, int alignment) +{ + setAlignment (alignment); + setText (text); + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the constant indicating the alignment of the text in this + * label. The value returned will be one of the alignment constants + * from this class. + * + * @return The alignment of the text in the label. + */ +public int +getAlignment() +{ + return(alignment); +} + +/*************************************************************************/ + +/** + * Sets the text alignment of this label to the specified value. + * + * @param alignment The desired alignment for the text in this label, + * which must be one of LEFT, CENTER, or + * RIGHT. + */ +public synchronized void +setAlignment(int alignment) +{ + if (alignment != CENTER && alignment != LEFT && alignment != RIGHT) + throw new IllegalArgumentException ("invalid alignment: " + alignment); + this.alignment = alignment; + if (peer != null) + { + LabelPeer lp = (LabelPeer) peer; + lp.setAlignment (alignment); + } +} + +/*************************************************************************/ + +/** + * Returns the text displayed in this label. + * + * @return The text for this label. + */ +public String +getText() +{ + return(text); +} + +/*************************************************************************/ + +/** + * Sets the text in this label to the specified value. + * + * @param text The new text for this label. + */ +public synchronized void +setText(String text) +{ + this.text = text; + + if (peer != null) + { + LabelPeer lp = (LabelPeer) peer; + lp.setText (text); + } +} + +/*************************************************************************/ + +/** + * Notifies this label that it has been added to a container, causing + * the peer to be created. This method is called internally by the AWT + * system. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createLabel (this); + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Returns a parameter string useful for debugging. + * + * @return A debugging string. + */ +protected String +paramString() +{ + return ("text=" + getText() + ",alignment=" + + getAlignment() + "," + super.paramString()); +} + +/** + * This class provides accessibility support for the label. + */ +protected class AccessibleAWTLabel + extends AccessibleAWTComponent +{ + /** + * For compatability with Sun's JDK 1.4.2 rev. 5 + */ + private static final long serialVersionUID = -3568967560160480438L; + + /** + * Constructor for the accessible label. + */ + public AccessibleAWTLabel() + { + } + + /** + * Returns the accessible name for the label. This is + * the text used in the label. + * + * @return a String containing the accessible + * name for this label. + */ + public String getAccessibleName() + { + return getText(); + } + + /** + * Returns the accessible role for the label. + * + * @return an instance of AccessibleRole, describing + * the role of the label. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.LABEL; + } + +} + +/** + * Gets the AccessibleContext associated with this Label. + * The context is created, if necessary. + * + * @return the associated context + */ +public AccessibleContext getAccessibleContext() +{ + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTLabel(); + return accessibleContext; +} + +} // class Label + diff --git a/libjava/classpath/java/awt/LayoutManager.java b/libjava/classpath/java/awt/LayoutManager.java new file mode 100644 index 0000000..62ff808 --- /dev/null +++ b/libjava/classpath/java/awt/LayoutManager.java @@ -0,0 +1,92 @@ +/* LayoutManager.java -- lay out elements in a Container + Copyright (C) 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 java.awt; + +/** + * This interface is for laying out containers in a particular sequence. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Container + * @since 1.0 + * @status updated to 1.4 + */ +public interface LayoutManager +{ + /** + * Adds the specified component to the layout group. + * + * @param name the name of the component to add + * @param component the component to add + */ + void addLayoutComponent(String name, Component component); + + /** + * Removes the specified component from the layout group. + * + * @param component the component to remove + */ + void removeLayoutComponent(Component component); + + /** + * Calculates the preferred size for this container, taking into account + * the components it contains. + * + * @param parent the parent container to lay out + * @return the preferred dimensions of this container + * @see #minimumLayoutSize(Container) + */ + Dimension preferredLayoutSize(Container parent); + + /** + * Calculates the minimum size for this container, taking into account + * the components it contains. + * + * @param parent the parent container to lay out + * @return the minimum dimensions of this container + * @see #preferredLayoutSize(Container) + */ + Dimension minimumLayoutSize(Container parent); + + /** + * Lays out the components in the given container. + * + * @param parent the container to lay out + */ + void layoutContainer(Container parent); +} // interface LayoutManager diff --git a/libjava/classpath/java/awt/LayoutManager2.java b/libjava/classpath/java/awt/LayoutManager2.java new file mode 100644 index 0000000..45fc543 --- /dev/null +++ b/libjava/classpath/java/awt/LayoutManager2.java @@ -0,0 +1,100 @@ +/* LayoutManager2.java -- enhanced layout manager + Copyright (C) 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 java.awt; + +/** + * Layout manager for laying out containers based on contraints. The + * constraints control how the layout will proceed. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see LayoutManager + * @see Container + * @since 1.0 + * @status updated to 1.4 + */ +public interface LayoutManager2 extends LayoutManager +{ + /** + * Adds the specified component to the layout, with the specified + * constraints object. + * + * @param component the component to add + * @param constraints the constraints to satisfy + */ + void addLayoutComponent(Component component, Object constraints); + + /** + * Determines the maximum size of the specified target container. + * + * @param target the container to lay out + * @return the maximum size of the container + * @see Component#getMaximumSize() + */ + Dimension maximumLayoutSize(Container target); + + /** + * Returns the preferred X axis alignment for the specified target + * container. This value will range from 0 to 1 where 0 is alignment + * closest to the origin, 0.5 is centered, and 1 is aligned furthest + * from the origin. + * + * @param target the target container + * @return the x-axis alignment preference + */ + float getLayoutAlignmentX(Container target); + + /** + * Returns the preferred Y axis alignment for the specified target + * container. This value will range from 0 to 1 where 0 is alignment + * closest to the origin, 0.5 is centered, and 1 is aligned furthest + * from the origin. + * + * @param target the target container + * @return the y-axis alignment preference + */ + float getLayoutAlignmentY(Container target); + + /** + * Forces the layout manager to purge any cached information about the + * layout of the target container. This will force it to be recalculated. + * + * @param target the target container + */ + void invalidateLayout(Container target); +} // interface LayoutManager2 diff --git a/libjava/classpath/java/awt/List.java b/libjava/classpath/java/awt/List.java new file mode 100644 index 0000000..5fcc79b --- /dev/null +++ b/libjava/classpath/java/awt/List.java @@ -0,0 +1,1263 @@ +/* List.java -- A listbox widget + Copyright (C) 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 java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.peer.ListPeer; +import java.util.EventListener; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * Class that implements a listbox widget + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class List extends Component + implements ItemSelectable, Accessible +{ + +/* + * Static Variables + */ + +// Serialization constant +private static final long serialVersionUID = -3304312411574666869L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +// FIXME: Need read/writeObject + +/** + * @serial The items in the list. + */ +private Vector items = new Vector(); + +/** + * @serial Indicates whether or not multiple items can be selected + * simultaneously. + */ +private boolean multipleMode; + +/** + * @serial The number of rows in the list. This is set on creation + * only and cannot be modified. + */ +private int rows; + +/** + * @serial An array of the item indices that are selected. + */ +private int[] selected; + +/** + * @serial An index value used by makeVisible() and + * getVisibleIndex. + */ +private int visibleIndex; + +// The list of ItemListeners for this object. +private ItemListener item_listeners; + +// The list of ActionListeners for this object. +private ActionListener action_listeners; + + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of List with no visible lines + * and multi-select disabled. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +List() +{ + this(4, false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of List with the specified + * number of visible lines and multi-select disabled. + * + * @param rows The number of visible rows in the list. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +List(int rows) +{ + this(rows, false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of List with the specified + * number of lines and the specified multi-select setting. + * + * @param rows The number of visible rows in the list. + * @param multipleMode true if multiple lines can be selected + * simultaneously, false otherwise. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +List(int rows, boolean multipleMode) +{ + this.rows = rows; + this.multipleMode = multipleMode; + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the number of items in this list. + * + * @return The number of items in this list. + */ +public int +getItemCount() +{ + return countItems (); +} + +/*************************************************************************/ + +/** + * Returns the number of items in this list. + * + * @return The number of items in this list. + * + * @deprecated This method is deprecated in favor of + * getItemCount() + */ +public int +countItems() +{ + return items.size (); +} + +/*************************************************************************/ + +/** + * Returns the complete list of items. + * + * @return The complete list of items in the list. + */ +public synchronized String[] +getItems() +{ + String[] l_items = new String[getItemCount()]; + + items.copyInto(l_items); + return(l_items); +} + +/*************************************************************************/ + +/** + * Returns the item at the specified index. + * + * @param index The index of the item to retrieve. + * + * @exception IndexOutOfBoundsException If the index value is not valid. + */ +public String +getItem(int index) +{ + return((String)items.elementAt(index)); +} + +/*************************************************************************/ + +/** + * Returns the number of visible rows in the list. + * + * @return The number of visible rows in the list. + */ +public int +getRows() +{ + return(rows); +} + +/*************************************************************************/ + +/** + * Tests whether or not multi-select mode is enabled. + * + * @return true if multi-select mode is enabled, + * false otherwise. + */ +public boolean +isMultipleMode() +{ + return allowsMultipleSelections (); +} + +/*************************************************************************/ + +/** + * Tests whether or not multi-select mode is enabled. + * + * @return true if multi-select mode is enabled, + * false otherwise. + * + * @deprecated This method is deprecated in favor of + * isMultipleMode(). + */ +public boolean +allowsMultipleSelections() +{ + return multipleMode; +} + +/*************************************************************************/ + +/** + * This method enables or disables multiple selection mode for this + * list. + * + * @param multipleMode true to enable multiple mode, + * false otherwise. + */ +public void +setMultipleMode(boolean multipleMode) +{ + setMultipleSelections (multipleMode); +} + +/*************************************************************************/ + +/** + * This method enables or disables multiple selection mode for this + * list. + * + * @param multipleMode true to enable multiple mode, + * false otherwise. + * + * @deprecated + */ +public void +setMultipleSelections(boolean multipleMode) +{ + this.multipleMode = multipleMode; + + ListPeer peer = (ListPeer) getPeer (); + if (peer != null) + peer.setMultipleMode (multipleMode); +} + +/*************************************************************************/ + +/** + * Returns the minimum size of this component. + * + * @return The minimum size of this component. + */ +public Dimension +getMinimumSize() +{ + return getMinimumSize (getRows ()); +} + +/*************************************************************************/ + +/** + * Returns the minimum size of this component. + * + * @return The minimum size of this component. + * + * @deprecated This method is deprecated in favor of + * getMinimumSize. + */ +public Dimension +minimumSize() +{ + return minimumSize (getRows ()); +} + +/*************************************************************************/ + +/** + * Returns the minimum size of this component assuming it had the specified + * number of rows. + * + * @param rows The number of rows to size for. + * + * @return The minimum size of this component. + */ +public Dimension +getMinimumSize(int rows) +{ + return minimumSize (rows); +} + +/*************************************************************************/ + +/** + * Returns the minimum size of this component assuming it had the specified + * number of rows. + * + * @param rows The number of rows to size for. + * + * @return The minimum size of this component. + * + * @deprecated This method is deprecated in favor of + * getMinimumSize(int)> + */ +public Dimension +minimumSize(int rows) +{ + ListPeer peer = (ListPeer) getPeer (); + if (peer != null) + return peer.minimumSize (rows); + else + return new Dimension (0, 0); +} + +/*************************************************************************/ + +/** + * Returns the preferred size of this component. + * + * @return The preferred size of this component. + */ +public Dimension +getPreferredSize() +{ + return getPreferredSize (getRows ()); +} + +/*************************************************************************/ + +/** + * Returns the preferred size of this component. + * + * @return The preferred size of this component. + * + * @deprecated This method is deprecated in favor of + * getPreferredSize. + */ +public Dimension +preferredSize() +{ + return preferredSize (getRows ()); +} + +/*************************************************************************/ + +/** + * Returns the preferred size of this component assuming it had the specified + * number of rows. + * + * @param rows The number of rows to size for. + * + * @return The preferred size of this component. + */ +public Dimension +getPreferredSize(int rows) +{ + return preferredSize (rows); +} + +/*************************************************************************/ + +/** + * Returns the preferred size of this component assuming it had the specified + * number of rows. + * + * @param rows The number of rows to size for. + * + * @return The preferred size of this component. + * + * @deprecated This method is deprecated in favor of + * getPreferredSize(int)> + */ +public Dimension +preferredSize(int rows) +{ + ListPeer peer = (ListPeer) getPeer (); + if (peer != null) + return peer.preferredSize (rows); + else + return new Dimension (0, 0); +} + +/*************************************************************************/ + +/** + * This method adds the specified item to the end of the list. + * + * @param item The item to add to the list. + */ +public void +add(String item) +{ + add (item, -1); +} + +/*************************************************************************/ + +/** + * This method adds the specified item to the end of the list. + * + * @param item The item to add to the list. + * + * @deprecated Use add() instead. + */ +public void +addItem(String item) +{ + addItem (item, -1); +} + +/*************************************************************************/ + +/** + * Adds the specified item to the specified location in the list. + * If the desired index is -1 or greater than the number of rows + * in the list, then the item is added to the end. + * + * @param item The item to add to the list. + * @param index The location in the list to add the item, or -1 to add + * to the end. + */ +public void +add(String item, int index) +{ + addItem (item, index); +} + +/*************************************************************************/ + +/** + * Adds the specified item to the specified location in the list. + * If the desired index is -1 or greater than the number of rows + * in the list, then the item is added to the end. + * + * @param item The item to add to the list. + * @param index The location in the list to add the item, or -1 to add + * to the end. + * + * @deprecated Use add() instead. + */ +public void +addItem(String item, int index) +{ + if ((index == -1) || (index >= items.size ())) + items.addElement (item); + else + items.insertElementAt (item, index); + + ListPeer peer = (ListPeer) getPeer (); + if (peer != null) + peer.add (item, index); +} + +/*************************************************************************/ + +/** + * Deletes the item at the specified index. + * + * @param index The index of the item to delete. + * + * @exception IllegalArgumentException If the index is not valid + * + * @deprecated + */ +public void +delItem(int index) throws IllegalArgumentException +{ + items.removeElementAt (index); + + ListPeer peer = (ListPeer) getPeer (); + if (peer != null) + peer.delItems (index, index); +} + +/*************************************************************************/ + +/** + * Deletes the item at the specified index. + * + * @param index The index of the item to delete. + * + * @exception IllegalArgumentException If the index is not valid + */ +public void +remove(int index) throws IllegalArgumentException +{ + delItem (index); +} + +/*************************************************************************/ + +/** + * Deletes all items in the specified index range. + * + * @param start The beginning index of the range to delete. + * @param end The ending index of the range to delete. + * + * @exception IllegalArgumentException If the indexes are not valid + * + * @deprecated This method is deprecated for some unknown reason. + */ +public synchronized void +delItems(int start, int end) throws IllegalArgumentException +{ + if ((start < 0) || (start >= items.size())) + throw new IllegalArgumentException("Bad list start index value: " + start); + + if ((start < 0) || (start >= items.size())) + throw new IllegalArgumentException("Bad list start index value: " + start); + + if (start > end) + throw new IllegalArgumentException("Start is greater than end!"); + + // We must run the loop in reverse direction. + for (int i = end; i >= start; --i) + items.removeElementAt (i); + if (peer != null) + { + ListPeer l = (ListPeer) peer; + l.delItems (start, end); + } +} + +/*************************************************************************/ + +/** + * Deletes the first occurrence of the specified item from the list. + * + * @param item The item to delete. + * + * @exception IllegalArgumentException If the specified item does not exist. + */ +public synchronized void +remove(String item) throws IllegalArgumentException +{ + int index = items.indexOf(item); + if (index == -1) + throw new IllegalArgumentException("List element to delete not found"); + + remove(index); +} + +/*************************************************************************/ + +/** + * Deletes all of the items from the list. + */ +public synchronized void +removeAll() +{ + clear (); +} + +/*************************************************************************/ + +/** + * Deletes all of the items from the list. + * + * @deprecated This method is deprecated in favor of removeAll(). + */ +public void +clear() +{ + items.clear(); + + ListPeer peer = (ListPeer) getPeer (); + if (peer != null) + peer.removeAll (); +} + +/*************************************************************************/ + +/** + * Replaces the item at the specified index with the specified item. + * + * @param item The new item value. + * @param index The index of the item to replace. + * + * @exception IllegalArgumentException If the index is not valid. + */ +public synchronized void +replaceItem(String item, int index) throws IllegalArgumentException +{ + if ((index < 0) || (index >= items.size())) + throw new IllegalArgumentException("Bad list index: " + index); + + items.insertElementAt(item, index + 1); + items.removeElementAt (index); + + if (peer != null) + { + ListPeer l = (ListPeer) peer; + + /* We add first and then remove so that the selected + item remains the same */ + l.add (item, index + 1); + l.delItems (index, index); + } +} + +/*************************************************************************/ + +/** + * Returns the index of the currently selected item. -1 will be returned + * if there are no selected rows or if there are multiple selected rows. + * + * @return The index of the selected row. + */ +public synchronized int +getSelectedIndex() +{ + if (peer != null) + { + ListPeer l = (ListPeer) peer; + selected = l.getSelectedIndexes (); + } + + if (selected == null || selected.length != 1) + return -1; + return selected[0]; +} + +/*************************************************************************/ + +/** + * Returns an array containing the indexes of the rows that are + * currently selected. + * + * @return A list of indexes of selected rows. + */ +public synchronized int[] +getSelectedIndexes() +{ + if (peer != null) + { + ListPeer l = (ListPeer) peer; + selected = l.getSelectedIndexes (); + } + return selected; +} + +/*************************************************************************/ + +/** + * Returns the item that is currently selected, or null if there + * is no item selected. FIXME: What happens if multiple items selected? + * + * @return The selected item, or null if there is no + * selected item. + */ +public synchronized String +getSelectedItem() +{ + int index = getSelectedIndex(); + if (index == -1) + return(null); + + return((String)items.elementAt(index)); +} + +/*************************************************************************/ + +/** + * Returns the list of items that are currently selected in this list. + * + * @return The list of currently selected items. + */ +public synchronized String[] +getSelectedItems() +{ + int[] indexes = getSelectedIndexes(); + if (indexes == null) + return(new String[0]); + + String[] retvals = new String[indexes.length]; + if (retvals.length > 0) + for (int i = 0 ; i < retvals.length; i++) + retvals[i] = (String)items.elementAt(indexes[i]); + + return(retvals); +} + +/*************************************************************************/ + +/** + * Returns the list of items that are currently selected in this list as + * an array of type Object[] instead of String[]. + * + * @return The list of currently selected items. + */ +public synchronized Object[] +getSelectedObjects() +{ + int[] indexes = getSelectedIndexes(); + if (indexes == null) + return(new Object[0]); + + Object[] retvals = new Object[indexes.length]; + if (retvals.length > 0) + for (int i = 0 ; i < retvals.length; i++) + retvals[i] = items.elementAt(indexes[i]); + + return(retvals); +} + +/*************************************************************************/ + +/** + * Tests whether or not the specified index is selected. + * + * @param index The index to test. + * + * @return true if the index is selected, false + * otherwise. + */ +public boolean +isIndexSelected(int index) +{ + return isSelected (index); +} + +/*************************************************************************/ + +/** + * Tests whether or not the specified index is selected. + * + * @param index The index to test. + * + * @return true if the index is selected, false + * otherwise. + * + * @deprecated This method is deprecated in favor of + * isIndexSelected(int). + */ +public boolean +isSelected(int index) +{ + int[] indexes = getSelectedIndexes (); + + for (int i = 0; i < indexes.length; i++) + if (indexes[i] == index) + return true; + + return false; +} + +/*************************************************************************/ + +/** + * This method ensures that the item at the specified index is visible. + * + * @exception IllegalArgumentException If the specified index is out of + * range. + */ +public synchronized void +makeVisible(int index) throws IllegalArgumentException +{ + if ((index < 0) || (index >= items.size())) + throw new IllegalArgumentException("Bad list index: " + index); + + visibleIndex = index; + if (peer != null) + { + ListPeer l = (ListPeer) peer; + l.makeVisible (index); + } +} + +/*************************************************************************/ + +/** + * Returns the index of the last item that was made visible via the + * makeVisible() method. + * + * @return The index of the last item made visible via the + * makeVisible() method. + */ +public int +getVisibleIndex() +{ + return(visibleIndex); +} + +/*************************************************************************/ + +/** + * Makes the item at the specified index selected. + * + * @param index The index of the item to select. + */ +public synchronized void +select(int index) +{ + ListPeer lp = (ListPeer)getPeer(); + if (lp != null) + lp.select(index); +} + +/*************************************************************************/ + +/** + * Makes the item at the specified index not selected. + * + * @param index The index of the item to unselect. + */ +public synchronized void +deselect(int index) +{ + ListPeer lp = (ListPeer)getPeer(); + if (lp != null) + lp.deselect(index); +} + +/*************************************************************************/ + +/** + * Notifies this object to create its native peer. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createList (this); + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Notifies this object to destroy its native peer. + */ +public void +removeNotify() +{ + super.removeNotify(); +} + +/*************************************************************************/ + +/** + * Adds the specified ActionListener to the list of + * registered listeners for this object. + * + * @param listener The listener to add. + */ +public synchronized void +addActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.add(action_listeners, listener); +} + +/*************************************************************************/ + +/** + * Removes the specified ActionListener from the list of + * registers listeners for this object. + * + * @param listener The listener to remove. + */ +public synchronized void +removeActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.remove(action_listeners, listener); +} + +/*************************************************************************/ + +/** + * Adds the specified ItemListener to the list of + * registered listeners for this object. + * + * @param listener The listener to add. + */ +public synchronized void +addItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.add(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Removes the specified ItemListener from the list of + * registers listeners for this object. + * + * @param listener The listener to remove. + */ +public synchronized void +removeItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.remove(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Processes the specified event for this object. If the event is an + * instance of ActionEvent then the + * processActionEvent() method is called. Similarly, if the + * even is an instance of ItemEvent then the + * processItemEvent() method is called. Otherwise the + * superclass method is called to process this event. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ActionEvent) + processActionEvent((ActionEvent)event); + else if (event instanceof ItemEvent) + processItemEvent((ItemEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * This method processes the specified event by dispatching it to any + * registered listeners. Note that this method will only get called if + * action events are enabled. This will happen automatically if any + * listeners are added, or it can be done "manually" by calling + * the enableEvents() method. + * + * @param event The event to process. + */ +protected void +processActionEvent(ActionEvent event) +{ + if (action_listeners != null) + action_listeners.actionPerformed(event); +} + +/*************************************************************************/ + +/** + * This method processes the specified event by dispatching it to any + * registered listeners. Note that this method will only get called if + * item events are enabled. This will happen automatically if any + * listeners are added, or it can be done "manually" by calling + * the enableEvents() method. + * + * @param event The event to process. + */ +protected void +processItemEvent(ItemEvent event) +{ + if (item_listeners != null) + item_listeners.itemStateChanged(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ItemEvent.ITEM_LAST + && e.id >= ItemEvent.ITEM_FIRST + && (item_listeners != null + || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) + processEvent(e); + else if (e.id <= ActionEvent.ACTION_LAST + && e.id >= ActionEvent.ACTION_FIRST + && (action_listeners != null + || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +protected String +paramString() +{ + return "multiple=" + multipleMode + ",rows=" + rows + super.paramString(); +} + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this List. FooListeners are registered using the + * addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + */ + public EventListener[] getListeners (Class listenerType) + { + if (listenerType == ActionListener.class) + return AWTEventMulticaster.getListeners (action_listeners, listenerType); + + if (listenerType == ItemListener.class) + return AWTEventMulticaster.getListeners (item_listeners, listenerType); + + return super.getListeners (listenerType); + } + + /** + * Returns all action listeners registered to this object. + */ + public ActionListener[] getActionListeners () + { + return (ActionListener[]) getListeners (ActionListener.class); + } + + /** + * Returns all action listeners registered to this object. + */ + public ItemListener[] getItemListeners () + { + return (ItemListener[]) getListeners (ItemListener.class); + } + + // Accessibility internal class + protected class AccessibleAWTList extends AccessibleAWTComponent + implements AccessibleSelection, ItemListener, ActionListener + { + protected class AccessibleAWTListChild extends AccessibleAWTComponent + implements Accessible + { + private int index; + private List parent; + + public AccessibleAWTListChild(List parent, int indexInParent) + { + this.parent = parent; + index = indexInParent; + if (parent == null) + index = -1; + } + + /* (non-Javadoc) + * @see javax.accessibility.Accessible#getAccessibleContext() + */ + public AccessibleContext getAccessibleContext() + { + return this; + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.LIST_ITEM; + } + + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (parent.isIndexSelected(index)) + states.add(AccessibleState.SELECTED); + return states; + } + + public int getAccessibleIndexInParent() + { + return index; + } + + } + + public AccessibleAWTList() + { + addItemListener(this); + addActionListener(this); + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.LIST; + } + + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + states.add(AccessibleState.SELECTABLE); + if (isMultipleMode()) + states.add(AccessibleState.MULTISELECTABLE); + return states; + } + + public int getAccessibleChildrenCount() + { + return getItemCount(); + } + + public Accessible getAccessibleChild(int i) + { + if (i >= getItemCount()) + return null; + return new AccessibleAWTListChild(List.this, i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#getAccessibleSelectionCount() + */ + public int getAccessibleSelectionCount() + { + return getSelectedIndexes().length; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#getAccessibleSelection() + */ + public AccessibleSelection getAccessibleSelection() + { + return this; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#getAccessibleSelection(int) + */ + public Accessible getAccessibleSelection(int i) + { + int[] items = getSelectedIndexes(); + if (i >= items.length) + return null; + return new AccessibleAWTListChild(List.this, items[i]); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#isAccessibleChildSelected(int) + */ + public boolean isAccessibleChildSelected(int i) + { + return isIndexSelected(i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#addAccessibleSelection(int) + */ + public void addAccessibleSelection(int i) + { + select(i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#removeAccessibleSelection(int) + */ + public void removeAccessibleSelection(int i) + { + deselect(i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#clearAccessibleSelection() + */ + public void clearAccessibleSelection() + { + for (int i = 0; i < getItemCount(); i++) + deselect(i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#selectAllAccessibleSelection() + */ + public void selectAllAccessibleSelection() + { + if (isMultipleMode()) + for (int i = 0; i < getItemCount(); i++) + select(i); + } + + /* (non-Javadoc) + * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) + */ + public void itemStateChanged(ItemEvent event) + { + } + + /* (non-Javadoc) + * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent event) + { + } + + } + + /** + * Gets the AccessibleContext associated with this List. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTList(); + return accessibleContext; + } +} // class List diff --git a/libjava/classpath/java/awt/MediaTracker.java b/libjava/classpath/java/awt/MediaTracker.java new file mode 100644 index 0000000..9abfde6 --- /dev/null +++ b/libjava/classpath/java/awt/MediaTracker.java @@ -0,0 +1,697 @@ +/* MediaTracker.java -- Class used for keeping track of images + Copyright (C) 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 java.awt; + +import java.awt.image.ImageObserver; +import java.util.ArrayList; + +/** + * This class is used for keeping track of the status of various media + * objects. + * + * Media objects are tracked by assigning them an ID. It is possible + * to assign the same ID to mutliple objects, effectivly grouping them + * together. In this case the status flags ({@link #statusID}) and error flag + * (@link #isErrorID} and {@link #getErrorsID}) are ORed together. This + * means that you cannot say exactly which media object has which status, + * at most you can say that there are certain media objects with + * some certain status. + * + * At the moment only images are supported by this class. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Bryce McKinlay + */ +public class MediaTracker implements java.io.Serializable +{ + /** Indicates that the media is still loading. */ + public static final int LOADING = 1 << 0; + + /** Indicates that the loading operation has been aborted. */ + public static final int ABORTED = 1 << 1; + + /** Indicates that an error has occured during loading of the media. */ + public static final int ERRORED = 1 << 2; + + /** Indicates that the media has been successfully and completely loaded. */ + public static final int COMPLETE = 1 << 3; + + /** The component on which the media is eventually been drawn. */ + Component target; + + /** The head of the linked list of tracked media objects. */ + MediaEntry head; + + /** Our serialVersionUID for serialization. */ + static final long serialVersionUID = -483174189758638095L; + + /** + * This represents a media object that is tracked by a MediaTracker. + * It also implements a simple linked list. + */ + // FIXME: The serialized form documentation says MediaEntry is a + // serializable field, but the serialized form of MediaEntry itself + // doesn't appear to be documented. + class MediaEntry implements ImageObserver + { + /** The ID of the media object. */ + int id; + + /** The media object. (only images are supported ATM). */ + Image image; + + /** The link to the next entry in the list. */ + MediaEntry next; + + /** The tracking status. */ + int status; + + /** The width of the image. */ + int width; + + /** The height of the image. */ + int height; + + /** + * Receives notification from an {@link java.awt.image.ImageProducer} + * that more data of the image is available. + * + * @param img the image that is updated + * @param flags flags from the ImageProducer that indicate the status + * of the loading process + * @param x the X coordinate of the upper left corner of the image + * @param y the Y coordinate of the upper left corner of the image + * @param width the width of the image + * @param height the height of the image + * + * @return true if more data is needed, false + * otherwise + * + * @see java.awt.image.ImageObserver + */ + public boolean imageUpdate(Image img, int flags, int x, int y, + int width, int height) + { + if ((flags & ABORT) != 0) + status = ABORTED; + else if ((flags & ERROR) != 0) + status = ERRORED; + else if ((flags & ALLBITS) != 0) + status = COMPLETE; + else + status = 0; + + synchronized (MediaTracker.this) + { + MediaTracker.this.notifyAll(); + } + + // If status is not COMPLETE then we need more updates. + return ((status & (COMPLETE | ERRORED | ABORTED)) == 0); + } + } + + /** + * Constructs a new MediaTracker for the component c. The + * component should be the component that uses the media (i.e. draws it). + * + * @param c the Component that wants to use the media + */ + public MediaTracker(Component c) + { + target = c; + } + + /** + * Adds an image to the tracker with the specified ID. + * + * @param image the image to be added + * @param id the ID of the tracker list to which the image is added + */ + public void addImage(Image image, int id) + { + MediaEntry e = new MediaEntry(); + e.id = id; + e.image = image; + synchronized(this) + { + e.next = head; + head = e; + } + } + + /** + * Adds an image to the tracker with the specified ID. + * The image is expected to be rendered with the specified width and + * height. + * + * @param image the image to be added + * @param id the ID of the tracker list to which the image is added + * @param width the width of the image + * @param height the height of the image + */ + public void addImage(Image image, int id, int width, int height) + { + MediaEntry e = new MediaEntry(); + e.id = id; + e.image = image; + e.width = width; + e.height = height; + synchronized(this) + { + e.next = head; + head = e; + } + } + + /** + * Checks if all media objects have finished loading, i.e. are + * {@link #COMPLETE}, {@link #ABORTED} or {@link #ERRORED}. + * + * If the media objects are not already loading, a call to this + * method does not start loading. This is equivalent to + * a call to checkAll(false). + * + * @return if all media objects have finished loading either by beeing + * complete, have been aborted or errored. + */ + public boolean checkAll() + { + return checkAll(false); + } + + /** + * Checks if all media objects have finished loading, i.e. are + * {@link #COMPLETE}, {@link #ABORTED} or {@link #ERRORED}. + * + * If the media objects are not already loading, and load + * is true then a call to this + * method starts loading the media objects. + * + * @param load if true this method starts loading objects + * that are not already loading + * + * @return if all media objects have finished loading either by beeing + * complete, have been aborted or errored. + */ + public boolean checkAll(boolean load) + { + MediaEntry e = head; + boolean result = true; + + while (e != null) + { + if ((e.status & (COMPLETE | ERRORED | ABORTED)) == 0) + { + if (load && ((e.status & LOADING) == 0)) + { + if (target.prepareImage(e.image, e)) + e.status = COMPLETE; + else + { + e.status = LOADING; + int flags = target.checkImage(e.image, e); + if ((flags & ImageObserver.ABORT) != 0) + e.status = ABORTED; + else if ((flags & ImageObserver.ERROR) != 0) + e.status = ERRORED; + else if ((flags & ImageObserver.ALLBITS) != 0) + e.status = COMPLETE; + } + boolean complete = (e.status + & (COMPLETE | ABORTED | ERRORED)) != 0; + if (!complete) + result = false; + } + else + result = false; + } + e = e.next; + } + return result; + } + + /** + * Checks if any of the registered media objects has encountered an error + * during loading. + * + * @return true if at least one media object has encountered + * an error during loading, false otherwise + * + */ + public boolean isErrorAny() + { + MediaEntry e = head; + while (e != null) + { + if ((e.status & ERRORED) != 0) + return true; + e = e.next; + } + return false; + } + + /** + * Returns all media objects that have encountered errors during loading. + * + * @return an array of all media objects that have encountered errors + * or null if there were no errors at all + */ + public Object[] getErrorsAny() + { + MediaEntry e = head; + ArrayList result = null; + while (e != null) + { + if ((e.status & ERRORED) != 0) + { + if (result == null) + result = new ArrayList(); + result.add(e.image); + } + e = e.next; + } + if (result == null) + return null; + else + return result.toArray(); + } + + /** + * Waits for all media objects to finish loading, either by completing + * successfully or by aborting or encountering an error. + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ + public void waitForAll() throws InterruptedException + { + synchronized (this) + { + while (checkAll(true) == false) + wait(); + } + } + + /** + * Waits for all media objects to finish loading, either by completing + * successfully or by aborting or encountering an error. + * + * This method waits at most ms milliseconds. If the + * media objects have not completed loading within this timeframe, this + * method returns false, otherwise true. + * + * @param ms timeframe in milliseconds to wait for the media objects to + * finish + * + * @return true if all media objects have successfully loaded + * within the timeframe, false otherwise + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ + public boolean waitForAll(long ms) throws InterruptedException + { + long start = System.currentTimeMillis(); + boolean result = checkAll(true); + synchronized (this) + { + while (result == false) + { + wait(ms); + result = checkAll(true); + if ((System.currentTimeMillis() - start) > ms) + break; + } + } + + return result; + } + + /** + * Returns the status flags of all registered media objects ORed together. + * If load is true then media objects that + * are not already loading will be started to load. + * + * @param load if set to true then media objects that are + * not already loading are started + * + * @return the status flags of all tracked media objects ORed together + */ + public int statusAll(boolean load) + { + int result = 0; + MediaEntry e = head; + while (e != null) + { + if (load && e.status == 0) + { + if (target.prepareImage(e.image, e)) + e.status = COMPLETE; + else + { + e.status = LOADING; + int flags = target.checkImage(e.image, e); + if ((flags & ImageObserver.ABORT) != 0) + e.status = ABORTED; + else if ((flags & ImageObserver.ERROR) != 0) + e.status = ERRORED; + else if ((flags & ImageObserver.ALLBITS) != 0) + e.status = COMPLETE; + } + } + result |= e.status; + e = e.next; + } + return result; + } + + /** + * Checks if the media objects with ID have completed loading. + * + * @param id the ID of the media objects to check + * + * @return true if all media objects with ID + * have successfully finished + */ + public boolean checkID(int id) + { + return checkID(id, false); + } + + /** + * Checks if the media objects with ID have completed loading. + * If load is true then media objects that + * are not already loading will be started to load. + * + * @param id the ID of the media objects to check + * @param load if set to true then media objects that are + * not already loading are started + * + * @return true if all media objects with ID + * have successfully finished + */ + public boolean checkID(int id, boolean load) + { + MediaEntry e = head; + boolean result = true; + + while (e != null) + { + if (e.id == id && ((e.status & (COMPLETE | ABORTED | ERRORED)) == 0)) + { + if (load && ((e.status & LOADING) == 0)) + { + e.status = LOADING; + if (target.prepareImage(e.image, e)) + e.status = COMPLETE; + else + { + int flags = target.checkImage(e.image, e); + if ((flags & ImageObserver.ABORT) != 0) + e.status = ABORTED; + else if ((flags & ImageObserver.ERROR) != 0) + e.status = ERRORED; + else if ((flags & ImageObserver.ALLBITS) != 0) + e.status = COMPLETE; + } + boolean complete = (e.status + & (COMPLETE | ABORTED | ERRORED)) != 0; + if (!complete) + result = false; + } + else + result = false; + } + e = e.next; + } + return result; + } + + /** + * Returns true if any of the media objects with ID + * have encountered errors during loading, false otherwise. + * + * @param id the ID of the media objects to check + * + * @return true if any of the media objects with ID + * have encountered errors during loading, false otherwise + */ + public boolean isErrorID(int id) + { + MediaEntry e = head; + while (e != null) + { + if (e.id == id && ((e.status & ERRORED) != 0)) + return true; + e = e.next; + } + return false; + } + + /** + * Returns all media objects with the specified ID that have encountered + * an error. + * + * @param id the ID of the media objects to check + * + * @return an array of all media objects with the specified ID that + * have encountered an error + */ + public Object[] getErrorsID(int id) + { + MediaEntry e = head; + ArrayList result = null; + while (e != null) + { + if (e.id == id && ((e.status & ERRORED) != 0)) + { + if (result == null) + result = new ArrayList(); + result.add(e.image); + } + e = e.next; + } + if (result == null) + return null; + else + return result.toArray(); + } + + /** + * Waits for all media objects with the specified ID to finish loading, + * either by completing successfully or by aborting or encountering an error. + * + * @param id the ID of the media objects to wait for + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ + public void waitForID(int id) throws InterruptedException + { + MediaEntry e = head; + synchronized (this) + { + while (checkID (id, true) == false) + wait(); + } + } + + /** + * Waits for all media objects with the specified ID to finish loading, + * either by completing successfully or by aborting or encountering an error. + * + * This method waits at most ms milliseconds. If the + * media objects have not completed loading within this timeframe, this + * method returns false, otherwise true. + * + * @param id the ID of the media objects to wait for + * @param ms timeframe in milliseconds to wait for the media objects to + * finish + * + * @return true if all media objects have successfully loaded + * within the timeframe, false otherwise + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ + public boolean waitForID(int id, long ms) throws InterruptedException + { + MediaEntry e = head; + long start = System.currentTimeMillis(); + boolean result = checkID(id, true); + + synchronized (this) + { + while (result == false) + { + wait(ms); + result = checkID(id, true); + if ((System.currentTimeMillis() - start) > ms) + break; + } + } + + return result; + } + + /** + * Returns the status flags of the media objects with the specified ID + * ORed together. + * + * If load is true then media objects that + * are not already loading will be started to load. + * + * @param load if set to true then media objects that are + * not already loading are started + * + * @return the status flags of all tracked media objects ORed together + */ + public int statusID(int id, boolean load) + { + int result = 0; + MediaEntry e = head; + while (e != null) + { + if (e.id == id) + { + if (load && e.status == 0) + { + if (target.prepareImage(e.image, e)) + e.status = COMPLETE; + else + { + e.status = LOADING; + int flags = target.checkImage(e.image, e); + if ((flags & ImageObserver.ABORT) != 0) + e.status = ABORTED; + else if ((flags & ImageObserver.ERROR) != 0) + e.status = ERRORED; + else if ((flags & ImageObserver.ALLBITS) != 0) + e.status = COMPLETE; + } + } + result |= e.status; + } + e = e.next; + } + return result; + } + + /** + * Removes an image from this MediaTracker. + * + * @param image the image to be removed + */ + public void removeImage(Image image) + { + synchronized (this) + { + MediaEntry e = head; + MediaEntry prev = null; + while (e != null) + { + if (e.image == image) + { + if (prev == null) + head = e.next; + else + prev.next = e.next; + } + prev = e; + e = e.next; + } + } + } + + /** + * Removes an image with the specified ID from this MediaTracker. + * + * @param image the image to be removed + */ + public void removeImage(Image image, int id) + { + synchronized (this) + { + MediaEntry e = head; + MediaEntry prev = null; + while (e != null) + { + if (e.id == id && e.image == image) + { + if (prev == null) + head = e.next; + else + prev.next = e.next; + } + else + prev = e; + e = e.next; + } + } + } + + /** + * Removes an image with the specified ID and scale from this MediaTracker. + * + * @param image the image to be removed + */ + public void removeImage(Image image, int id, int width, int height) + { + synchronized (this) + { + MediaEntry e = head; + MediaEntry prev = null; + while (e != null) + { + if (e.id == id && e.image == image + && e.width == width && e.height == height) + { + if (prev == null) + head = e.next; + else + prev.next = e.next; + } + else + prev = e; + e = e.next; + } + } + } +} diff --git a/libjava/classpath/java/awt/Menu.java b/libjava/classpath/java/awt/Menu.java new file mode 100644 index 0000000..56ceccf --- /dev/null +++ b/libjava/classpath/java/awt/Menu.java @@ -0,0 +1,468 @@ +/* Menu.java -- A Java AWT Menu + Copyright (C) 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 java.awt; + +import java.awt.peer.MenuPeer; +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Vector; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class represents a pull down or tear off menu in Java's AWT. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Menu extends MenuItem implements MenuContainer, Serializable +{ + +/* + * Static Variables + */ + +// Serialization Constant +private static final long serialVersionUID = -8809584163345499784L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The actual items in the menu + */ +private Vector items = new Vector(); + +/** + * @serial Flag indicating whether or not this menu is a tear off + */ +private boolean tearOff; + +/** + * @serial Indicates whether or not this is a help menu. + */ +private boolean isHelpMenu; + + /* + * @serial Unused in this implementation, but present in Sun's + * serialization spec. Value obtained via reflection. + */ + private int menuSerializedDataVersion = 1; + +static final transient String separatorLabel = "-"; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of Menu with no label and that + * is not a tearoff; + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +Menu() +{ +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Menu that is not a tearoff and + * that has the specified label. + * + * @param label The menu label. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +Menu(String label) +{ + this(label, false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of Menu with the specified + * label and tearoff status. + * + * @param label The label for this menu + * @param isTearOff true if this menu is a tear off menu, + * false otherwise. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +Menu(String label, boolean isTearOff) +{ + super(label); + + tearOff = isTearOff; + + if (label.equals("Help")) + isHelpMenu = true; + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Tests whether or not this menu is a tearoff. + * + * @return true if this menu is a tearoff, false + * otherwise. + */ +public boolean +isTearOff() +{ + return(tearOff); +} + +/*************************************************************************/ + +/** + * Returns the number of items in this menu. + * + * @return The number of items in this menu. + */ +public int +getItemCount() +{ + return countItems (); +} + +/** + * Returns the number of items in this menu. + * + * @return The number of items in this menu. + * + * @deprecated As of JDK 1.1, replaced by getItemCount(). + */ +public int countItems () +{ + return items.size (); +} + +/*************************************************************************/ + +/** + * Returns the item at the specified index. + * + * @return The item at the specified index. + * + * @exception ArrayIndexOutOfBoundsException If the index value is not valid. + */ +public MenuItem +getItem(int index) +{ + return((MenuItem)items.elementAt(index)); +} + +/*************************************************************************/ + +/** + * Adds the specified item to this menu. If it was previously part of + * another menu, it is first removed from that menu. + * + * @param item The new item to add. + * + * @return The item that was added. + */ +public MenuItem +add(MenuItem item) +{ + items.addElement(item); + if (item.parent != null) + { + item.parent.remove(item); + } + item.parent = this; + + if (peer != null) + { + MenuPeer mp = (MenuPeer) peer; + mp.addItem(item); + } + + return item; +} + +/*************************************************************************/ + +/** + * Add an item with the specified label to this menu. + * + * @param label The label of the menu item to add. + */ +public void +add(String label) +{ + add(new MenuItem(label)); +} + +/*************************************************************************/ + +/** + * Inserts the specified menu item into this menu at the specified index. + * + * @param item The menu item to add. + * @param index The index of the menu item. + * + * @exception IllegalArgumentException If the index is less than zero. + * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid. + */ +public void +insert(MenuItem item, int index) +{ + if (index < 0) + throw new IllegalArgumentException("Index is less than zero"); + + MenuPeer peer = (MenuPeer) getPeer(); + if (peer == null) + return; + + int count = getItemCount (); + + if (index >= count) + peer.addItem (item); + else + { + for (int i = count - 1; i >= index; i--) + peer.delItem (i); + + peer.addItem (item); + + for (int i = index; i < count; i++) + peer.addItem ((MenuItem) items.elementAt (i)); + } + + items.insertElementAt(item, index); +} + +/*************************************************************************/ + +/** + * Inserts an item with the specified label into this menu at the specified index. + * + * @param label The label of the item to add. + * @param index The index of the menu item. + * + * @exception IllegalArgumentException If the index is less than zero. + * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid. + */ +public void +insert(String label, int index) +{ + insert(new MenuItem(label), index); +} + +/*************************************************************************/ + +/** + * Adds a separator bar at the current menu location. + */ +public void +addSeparator() +{ + add(new MenuItem(separatorLabel)); +} + +/*************************************************************************/ + +/** + * Inserts a separator bar at the specified index value. + * + * @param index The index at which to insert a separator bar. + * + * @exception IllegalArgumentException If the index is less than zero. + * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid. + */ +public void +insertSeparator(int index) +{ + insert(new MenuItem(separatorLabel), index); +} + +/*************************************************************************/ + +/** + * Deletes the item at the specified index from this menu. + * + * @param index The index of the item to remove. + * + * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid. + */ +public synchronized void +remove(int index) +{ + items.removeElementAt(index); + + MenuPeer mp = (MenuPeer)getPeer(); + if (mp != null) + mp.delItem(index); +} + +/*************************************************************************/ + +/** + * Removes the specifed item from the menu. If the specified component + * does not exist, this method does nothing. + * + * @param item The component to remove. + */ +public void +remove(MenuComponent item) +{ + int index = items.indexOf(item); + if (index == -1) + return; + + remove(index); +} + +/*************************************************************************/ + +/** + * Removes all the elements from this menu. + */ +public synchronized void +removeAll() +{ + int count = getItemCount(); + for(int i = 0; i < count; i++) + { + // We must always remove item 0. + remove(0); + } +} + +/*************************************************************************/ + +/** + * Creates the native peer for this object. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit().createMenu(this); + Enumeration e = items.elements(); + while (e.hasMoreElements()) + { + MenuItem mi = (MenuItem)e.nextElement(); + mi.addNotify(); + } + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Destroys the native peer for this object. + */ +public void +removeNotify() +{ + Enumeration e = items.elements(); + while (e.hasMoreElements()) + { + MenuItem mi = (MenuItem) e.nextElement(); + mi.removeNotify(); + } + super.removeNotify(); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this menu. + * + * @return A debugging string for this menu. + */ +public String +paramString() +{ + return (",tearOff=" + tearOff + ",isHelpMenu=" + isHelpMenu + + super.paramString()); +} + + /** + * Basic Accessibility class for Menu. Details get provided in derived + * classes. + */ + protected class AccessibleAWTMenu extends AccessibleAWTMenuItem + { + protected AccessibleAWTMenu() + { + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.MENU; + } + } + + /** + * Gets the AccessibleContext associated with this Menu. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTMenu(); + return accessibleContext; + } + +} // class Menu diff --git a/libjava/classpath/java/awt/MenuBar.java b/libjava/classpath/java/awt/MenuBar.java new file mode 100644 index 0000000..4089fe1 --- /dev/null +++ b/libjava/classpath/java/awt/MenuBar.java @@ -0,0 +1,423 @@ +/* MenuBar.java -- An AWT menu bar class + Copyright (C) 1999, 2000, 2001, 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 java.awt; + +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuComponentPeer; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class implements a menu bar in the AWT system. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class MenuBar extends MenuComponent + implements MenuContainer, Serializable, Accessible +{ + +/* + * Static Variables + */ + +// Serialization Constant +private static final long serialVersionUID = -4930327919388951260L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The menu used for providing help information + */ +private Menu helpMenu; + +/** + * @serial The menus contained in this menu bar. + */ +private Vector menus = new Vector(); + + /** + * The accessible context for this component. + * + * @see #getAccessibleContext() + * @serial ignored. + */ + private transient AccessibleContext accessibleContext; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of MenuBar. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +MenuBar() +{ + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the help menu for this menu bar. This may be null. + * + * @return The help menu for this menu bar. + */ +public Menu +getHelpMenu() +{ + return(helpMenu); +} + +/*************************************************************************/ + +/** + * Sets the help menu for this menu bar. + * + * @param menu The new help menu for this menu bar. + */ +public synchronized void +setHelpMenu(Menu menu) +{ + if (helpMenu != null) + { + helpMenu.removeNotify (); + helpMenu.parent = null; + } + helpMenu = menu; + + if (menu.parent != null) + menu.parent.remove (menu); + menu.parent = this; + + MenuBarPeer peer = (MenuBarPeer) getPeer (); + if (peer != null) + { + menu.addNotify(); + peer.addHelpMenu (menu); + } +} + +/*************************************************************************/ + +/** Add a menu to this MenuBar. If the menu has already has a + * parent, it is first removed from its old parent before being + * added. + * + * @param menu The menu to add. + * + * @return The menu that was added. + */ +public synchronized Menu +add(Menu menu) +{ + if (menu.parent != null) + menu.parent.remove (menu); + + menu.parent = this; + menus.addElement(menu); + + if (peer != null) + { + menu.addNotify(); + } + + return(menu); +} + +/*************************************************************************/ + +/** + * Removes the menu at the specified index. + * + * @param index The index of the menu to remove from the menu bar. + */ +public synchronized void +remove(int index) +{ + Menu m = (Menu) menus.get (index); + menus.remove (index); + m.removeNotify (); + m.parent = null; + + if (peer != null) + { + MenuBarPeer mp = (MenuBarPeer) peer; + mp.delMenu (index); + } +} + +/*************************************************************************/ + +/** + * Removes the specified menu from the menu bar. + * + * @param menu The menu to remove from the menu bar. + */ +public void +remove(MenuComponent menu) +{ + int index = menus.indexOf(menu); + if (index == -1) + return; + + remove(index); +} + +/*************************************************************************/ + +/** + * Returns the number of elements in this menu bar. + * + * @return The number of elements in the menu bar. + */ +public int +getMenuCount() +{ + return countMenus (); +} + +/*************************************************************************/ + +/** + * Returns the number of elements in this menu bar. + * + * @return The number of elements in the menu bar. + * + * @deprecated This method is deprecated in favor of getMenuCount(). + */ +public int +countMenus() +{ + return menus.size () + (getHelpMenu () == null ? 0 : 1); +} + +/*************************************************************************/ + +/** + * Returns the menu at the specified index. + * + * @param index the index of the menu + * + * @return The requested menu. + * + * @exception ArrayIndexOutOfBoundsException If the index is not valid. + */ +public Menu +getMenu(int index) +{ + return((Menu)menus.elementAt(index)); +} + +/*************************************************************************/ + +/** + * Creates this object's native peer. + */ +public void +addNotify() +{ + if (getPeer() == null) + setPeer((MenuComponentPeer)getToolkit().createMenuBar(this)); + Enumeration e = menus.elements(); + while (e.hasMoreElements()) + { + Menu mi = (Menu)e.nextElement(); + mi.addNotify(); + } + if (helpMenu != null) + { + helpMenu.addNotify(); + ((MenuBarPeer) peer).addHelpMenu(helpMenu); + } +} + +/*************************************************************************/ + +/** + * Destroys this object's native peer. + */ +public void +removeNotify() +{ + Enumeration e = menus.elements(); + while (e.hasMoreElements()) + { + Menu mi = (Menu) e.nextElement(); + mi.removeNotify(); + } + super.removeNotify(); +} + +/*************************************************************************/ + +/** + * Returns a list of all shortcuts for the menus in this menu bar. + * + * @return A list of all shortcuts for the menus in this menu bar. + */ +public synchronized Enumeration +shortcuts() +{ + Vector shortcuts = new Vector(); + Enumeration e = menus.elements(); + + while (e.hasMoreElements()) + { + Menu menu = (Menu)e.nextElement(); + if (menu.getShortcut() != null) + shortcuts.addElement(menu.getShortcut()); + } + + return(shortcuts.elements()); +} + +/*************************************************************************/ + +/** + * Returns the menu item for the specified shortcut, or null + * if no such item exists. + * + * @param shortcut The shortcut to return the menu item for. + * + * @return The menu item for the specified shortcut. + */ +public MenuItem +getShortcutMenuItem(MenuShortcut shortcut) +{ + Enumeration e = menus.elements(); + + while (e.hasMoreElements()) + { + Menu menu = (Menu)e.nextElement(); + MenuShortcut s = menu.getShortcut(); + if ((s != null) && (s.equals(shortcut))) + return(menu); + } + + return(null); +} + +/*************************************************************************/ + +/** + * Deletes the specified menu shortcut. + * + * @param shortcut The shortcut to delete. + */ +public void +deleteShortcut(MenuShortcut shortcut) +{ + MenuItem it; + // This is a slow implementation, but it probably doesn't matter. + while ((it = getShortcutMenuItem (shortcut)) != null) + it.deleteShortcut (); +} + +/** + * Gets the AccessibleContext associated with this MenuBar. + * The context is created, if necessary. + * + * @return the associated context + */ +public AccessibleContext getAccessibleContext() +{ + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTMenuBar(); + return accessibleContext; +} + +/** + * This class provides accessibility support for AWT menu bars. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +protected class AccessibleAWTMenuBar + extends AccessibleAWTMenuComponent +{ + + /** + * Compatible with JDK 1.4.2 revision 5 + */ + private static final long serialVersionUID = -8577604491830083815L; + + /** + * This is the default constructor, which simply calls the default + * constructor of the superclass. + */ + protected AccessibleAWTMenuBar() + { + super(); + } + + /** + * Returns the accessible role relating to the menu bar. + * + * @return AccessibleRole.MENU_BAR. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.MENU_BAR; + } + +} // class AccessibleAWTMenuBar + +} // class MenuBar diff --git a/libjava/classpath/java/awt/MenuComponent.java b/libjava/classpath/java/awt/MenuComponent.java new file mode 100644 index 0000000..ec6980e1 --- /dev/null +++ b/libjava/classpath/java/awt/MenuComponent.java @@ -0,0 +1,1324 @@ +/* MenuComponent.java -- Superclass of all AWT menu components + Copyright (C) 1999, 2000, 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 java.awt; + +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.peer.MenuComponentPeer; +import java.io.Serializable; +import java.util.Locale; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleComponent; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleStateSet; + +/** + * This is the superclass of all menu AWT widgets. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public abstract class MenuComponent implements Serializable +{ + +/* + * Static Variables + */ + +// Serialization Constant +private static final long serialVersionUID = -4536902356223894379L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * The font for this component. + * + * @see #getFont() + * @see #setFont(java.awt.Font) + * @serial the component's font. + */ + private Font font; + + /** + * The name of the component. + * + * @see #getName() + * @see #setName(String) + * @serial the component's name. + */ + private String name; + + /** + * The parent of this component. + * + * @see #getParent() + * @see #setParent(java.awt.MenuContainer) + * @serial ignored. + */ + transient MenuContainer parent; + + /** + * The native peer for this component. + * + * @see #getPeer() + * @see #setPeer(java.awt.peer.MenuComponentPeer) + * @serial ignored. + */ + transient MenuComponentPeer peer; + + /** + * The synchronization locking object for this component. + * + * @serial ignored. + */ + private transient Object tree_lock = this; + + /** + * The toolkit for this object. + * + * @see #getToolkit() + * @serial ignored. + */ + private static transient Toolkit toolkit = Toolkit.getDefaultToolkit(); + + /** + * The accessible context for this component. + * + * @see #getAccessibleContext() + * @serial the accessibility information for this component. + */ + AccessibleContext accessibleContext; + + /** + * Was the name of the component set? This value defaults + * to false and becomes true after a call to setName(). + * Please note that this does not guarantee that name will then + * be non-null, as this may be the value passed to setName(). + * + * @see #setName(String) + * @serial true if the name value has been explicitly set by calling + * setName(). + */ + private boolean nameExplicitlySet; + + /** + * Does this component handle new events? Events will be handled + * by this component if this is true. Otherwise, they will be forwarded + * up the component hierarchy. This implementation does not use this + * variable; it is merely provided for serialization compatability. + * + * @see #dispatchEvent(AWTEvent) + * @serial true if events are to be processed locally. Unused. + */ + private boolean newEventsOnly; + + /** + * The focus listener chain handler which deals with focus events for + * the accessible context of this component. + * + * @see AccessibleAWTMenuComponent#addFocusListener(java.awt.event.FocusListener) + * @serial ignored. + * This is package-private to avoid an accessor method. + */ + transient FocusListener focusListener; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Default constructor for subclasses. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +MenuComponent() +{ + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the font in use for this component. + * + * @return The font for this component. + */ +public Font +getFont() +{ + if (font != null) + return font; + + if (parent != null) + return parent.getFont (); + + return null; +} + +/*************************************************************************/ + +/** + * Sets the font for this component to the specified font. + * + * @param font The new font for this component. + */ +public void +setFont(Font font) +{ + this.font = font; +} + +/*************************************************************************/ + +/** + * Returns the name of this component. + * + * @return The name of this component. + */ +public String +getName() +{ + return(name); +} + +/*************************************************************************/ + +/** + * Sets the name of this component to the specified name. + * + * @param name The new name of this component. + */ +public void +setName(String name) +{ + this.name = name; + nameExplicitlySet = true; +} + +/*************************************************************************/ + +/** + * Returns the parent of this component. + * + * @return The parent of this component. + */ +public MenuContainer +getParent() +{ + return(parent); +} + +/*************************************************************************/ + +// Sets the parent of this component. +final void +setParent(MenuContainer parent) +{ + this.parent = parent; +} + +/*************************************************************************/ + +/** + * Returns the native windowing system peer for this component. + * + * @return The peer for this component. + * + * @deprecated + */ +public MenuComponentPeer +getPeer() +{ + return(peer); +} + +/*************************************************************************/ + +// Sets the peer for this component. +final void +setPeer(MenuComponentPeer peer) +{ + this.peer = peer; +} + +/*************************************************************************/ + +/** + * Destroys this component's native peer + */ +public void +removeNotify() +{ + if (peer != null) + peer.dispose(); + peer = null; +} + +/*************************************************************************/ + +/** + * Returns the toolkit in use for this component. + * + * @return The toolkit for this component. + */ +final Toolkit +getToolkit() +{ + return(toolkit); +} + +/*************************************************************************/ + +/** + * Returns the object used for synchronization locks on this component + * when performing tree and layout functions. + * + * @return The synchronization lock for this component. + */ +protected final Object +getTreeLock() +{ + return(tree_lock); +} + +/*************************************************************************/ + +// The sync lock object for this component. +final void +setTreeLock(Object tree_lock) +{ + this.tree_lock = tree_lock; +} + +/*************************************************************************/ + +/** + * AWT 1.0 event dispatcher. + * + * @deprecated Deprecated in favor of dispatchEvent(). + * @return true if the event was dispatched, false otherwise. + */ +public boolean +postEvent(Event event) +{ + // This is overridden by subclasses that support events. + return false; +} +/*************************************************************************/ + +/** + * Sends this event to this component or a subcomponent for processing. + * + * @param event The event to dispatch + */ +public final void dispatchEvent(AWTEvent event) +{ + // See comment in Component.dispatchEvent(). + dispatchEventImpl(event); +} + + +/** + * Implementation of dispatchEvent. Allows trusted package classes + * to dispatch additional events first. This implementation first + * translates event to an AWT 1.0 event and sends the + * result to {@link #postEvent}. The event is then + * passed on to {@link #processEvent} for local processing. + * + * @param event the event to dispatch. + */ +void dispatchEventImpl(AWTEvent event) +{ + Event oldStyleEvent; + + // This is overridden by subclasses that support events. + /* Convert AWT 1.1 event to AWT 1.0 event */ + oldStyleEvent = Component.translateEvent(event); + if (oldStyleEvent != null) + { + postEvent(oldStyleEvent); + } + /* Do local processing */ + processEvent(event); +} + +/*************************************************************************/ + +/** + * Processes the specified event. In this class, this method simply + * calls one of the more specific event handlers. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + /* + Pass a focus event to the focus listener for + the accessibility context. + */ + if (event instanceof FocusEvent) + { + if (focusListener != null) + { + switch (event.id) + { + case FocusEvent.FOCUS_GAINED: + focusListener.focusGained((FocusEvent) event); + break; + case FocusEvent.FOCUS_LOST: + focusListener.focusLost((FocusEvent) event); + break; + } + } + } +} + +/*************************************************************************/ + +/** + * Returns a string representation of this component. + * + * @return A string representation of this component + */ +public String +toString() +{ + return this.getClass().getName() + "[" + paramString() + "]"; +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this component + */ +protected String +paramString() +{ + return "name=" + getName(); +} + +/** + * Gets the AccessibleContext associated with this MenuComponent. + * As an abstract class, we return null. Concrete subclasses should return + * their implementation of the accessibility context. + * + * @return null. + */ + +public AccessibleContext getAccessibleContext() +{ + return null; +} + +/** + * This class provides a base for the accessibility support of menu + * components. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +protected abstract class AccessibleAWTMenuComponent + extends AccessibleContext + implements Serializable, AccessibleComponent, AccessibleSelection +{ + + /** + * Compatible with JDK 1.4.2 revision 5 + */ + private static final long serialVersionUID = -4269533416223798698L; + + /** + * This is the default constructor. It should be called by + * concrete subclasses to ensure necessary groundwork is completed. + */ + protected AccessibleAWTMenuComponent() + { + } + + /** + * Replaces or supplements the component's selection with the + * Accessible child at the supplied index. If + * the component supports multiple selection, the child is + * added to the current selection. Otherwise, the current + * selection becomes the specified child. If the child is + * already selected, nothing happens. + *
+ *
+ * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the specified child within a + * zero-based list of the component's children. + */ + public void addAccessibleSelection(int index) + { + /* Subclasses with children should implement this */ + } + + /** + * Registers the specified focus listener to receive + * focus events from this component. + * + * @param listener the new focus listener. + */ + public void addFocusListener(FocusListener listener) + { + /* + * Chain the new focus listener to the existing chain + * of focus listeners. Each new focus listener is + * coupled via multicasting to the existing chain. + */ + focusListener = AWTEventMulticaster.add(focusListener, listener); + } + + /** + * Clears the component's current selection. Following + * the calling of this method, no children of the component + * will be selected. + *
+ *
+ * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + */ + public void clearAccessibleSelection() + { + } + + /** + * Returns true if the specified point lies within the + * component. The supplied co-ordinates are assumed to + * be relative to the co-ordinate system of the component + * itself. Thus, the point (0,0) is the upper left corner + * of this component. + *
+ *
+ * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @param point the point to check against this component. + * @return true if the point is within this component. + * @see #getBounds() + */ + public boolean contains(Point point) + { + /* + We can simply return the result of a + test for containment in the bounding rectangle + */ + return getBounds().contains(point); + } + + /** + * Returns the Accessible child of this component present + * at the specified point. The supplied co-ordinates are + * assumed to be relative to the co-ordinate system of this + * component (the parent of any returned accessible). Thus, + * the point (0,0) is the upper left corner of this menu + * component. + *
+ *
+ * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param point the point at which the returned accessible + * is located. + * @return null. + */ + public Accessible getAccessibleAt(Point point) + { + return null; + } + + /** + * Returns the Accessible child at the supplied + * index within the list of children of this component. + *
+ *
+ * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the Accessible child + * to retrieve. + * @return null. + */ + public Accessible getAccessibleChild(int index) + { + return null; + } + + /** + * Returns the number of children of this component which + * implement the Accessible interface. If + * all children of this component are accessible, then + * the returned value will be the same as the number of + * children. + *
+ *
+ * + * @return 0. + */ + public int getAccessibleChildrenCount() + { + return 0; + } + + /** + * Retrieves the AccessibleComponent associated + * with this accessible context and its component. As the + * context itself implements AccessibleComponent, + * this is the return value. + * + * @return the context itself. + */ + public AccessibleComponent getAccessibleComponent() + { + return this; + } + + /** + * Returns the accessible name for this menu component. This + * is the name given to the component, which may be null if + * not set using setName(). + *
+ *
+ * The name is not the most appropriate description of this + * object. Subclasses should preferably provide a more + * accurate description. For example, a File menu could + * have the description `Lists commands related to the + * file system'. + * + * @return a description of the component. Currently, + * this is just the contents of the name property. + * @see MenuComponent#setName(String) + */ + public String getAccessibleDescription() + { + return MenuComponent.this.getName(); + } + + /** + * Retrieves the index of this component within its parent. + * If no parent exists, -1 is returned. + * + * @return -1 as the parent, a MenuContainer + * is not Accessible. + */ + public int getAccessibleIndexInParent() + { + return -1; + } + + /** + * Returns the accessible name of this component. This + * is the name given to the component, which may be null if + * not set using setName(). + *
+ *
+ * The name property is not the most suitable string to return + * for this method. The string should be localized, and + * relevant to the operation of the component. For example, + * it could be the text of a menu item. However, this can + * not be used at this level of abstraction, so it is the + * responsibility of subclasses to provide a more appropriate + * name. + * + * @return a localized name for this component. Currently, this + * is just the contents of the name property. + * @see MenuComponent#setName(String) + */ + public String getAccessibleName() + { + return MenuComponent.this.getName(); + } + + /** + * Returns the Accessible parent of this component. + * As the parent of a MenuComponent is a + * MenuContainer, which doesn't implement + * Accessible, this method returns null. + * + * @return null. + */ + public Accessible getAccessibleParent() + { + return null; + } + + /** + * Returns the accessible role of this component. + *
+ *
+ * The abstract implementation of this method returns + * AccessibleRole.AWT_COMPONENT, + * as the abstract component has no specific role. This + * method should be overridden by concrete subclasses, so + * as to return an appropriate role for the component. + * + * @return AccessibleRole.AWT_COMPONENT. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.AWT_COMPONENT; + } + + /** + * Retrieves the AccessibleSelection associated + * with this accessible context and its component. As the + * context itself implements AccessibleSelection, + * this is the return value. + * + * @return the context itself. + */ + public AccessibleSelection getAccessibleSelection() + { + return this; + } + + /** + * Retrieves the Accessible selected child + * at the specified index. If there are no selected children + * or the index is outside the range of selected children, + * null is returned. Please note that the index refers + * to the index of the child in the list of selected + * children, and not the index of the child in + * the list of all Accessible children. + *
+ *
+ * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the selected Accessible + * child. + */ + public Accessible getAccessibleSelection(int index) + { + return null; + } + + /** + * Returns a count of the number of Accessible + * children of this component which are currently selected. + * If there are no children currently selected, 0 is returned. + *
+ *
+ * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @return 0. + */ + public int getAccessibleSelectionCount() + { + return 0; + } + + /** + * Retrieves the current state of this component + * in an accessible form. For example, a given component + * may be visible, selected, disabled, etc. + *
+ *
+ * As this class tells us virtually nothing about the component, + * except for its name and font, no state information can be + * provided. This implementation thus returns an empty + * state set, and it is left to concrete subclasses to provide + * a more acceptable and relevant state set. Changes to these + * properties also need to be handled using + * PropertyChangeListeners. + * + * @return an empty AccessibleStateSet. + */ + public AccessibleStateSet getAccessibleStateSet() + { + return new AccessibleStateSet(); + } + + /** + * Returns the background color of the component, or null + * if this property is unsupported. + *
+ *
+ * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns the + * default system background color used for rendering menus. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return the default system background color for menus. + * @see #setBackground(java.awt.Color) + */ + public Color getBackground() + { + return SystemColor.menu; + } + + /** + * Returns a Rectangle which represents the + * bounds of this component. The returned rectangle has the + * height and width of the component's bounds, and is positioned + * at a location relative to this component's parent, the + * MenuContainer. null is returned if bounds + * are not supported by the component. + *
+ *
+ * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns null. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return null. + * @see #setBounds(java.awt.Rectangle) + */ + public Rectangle getBounds() + { + return null; + } + + /** + * Returns the Cursor displayed when the pointer + * is positioned over this component. Alternatively, null + * is returned if the component doesn't support the cursor + * property. + *
+ *
+ * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns the default + * system cursor. Concrete subclasses which handle the drawing + * of an onscreen menu component may override this method and provide + * the appropriate information. + * + * @return the default system cursor. + * @see #setCursor(java.awt.Cursor) + */ + public Cursor getCursor() + { + return Cursor.getDefaultCursor(); + } + + /** + * Returns the Font used for text created by this component. + * + * @return the current font. + * @see #setFont(java.awt.Font) + */ + public Font getFont() + { + return MenuComponent.this.getFont(); + } + + /** + * Retrieves information on the rendering and metrics of the supplied + * font. If font metrics are not supported by this component, null + * is returned. + *
+ *
+ * The abstract implementation of this method simply uses the toolkit + * to obtain the FontMetrics. Concrete subclasses may + * find it more efficient to invoke their peer class directly, if one + * is available. + * + * @param font the font about which to retrieve rendering and metric + * information. + * @return the metrics of the given font, as provided by the system + * toolkit. + * @throws NullPointerException if the supplied font was null. + */ + public FontMetrics getFontMetrics(Font font) + { + return MenuComponent.this.getToolkit().getFontMetrics(font); + } + + /** + * Returns the foreground color of the component, or null + * if this property is unsupported. + *
+ *
+ * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns the + * default system text color used for rendering menus. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return the default system text color for menus. + * @see #setForeground(java.awt.Color) + */ + public Color getForeground() + { + return SystemColor.menuText; + } + + /** + * Returns the locale currently in use by this component. + *
+ *
+ * This abstract class has no property relating to the + * locale used by the component, so this method simply + * returns the default locale for the current instance + * of the Java Virtual Machine (JVM). Concrete subclasses + * which maintain such a property should override this method + * and provide the locale information more accurately. + * + * @return the default locale for this JVM instance. + */ + public Locale getLocale() + { + return Locale.getDefault(); + } + + /** + * Returns the location of the component, with co-ordinates + * relative to the parent component and using the co-ordinate + * space of the screen. Thus, the point (0,0) is the upper + * left corner of the parent component. + *
+ *
+ * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @return the location of the component, relative to its parent. + * @see #setLocation(java.awt.Point) + */ + public Point getLocation() + { + /* Simply return the location of the bounding rectangle */ + return getBounds().getLocation(); + } + + /** + * Returns the location of the component, with co-ordinates + * relative to the screen. Thus, the point (0,0) is the upper + * left corner of the screen. null is returned if the component + * is either not on screen or if this property is unsupported. + *
+ *
+ * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns null. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return the location of the component, relative to the screen. + */ + public Point getLocationOnScreen() + { + return null; + } + + /** + * Returns the size of the component. + *
+ *
+ * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @return the size of the component. + * @see #setSize(java.awt.Dimension) + */ + public Dimension getSize() + { + /* Simply return the size of the bounding rectangle */ + return getBounds().getSize(); + } + + /** + * Returns true if the accessible child specified by the supplied index + * is currently selected. + *
+ *
+ * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the accessible child to check for selection. + * @return false. + */ + public boolean isAccessibleChildSelected(int index) + { + return false; + } + + /** + * Returns true if this component is currently enabled. + *
+ *
+ * As this abstract component has no properties related to + * its enabled or disabled state, the implementation of this + * method is left to subclasses. + * + * @return false. + * @see #setEnabled(boolean) + */ + public boolean isEnabled() + { + return false; + } + + /** + * Returns true if this component is included in the traversal + * of the current focus from one component to the other. + *
+ *
+ * As this abstract component has no properties related to + * its ability to accept the focus, the implementation of this + * method is left to subclasses. + * + * @return false. + */ + public boolean isFocusTraversable() + { + return false; + } + + /** + * Returns true if the component is being shown on screen. + * A component is determined to be shown if it is visible, + * and each parent component is also visible. Please note + * that, even when a component is showing, it may still be + * obscured by other components in front. This method only + * determines if the component is being drawn on the screen. + *
+ *
+ * As this abstract component and its parent have no properties + * relating to visibility, the implementation of this method is + * left to subclasses. + * + * @return false. + * @see #isVisible() + */ + public boolean isShowing() + { + return false; + } + + /** + * Returns true if the component is visible. A component may + * be visible but not drawn on the screen if one of its parent + * components is not visible. To determine if the component is + * actually drawn on screen, isShowing() should be + * used. + *
+ *
+ * As this abstract component has no properties relating to its + * visibility, the implementation of this method is left to subclasses. + * + * @return false. + * @see #isShowing() + * @see #setVisible(boolean) + */ + public boolean isVisible() + { + return false; + } + + /** + * Removes the accessible child specified by the supplied index from + * the list of currently selected children. If the child specified + * is not selected, nothing happens. + *
+ *
+ * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the Accessible child. + */ + public void removeAccessibleSelection(int index) + { + /* Subclasses with children should implement this */ + } + + /** + * Removes the specified focus listener from the list of registered + * focus listeners for this component. + * + * @param listener the listener to remove. + */ + public void removeFocusListener(FocusListener listener) + { + /* Remove the focus listener from the chain */ + focusListener = AWTEventMulticaster.remove(focusListener, listener); + } + + /** + * Requests that this component gains focus. This depends on the + * component being focus traversable. + *
+ *
+ * As this abstract component has no properties relating to its + * focus traversability, or access to a peer with request focusing + * abilities, the implementation of this method is left to subclasses. + */ + public void requestFocus() + { + /* Ignored */ + } + + /** + * Selects all Accessible children of this component which + * it is possible to select. The component needs to support multiple + * selections. + *
+ *
+ * This abstract component provides a simplistic implementation of this + * method, which ignores the ability of the component to support multiple + * selections and simply uses addAccessibleSelection to + * add each Accessible child to the selection. The last + * Accessible component is thus selected for components + * which don't support multiple selections. Concrete implementations should + * override this with a more appopriate and efficient implementation, which + * properly takes into account the ability of the component to support multiple + * selections. + */ + public void selectAllAccessibleSelection() + { + /* Simply call addAccessibleSelection() on all accessible children */ + for (int a = 0; a < getAccessibleChildrenCount(); ++a) + { + addAccessibleSelection(a); + } + } + + /** + * Sets the background color of the component to that specified. + * Unspecified behaviour occurs when null is given as the new + * background color. + *
+ *
+ * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the supplied + * color and continues to use the default system color. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @param color the new color to use for the background. + * @see getBackground() + */ + public void setBackground(Color color) + { + /* Ignored */ + } + + /** + * Sets the height and width of the component, and its position + * relative to this component's parent, to the values specified + * by the supplied rectangle. Unspecified behaviour occurs when + * null is given as the new bounds. + *
+ *
+ * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the new + * rectangle and continues to return null from getBounds(). + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @param rectangle a rectangle which specifies the new bounds of + * the component. + * @see #getBounds() + */ + public void setBounds(Rectangle rectangle) + { + /* Ignored */ + } + + /** + * Sets the Cursor used when the pointer is positioned over the + * component. Unspecified behaviour occurs when null is given as the new + * cursor. + *
+ *
+ * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the new cursor + * and continues to return the default system cursor. Concrete + * subclasses which handle the drawing of an onscreen menu component + * may override this method and provide the appropriate information. + * + * @param cursor the new cursor to use. + * @see #getCursor() + */ + public void setCursor(Cursor cursor) + { + /* Ignored */ + } + + /** + * Sets the enabled/disabled state of this component. + *
+ *
+ * As this abstract component has no properties related to + * its enabled or disabled state, the implementation of this + * method is left to subclasses. + * + * @param enabled true if the component should be enabled, + * false otherwise. + * @see #getEnabled() + */ + public void setEnabled(boolean enabled) + { + /* Ignored */ + } + + /** + * Sets the Font used for text created by this component. + * Unspecified behaviour occurs when null is given as the new + * font. + * + * @param font the new font to use for text. + * @see #getFont() + */ + public void setFont(Font font) + { + /* Call the method of the enclosing component */ + MenuComponent.this.setFont(font); + } + + /** + * Sets the foreground color of the component to that specified. + * Unspecified behaviour occurs when null is given as the new + * background color. + *
+ *
+ * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the supplied + * color and continues to return the default system text color used + * for rendering menus. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @param color the new foreground color. + * @see #getForeground() + */ + public void setForeground(Color color) + { + /* Ignored */ + } + + /** + * Sets the location of the component, with co-ordinates + * relative to the parent component and using the co-ordinate + * space of the screen. Thus, the point (0,0) is the upper + * left corner of the parent component. + *
+ *
+ * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @param point the location of the component, relative to its parent. + * @see #getLocation() + */ + public void setLocation(Point point) + { + getBounds().setLocation(point); + } + + /** + * Sets the size of the component. + *
+ *
+ * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @param size the new size of the component. + * @see #getSize() + */ + public void setSize(Dimension size) + { + getBounds().setSize(size); + } + + /** + * Sets the visibility state of the component. A component may + * be visible but not drawn on the screen if one of its parent + * components is not visible. To determine if the component is + * actually drawn on screen, isShowing() should be + * used. + *
+ *
+ * As this abstract component has no properties relating to its + * visibility, the implementation of this method is left to subclasses. + * + * @param visibility the new visibility of the component -- true if + * the component is visible, false if not. + * @see #isShowing() + * @see #isVisible() + */ + public void setVisible(boolean visibility) + { + /* Ignored */ + } + +} /* class AccessibleAWTMenuComponent */ + + +} // class MenuComponent diff --git a/libjava/classpath/java/awt/MenuContainer.java b/libjava/classpath/java/awt/MenuContainer.java new file mode 100644 index 0000000..c76ec96 --- /dev/null +++ b/libjava/classpath/java/awt/MenuContainer.java @@ -0,0 +1,71 @@ +/* MenuContainer.java -- container for menu items + Copyright (C) 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 java.awt; + +/** + * This interface is a container for menu components. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface MenuContainer +{ + /** + * Returns the font in use by this container. + * + * @return the menu font + */ + Font getFont(); + + /** + * Removes the specified menu component from the menu. + * + * @param component the menu component to remove + */ + void remove(MenuComponent component); + + /** + * Posts an event to the listeners. + * + * @param event the event to dispatch + * @deprecated use {@link MenuComponent#dispatchEvent(AWTEvent)} instead + */ + boolean postEvent(Event event); +} // interface MenuContainer diff --git a/libjava/classpath/java/awt/MenuItem.java b/libjava/classpath/java/awt/MenuItem.java new file mode 100644 index 0000000..66798c8 --- /dev/null +++ b/libjava/classpath/java/awt/MenuItem.java @@ -0,0 +1,603 @@ +/* MenuItem.java -- An item in a menu + Copyright (C) 1999, 2000, 2001, 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 java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.peer.MenuItemPeer; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleValue; + +/** + * This class represents an item in a menu. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class MenuItem extends MenuComponent + implements Serializable, Accessible +{ + +/* + * Static Variables + */ + +// Serialization Constant +private static final long serialVersionUID = -21757335363267194L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The name of the action command generated by this item. + * This is package-private to avoid an accessor method. + */ +String actionCommand; + +/** + * @serial Indicates whether or not this menu item is enabled. + * This is package-private to avoid an accessor method. + */ +boolean enabled = true; + +/** + * @serial The mask of events that are enabled for this menu item. + */ +long eventMask; + +/** + * @serial This menu item's label + * This is package-private to avoid an accessor method. + */ +String label = ""; + +/** + * @serial The shortcut for this menu item, if any + */ +private MenuShortcut shortcut; + +// The list of action listeners for this menu item. +private transient ActionListener action_listeners; + + protected class AccessibleAWTMenuItem + extends MenuComponent.AccessibleAWTMenuComponent + implements AccessibleAction, AccessibleValue + { + /** Constructor */ + public AccessibleAWTMenuItem() + { + super(); + } + + + + public String getAccessibleName() + { + return label; + } + + public AccessibleAction getAccessibleAction() + { + return this; + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.MENU_ITEM; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#getAccessibleActionCount() + */ + public int getAccessibleActionCount() + { + return 1; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int) + */ + public String getAccessibleActionDescription(int i) + { + if (i == 0) + return label; + else + return null; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#doAccessibleAction(int) + */ + public boolean doAccessibleAction(int i) + { + if (i != 0) + return false; + processActionEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, actionCommand)); + return true; + } + + public AccessibleValue getAccessibleValue() + { + return this; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() + */ + public Number getCurrentAccessibleValue() + { + return (enabled) ? new Integer(1) : new Integer(0); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) + */ + public boolean setCurrentAccessibleValue(Number number) + { + if (number.intValue() == 0) + { + setEnabled(false); + return false; + } + + setEnabled(true); + return true; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() + */ + public Number getMinimumAccessibleValue() + { + return new Integer(0); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() + */ + public Number getMaximumAccessibleValue() + { + return new Integer(0); + } + + } + + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of MenuItem with no label + * and no shortcut. + */ +public +MenuItem() +{ +} + +/*************************************************************************/ + +/** + * Initializes a new instance of MenuItem with the specified + * label and no shortcut. + * + * @param label The label for this menu item. + */ +public +MenuItem(String label) +{ + this.label = label; +} + +/*************************************************************************/ + +/** + * Initializes a new instance of MenuItem with the specified + * label and shortcut. + * + * @param label The label for this menu item. + * @param shortcut The shortcut for this menu item. + */ +public +MenuItem(String label, MenuShortcut shortcut) +{ + this.label = label; + this.shortcut = shortcut; +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the label for this menu item, which may be null. + * + * @return The label for this menu item. + */ +public String +getLabel() +{ + return(label); +} + +/*************************************************************************/ + +/** + * This method sets the label for this menu to the specified value. + * + * @param label The new label for this menu item. + */ +public synchronized void +setLabel(String label) +{ + this.label = label; + if (peer != null) + { + MenuItemPeer mp = (MenuItemPeer) peer; + mp.setLabel (label); + } +} + +/*************************************************************************/ + +/** + * Tests whether or not this menu item is enabled. + * + * @return true if this menu item is enabled, false + * otherwise. + */ +public boolean +isEnabled() +{ + return(enabled); +} + +/*************************************************************************/ + +/** + * Sets the enabled status of this menu item. + * + * @param enabled true to enable this menu item, + * false otherwise. + */ +public synchronized void +setEnabled(boolean enabled) +{ + enable (enabled); +} + +/*************************************************************************/ + +/** + * Sets the enabled status of this menu item. + * + * @param enabled true to enable this menu item, + * false otherwise. + * + * @deprecated This method is deprecated in favor of setEnabled(). + */ +public void +enable(boolean enabled) +{ + if (enabled) + enable (); + else + disable (); +} + +/*************************************************************************/ + +/** + * Enables this menu item. + * + * @deprecated This method is deprecated in favor of setEnabled(). + */ +public void +enable() +{ + if (enabled) + return; + + this.enabled = true; + if (peer != null) + ((MenuItemPeer) peer).setEnabled (true); +} + +/*************************************************************************/ + +/** + * Disables this menu item. + * + * @deprecated This method is deprecated in favor of setEnabled(). + */ +public void +disable() +{ + if (!enabled) + return; + + this.enabled = false; + if (peer != null) + ((MenuItemPeer) peer).setEnabled (false); +} + +/*************************************************************************/ + +/** + * Returns the shortcut for this menu item, which may be null. + * + * @return The shortcut for this menu item. + */ +public MenuShortcut +getShortcut() +{ + return(shortcut); +} + +/*************************************************************************/ + +/** + * Sets the shortcut for this menu item to the specified value. This + * must be done before the native peer is created. + * + * @param shortcut The new shortcut for this menu item. + */ +public void +setShortcut(MenuShortcut shortcut) +{ + this.shortcut = shortcut; +} + +/*************************************************************************/ + +/** + * Deletes the shortcut for this menu item if one exists. This must be + * done before the native peer is created. + */ +public void +deleteShortcut() +{ + shortcut = null; +} + +/*************************************************************************/ + +/** + * Returns the name of the action command in the action events + * generated by this menu item. + * + * @return The action command name + */ +public String +getActionCommand() +{ + if (actionCommand == null) + return label; + else + return actionCommand; +} + +/*************************************************************************/ + +/** + * Sets the name of the action command in the action events generated by + * this menu item. + * + * @param actionCommand The new action command name. + */ +public void +setActionCommand(String actionCommand) +{ + this.actionCommand = actionCommand; +} + +/*************************************************************************/ + +/** + * Enables the specified events. This is done automatically when a + * listener is added and does not normally need to be done by + * application code. + * + * @param events The events to enable, which should be the bit masks + * from AWTEvent. + */ +protected final void +enableEvents(long events) +{ + eventMask |= events; + // TODO: see comment in Component.enableEvents(). +} + +/*************************************************************************/ + +/** + * Disables the specified events. + * + * @param events The events to enable, which should be the bit masks + * from AWTEvent. + */ +protected final void +disableEvents(long events) +{ + eventMask &= ~events; +} + +/*************************************************************************/ + +/** + * Creates the native peer for this object. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createMenuItem (this); +} + +/*************************************************************************/ + +/** + * Adds the specified listener to the list of registered action listeners + * for this component. + * + * @param listener The listener to add. + */ +public synchronized void +addActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.add(action_listeners, listener); + + enableEvents(AWTEvent.ACTION_EVENT_MASK); +} + +public synchronized void +removeActionListener(ActionListener l) +{ + action_listeners = AWTEventMulticaster.remove(action_listeners, l); +} + + public synchronized ActionListener[] getActionListeners() + { + return (ActionListener[]) + AWTEventMulticaster.getListeners(action_listeners, + ActionListener.class); + } + +/** Returns all registered EventListers of the given listenerType. + * listenerType must be a subclass of EventListener, or a + * ClassClassException is thrown. + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + if (listenerType == ActionListener.class) + return getActionListeners(); + return (EventListener[]) Array.newInstance(listenerType, 0); + } + +/*************************************************************************/ + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ActionEvent.ACTION_LAST + && e.id >= ActionEvent.ACTION_FIRST + && (action_listeners != null + || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) + processEvent(e); + + // Send the event to the parent menu if it has not yet been + // consumed. + if (!e.isConsumed ()) + ((Menu) getParent ()).processEvent (e); +} + +/** + * Processes the specified event by calling processActionEvent() + * if it is an instance of ActionEvent. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ActionEvent) + processActionEvent((ActionEvent)event); +} + +/*************************************************************************/ + +/** + * Processes the specified event by dispatching it to any registered listeners. + * + * @param event The event to process. + */ +protected void +processActionEvent(ActionEvent event) +{ + if (action_listeners != null) + { + event.setSource(this); + action_listeners.actionPerformed(event); + } +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +public String +paramString() +{ + return ("label=" + label + ",enabled=" + enabled + + ",actionCommand=" + actionCommand + "," + super.paramString()); +} + +/** + * Gets the AccessibleContext associated with this MenuItem. + * The context is created, if necessary. + * + * @return the associated context + */ +public AccessibleContext getAccessibleContext() +{ + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTMenuItem(); + return accessibleContext; +} + +} // class MenuItem diff --git a/libjava/classpath/java/awt/MenuShortcut.java b/libjava/classpath/java/awt/MenuShortcut.java new file mode 100644 index 0000000..adfd1d3 --- /dev/null +++ b/libjava/classpath/java/awt/MenuShortcut.java @@ -0,0 +1,207 @@ +/* MenuShortcut.java -- A class for menu accelerators + Copyright (C) 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 java.awt; + +/** + * This class implements a keyboard accelerator for a menu item. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class MenuShortcut implements java.io.Serializable +{ + +/* + * Static Variables + */ + +// Serialization Constant +private static final long serialVersionUID = 143448358473180225L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The virtual keycode for the shortcut. + */ +private int key; + +/** + * @serial true if the shift key was used with this shortcut, + * or false otherwise. + */ +private boolean usesShift; + +/*************************************************************************/ + +/** + * Initializes a new instance of MenuShortcut with the + * specified virtual key value. + * + * @param key The virtual keycode for the shortcut. + */ +public +MenuShortcut(int key) +{ + this(key, false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of MenuShortcut with the + * specified virtual key value and shift setting. + * + * @param key The virtual keycode for the shortcut. + * @param usesShift true if the shift key was pressed, + * false otherwise. + */ +public +MenuShortcut(int key, boolean usesShift) +{ + this.key = key; + this.usesShift = usesShift; +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the virtual keycode for this shortcut. + * + * @return The virtual keycode for this shortcut. + */ +public int +getKey() +{ + return(key); +} + +/*************************************************************************/ + +/** + * Returns the shift setting for this shortcut. + * + * @return true if the shift key was pressed, false + * otherwise. + */ +public boolean +usesShiftModifier() +{ + return(usesShift); +} + +/*************************************************************************/ + +/** + * Tests this object for equality against the specified object. The two + * objects will be considered equal if and only if the specified object + * is an instance of MenuShortcut and has the same key value + * and shift setting as this object. + * + * @param obj The object to test for equality against. + * + * @return true if the two objects are equal, false + * otherwise. + */ +public boolean +equals(MenuShortcut obj) +{ + if (obj == null) + return(false); + + if (obj.key != this.key) + return(false); + + if (obj.usesShift != this.usesShift) + return(false); + + return(true); +} + +public boolean +equals(Object obj) +{ + if (obj instanceof MenuShortcut) + { + MenuShortcut ms = (MenuShortcut) obj; + return (ms.key == key && ms.usesShift == usesShift); + } + return false; +} + +/*************************************************************************/ + +/** + * Returns a string representation of this shortcut. + * + * @return A string representation of this shortcut. + */ +public String +toString() +{ + return(getClass().getName() + "[" + paramString () + "]"); +} + +public int +hashCode() +{ + // Arbitrary. + return key + (usesShift ? 23 : 57); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +protected String +paramString() +{ + return "key=" + key + ",usesShift=" + usesShift; +} + +} // class MenuShortcut diff --git a/libjava/classpath/java/awt/PageAttributes.java b/libjava/classpath/java/awt/PageAttributes.java new file mode 100644 index 0000000..38fb696 --- /dev/null +++ b/libjava/classpath/java/awt/PageAttributes.java @@ -0,0 +1,482 @@ +/* PageAttributes.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 java.awt; + +import java.util.Locale; + +/** + * Missing Documentation + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4, but missing documentation + */ +public final class PageAttributes implements Cloneable +{ + public static final class ColorType extends AttributeValue + { + private static final String[] NAMES = { "color", "monochrome" }; + public static final ColorType COLOR = new ColorType(0); + public static final ColorType MONOCHROME = new ColorType(1); + private ColorType(int value) + { + super(value, NAMES); + } + } // class ColorType + public static final class MediaType extends AttributeValue + { + private static final String[] NAMES + = { "iso-4a0", "iso-2a0", "iso-a0", "iso-a1", "iso-a2", "iso-a3", + "iso-a4", "iso-a5", "iso-a6", "iso-a7", "iso-a8", "iso-a9", + "iso-a10", "iso-b0", "iso-b1", "iso-b2", "iso-b3", "iso-b4", + "iso-b5", "iso-b6", "iso-b7", "iso-b8", "iso-b9", "iso-b10", + "jis-b0", "jis-b1", "jis-b2", "jis-b3", "jis-b4", "jis-b5", + "jis-b6", "jis-b7", "jis-b8", "jis-b9", "jis-b10", "iso-c0", + "iso-c1", "iso-c2", "iso-c3", "iso-c4", "iso-c5", "iso-c6", + "iso-c7", "iso-c8", "iso-c9", "iso-c10", "iso-designated-long", + "executive", "folio", "invoice", "ledger", "na-letter", "na-legal", + "quarto", "a", "b", "c", "d", "e", "na-10x15-envelope", + "na-10x14-envelope", "na-10x13-envelope", "na-9x12-envelope", + "na-9x11-envelope", "na-7x9-envelope", "na-6x9-envelope", + "na-number-9-envelope", "na-number-10-envelope", + "na-number-11-envelope", "na-number-12-envelope", + "na-number-14-envelope", "invite-envelope", "italy-envelope", + "monarch-envelope", "personal-envelope" }; + public static final MediaType ISO_4A0 = new MediaType(0); + public static final MediaType ISO_2A0 = new MediaType(1); + public static final MediaType ISO_A0 = new MediaType(2); + public static final MediaType ISO_A1 = new MediaType(3); + public static final MediaType ISO_A2 = new MediaType(4); + public static final MediaType ISO_A3 = new MediaType(5); + public static final MediaType ISO_A4 = new MediaType(6); + public static final MediaType ISO_A5 = new MediaType(7); + public static final MediaType ISO_A6 = new MediaType(8); + public static final MediaType ISO_A7 = new MediaType(9); + public static final MediaType ISO_A8 = new MediaType(10); + public static final MediaType ISO_A9 = new MediaType(11); + public static final MediaType ISO_A10 = new MediaType(12); + public static final MediaType ISO_B0 = new MediaType(13); + public static final MediaType ISO_B1 = new MediaType(14); + public static final MediaType ISO_B2 = new MediaType(15); + public static final MediaType ISO_B3 = new MediaType(16); + public static final MediaType ISO_B4 = new MediaType(17); + public static final MediaType ISO_B5 = new MediaType(18); + public static final MediaType ISO_B6 = new MediaType(19); + public static final MediaType ISO_B7 = new MediaType(20); + public static final MediaType ISO_B8 = new MediaType(21); + public static final MediaType ISO_B9 = new MediaType(22); + public static final MediaType ISO_B10 = new MediaType(23); + public static final MediaType JIS_B0 = new MediaType(24); + public static final MediaType JIS_B1 = new MediaType(25); + public static final MediaType JIS_B2 = new MediaType(26); + public static final MediaType JIS_B3 = new MediaType(27); + public static final MediaType JIS_B4 = new MediaType(28); + public static final MediaType JIS_B5 = new MediaType(29); + public static final MediaType JIS_B6 = new MediaType(30); + public static final MediaType JIS_B7 = new MediaType(31); + public static final MediaType JIS_B8 = new MediaType(32); + public static final MediaType JIS_B9 = new MediaType(33); + public static final MediaType JIS_B10 = new MediaType(34); + public static final MediaType ISO_C0 = new MediaType(35); + public static final MediaType ISO_C1 = new MediaType(36); + public static final MediaType ISO_C2 = new MediaType(37); + public static final MediaType ISO_C3 = new MediaType(38); + public static final MediaType ISO_C4 = new MediaType(39); + public static final MediaType ISO_C5 = new MediaType(40); + public static final MediaType ISO_C6 = new MediaType(41); + public static final MediaType ISO_C7 = new MediaType(42); + public static final MediaType ISO_C8 = new MediaType(43); + public static final MediaType ISO_C9 = new MediaType(44); + public static final MediaType ISO_C10 = new MediaType(45); + public static final MediaType ISO_DESIGNATED_LONG = new MediaType(46); + public static final MediaType EXECUTIVE = new MediaType(47); + public static final MediaType FOLIO = new MediaType(48); + public static final MediaType INVOICE = new MediaType(49); + public static final MediaType LEDGER = new MediaType(50); + public static final MediaType NA_LETTER = new MediaType(51); + public static final MediaType NA_LEGAL = new MediaType(52); + public static final MediaType QUARTO = new MediaType(53); + public static final MediaType A = new MediaType(54); + public static final MediaType B = new MediaType(55); + public static final MediaType C = new MediaType(56); + public static final MediaType D = new MediaType(57); + public static final MediaType E = new MediaType(58); + public static final MediaType NA_10X15_ENVELOPE = new MediaType(59); + public static final MediaType NA_10X14_ENVELOPE = new MediaType(60); + public static final MediaType NA_10X13_ENVELOPE = new MediaType(61); + public static final MediaType NA_9X12_ENVELOPE = new MediaType(62); + public static final MediaType NA_9X11_ENVELOPE = new MediaType(63); + public static final MediaType NA_7X9_ENVELOPE = new MediaType(64); + public static final MediaType NA_6X9_ENVELOPE = new MediaType(65); + public static final MediaType NA_NUMBER_9_ENVELOPE = new MediaType(66); + public static final MediaType NA_NUMBER_10_ENVELOPE = new MediaType(67); + public static final MediaType NA_NUMBER_11_ENVELOPE = new MediaType(68); + public static final MediaType NA_NUMBER_12_ENVELOPE = new MediaType(69); + public static final MediaType NA_NUMBER_14_ENVELOPE = new MediaType(70); + public static final MediaType INVITE_ENVELOPE = new MediaType(71); + public static final MediaType ITALY_ENVELOPE = new MediaType(72); + public static final MediaType MONARCH_ENVELOPE = new MediaType(73); + public static final MediaType PERSONAL_ENVELOPE = new MediaType(74); + public static final MediaType A0 = ISO_A0; + public static final MediaType A1 = ISO_A1; + public static final MediaType A2 = ISO_A2; + public static final MediaType A3 = ISO_A3; + public static final MediaType A4 = ISO_A4; + public static final MediaType A5 = ISO_A5; + public static final MediaType A6 = ISO_A6; + public static final MediaType A7 = ISO_A7; + public static final MediaType A8 = ISO_A8; + public static final MediaType A9 = ISO_A9; + public static final MediaType A10 = ISO_A10; + public static final MediaType B0 = ISO_B0; + public static final MediaType B1 = ISO_B1; + public static final MediaType B2 = ISO_B2; + public static final MediaType B3 = ISO_B3; + public static final MediaType B4 = ISO_B4; + public static final MediaType ISO_B4_ENVELOPE = ISO_B4; + public static final MediaType B5 = ISO_B5; + public static final MediaType ISO_B5_ENVELOPE = ISO_B4; + public static final MediaType B6 = ISO_B6; + public static final MediaType B7 = ISO_B7; + public static final MediaType B8 = ISO_B8; + public static final MediaType B9 = ISO_B9; + public static final MediaType B10 = ISO_B10; + public static final MediaType C0 = ISO_B0; + public static final MediaType ISO_C0_ENVELOPE = ISO_C0; + public static final MediaType C1 = ISO_C1; + public static final MediaType ISO_C1_ENVELOPE = ISO_C1; + public static final MediaType C2 = ISO_C2; + public static final MediaType ISO_C2_ENVELOPE = ISO_C2; + public static final MediaType C3 = ISO_C3; + public static final MediaType ISO_C3_ENVELOPE = ISO_C3; + public static final MediaType C4 = ISO_C4; + public static final MediaType ISO_C4_ENVELOPE = ISO_C4; + public static final MediaType C5 = ISO_C5; + public static final MediaType ISO_C5_ENVELOPE = ISO_C5; + public static final MediaType C6 = ISO_C6; + public static final MediaType ISO_C6_ENVELOPE = ISO_C6; + public static final MediaType C7 = ISO_C7; + public static final MediaType ISO_C7_ENVELOPE = ISO_C7; + public static final MediaType C8 = ISO_C8; + public static final MediaType ISO_C8_ENVELOPE = ISO_C8; + public static final MediaType C9 = ISO_C9; + public static final MediaType ISO_C9_ENVELOPE = ISO_C9; + public static final MediaType C10 = ISO_C10; + public static final MediaType ISO_C10_ENVELOPE = ISO_C10; + public static final MediaType ISO_DESIGNATED_LONG_ENVELOPE + = ISO_DESIGNATED_LONG; + public static final MediaType STATEMENT = INVOICE; + public static final MediaType TABLOID = LEDGER; + public static final MediaType LETTER = NA_LETTER; + public static final MediaType NOTE = NA_LETTER; + public static final MediaType LEGAL = NA_LEGAL; + public static final MediaType ENV_10X15 = NA_10X15_ENVELOPE; + public static final MediaType ENV_10X14 = NA_10X14_ENVELOPE; + public static final MediaType ENV_10X13 = NA_10X13_ENVELOPE; + public static final MediaType ENV_9X12 = NA_9X12_ENVELOPE; + public static final MediaType ENV_9X11 = NA_9X11_ENVELOPE; + public static final MediaType ENV_7X9 = NA_7X9_ENVELOPE; + public static final MediaType ENV_6X9 = NA_6X9_ENVELOPE; + public static final MediaType ENV_9 = NA_NUMBER_9_ENVELOPE; + public static final MediaType ENV_10 = NA_NUMBER_10_ENVELOPE; + public static final MediaType ENV_11 = NA_NUMBER_11_ENVELOPE; + public static final MediaType ENV_12 = NA_NUMBER_12_ENVELOPE; + public static final MediaType ENV_14 = NA_NUMBER_14_ENVELOPE; + public static final MediaType ENV_INVITE = INVITE_ENVELOPE; + public static final MediaType ENV_ITALY = ITALY_ENVELOPE; + public static final MediaType ENV_MONARCH = MONARCH_ENVELOPE; + public static final MediaType ENV_PERSONAL = PERSONAL_ENVELOPE; + public static final MediaType INVITE = INVITE_ENVELOPE; + public static final MediaType ITALY = ITALY_ENVELOPE; + public static final MediaType MONARCH = MONARCH_ENVELOPE; + public static final MediaType PERSONAL = PERSONAL_ENVELOPE; + private MediaType(int value) + { + super(value, NAMES); + } + } // class MediaType + public static final class OrientationRequestedType extends AttributeValue + { + private static final String[] NAMES = { "portrait", "landscape" }; + public static final OrientationRequestedType PORTRAIT + = new OrientationRequestedType(0); + public static final OrientationRequestedType LANDSCAPE + = new OrientationRequestedType(1); + private OrientationRequestedType(int value) + { + super(value, NAMES); + } + } // class OrientationRequestedType + public static final class OriginType extends AttributeValue + { + private static final String[] NAMES = { "physical", "printable" }; + public static final OriginType PHYSICAL = new OriginType(0); + public static final OriginType PRINTABLE = new OriginType(1); + private OriginType(int value) + { + super(value, NAMES); + } + } // class OriginType + public static final class PrintQualityType extends AttributeValue + { + private static final String[] NAMES = { "high", "normal", "draft" }; + public static final PrintQualityType HIGH = new PrintQualityType(0); + public static final PrintQualityType NORMAL = new PrintQualityType(1); + public static final PrintQualityType DRAFT = new PrintQualityType(2); + private PrintQualityType(int value) + { + super(value, NAMES); + } + } // class PrintQualityType + + + private ColorType color; + private MediaType media; + private OrientationRequestedType orientation; + private OriginType origin; + private PrintQualityType quality; + private int resolutionX; + private int resolutionY; + private int resolutionScale; + public PageAttributes() + { + color = ColorType.MONOCHROME; + setMediaToDefault(); + orientation = OrientationRequestedType.PORTRAIT; + origin = OriginType.PHYSICAL; + quality = PrintQualityType.NORMAL; + setPrinterResolutionToDefault(); + } + + public PageAttributes(PageAttributes attr) + { + set(attr); + } + + public PageAttributes(ColorType color, MediaType media, + OrientationRequestedType orientation, + OriginType origin, PrintQualityType quality, + int[] resolution) + { + if (color == null || media == null || orientation == null + || origin == null || quality == null) + throw new IllegalArgumentException(); + setPrinterResolution(resolution); + this.color = color; + this.media = media; + this.orientation = orientation; + this.origin = origin; + this.quality = quality; + } + + public Object clone() + { + return new PageAttributes(this); + } + + public void set(PageAttributes attr) + { + color = attr.color; + media = attr.media; + orientation = attr.orientation; + origin = attr.origin; + quality = attr.quality; + resolutionX = attr.resolutionX; + resolutionY = attr.resolutionY; + resolutionScale = attr.resolutionScale; + } + + public ColorType getColor() + { + return color; + } + + public void setColor(ColorType color) + { + if (color == null) + throw new IllegalArgumentException(); + this.color = color; + } + + public MediaType getMedia() + { + return media; + } + + public void setMedia(MediaType media) + { + if (media == null) + throw new IllegalArgumentException(); + this.media = media; + } + + public void setMediaToDefault() + { + String country = Locale.getDefault().getCountry(); + media = ("US".equals(country) || "CA".equals(country)) ? MediaType.LETTER + : MediaType.A4; + } + + public OrientationRequestedType getOrientationRequested() + { + return orientation; + } + + public void setOrientationRequested(OrientationRequestedType orientation) + { + if (orientation == null) + throw new IllegalArgumentException(); + this.orientation = orientation; + } + + public void setOrientationRequested(int orientation) + { + if (orientation == 3) + this.orientation = OrientationRequestedType.PORTRAIT; + else if (orientation == 4) + this.orientation = OrientationRequestedType.LANDSCAPE; + else + throw new IllegalArgumentException(); + } + + public void setOrientationRequestedToDefault() + { + orientation = OrientationRequestedType.PORTRAIT; + } + + public OriginType getOrigin() + { + return origin; + } + + public void setOrigin(OriginType origin) + { + if (origin == null) + throw new IllegalArgumentException(); + this.origin = origin; + } + + public PrintQualityType getPrintQuality() + { + return quality; + } + + public void setPrintQuality(PrintQualityType quality) + { + if (quality == null) + throw new IllegalArgumentException(); + this.quality = quality; + } + + public void setPrintQuality(int quality) + { + if (quality == 3) + this.quality = PrintQualityType.DRAFT; + else if (quality == 4) + this.quality = PrintQualityType.NORMAL; + else if (quality == 5) + this.quality = PrintQualityType.HIGH; + else + throw new IllegalArgumentException(); + } + + public void setPrintQualityToDefault() + { + quality = PrintQualityType.NORMAL; + } + + public int[] getPrinterResolution() + { + return new int[] { resolutionX, resolutionY, resolutionScale }; + } + + public void setPrinterResolution(int[] resolution) + { + if (resolution == null || resolution.length != 3 || resolution[0] <= 0 + || resolution[1] <= 0 || resolution[2] < 3 || resolution[2] > 4) + throw new IllegalArgumentException(); + resolutionX = resolution[0]; + resolutionY = resolution[1]; + resolutionScale = resolution[2]; + } + + public void setPrinterResolution(int resolution) + { + if (resolution <= 0) + throw new IllegalArgumentException(); + resolutionX = resolution; + resolutionY = resolution; + resolutionScale = 3; + } + + public void setPrinterResolutionToDefault() + { + resolutionX = 72; + resolutionY = 72; + resolutionScale = 3; + } + + public boolean equals(Object o) + { + if (this == o) + return true; + if (! (o instanceof PageAttributes)) + return false; + PageAttributes pa = (PageAttributes) o; + return color == pa.color && media == pa.media + && orientation == pa.orientation && origin == pa.origin + && quality == pa.quality && resolutionX == pa.resolutionX + && resolutionY == pa.resolutionY + && resolutionScale == pa.resolutionScale; + } + public int hashCode() + { + return (color.value << 31) ^ (media.value << 24) + ^ (orientation.value << 23) ^ (origin.value << 22) + ^ (quality.value << 20) ^ (resolutionScale << 19) + ^ (resolutionY << 10) ^ resolutionX; + } + public String toString() + { + return "color=" + color + ",media=" + media + ",orientation-requested=" + + orientation + ",origin=" + origin + ",print-quality=" + quality + + ",printer-resolution=[" + resolutionX + ',' + resolutionY + ',' + + resolutionScale + ']'; + } +} // class PageAttributes diff --git a/libjava/classpath/java/awt/Paint.java b/libjava/classpath/java/awt/Paint.java new file mode 100644 index 0000000..0f099cc --- /dev/null +++ b/libjava/classpath/java/awt/Paint.java @@ -0,0 +1,79 @@ +/* Paint.java -- generate colors for Graphics2D operations + 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 java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; + +/** + * Defines how color patterns are generated for Graphics2D operations. This + * is used to perform the draw and fill methods + * of the graphics object. Instances must be immutable, because the graphics + * object does not clone them. + * + * @author Warren Levy (warrenl@cygnus.com) + * @see PaintContext + * @see Color + * @see GradientPaint + * @see TexturePaint + * @see Graphics2D#setPaint(Paint) + * @since 1.1 + * @status updated to 1.4 + */ +public interface Paint extends Transparency +{ + /** + * Create the context necessary for performing the color pattern generation. + * The color model is a hint, and may be null for Classpath implementations; + * however some legacy code may throw a NullPointerException when passed a + * null. Leaving the color model null provides the most efficiency and leeway + * in the generation of the color pattern. + * + * @param cm the color model, used as a hint + * @param deviceBounds the device space bounding box of the painted area + * @param userBounds the user space bounding box of the painted area + * @param xform the transformation from user space to device space + * @param hints any hints for choosing between rendering alternatives + * @return the context for performing the paint + */ + PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, AffineTransform xform, + RenderingHints hints); +} // interface Paint diff --git a/libjava/classpath/java/awt/PaintContext.java b/libjava/classpath/java/awt/PaintContext.java new file mode 100644 index 0000000..3d5fdcd --- /dev/null +++ b/libjava/classpath/java/awt/PaintContext.java @@ -0,0 +1,76 @@ +/* PaintContext.java -- the environment for performing a paint operation + 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 java.awt; + +import java.awt.image.ColorModel; +import java.awt.image.Raster; + +/** + * @author Warren Levy (warrenl@cygnus.com) + * @see Paint + * @since 1.1 + * @status updated to 1.4 + */ +public interface PaintContext +{ + /** + * Release the resources allocated for the paint. + */ + void dispose(); + + /** + * Return the color model of this context. It may be different from the + * hint specified during createContext, as not all contexts can generate + * color patterns in an arbitrary model. + * + * @return the context color model + */ + ColorModel getColorModel(); + + /** + * Return a raster containing the colors for the graphics operation. + * + * @param x the x-coordinate, in device space + * @param y the y-coordinate, in device space + * @param w the width, in device space + * @param h the height, in device space + * @return a raster for the given area and color + */ + Raster getRaster(int x, int y, int w, int h); +} // interface PaintContext diff --git a/libjava/classpath/java/awt/Panel.java b/libjava/classpath/java/awt/Panel.java new file mode 100644 index 0000000..cc17eef --- /dev/null +++ b/libjava/classpath/java/awt/Panel.java @@ -0,0 +1,173 @@ +/* Panel.java -- Simple container object + Copyright (C) 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 java.awt; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * A panel is a simple container class. It's default layout is the + * FlowLayout manager. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see FlowLayout + * @since 1.0 + * @status updated to 1.4 + */ +public class Panel extends Container implements Accessible +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -2728009084054400034L; + + /** The cached accessible context. */ + private transient AccessibleContext context; + + /** Flag set when the first system-requested paint event is + dispatched. */ + private transient boolean initialSystemUpdateDone; + + /** Flag set when the first application-requested paint event is + consumed. */ + private transient boolean initialUpdateConsumed; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_panel_number; + + /** + * Initializes a new instance of Panel that has a default + * layout manager of FlowLayout. + */ + public Panel() + { + this(new FlowLayout()); + } + + /** + * Initializes a new instance of Panel with the specified + * layout manager. + * + * @param layoutManager the layout manager for this object + * @since 1.1 + */ + public Panel(LayoutManager layoutManager) + { + setLayout(layoutManager); + } + + /** + * Notifies this object to create its native peer. + * + * @see #isDisplayable() + * @see #removeNotify() + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit().createPanel(this); + super.addNotify(); + } + + /** + * Gets the AccessibleContext associated with this panel, creating one if + * necessary. This always returns an instance of {@link AccessibleAWTPanel}. + * + * @return the accessibility context of this panel + * @since 1.3 + */ + public AccessibleContext getAccessibleContext() + { + if (context == null) + context = new AccessibleAWTPanel(); + return context; + } + + /** + * This class provides accessibility support for Panels, and is the + * runtime type returned by {@link #getAccessibleContext()}. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + */ + protected class AccessibleAWTPanel extends AccessibleAWTContainer + { + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = -6409552226660031050L; + + /** + * The default constructor. + */ + protected AccessibleAWTPanel() + { + } + + /** + * Get the role of this accessible object, a panel. + * + * @return the role of the object + * @see AccessibleRole#PANEL + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PANEL; + } + } + + /** + * Generate a unique name for this panel. + * + * @return A unique name for this panel. + */ + String generateName () + { + return "panel" + getUniqueLong (); + } + + private static synchronized long getUniqueLong () + { + return next_panel_number++; + } +} diff --git a/libjava/classpath/java/awt/Point.java b/libjava/classpath/java/awt/Point.java new file mode 100644 index 0000000..492749b --- /dev/null +++ b/libjava/classpath/java/awt/Point.java @@ -0,0 +1,245 @@ +/* Point.java -- represents a point in 2-D space + Copyright (C) 1999, 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 java.awt; + +import java.awt.geom.Point2D; +import java.io.Serializable; + +/** + * This class represents a point on the screen using cartesian coordinates. + * Remember that in screen coordinates, increasing x values go from left to + * right, and increasing y values go from top to bottom. + * + *

There are some public fields; if you mess with them in an inconsistent + * manner, it is your own fault when you get invalid results. Also, this + * class is not threadsafe. + * + * @author Per Bothner (bothner@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Point extends Point2D implements Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -5276940640259749850L; + + /** + * The x coordinate. + * + * @see #getLocation() + * @see #move(int, int) + * @serial the X coordinate of the point + */ + public int x; + + /** + * The y coordinate. + * + * @see #getLocation() + * @see #move(int, int) + * @serial The Y coordinate of the point + */ + public int y; + + /** + * Initializes a new instance of Point representing the + * coordiates (0,0). + * + * @since 1.1 + */ + public Point() + { + } + + /** + * Initializes a new instance of Point with coordinates + * identical to the coordinates of the specified points. + * + * @param p the point to copy the coordinates from + * @throws NullPointerException if p is null + */ + public Point(Point p) + { + x = p.x; + y = p.y; + } + + /** + * Initializes a new instance of Point with the specified + * coordinates. + * + * @param x the X coordinate + * @param y the Y coordinate + */ + public Point(int x, int y) + { + this.x = x; + this.y = y; + } + + /** + * Get the x coordinate. + * + * @return the value of x, as a double + */ + public double getX() + { + return x; + } + + /** + * Get the y coordinate. + * + * @return the value of y, as a double + */ + public double getY() + { + return y; + } + + /** + * Returns the location of this point. A pretty useless method, as this + * is already a point. + * + * @return a copy of this point + * @see #setLocation(Point) + * @since 1.1 + */ + public Point getLocation() + { + return new Point(x, y); + } + + /** + * Sets this object's coordinates to match those of the specified point. + * + * @param p the point to copy the coordinates from + * @throws NullPointerException if p is null + * @since 1.1 + */ + public void setLocation(Point p) + { + x = p.x; + y = p.y; + } + + /** + * Sets this object's coordinates to the specified values. This method + * is identical to the move() method. + * + * @param x the new X coordinate + * @param y the new Y coordinate + */ + public void setLocation(int x, int y) + { + this.x = x; + this.y = y; + } + + /** + * Sets this object's coordinates to the specified values. This method + * performs normal casting from double to int, so you may lose precision. + * + * @param x the new X coordinate + * @param y the new Y coordinate + */ + public void setLocation(double x, double y) + { + this.x = (int) x; + this.y = (int) y; + } + + /** + * Sets this object's coordinates to the specified values. This method + * is identical to the setLocation(int, int) method. + * + * @param x the new X coordinate + * @param y the new Y coordinate + */ + public void move(int x, int y) + { + this.x = x; + this.y = y; + } + + /** + * Changes the coordinates of this point such that the specified + * dx parameter is added to the existing X coordinate and + * dy is added to the existing Y coordinate. + * + * @param dx the amount to add to the X coordinate + * @param dy the amount to add to the Y coordinate + */ + public void translate(int dx, int dy) + { + x += dx; + y += dy; + } + + /** + * Tests whether or not this object is equal to the specified object. + * This will be true if and only if the specified object is an instance + * of Point2D and has the same X and Y coordinates. + * + * @param obj the object to test against for equality + * @return true if the specified object is equal + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Point2D)) + return false; + Point2D p = (Point2D) obj; + return x == p.getX() && y == p.getY(); + } + + /** + * Returns a string representation of this object. The format is: + * getClass().getName() + "[x=" + x + ",y=" + y + ']'. + * + * @return a string representation of this object + */ + public String toString() + { + return getClass().getName() + "[x=" + x + ",y=" + y + ']'; + } +} // class Point diff --git a/libjava/classpath/java/awt/Polygon.java b/libjava/classpath/java/awt/Polygon.java new file mode 100644 index 0000000..a72522c --- /dev/null +++ b/libjava/classpath/java/awt/Polygon.java @@ -0,0 +1,613 @@ +/* Polygon.java -- class representing a polygon + Copyright (C) 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 java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Line2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.Serializable; + +/** + * This class represents a polygon, a closed, two-dimensional region in a + * coordinate space. The region is bounded by an arbitrary number of line + * segments, between (x,y) coordinate vertices. The polygon has even-odd + * winding, meaning that a point is inside the shape if it crosses the + * boundary an odd number of times on the way to infinity. + * + *

There are some public fields; if you mess with them in an inconsistent + * manner, it is your own fault when you get NullPointerException, + * ArrayIndexOutOfBoundsException, or invalid results. Also, this class is + * not threadsafe. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Polygon implements Shape, Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -6460061437900069969L; + + /** + * This total number of endpoints. + * + * @serial the number of endpoints, possibly less than the array sizes + */ + public int npoints; + + /** + * The array of X coordinates of endpoints. This should not be null. + * + * @see #addPoint(int, int) + * @serial the x coordinates + */ + public int[] xpoints; + + /** + * The array of Y coordinates of endpoints. This should not be null. + * + * @see #addPoint(int, int) + * @serial the y coordinates + */ + public int[] ypoints; + + /** + * The bounding box of this polygon. This is lazily created and cached, so + * it must be invalidated after changing points. + * + * @see #getBounds() + * @serial the bounding box, or null + */ + protected Rectangle bounds; + + /** A big number, but not so big it can't survive a few float operations */ + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; + + /** + * Initializes an empty polygon. + */ + public Polygon() + { + // Leave room for growth. + xpoints = new int[4]; + ypoints = new int[4]; + } + + /** + * Create a new polygon with the specified endpoints. The arrays are copied, + * so that future modifications to the parameters do not affect the polygon. + * + * @param xpoints the array of X coordinates for this polygon + * @param ypoints the array of Y coordinates for this polygon + * @param npoints the total number of endpoints in this polygon + * @throws NegativeArraySizeException if npoints is negative + * @throws IndexOutOfBoundsException if npoints exceeds either array + * @throws NullPointerException if xpoints or ypoints is null + */ + public Polygon(int[] xpoints, int[] ypoints, int npoints) + { + this.xpoints = new int[npoints]; + this.ypoints = new int[npoints]; + System.arraycopy(xpoints, 0, this.xpoints, 0, npoints); + System.arraycopy(ypoints, 0, this.ypoints, 0, npoints); + this.npoints = npoints; + } + + /** + * Reset the polygon to be empty. The arrays are left alone, to avoid object + * allocation, but the number of points is set to 0, and all cached data + * is discarded. If you are discarding a huge number of points, it may be + * more efficient to just create a new Polygon. + * + * @see #invalidate() + * @since 1.4 + */ + public void reset() + { + npoints = 0; + invalidate(); + } + + /** + * Invalidate or flush all cached data. After direct manipulation of the + * public member fields, this is necessary to avoid inconsistent results + * in methods like contains. + * + * @see #getBounds() + * @since 1.4 + */ + public void invalidate() + { + bounds = null; + } + + /** + * Translates the polygon by adding the specified values to all X and Y + * coordinates. This updates the bounding box, if it has been calculated. + * + * @param dx the amount to add to all X coordinates + * @param dy the amount to add to all Y coordinates + * @since 1.1 + */ + public void translate(int dx, int dy) + { + int i = npoints; + while (--i >= 0) + { + xpoints[i] += dx; + ypoints[i] += dy; + } + if (bounds != null) + { + bounds.x += dx; + bounds.y += dy; + } + } + + /** + * Adds the specified endpoint to the polygon. This updates the bounding + * box, if it has been created. + * + * @param x the X coordinate of the point to add + * @param y the Y coordiante of the point to add + */ + public void addPoint(int x, int y) + { + if (npoints + 1 > xpoints.length) + { + int[] newx = new int[npoints + 1]; + System.arraycopy(xpoints, 0, newx, 0, npoints); + xpoints = newx; + } + if (npoints + 1 > ypoints.length) + { + int[] newy = new int[npoints + 1]; + System.arraycopy(ypoints, 0, newy, 0, npoints); + ypoints = newy; + } + xpoints[npoints] = x; + ypoints[npoints] = y; + npoints++; + if (bounds != null) + { + if (npoints == 1) + { + bounds.x = x; + bounds.y = y; + } + else + { + if (x < bounds.x) + { + bounds.width += bounds.x - x; + bounds.x = x; + } + else if (x > bounds.x + bounds.width) + bounds.width = x - bounds.x; + if (y < bounds.y) + { + bounds.height += bounds.y - y; + bounds.y = y; + } + else if (y > bounds.y + bounds.height) + bounds.height = y - bounds.y; + } + } + } + + /** + * Returns the bounding box of this polygon. This is the smallest + * rectangle with sides parallel to the X axis that will contain this + * polygon. + * + * @return the bounding box for this polygon + * @see #getBounds2D() + * @since 1.1 + */ + public Rectangle getBounds() + { + return getBoundingBox(); + } + + /** + * Returns the bounding box of this polygon. This is the smallest + * rectangle with sides parallel to the X axis that will contain this + * polygon. + * + * @return the bounding box for this polygon + * @see #getBounds2D() + * @deprecated use {@link #getBounds()} instead + */ + public Rectangle getBoundingBox() + { + if (bounds == null) + { + if (npoints == 0) + return bounds = new Rectangle(); + int i = npoints - 1; + int minx = xpoints[i]; + int maxx = minx; + int miny = ypoints[i]; + int maxy = miny; + while (--i >= 0) + { + int x = xpoints[i]; + int y = ypoints[i]; + if (x < minx) + minx = x; + else if (x > maxx) + maxx = x; + if (y < miny) + miny = y; + else if (y > maxy) + maxy = y; + } + bounds = new Rectangle(minx, miny, maxx - minx, maxy - miny); + } + return bounds; + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param p the point to test + * @return true if the point is inside this polygon + * @throws NullPointerException if p is null + * @see #contains(double, double) + */ + public boolean contains(Point p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside this polygon + * @see #contains(double, double) + * @since 1.1 + */ + public boolean contains(int x, int y) + { + return contains((double) x, (double) y); + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside this polygon + * @see #contains(double, double) + * @deprecated use {@link #contains(int, int)} instead + */ + public boolean inside(int x, int y) + { + return contains((double) x, (double) y); + } + + /** + * Returns a high-precision bounding box of this polygon. This is the + * smallest rectangle with sides parallel to the X axis that will contain + * this polygon. + * + * @return the bounding box for this polygon + * @see #getBounds() + * @since 1.2 + */ + public Rectangle2D getBounds2D() + { + // For polygons, the integer version is exact! + return getBounds(); + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside this polygon + * @since 1.2 + */ + public boolean contains(double x, double y) + { + return ((evaluateCrossings(x, y, false, BIG_VALUE) & 1) != 0); + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param p the point to test + * @return true if the point is inside this polygon + * @throws NullPointerException if p is null + * @see #contains(double, double) + * @since 1.2 + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Test if a high-precision rectangle intersects the shape. This is true + * if any point in the rectangle is in the shape. This implementation is + * precise. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle, treated as point if negative + * @param h the height of the rectangle, treated as point if negative + * @return true if the rectangle intersects this shape + * @since 1.2 + */ + public boolean intersects(double x, double y, double w, double h) + { + /* Does any edge intersect? */ + if (evaluateCrossings(x, y, false, w) != 0 /* top */ + || evaluateCrossings(x, y + h, false, w) != 0 /* bottom */ + || evaluateCrossings(x + w, y, true, h) != 0 /* right */ + || evaluateCrossings(x, y, true, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if ((evaluateCrossings(x, y, false, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Test if a high-precision rectangle intersects the shape. This is true + * if any point in the rectangle is in the shape. This implementation is + * precise. + * + * @param r the rectangle + * @return true if the rectangle intersects this shape + * @throws NullPointerException if r is null + * @see #intersects(double, double, double, double) + * @since 1.2 + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Test if a high-precision rectangle lies completely in the shape. This is + * true if all points in the rectangle are in the shape. This implementation + * is precise. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle, treated as point if negative + * @param h the height of the rectangle, treated as point if negative + * @return true if the rectangle is contained in this shape + * @since 1.2 + */ + public boolean contains(double x, double y, double w, double h) + { + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (evaluateCrossings(x, y, false, w) != 0 /* top */ + || evaluateCrossings(x, y + h, false, w) != 0 /* bottom */ + || evaluateCrossings(x + w, y, true, h) != 0 /* right */ + || evaluateCrossings(x, y, true, h) != 0) /* left */ + return false; + + /* No intersections, is any point inside? */ + if ((evaluateCrossings(x, y, false, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Test if a high-precision rectangle lies completely in the shape. This is + * true if all points in the rectangle are in the shape. This implementation + * is precise. + * + * @param r the rectangle + * @return true if the rectangle is contained in this shape + * @throws NullPointerException if r is null + * @see #contains(double, double, double, double) + * @since 1.2 + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. Each call returns + * a new object, independent from others in use. This class is not + * threadsafe to begin with, so the path iterator is not either. + * + * @param transform an optional transform to apply to the iterator + * @return a new iterator over the boundary + * @since 1.2 + */ + public PathIterator getPathIterator(final AffineTransform transform) + { + return new PathIterator() + { + /** The current vertex of iteration. */ + private int vertex; + + public int getWindingRule() + { + return WIND_EVEN_ODD; + } + + public boolean isDone() + { + return vertex > npoints; + } + + public void next() + { + vertex++; + } + + public int currentSegment(float[] coords) + { + if (vertex >= npoints) + return SEG_CLOSE; + coords[0] = xpoints[vertex]; + coords[1] = ypoints[vertex]; + if (transform != null) + transform.transform(coords, 0, coords, 0, 1); + return vertex == 0 ? SEG_MOVETO : SEG_LINETO; + } + + public int currentSegment(double[] coords) + { + if (vertex >= npoints) + return SEG_CLOSE; + coords[0] = xpoints[vertex]; + coords[1] = ypoints[vertex]; + if (transform != null) + transform.transform(coords, 0, coords, 0, 1); + return vertex == 0 ? SEG_MOVETO : SEG_LINETO; + } + }; + } + + /** + * Return an iterator along the flattened version of the shape boundary. + * Since polygons are already flat, the flatness parameter is ignored, and + * the resulting iterator only has SEG_MOVETO, SEG_LINETO and SEG_CLOSE + * points. If the optional transform is provided, the iterator is + * transformed accordingly. Each call returns a new object, independent + * from others in use. This class is not threadsafe to begin with, so the + * path iterator is not either. + * + * @param transform an optional transform to apply to the iterator + * @param flatness the maximum distance for deviation from the real boundary + * @return a new iterator over the boundary + * @since 1.2 + */ + public PathIterator getPathIterator(AffineTransform transform, + double flatness) + { + return getPathIterator(transform); + } + + /** + * Helper for contains, intersects, calculates the number of intersections + * between the polygon and a line extending from the point (x, y) along + * the positive X, or Y axis, within a given interval. + * + * @return the winding number. + * @see #condensed + * @see #contains(double, double) + */ + private int evaluateCrossings(double x, double y, boolean useYaxis, + double distance) + { + double x0; + double x1; + double y0; + double y1; + double epsilon = 0.0; + int crossings = 0; + int[] xp; + int[] yp; + + if (useYaxis) + { + xp = ypoints; + yp = xpoints; + double swap; + swap = y; + y = x; + x = swap; + } + else + { + xp = xpoints; + yp = ypoints; + } + + /* Get a value which is small but not insignificant relative the path. */ + epsilon = 1E-7; + + x0 = xp[0] - x; + y0 = yp[0] - y; + for (int i = 1; i < npoints; i++) + { + x1 = xp[i] - x; + y1 = yp[i] - y; + + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (y0 * y1 < 0) + if (Line2D.linesIntersect(x0, y0, x1, y1, epsilon, 0.0, distance, 0.0)) + ++crossings; + + x0 = xp[i] - x; + y0 = yp[i] - y; + } + + // end segment + x1 = xp[0] - x; + y1 = yp[0] - y; + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (y0 * y1 < 0) + if (Line2D.linesIntersect(x0, y0, x1, y1, epsilon, 0.0, distance, 0.0)) + ++crossings; + + return crossings; + } +} // class Polygon + diff --git a/libjava/classpath/java/awt/PopupMenu.java b/libjava/classpath/java/awt/PopupMenu.java new file mode 100644 index 0000000..90d48d9 --- /dev/null +++ b/libjava/classpath/java/awt/PopupMenu.java @@ -0,0 +1,169 @@ +/* PopupMenu.java -- An AWT popup menu + Copyright (C) 1999, 2000, 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 java.awt; + +import java.awt.peer.PopupMenuPeer; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class implement an AWT popup menu widget + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PopupMenu extends Menu +{ + +/* + * Static Variables + */ + +// Serialization Constant +private static final long serialVersionUID = -4620452533522760060L; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of PopupMenu. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +PopupMenu() +{ +} + +/*************************************************************************/ + +/** + * Initializes a new instance of PopupMenu with the specified + * label. + * + * @param label The label for this popup menu. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +PopupMenu(String label) +{ + super(label); + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Creates this object's native peer. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createPopupMenu (this); + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Displays this popup menu at the specified coordinates relative to + * the specified component. + * + * @param component The component to which the display coordinates are relative. + * @param x The X coordinate of the menu. + * @param y The Y coordinate of the menu. + */ +public void +show(Component component, int x, int y) +{ + if (getPeer() == null) + this.addNotify(); + PopupMenuPeer pmp = (PopupMenuPeer)getPeer(); + if (pmp != null) + { + /* XXX + Event e = new Event (component, Event.ACTION_EVENT, component); + e.x = x; + e.y = y;*/ + pmp.show (component, x, y); + } +} + + protected class AccessibleAWTPopupMenu extends AccessibleAWTMenu + { + protected AccessibleAWTPopupMenu() + { + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.POPUP_MENU; + } + + } + + /** + * Gets the AccessibleContext associated with this PopupMenu. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTPopupMenu(); + return accessibleContext; + } + +} // class PopupMenu + diff --git a/libjava/classpath/java/awt/PrintGraphics.java b/libjava/classpath/java/awt/PrintGraphics.java new file mode 100644 index 0000000..e7f8577 --- /dev/null +++ b/libjava/classpath/java/awt/PrintGraphics.java @@ -0,0 +1,57 @@ +/* PrintGraphics.java -- a print graphics context + Copyright (C) 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 java.awt; + +/** + * This interface allows the originating print job to be obtained. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface PrintGraphics +{ + /** + * Returns the PrintJob that this object is being + * managed by. + * + * @return the print job for this object + */ + PrintJob getPrintJob(); +} // interface PrintGraphics diff --git a/libjava/classpath/java/awt/PrintJob.java b/libjava/classpath/java/awt/PrintJob.java new file mode 100644 index 0000000..62aa8b1 --- /dev/null +++ b/libjava/classpath/java/awt/PrintJob.java @@ -0,0 +1,104 @@ +/* PrintJob.java -- A print job class + Copyright (C) 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 java.awt; + +import java.util.Properties; + +/** + * This abstract class represents a print job. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Toolkit#getPrintJob(Frame, String, Properties) + * @since 1.0 + * @status updated to 1.4 + */ +public abstract class PrintJob +{ + /** + * Create a new PrintJob. + */ + public PrintJob() + { + } + + /** + * Returns a graphics context suitable for rendering the next page. The + * return must also implement {@link PrintGraphics}. + * + * @return a graphics context for printing the next page + */ + public abstract Graphics getGraphics(); + + /** + * Returns the dimension of the page in pixels. The resolution will be + * chosen to be similar to the on screen image. + * + * @return the page dimensions + */ + public abstract Dimension getPageDimension(); + + /** + * Returns the resolution of the page in pixels per inch. Note that this is + * not necessarily the printer's resolution. + * + * @return the resolution of the page in pixels per inch + */ + public abstract int getPageResolution(); + + /** + * Tests whether or not the last page will be printed first. + * + * @return true if the last page prints first + */ + public abstract boolean lastPageFirst(); + + /** + * Informs the print job that printing is complete or should be aborted. + */ + public abstract void end(); + + /** + * This method explicitly ends the print job in the event the job + * becomes un-referenced without the application having done so. + */ + public void finalize() + { + end(); + } +} // class PrintJob diff --git a/libjava/classpath/java/awt/Rectangle.java b/libjava/classpath/java/awt/Rectangle.java new file mode 100644 index 0000000..0f21d49 --- /dev/null +++ b/libjava/classpath/java/awt/Rectangle.java @@ -0,0 +1,749 @@ +/* Rectangle.java -- represents a graphics rectangle + Copyright (C) 1999, 2000, 2001, 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 java.awt; + +import java.awt.geom.Rectangle2D; +import java.io.Serializable; + +/** + * This class represents a rectangle and all the interesting things you + * might want to do with it. Note that the coordinate system uses + * the origin (0,0) as the top left of the screen, with the x and y + * values increasing as they move to the right and down respectively. + * + *

It is valid for a rectangle to have negative width or height; but it + * is considered to have no area or internal points. Therefore, the behavior + * in methods like contains or intersects is + * undefined unless the rectangle has positive width and height. + * + *

There are some public fields; if you mess with them in an inconsistent + * manner, it is your own fault when you get NullPointerException, + * ArrayIndexOutOfBoundsException, or invalid results. Also, this class is + * not threadsafe. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Rectangle extends Rectangle2D implements Shape, Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4345857070255674764L; + + /** + * The X coordinate of the top-left corner of the rectangle. + * + * @see #setLocation(int, int) + * @see #getLocation() + * @serial the x coordinate + */ + public int x; + + /** + * The Y coordinate of the top-left corner of the rectangle. + * + * @see #setLocation(int, int) + * @see #getLocation() + * @serial the y coordinate + */ + public int y; + + /** + * The width of the rectangle. + * + * @see #setSize(int, int) + * @see #getSize() + * @serial + */ + public int width; + + /** + * The height of the rectangle. + * + * @see #setSize(int, int) + * @see #getSize() + * @serial + */ + public int height; + + /** + * Initializes a new instance of Rectangle with a top + * left corner at (0,0) and a width and height of 0. + */ + public Rectangle() + { + } + + /** + * Initializes a new instance of Rectangle from the + * coordinates of the specified rectangle. + * + * @param r the rectangle to copy from + * @throws NullPointerException if r is null + * @since 1.1 + */ + public Rectangle(Rectangle r) + { + x = r.x; + y = r.y; + width = r.width; + height = r.height; + } + + /** + * Initializes a new instance of Rectangle from the specified + * inputs. + * + * @param x the X coordinate of the top left corner + * @param y the Y coordinate of the top left corner + * @param width the width of the rectangle + * @param height the height of the rectangle + */ + public Rectangle(int x, int y, int width, int height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + /** + * Initializes a new instance of Rectangle with the specified + * width and height. The upper left corner of the rectangle will be at + * the origin (0,0). + * + * @param width the width of the rectangle + * @param height the height of the rectange + */ + public Rectangle(int width, int height) + { + this.width = width; + this.height = height; + } + + /** + * Initializes a new instance of Rectangle with a top-left + * corner represented by the specified point and the width and height + * represented by the specified dimension. + * + * @param p the upper left corner of the rectangle + * @param d the width and height of the rectangle + * @throws NullPointerException if p or d is null + */ + public Rectangle(Point p, Dimension d) + { + x = p.x; + y = p.y; + width = d.width; + height = d.height; + } + + /** + * Initializes a new instance of Rectangle with a top left + * corner at the specified point and a width and height of zero. + * + * @param p the upper left corner of the rectangle + */ + public Rectangle(Point p) + { + x = p.x; + y = p.y; + } + + /** + * Initializes a new instance of Rectangle with an + * upper left corner at the origin (0,0) and a width and height represented + * by the specified dimension. + * + * @param d the width and height of the rectangle + */ + public Rectangle(Dimension d) + { + width = d.width; + height = d.height; + } + + /** + * Get the X coordinate of the upper-left corner. + * + * @return the value of x, as a double + */ + public double getX() + { + return x; + } + + /** + * Get the Y coordinate of the upper-left corner. + * + * @return the value of y, as a double + */ + public double getY() + { + return y; + } + + /** + * Get the width of the rectangle. + * + * @return the value of width, as a double + */ + public double getWidth() + { + return width; + } + + /** + * Get the height of the rectangle. + * + * @return the value of height, as a double + */ + public double getHeight() + { + return height; + } + + /** + * Returns the bounds of this rectangle. A pretty useless method, as this + * is already a rectangle; it is included to mimic the + * getBounds method in Component. + * + * @return a copy of this rectangle + * @see #setBounds(Rectangle) + * @since 1.1 + */ + public Rectangle getBounds() + { + return new Rectangle(this); + } + + /** + * Returns the high-precision bounds of this rectangle. A pretty useless + * method, as this is already a rectangle. + * + * @return a copy of this rectangle + * @see #setBounds(Rectangle) + * @since 1.2 + */ + public Rectangle2D getBounds2D() + { + return new Rectangle(x, y, width, height); + } + + /** + * Updates this rectangle to match the dimensions of the specified + * rectangle. + * + * @param r the rectangle to update from + * @throws NullPointerException if r is null + * @see #setBounds(int, int, int, int) + * @since 1.1 + */ + public void setBounds(Rectangle r) + { + setBounds (r.x, r.y, r.width, r.height); + } + + /** + * Updates this rectangle to have the specified dimensions. + * + * @param x the new X coordinate of the upper left hand corner + * @param y the new Y coordinate of the upper left hand corner + * @param width the new width of this rectangle + * @param height the new height of this rectangle + * @since 1.1 + */ + public void setBounds(int x, int y, int width, int height) + { + reshape (x, y, width, height); + } + + /** + * Updates this rectangle to have the specified dimensions, as rounded to + * integers. + * + * @param x the new X coordinate of the upper left hand corner + * @param y the new Y coordinate of the upper left hand corner + * @param width the new width of this rectangle + * @param height the new height of this rectangle + * @since 1.2 + */ + public void setRect(double x, double y, double width, double height) + { + this.x = (int) x; + this.y = (int) y; + this.width = (int) width; + this.height = (int) height; + } + + /** + * Updates this rectangle to have the specified dimensions. + * + * @param x the new X coordinate of the upper left hand corner + * @param y the new Y coordinate of the upper left hand corner + * @param width the new width of this rectangle + * @param height the new height of this rectangle + * @deprecated use {@link #setBounds(int, int, int, int)} instead + */ + public void reshape(int x, int y, int width, int height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + /** + * Returns the location of this rectangle, which is the coordinates of + * its upper left corner. + * + * @return the point where this rectangle is located + * @see #setLocation(Point) + * @since 1.1 + */ + public Point getLocation() + { + return new Point(x,y); + } + + /** + * Moves the location of this rectangle by setting its upper left + * corner to the specified point. + * + * @param p the point to move the rectangle to + * @throws NullPointerException if p is null + * @see #getLocation() + * @since 1.1 + */ + public void setLocation(Point p) + { + setLocation (p.x, p.y); + } + + /** + * Moves the location of this rectangle by setting its upper left + * corner to the specified coordinates. + * + * @param x the new X coordinate for this rectangle + * @param y the new Y coordinate for this rectangle + * @since 1.1 + */ + public void setLocation(int x, int y) + { + move (x, y); + } + + /** + * Moves the location of this rectangle by setting its upper left + * corner to the specified coordinates. + * + * @param x the new X coordinate for this rectangle + * @param y the new Y coordinate for this rectangle + * @deprecated use {@link #setLocation(int, int)} instead + */ + public void move(int x, int y) + { + this.x = x; + this.y = y; + } + + /** + * Translate the location of this rectangle by the given amounts. + * + * @param dx the x distance to move by + * @param dy the y distance to move by + * @see #setLocation(int, int) + */ + public void translate(int dx, int dy) + { + x += dx; + y += dy; + } + + /** + * Returns the size of this rectangle. + * + * @return the size of this rectangle + * @see #setSize(Dimension) + * @since 1.1 + */ + public Dimension getSize() + { + return new Dimension(width, height); + } + + /** + * Sets the size of this rectangle based on the specified dimensions. + * + * @param d the new dimensions of the rectangle + * @throws NullPointerException if d is null + * @see #getSize() + * @since 1.1 + */ + public void setSize(Dimension d) + { + setSize (d.width, d.height); + } + + /** + * Sets the size of this rectangle based on the specified dimensions. + * + * @param width the new width of the rectangle + * @param height the new height of the rectangle + * @since 1.1 + */ + public void setSize(int width, int height) + { + resize (width, height); + } + + /** + * Sets the size of this rectangle based on the specified dimensions. + * + * @param width the new width of the rectangle + * @param height the new height of the rectangle + * @deprecated use {@link #setSize(int, int)} instead + */ + public void resize(int width, int height) + { + this.width = width; + this.height = height; + } + + /** + * Tests whether or not the specified point is inside this rectangle. + * According to the contract of Shape, a point on the border is in only if + * it has an adjacent point inside the rectangle in either the increasing + * x or y direction. + * + * @param p the point to test + * @return true if the point is inside the rectangle + * @throws NullPointerException if p is null + * @see #contains(int, int) + * @since 1.1 + */ + public boolean contains(Point p) + { + return contains (p.x, p.y); + } + + /** + * Tests whether or not the specified point is inside this rectangle. + * According to the contract of Shape, a point on the border is in only if + * it has an adjacent point inside the rectangle in either the increasing + * x or y direction. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside the rectangle + * @since 1.1 + */ + public boolean contains(int x, int y) + { + return inside (x, y); + } + + /** + * Checks whether all points in the given rectangle are contained in this + * rectangle. + * + * @param r the rectangle to check + * @return true if r is contained in this rectangle + * @throws NullPointerException if r is null + * @see #contains(int, int, int, int) + * @since 1.1 + */ + public boolean contains(Rectangle r) + { + return contains (r.x, r.y, r.width, r.height); + } + + /** + * Checks whether all points in the given rectangle are contained in this + * rectangle. + * + * @param x the x coordinate of the rectangle to check + * @param y the y coordinate of the rectangle to check + * @param w the width of the rectangle to check + * @param h the height of the rectangle to check + * @return true if the parameters are contained in this rectangle + * @since 1.1 + */ + public boolean contains(int x, int y, int w, int h) + { + return width > 0 && height > 0 && w > 0 && h > 0 + && x >= this.x && x + w <= this.x + this.width + && y >= this.y && y + h <= this.y + this.height; + } + + /** + * Tests whether or not the specified point is inside this rectangle. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside the rectangle + * @deprecated use {@link #contains(int, int)} instead + */ + public boolean inside(int x, int y) + { + return width > 0 && height > 0 + && x >= this.x && x < this.x + width + && y >= this.y && y < this.y + height; + } + + /** + * Tests whether or not the specified rectangle intersects this rectangle. + * This means the two rectangles share at least one internal point. + * + * @param r the rectangle to test against + * @return true if the specified rectangle intersects this one + * @throws NullPointerException if r is null + * @since 1.2 + */ + public boolean intersects(Rectangle r) + { + return r.width > 0 && r.height > 0 && width > 0 && height > 0 + && r.x < x + width && r.x + r.width > x + && r.y < y + height && r.y + r.height > y; + } + + /** + * Determines the rectangle which is formed by the intersection of this + * rectangle with the specified rectangle. If the two do not intersect, + * an empty rectangle will be returned (meaning the width and/or height + * will be non-positive). + * + * @param r the rectange to calculate the intersection with + * @return a new rectangle bounding the intersection + * @throws NullPointerException if r is null + */ + public Rectangle intersection(Rectangle r) + { + Rectangle res = new Rectangle(); + intersect(this, r, res); + return res; + } + + /** + * Returns the smallest rectangle that contains both this rectangle + * and the specified rectangle. + * + * @param r the rectangle to compute the union with + * @return the smallest rectangle containing both rectangles + * @throws NullPointerException if r is null + */ + public Rectangle union(Rectangle r) + { + Rectangle res = new Rectangle(); + union(this, r, res); + return res; + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified point. + * However, if the point falls on one of the two borders which are not + * inside the rectangle, a subsequent call to contains may + * return false. + * + * @param x the X coordinate of the point to add to this rectangle + * @param y the Y coordinate of the point to add to this rectangle + */ + public void add(int x, int y) + { + add((double) x, (double) y); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified point. + * However, if the point falls on one of the two borders which are not + * inside the rectangle, a subsequent call to contains may + * return false. + * + * @param p the point to add to this rectangle + * @throws NullPointerException if p is null + */ + public void add(Point p) + { + add((double) p.x, (double) p.y); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified rectangle. + * + * @param r the rectangle to add to this rectangle + * @throws NullPointerException if r is null + * @see #union(Rectangle) + */ + public void add(Rectangle r) + { + union(this, r, this); + } + + /** + * Expands the rectangle by the specified amount. The horizontal + * and vertical expansion values are applied both to the X,Y coordinate + * of this rectangle, and its width and height. Thus the width and + * height will increase by 2h and 2v accordingly. + * + * @param h the horizontal expansion value + * @param v the vertical expansion value + */ + public void grow(int h, int v) + { + x -= h; + y -= v; + width += h + h; + height += v + v; + } + + /** + * Tests whether or not this rectangle is empty. An empty rectangle + * has a non-positive width or height. + * + * @return true if the rectangle is empty + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param x the x coordinate to check + * @param y the y coordinate to check + * @return the binary OR of the result + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + * @since 1.2 + */ + public int outcode(double x, double y) + { + int result = 0; + if (width <= 0) + result |= OUT_LEFT | OUT_RIGHT; + else if (x < this.x) + result |= OUT_LEFT; + else if (x > this.x + width) + result |= OUT_RIGHT; + if (height <= 0) + result |= OUT_BOTTOM | OUT_TOP; + else if (y < this.y) // Remember that +y heads top-to-bottom. + result |= OUT_TOP; + else if (y > this.y + height) + result |= OUT_BOTTOM; + return result; + } + + /** + * Determines the rectangle which is formed by the intersection of this + * rectangle with the specified rectangle. If the two do not intersect, + * an empty rectangle will be returned (meaning the width and/or height + * will be non-positive). + * + * @param r the rectange to calculate the intersection with + * @return a new rectangle bounding the intersection + * @throws NullPointerException if r is null + * @since 1.2 + */ + public Rectangle2D createIntersection(Rectangle2D r) + { + // Favor runtime type of other rectangle. + Rectangle2D res = r.getBounds2D(); + intersect(this, r, res); + return res; + } + + /** + * Returns the smallest rectangle that contains both this rectangle + * and the specified rectangle. + * + * @param r the rectangle to compute the union with + * @return the smallest rectangle containing both rectangles + * @throws NullPointerException if r is null + * @since 1.2 + */ + public Rectangle2D createUnion(Rectangle2D r) + { + // Favor runtime type of other rectangle. + Rectangle2D res = r.getBounds2D(); + union(this, r, res); + return res; + } + + /** + * Tests this rectangle for equality against the specified object. This + * will be true if an only if the specified object is an instance of + * Rectangle2D with the same coordinates and dimensions. + * + * @param obj the object to test against for equality + * @return true if the specified object is equal to this one + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Rectangle2D)) + return false; + Rectangle2D r = (Rectangle2D) obj; + return r.getX() == x && r.getY() == y + && r.getWidth() == width && r.getHeight() == height; + } + + /** + * Returns a string representation of this rectangle. This is in the form + * getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + * + ",height=" + height + ']'. + * + * @return a string representation of this rectangle + */ + public String toString() + { + return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + + ",height=" + height + ']'; + } +} // class Rectangle diff --git a/libjava/classpath/java/awt/RenderingHints.java b/libjava/classpath/java/awt/RenderingHints.java new file mode 100644 index 0000000..0e1db72 --- /dev/null +++ b/libjava/classpath/java/awt/RenderingHints.java @@ -0,0 +1,803 @@ +/* RenderingHints.java -- + Copyright (C) 2000, 2001, 2002, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * A collection of (key, value) items that provide 'hints' for the + * {@link java.awt.Graphics2D} rendering pipeline. Because these + * items are hints only, they may be ignored by a particular + * {@link java.awt.Graphics2D} implementation. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author Eric Blake (ebb9@email.byu.edu) + */ +public class RenderingHints implements Map, Cloneable +{ + /** + * The base class used to represent keys. + */ + public abstract static class Key + { + private final int key; + + /** + * Creates a new key. + * + * @param privateKey the private key. + */ + protected Key(int privateKey) + { + key = privateKey; + } + + /** + * Returns true if the specified value is compatible with + * this key, and false otherwise. + * + * @param value the value (null permitted). + * + * @return A boolean. + */ + public abstract boolean isCompatibleValue(Object value); + + /** + * Returns the private key for this instance. + * + * @return The private key. + */ + protected final int intKey() + { + return key; + } + + /** + * Returns a hash code for the key. + * + * @return A hash code. + */ + public final int hashCode() + { + return System.identityHashCode(this); + } + + /** + * Checks this key for equality with an arbitrary object. + * + * @param other the object (null permitted) + * + * @return A boolean. + */ + public final boolean equals(Object other) + { + return this == other; + } + } // class Key + + private static final class KeyImpl extends Key + { + final String description; + final Object v1; + final Object v2; + final Object v3; + + KeyImpl(int privateKey, String description, + Object v1, Object v2, Object v3) + { + super(privateKey); + this.description = description; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + } + + /** + * Returns true if the specified value is compatible with + * this key, and false otherwise. + * + * @param value the value (null permitted). + * + * @return A boolean. + */ + public boolean isCompatibleValue(Object value) + { + return value == v1 || value == v2 || value == v3; + } + + /** + * Returns a string representation of the key. + * + * @return A string. + */ + public String toString() + { + return description; + } + } // class KeyImpl + + private HashMap hintMap = new HashMap(); + + /** + * A key for the 'antialiasing' hint. Permitted values are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link #VALUE_ANTIALIAS_OFF}Render without antialiasing (better speed).
{@link #VALUE_ANTIALIAS_ON}Render with antialiasing (better quality).
{@link #VALUE_ANTIALIAS_DEFAULT}Use the default value for antialiasing.
+ */ + public static final Key KEY_ANTIALIASING; + + /** + * This value is for use with the {@link #KEY_ANTIALIASING} key. + */ + public static final Object VALUE_ANTIALIAS_ON + = "Antialiased rendering mode"; + + /** + * This value is for use with the {@link #KEY_ANTIALIASING} key. + */ + public static final Object VALUE_ANTIALIAS_OFF + = "Nonantialiased rendering mode"; + + /** + * This value is for use with the {@link #KEY_ANTIALIASING} key. + */ + public static final Object VALUE_ANTIALIAS_DEFAULT + = "Default antialiasing rendering mode"; + + /** + * A key for the 'rendering' hint. Permitted values are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link #VALUE_RENDER_SPEED}Prefer speed over quality when rendering.
{@link #VALUE_RENDER_QUALITY}Prefer quality over speed when rendering.
{@link #VALUE_RENDER_DEFAULT}Use the default value for quality vs. speed when rendering.
+ */ + public static final Key KEY_RENDERING; + + /** + * This value is for use with the {@link #KEY_RENDERING} key. + */ + public static final Object VALUE_RENDER_SPEED + = "Fastest rendering methods"; + + /** + * This value is for use with the {@link #KEY_RENDERING} key. + */ + public static final Object VALUE_RENDER_QUALITY + = "Highest quality rendering methods"; + + /** + * This value is for use with the {@link #KEY_RENDERING} key. + */ + public static final Object VALUE_RENDER_DEFAULT + = "Default rendering methods"; + + /** + * A key for the 'dithering' hint. Permitted values are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link #VALUE_DITHER_DISABLE}Disable dithering.
{@link #VALUE_DITHER_ENABLE}Enable dithering.
{@link #VALUE_DITHER_DEFAULT}Use the default value for dithering.
+ */ + public static final Key KEY_DITHERING; + + /** + * This value is for use with the {@link #KEY_DITHERING} key. + */ + public static final Object VALUE_DITHER_DISABLE + = "Nondithered rendering mode"; + + /** + * This value is for use with the {@link #KEY_DITHERING} key. + */ + public static final Object VALUE_DITHER_ENABLE + = "Dithered rendering mode"; + + /** + * This value is for use with the {@link #KEY_DITHERING} key. + */ + public static final Object VALUE_DITHER_DEFAULT + = "Default dithering mode"; + + /** + * A key for the 'text antialiasing' hint. Permitted values are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link #VALUE_TEXT_ANTIALIAS_ON}Render text with antialiasing (better quality usually).
{@link #VALUE_TEXT_ANTIALIAS_OFF}Render test without antialiasing (better speed).
{@link #VALUE_TEXT_ANTIALIAS_DEFAULT}Use the default value for text antialiasing.
+ */ + public static final Key KEY_TEXT_ANTIALIASING; + + /** + * This value is for use with the {@link #KEY_TEXT_ANTIALIASING} key. + */ + public static final Object VALUE_TEXT_ANTIALIAS_ON + = "Antialiased text mode"; + + /** + * This value is for use with the {@link #KEY_TEXT_ANTIALIASING} key. + */ + public static final Object VALUE_TEXT_ANTIALIAS_OFF + = "Nonantialiased text mode"; + + /** + * This value is for use with the {@link #KEY_TEXT_ANTIALIASING} key. + */ + public static final Object VALUE_TEXT_ANTIALIAS_DEFAULT + = "Default antialiasing text mode"; + + /** + * A key for the 'fractional metrics' hint. Permitted values are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link #VALUE_FRACTIONALMETRICS_OFF}Render text with fractional metrics off.
{@link #VALUE_FRACTIONALMETRICS_ON}Render text with fractional metrics on.
{@link #VALUE_FRACTIONALMETRICS_DEFAULT}Use the default value for fractional metrics.
+ */ + public static final Key KEY_FRACTIONALMETRICS; + + /** + * This value is for use with the {@link #KEY_FRACTIONALMETRICS} key. + */ + public static final Object VALUE_FRACTIONALMETRICS_OFF + = "Integer text metrics mode"; + + /** + * This value is for use with the {@link #KEY_FRACTIONALMETRICS} key. + */ + public static final Object VALUE_FRACTIONALMETRICS_ON + = "Fractional text metrics mode"; + + /** + * This value is for use with the {@link #KEY_FRACTIONALMETRICS} key. + */ + public static final Object VALUE_FRACTIONALMETRICS_DEFAULT + = "Default fractional text metrics mode"; + + /** + * A key for the 'interpolation' hint. Permitted values are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link #VALUE_INTERPOLATION_NEAREST_NEIGHBOR}Use nearest neighbour interpolation.
{@link #VALUE_INTERPOLATION_BILINEAR}Use bilinear interpolation.
{@link #VALUE_INTERPOLATION_BICUBIC}Use bicubic interpolation.
+ */ + public static final Key KEY_INTERPOLATION; + + /** + * This value is for use with the {@link #KEY_INTERPOLATION} key. + */ + public static final Object VALUE_INTERPOLATION_NEAREST_NEIGHBOR + = "Nearest Neighbor image interpolation mode"; + + /** + * This value is for use with the {@link #KEY_INTERPOLATION} key. + */ + public static final Object VALUE_INTERPOLATION_BILINEAR + = "Bilinear image interpolation mode"; + + /** + * This value is for use with the {@link #KEY_INTERPOLATION} key. + */ + public static final Object VALUE_INTERPOLATION_BICUBIC + = "Bicubic image interpolation mode"; + + /** + * A key for the 'alpha interpolation' hint. Permitted values are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link #VALUE_ALPHA_INTERPOLATION_SPEED}Prefer speed over quality.
{@link #VALUE_ALPHA_INTERPOLATION_QUALITY}Prefer quality over speed.
{@link #VALUE_ALPHA_INTERPOLATION_DEFAULT}Use the default setting.
+ */ + public static final Key KEY_ALPHA_INTERPOLATION; + + /** + * This value is for use with the {@link #KEY_ALPHA_INTERPOLATION} key. + */ + public static final Object VALUE_ALPHA_INTERPOLATION_SPEED + = "Fastest alpha blending methods"; + + /** + * This value is for use with the {@link #KEY_ALPHA_INTERPOLATION} key. + */ + public static final Object VALUE_ALPHA_INTERPOLATION_QUALITY + = "Highest quality alpha blending methods"; + + /** + * This value is for use with the {@link #KEY_ALPHA_INTERPOLATION} key. + */ + public static final Object VALUE_ALPHA_INTERPOLATION_DEFAULT + = "Default alpha blending methods"; + + /** + * A key for the 'color rendering' hint. Permitted values are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link #VALUE_COLOR_RENDER_SPEED}Prefer speed over quality.
{@link #VALUE_COLOR_RENDER_QUALITY}Prefer quality over speed.
{@link #VALUE_COLOR_RENDER_DEFAULT}Use the default setting.
+ */ + public static final Key KEY_COLOR_RENDERING; + + /** + * This value is for use with the {@link #KEY_COLOR_RENDERING} key. + */ + public static final Object VALUE_COLOR_RENDER_SPEED + = "Fastest color rendering mode"; + + /** + * This value is for use with the {@link #KEY_COLOR_RENDERING} key. + */ + public static final Object VALUE_COLOR_RENDER_QUALITY + = "Highest quality color rendering mode"; + + /** + * This value is for use with the {@link #KEY_COLOR_RENDERING} key. + */ + public static final Object VALUE_COLOR_RENDER_DEFAULT + = "Default color rendering mode"; + + /** + * A key for the 'stroke control' hint. Permitted values are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link #VALUE_STROKE_DEFAULT}Use the default setting.
{@link #VALUE_STROKE_NORMALIZE}XXX
{@link #VALUE_STROKE_PURE}XXX
+ */ + public static final Key KEY_STROKE_CONTROL; + + /** + * This value is for use with the {@link #KEY_STROKE_CONTROL} key. + */ + public static final Object VALUE_STROKE_DEFAULT + = "Default stroke normalization"; + + /** + * This value is for use with the {@link #KEY_STROKE_CONTROL} key. + */ + public static final Object VALUE_STROKE_NORMALIZE + = "Normalize strokes for consistent rendering"; + + /** + * This value is for use with the {@link #KEY_STROKE_CONTROL} key. + */ + public static final Object VALUE_STROKE_PURE + = "Pure stroke conversion for accurate paths"; + + static + { + KEY_ANTIALIASING = new KeyImpl(1, "Global antialiasing enable key", + VALUE_ANTIALIAS_ON, + VALUE_ANTIALIAS_OFF, + VALUE_ANTIALIAS_DEFAULT); + KEY_RENDERING = new KeyImpl(2, "Global rendering quality key", + VALUE_RENDER_SPEED, + VALUE_RENDER_QUALITY, + VALUE_RENDER_DEFAULT); + KEY_DITHERING = new KeyImpl(3, "Dithering quality key", + VALUE_DITHER_DISABLE, + VALUE_DITHER_ENABLE, + VALUE_DITHER_DEFAULT); + KEY_TEXT_ANTIALIASING + = new KeyImpl(4, "Text-specific antialiasing enable key", + VALUE_TEXT_ANTIALIAS_ON, + VALUE_TEXT_ANTIALIAS_OFF, + VALUE_TEXT_ANTIALIAS_DEFAULT); + KEY_FRACTIONALMETRICS = new KeyImpl(5, "Fractional metrics enable key", + VALUE_FRACTIONALMETRICS_OFF, + VALUE_FRACTIONALMETRICS_ON, + VALUE_FRACTIONALMETRICS_DEFAULT); + KEY_INTERPOLATION = new KeyImpl(6, "Image interpolation method key", + VALUE_INTERPOLATION_NEAREST_NEIGHBOR, + VALUE_INTERPOLATION_BILINEAR, + VALUE_INTERPOLATION_BICUBIC); + KEY_ALPHA_INTERPOLATION + = new KeyImpl(7, "Alpha blending interpolation method key", + VALUE_ALPHA_INTERPOLATION_SPEED, + VALUE_ALPHA_INTERPOLATION_QUALITY, + VALUE_ALPHA_INTERPOLATION_DEFAULT); + KEY_COLOR_RENDERING = new KeyImpl(8, "Color rendering quality key", + VALUE_COLOR_RENDER_SPEED, + VALUE_COLOR_RENDER_QUALITY, + VALUE_COLOR_RENDER_DEFAULT); + KEY_STROKE_CONTROL = new KeyImpl(9, "Stroke normalization control key", + VALUE_STROKE_DEFAULT, + VALUE_STROKE_NORMALIZE, + VALUE_STROKE_PURE); + } + + /** + * Creates a new collection of hints containing all the (key, value) pairs + * in the specified map. + * + * @param init a map containing a collection of hints (null + * permitted). + */ + public RenderingHints(Map init) + { + if (init != null) + putAll(init); + } + + /** + * Creates a new collection containing a single (key, value) pair. + * + * @param key the key. + * @param value the value. + */ + public RenderingHints(Key key, Object value) + { + put(key, value); + } + + /** + * Returns the number of hints in the collection. + * + * @return The number of hints. + */ + public int size() + { + return hintMap.size(); + } + + /** + * Returns true if there are no hints in the collection, + * and false otherwise. + * + * @return A boolean. + */ + public boolean isEmpty() + { + return hintMap.isEmpty(); + } + + /** + * Returns true if the collection of hints contains the + * specified key, and false otherwise. + * + * @param key the key (null not permitted). + * + * @return A boolean. + * + * @throws NullPointerException if key is null. + * @throws ClassCastException if key is not a {@link Key}. + */ + public boolean containsKey(Object key) + { + if (key == null) + throw new NullPointerException(); + // don't remove the cast, it is necessary to throw the required exception + return hintMap.containsKey((Key) key); + } + + /** + * Returns true if the collection of hints contains the + * specified value, and false otherwise. + * + * @param value the value. + * + * @return A boolean. + */ + public boolean containsValue(Object value) + { + return hintMap.containsValue(value); + } + + /** + * Returns the value associated with the specified key, or null + * if there is no value defined for the key. + * + * @param key the key (null permitted). + * + * @return The value (possibly null). + * + * @throws ClassCastException if key is not a {@link Key}. + * + * @see #containsKey(Object) + */ + public Object get(Object key) + { + // don't remove the cast, it is necessary to throw the required exception + return hintMap.get((Key) key); + } + + /** + * Adds a (key, value) pair to the collection of hints (if the + * collection already contains the specified key, then the + * value is updated). + * + * @param key the key. + * @param value the value. + * + * @return the previous value of the key or null if the key + * didn't have a value yet. + */ + public Object put(Object key, Object value) + { + if (key == null || value == null) + throw new NullPointerException(); + if (! ((Key) key).isCompatibleValue(value)) + throw new IllegalArgumentException(); + return hintMap.put(key, value); + } + + /** + * Adds all the hints from a collection to this collection. + * + * @param hints the hint collection. + */ + public void add(RenderingHints hints) + { + hintMap.putAll(hints); + } + + /** + * Clears all the hints from this collection. + */ + public void clear() + { + hintMap.clear(); + } + + /** + * Removes a hint from the collection. + * + * @param key the key. + * + * @return The value that was associated with the key, or null if + * the key was not part of the collection + * + * @throws ClassCastException if the key is not a subclass of + * {@link RenderingHints.Key}. + */ + public Object remove(Object key) + { + // don't remove the (Key) cast, it is necessary to throw the exception + // required by the spec + return hintMap.remove((Key) key); + } + + /** + * Adds a collection of (key, value) pairs to the collection. + * + * @param m a map containing (key, value) items. + * + * @throws ClassCastException if the map contains a key that is not + * a subclass of {@link RenderingHints.Key}. + * @throws IllegalArgumentException if the map contains a value that is + * not compatible with its key. + */ + public void putAll(Map m) + { + // preprocess map to generate appropriate exceptions + Iterator iterator = m.keySet().iterator(); + while (iterator.hasNext()) + { + Key key = (Key) iterator.next(); + if (!key.isCompatibleValue(m.get(key))) + throw new IllegalArgumentException(); + } + // map is OK, update + hintMap.putAll(m); + } + + /** + * Returns a set containing the keys from this collection. + * + * @return A set of keys. + */ + public Set keySet() + { + return hintMap.keySet(); + } + + /** + * Returns a collection of the values from this hint collection. The + * collection is backed by the RenderingHints instance, + * so updates to one will affect the other. + * + * @return A collection of values. + */ + public Collection values() + { + return hintMap.values(); + } + + /** + * Returns a set of entries from the collection. + * + * @return A set of entries. + */ + public Set entrySet() + { + return Collections.unmodifiableSet(hintMap.entrySet()); + } + + /** + * Checks this collection for equality with an arbitrary object. + * + * @param o the object (null permitted) + * + * @return A boolean. + */ + public boolean equals(Object o) + { + return hintMap.equals(o); + } + + /** + * Returns a hash code for the collection of hints. + * + * @return A hash code. + */ + public int hashCode() + { + return hintMap.hashCode(); + } + + /** + * Creates a clone of this instance. + * + * @return A clone. + */ + public Object clone() + { + try + { + RenderingHints copy = (RenderingHints) super.clone(); + copy.hintMap = (HashMap) hintMap.clone(); + return copy; + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Returns a string representation of this instance. + * + * @return A string. + */ + public String toString() + { + return hintMap.toString(); + } +} // class RenderingHints diff --git a/libjava/classpath/java/awt/Robot.java b/libjava/classpath/java/awt/Robot.java new file mode 100644 index 0000000..485a14e --- /dev/null +++ b/libjava/classpath/java/awt/Robot.java @@ -0,0 +1,423 @@ +/* Robot.java -- a native input event generator + 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 java.awt; + +import gnu.java.awt.ClasspathToolkit; + +import java.lang.reflect.InvocationTargetException; +import java.awt.event.InputEvent; +import java.awt.image.BufferedImage; +import java.awt.peer.RobotPeer; + +/** + * The Robot class is used to simulate user interaction with graphical + * programs. It can generate native windowing system input events and + * retrieve image data from the current screen. Robot is used to test + * the AWT and Swing library implementations; it can also be used to + * create self-running demo programs. + * + * Since Robot generates native windowing system events, rather than + * simply inserting {@link AWTEvent}s on the AWT event queue, its use + * is not restricted to Java programs. It can be used to + * programatically drive any graphical application. + * + * This implementation requires an X server that supports the XTest + * extension. + * + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + * + * @since 1.3 + */ +public class Robot +{ + private boolean waitForIdle; + private int autoDelay; + private RobotPeer peer; + + /** + * Construct a Robot object that operates on the default screen. + * + * @exception AWTException if GraphicsEnvironment.isHeadless() + * returns true or if the X server does not support the XTest + * extension + * @exception SecurityException if createRobot permission is not + * granted + */ + public Robot () throws AWTException + { + if (GraphicsEnvironment.isHeadless ()) + throw new AWTException ("Robot: headless graphics environment"); + + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission (new AWTPermission ("createRobot")); + + ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit (); + + // createRobot will throw AWTException if XTest is not supported. + peer = tk.createRobot (GraphicsEnvironment.getLocalGraphicsEnvironment () + .getDefaultScreenDevice ()); + } + + /** + * Construct a Robot object that operates on the specified screen. + * + * @exception AWTException if GraphicsEnvironment.isHeadless() + * returns true or if the X server does not support the XTest + * extension + * @exception IllegalArgumentException if screen is not a screen + * GraphicsDevice + * @exception SecurityException if createRobot permission is not + * granted + */ + public Robot (GraphicsDevice screen) throws AWTException + { + if (GraphicsEnvironment.isHeadless ()) + throw new AWTException ("Robot: headless graphics environment"); + + if (screen.getType () != GraphicsDevice.TYPE_RASTER_SCREEN) + throw new IllegalArgumentException ("Robot: graphics" + + " device is not a screen"); + + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission (new AWTPermission ("createRobot")); + + ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit (); + + // createRobot will throw AWTException if XTest is not supported. + peer = tk.createRobot (screen); + } + + /** + * Move the mouse pointer to absolute coordinates (x, y). + * + * @param x the destination x coordinate + * @param y the destination y coordinate + */ + public void mouseMove(int x, int y) + { + peer.mouseMove (x, y); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Press one or more mouse buttons. + * + * @param buttons the buttons to press; a bitmask of one or more of + * these {@link InputEvent} fields: + * + *

+ * + * @exception IllegalArgumentException if the button mask is invalid + */ + public void mousePress (int buttons) + { + if ((buttons & InputEvent.BUTTON1_MASK) == 0 + && (buttons & InputEvent.BUTTON2_MASK) == 0 + && (buttons & InputEvent.BUTTON3_MASK) == 0) + throw new IllegalArgumentException ("Robot: mousePress:" + + " invalid button mask"); + + peer.mousePress (buttons); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Release one or more mouse buttons. + * + * @param buttons the buttons to release; a bitmask of one or more + * of these {@link InputEvent} fields: + * + * + * + * @exception IllegalArgumentException if the button mask is invalid + */ + public void mouseRelease(int buttons) + { + if ((buttons & InputEvent.BUTTON1_MASK) == 0 + && (buttons & InputEvent.BUTTON2_MASK) == 0 + && (buttons & InputEvent.BUTTON3_MASK) == 0) + throw new IllegalArgumentException ("Robot: mouseRelease:" + + " invalid button mask"); + + peer.mouseRelease (buttons); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Rotate the mouse scroll wheel. + * + * @param wheelAmt number of steps to rotate mouse wheel. negative + * to rotate wheel up (away from the user), positive to rotate wheel + * down (toward the user). + * + * @since 1.4 + */ + public void mouseWheel (int wheelAmt) + { + peer.mouseWheel (wheelAmt); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Press a key. + * + * @param keycode key to press, a {@link java.awt.event.KeyEvent} VK_ constant + * + * @exception IllegalArgumentException if keycode is not a valid key + */ + public void keyPress (int keycode) + { + peer.keyPress (keycode); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Release a key. + * + * @param keycode key to release, a {@link java.awt.event.KeyEvent} VK_ + * constant + * + * @exception IllegalArgumentException if keycode is not a valid key + */ + public void keyRelease (int keycode) + { + peer.keyRelease (keycode); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Return the color of the pixel at the given screen coordinates. + * + * @param x the x coordinate of the pixel + * @param y the y coordinate of the pixel + * + * @return the Color of the pixel at screen coodinates (x, y) + */ + public Color getPixelColor (int x, int y) + { + return new Color (peer.getRGBPixel (x, y)); + } + + /** + * Create an image containing pixels read from the screen. The + * image does not include the mouse pointer. + * + * @param screenRect the rectangle of pixels to capture, in screen + * coordinates + * + * @return a BufferedImage containing the requested pixels + * + * @exception IllegalArgumentException if requested width and height + * are not both greater than zero + * @exception SecurityException if readDisplayPixels permission is + * not granted + */ + public BufferedImage createScreenCapture (Rectangle screenRect) + { + if (screenRect.width <= 0) + throw new IllegalArgumentException ("Robot: capture width is <= 0"); + + if (screenRect.height <= 0) + throw new IllegalArgumentException ("Robot: capture height is <= 0"); + + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission (new AWTPermission ("readDisplayPixels")); + + int[] pixels = peer.getRGBPixels (screenRect); + + BufferedImage bufferedImage = + new BufferedImage (screenRect.width, screenRect.height, + BufferedImage.TYPE_INT_ARGB); + + bufferedImage.setRGB (0, 0, screenRect.width, screenRect.height, + pixels, 0, screenRect.width); + + return bufferedImage; + } + + /** + * Check if this Robot automatically calls {@link #waitForIdle()} after + * generating an event. + * + * @return true if waitForIdle is automatically called + */ + public boolean isAutoWaitForIdle () + { + return waitForIdle; + } + + /** + * Set whether or not this Robot automatically calls {@link + * #waitForIdle()} after generating an event. + * + * @param isOn true if waitForIdle should be called automatically + */ + public void setAutoWaitForIdle (boolean isOn) + { + waitForIdle = isOn; + } + + /** + * Retrieve the length of time this Robot sleeps after generating an + * event. + * + * @return the length of time in milliseconds + */ + public int getAutoDelay () + { + return autoDelay; + } + + /** + * Set the length of time this Robot sleeps after generating an + * event. + * + * @param ms the length of time in milliseconds + * + * @exception IllegalArgumentException if ms is not between 0 and + * 60,000 milliseconds inclusive + */ + public void setAutoDelay (int ms) + { + if (ms <= 0 || ms >= 60000) + throw new IllegalArgumentException ("Robot: delay length out-of-bounds"); + + autoDelay = ms; + } + + /** + * Sleep for a specified length of time. + * + * @param ms the length of time in milliseconds + * + * @exception IllegalArgumentException if ms is not between 0 and + * 60,000 milliseconds inclusive + */ + public void delay (int ms) + { + if (ms < 0 || ms > 60000) + throw new IllegalArgumentException ("Robot: delay length out-of-bounds"); + + try + { + Thread.sleep (ms); + } + catch (InterruptedException e) + { + System.err.println ("Robot: delay interrupted"); + } + } + + /** + * Wait until all events currently on the event queue have been + * dispatched. + */ + public void waitForIdle () + { + if (EventQueue.isDispatchThread ()) + throw new IllegalThreadStateException ("Robot: waitForIdle called from " + + "the event dispatch thread"); + + try + { + EventQueue.invokeAndWait (new Runnable () { public void run () { } }); + } + catch (InterruptedException e) + { + System.err.println ("Robot: waitForIdle interrupted"); + } + catch (InvocationTargetException e) + { + System.err.println ("Robot: waitForIdle cannot invoke target"); + } + } + + /** + * Return a string representation of this Robot. + * + * @return a string representation + */ + public String toString () + { + return getClass ().getName () + + "[ autoDelay = " + autoDelay + ", autoWaitForIdle = " + + waitForIdle + " ]"; + } +} diff --git a/libjava/classpath/java/awt/ScrollPane.java b/libjava/classpath/java/awt/ScrollPane.java new file mode 100644 index 0000000..b3ecc59 --- /dev/null +++ b/libjava/classpath/java/awt/ScrollPane.java @@ -0,0 +1,615 @@ +/* ScrollPane.java -- Scrolling window + Copyright (C) 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 java.awt; + +import java.awt.event.MouseEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ScrollPanePeer; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This widget provides a scrollable region that allows a single + * subcomponent to be viewed through a smaller window. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class ScrollPane extends Container implements Accessible +{ + +/* + * Static Variables + */ + +/** + * Constant indicating that scrollbars are created as needed in this + * windows. + */ +public static final int SCROLLBARS_AS_NEEDED = 0; + +/** + * Constant indicating that scrollbars are always displayed in this + * window. + */ +public static final int SCROLLBARS_ALWAYS = 1; + +/** + * Constant indicating that scrollbars are never displayed in this window. + */ +public static final int SCROLLBARS_NEVER = 2; + +// Serialization constant +private static final long serialVersionUID = 7956609840827222915L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The horizontal scrollbar for this window. The methods + * setMinimum(), setMaximum, and + * setVisibleAmount must not be called on this scrollbar. + */ +private ScrollPaneAdjustable hAdjustable; + +/** + * @serial The vertical scrollbar for this window. The methods + * setMinimum(), setMaximum, and + * setVisibleAmount must not be called on this scrollbar. + */ +private ScrollPaneAdjustable vAdjustable; + +/** + * @serial Indicates when scrollbars are displayed in this window, will + * be one of the constants from this class. + */ +private int scrollbarDisplayPolicy; + +// Current scroll position +private Point scrollPosition = new Point(0, 0); + +private boolean wheelScrollingEnabled; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of ScrollPane with a default + * scrollbar policy of SCROLLBARS_AS_NEEDED. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +ScrollPane() +{ + this(SCROLLBARS_AS_NEEDED); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of ScrollPane with the + * specified scrollbar policy. + * + * @param scrollbarDisplayPolicy When to display scrollbars, which must + * be one of the constants defined in this class. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +ScrollPane(int scrollbarDisplayPolicy) +{ + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); + + this.scrollbarDisplayPolicy = scrollbarDisplayPolicy; + + if (scrollbarDisplayPolicy != SCROLLBARS_ALWAYS + && scrollbarDisplayPolicy != SCROLLBARS_AS_NEEDED + && scrollbarDisplayPolicy != SCROLLBARS_NEVER) + throw new IllegalArgumentException("Bad scrollbarDisplayPolicy: " + + scrollbarDisplayPolicy); + + if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) + { + hAdjustable = new ScrollPaneAdjustable (this, Scrollbar.HORIZONTAL); + vAdjustable = new ScrollPaneAdjustable (this, Scrollbar.VERTICAL); + } + + wheelScrollingEnabled = true; + + // Default size. + setSize(100,100); +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the current scrollbar display policy. + * + * @return The current scrollbar display policy. + */ +public int +getScrollbarDisplayPolicy() +{ + return(scrollbarDisplayPolicy); +} + +/*************************************************************************/ + +/** + * Returns the horizontal scrollbar for this object. If the scrollbar + * display policy is set to SCROLLBARS_NEVER then this + * will be null. + * + * @return The horizontal scrollbar for this window. + */ +public Adjustable +getHAdjustable() +{ + return(hAdjustable); +} + +/*************************************************************************/ + +/** + * Returns the vertical scrollbar for this object. If the scrollbar + * display policy is set to SCROLLBARS_NEVER then this + * will be null. + * + * @return The horizontal scrollbar for this window. + */ +public Adjustable +getVAdjustable() +{ + return(vAdjustable); +} + +/*************************************************************************/ + +/** + * Returns the current viewport size. The viewport is the region of + * this object's window where the child is actually displayed. + * + * @return The viewport size. + */ +public Dimension getViewportSize () +{ + Dimension viewsize = getSize (); + Insets insets = getInsets (); + + viewsize.width -= (insets.left + insets.right); + viewsize.height -= (insets.top + insets.bottom); + + Component[] list = getComponents(); + if ((list == null) || (list.length <= 0)) + return viewsize; + + Dimension dim = list[0].getPreferredSize(); + + if (dim.width <= 0 && dim.height <= 0) + return viewsize; + + int vScrollbarWidth = getVScrollbarWidth (); + int hScrollbarHeight = getHScrollbarHeight (); + + if (scrollbarDisplayPolicy == SCROLLBARS_ALWAYS) + { + viewsize.width -= vScrollbarWidth; + viewsize.height -= hScrollbarHeight; + return viewsize; + } + + if (scrollbarDisplayPolicy == SCROLLBARS_NEVER) + return viewsize; + + // The scroll policy is SCROLLBARS_AS_NEEDED, so we need to see if + // either scrollbar is needed. + + // Assume we don't need either scrollbar. + boolean mayNeedVertical = false; + boolean mayNeedHorizontal = false; + + boolean needVertical = false; + boolean needHorizontal = false; + + // Check if we need vertical scrollbars. If we do, then we need to + // subtract the width of the vertical scrollbar from the viewport's + // width. + if (dim.height > viewsize.height) + needVertical = true; + else if (dim.height > (viewsize.height - hScrollbarHeight)) + // This is tricky. In this case the child is tall enough that its + // bottom edge would be covered by a horizontal scrollbar, if one + // were present. This means that if there's a horizontal + // scrollbar then we need a vertical scrollbar. + mayNeedVertical = true; + + if (dim.width > viewsize.width) + needHorizontal = true; + else if (dim.width > (viewsize.width - vScrollbarWidth)) + mayNeedHorizontal = true; + + if (needVertical && mayNeedHorizontal) + needHorizontal = true; + + if (needHorizontal && mayNeedVertical) + needVertical = true; + + if (needHorizontal) + viewsize.height -= hScrollbarHeight; + + if (needVertical) + viewsize.width -= vScrollbarWidth; + + return viewsize; +} + +/*************************************************************************/ + +/** + * Returns the height of a horizontal scrollbar. + * + * @return The height of a horizontal scrollbar. + */ +public int +getHScrollbarHeight() +{ + ScrollPanePeer spp = (ScrollPanePeer)getPeer(); + if (spp != null) + return(spp.getHScrollbarHeight()); + else + return(0); // FIXME: What to do here? +} + +/*************************************************************************/ + +/** + * Returns the width of a vertical scrollbar. + * + * @return The width of a vertical scrollbar. + */ +public int +getVScrollbarWidth() +{ + ScrollPanePeer spp = (ScrollPanePeer)getPeer(); + if (spp != null) + return(spp.getVScrollbarWidth()); + else + return(0); // FIXME: What to do here? +} + +/*************************************************************************/ + +/** + * Returns the current scroll position of the viewport. + * + * @return The current scroll position of the viewport. + */ +public Point +getScrollPosition() +{ + int x = 0; + int y = 0; + + Adjustable v = getVAdjustable(); + Adjustable h = getHAdjustable(); + + if (v != null) + y = v.getValue(); + if (h != null) + x = h.getValue(); + + return(new Point(x, y)); +} + +/*************************************************************************/ + +/** + * Sets the scroll position to the specified value. + * + * @param scrollPosition The new scrollPosition. + * + * @exception IllegalArgumentException If the specified value is outside + * the legal scrolling range. + */ +public void +setScrollPosition(Point scrollPosition) throws IllegalArgumentException +{ + setScrollPosition(scrollPosition.x, scrollPosition.y); +} + +/*************************************************************************/ + +/** + * Sets the scroll position to the specified value. + * + * @param x The new X coordinate of the scroll position. + * @param y The new Y coordinate of the scroll position. + * + * @exception IllegalArgumentException If the specified value is outside + * the legal scrolling range. + */ +public void +setScrollPosition(int x, int y) +{ + Adjustable h = getHAdjustable(); + Adjustable v = getVAdjustable(); + + if (h != null) + h.setValue(x); + if (v != null) + v.setValue(y); + + ScrollPanePeer spp = (ScrollPanePeer)getPeer(); + if (spp != null) + spp.setScrollPosition(x, y); +} + +/*************************************************************************/ + +/** + * Notifies this object that it should create its native peer. + */ +public void +addNotify() +{ + if (!isDisplayable ()) + return; + + setPeer((ComponentPeer)getToolkit().createScrollPane(this)); + super.addNotify(); + + Component[] list = getComponents(); + if (list != null && list.length > 0 && ! (list[0] instanceof Panel)) + { + Panel panel = new Panel(); + panel.setLayout(new BorderLayout()); + panel.add(list[0], BorderLayout.CENTER); + add(panel); + } +} + +/*************************************************************************/ + +/** + * Notifies this object that it should destroy its native peers. + */ +public void +removeNotify() +{ + super.removeNotify(); +} + +/*************************************************************************/ + +/** + * Adds the specified child component to this container. A + * ScrollPane can have at most one child, so if a second + * one is added, then first one is removed. + * + * @param component The component to add to this container. + * @param constraints A list of layout constraints for this object. + * @param index The index at which to add the child, which is ignored + * in this implementation. + */ + protected final void addImpl (Component component, Object constraints, + int index) +{ + Component[] list = getComponents(); + if ((list != null) && (list.length > 0)) + remove(list[0]); + + super.addImpl(component, constraints, -1); + + doLayout(); +} + +/*************************************************************************/ + +/** + * Lays out this component. This consists of resizing the sole child + * component to its perferred size. + */ +public void +doLayout() +{ + layout (); +} + +/*************************************************************************/ + +/** + * Lays out this component. This consists of resizing the sole child + * component to its perferred size. + * + * @deprecated This method is deprecated in favor of + * doLayout(). + */ +public void +layout() +{ + Component[] list = getComponents (); + if ((list != null) && (list.length > 0)) + { + Dimension dim = list[0].getPreferredSize (); + Dimension vp = getViewportSize (); + + if (dim.width < vp.width) + dim.width = vp.width; + + if (dim.height < vp.height) + dim.height = vp.height; + + ScrollPanePeer peer = (ScrollPanePeer) getPeer (); + if (peer != null) + peer.childResized (dim.width, dim.height); + + list[0].setSize (dim); + + Point p = getScrollPosition (); + if (p.x > dim.width) + p.x = dim.width; + if (p.y > dim.height) + p.y = dim.height; + + setScrollPosition (p); + } +} + +/*************************************************************************/ + +/** + * This method overrides its superclass method to ensure no layout + * manager is set for this container. ScrollPane's do + * not have layout managers. + * + * @param layoutManager Ignored + */ +public final void +setLayout(LayoutManager layoutManager) +{ + return; +} + +/*************************************************************************/ + +/** + * Prints all of the components in this container. + * + * @param graphics The desired graphics context for printing. + */ +public void +printComponents(Graphics graphics) +{ + super.printComponents(graphics); +} + +/*************************************************************************/ + +/** + * Returns a debug string for this object. + * + * @return A debug string for this object. + */ +public String +paramString() +{ + Insets insets = getInsets(); + return getName() + "," + + getX() + "," + + getY() + "," + + getWidth() + "x" + getHeight() + "," + + "ScrollPosition=(" + scrollPosition.getX() + "," + + scrollPosition.getY() + ")," + + "Insets=(" + insets.top + "," + + insets.left + "," + + insets.bottom + "," + + insets.right + ")," + + "ScrollbarDisplayPolicy=" + getScrollbarDisplayPolicy() + "," + + "wheelScrollingEnabled=" + isWheelScrollingEnabled(); +} + + /** + * Tells whether or not an event is enabled. + * + * @since 1.4 + */ + protected boolean eventTypeEnabled (int type) + { + if (type == MouseEvent.MOUSE_WHEEL) + return wheelScrollingEnabled; + + return super.eventTypeEnabled (type); + } + + /** + * Tells whether or not wheel scrolling is enabled. + * + * @since 1.4 + */ + public boolean isWheelScrollingEnabled () + { + return wheelScrollingEnabled; + } + + /** + * Enables/disables wheel scrolling. + * + * @since 1.4 + */ + public void setWheelScrollingEnabled (boolean enable) + { + wheelScrollingEnabled = enable; + } + + protected class AccessibleAWTScrollPane extends AccessibleAWTContainer + { + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.SCROLL_PANE; + } + } + + /** + * Gets the AccessibleContext associated with this ScrollPane. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTScrollPane(); + return accessibleContext; + } +} // class ScrollPane + diff --git a/libjava/classpath/java/awt/ScrollPaneAdjustable.java b/libjava/classpath/java/awt/ScrollPaneAdjustable.java new file mode 100644 index 0000000..cfca19b --- /dev/null +++ b/libjava/classpath/java/awt/ScrollPaneAdjustable.java @@ -0,0 +1,200 @@ +/* ScrollPaneAdjustable.java -- Scrollbars for a ScrollPane + Copyright (C) 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 java.awt; + +import java.awt.event.AdjustmentListener; +import java.io.Serializable; + +/** + * Need this class since the serialization spec for ScrollPane + * uses it. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.4 + */ +public class ScrollPaneAdjustable + implements Adjustable, Serializable +{ + private static final long serialVersionUID = -3359745691033257079L; + + ScrollPane sp; + int orientation; + int value; + int minimum; + int maximum; + int visibleAmount; + int unitIncrement = 1; + int blockIncrement = 1; + AdjustmentListener adjustmentListener; + + private transient boolean valueIsAdjusting = false; + + ScrollPaneAdjustable (ScrollPane sp, int orientation) + { + this.sp = sp; + this.orientation = orientation; + } + + ScrollPaneAdjustable (ScrollPane sp, int orientation, int value, int minimum, + int maximum, int visibleAmount, int unitIncrement, + int blockIncrement) + { + this.sp = sp; + this.orientation = orientation; + this.value = value; + this.minimum = minimum; + this.maximum = maximum; + this.visibleAmount = visibleAmount; + this.unitIncrement = unitIncrement; + this.blockIncrement = blockIncrement; + } + + public void addAdjustmentListener (AdjustmentListener listener) + { + AWTEventMulticaster.add (adjustmentListener, listener); + } + + public void removeAdjustmentListener (AdjustmentListener listener) + { + AWTEventMulticaster.remove (adjustmentListener, listener); + } + + public AdjustmentListener[] getAdjustmentListeners () + { + return (AdjustmentListener[]) AWTEventMulticaster.getListeners + (adjustmentListener, AdjustmentListener.class); + } + + public int getBlockIncrement () + { + return blockIncrement; + } + + public int getMaximum () + { + return maximum; + } + + public int getMinimum () + { + return minimum; + } + + public int getOrientation () + { + return orientation; + } + + public int getUnitIncrement () + { + return unitIncrement; + } + + public int getValue () + { + return value; + } + + public int getVisibleAmount () + { + return visibleAmount; + } + + public void setBlockIncrement (int blockIncrement) + { + this.blockIncrement = blockIncrement; + } + + public void setMaximum (int maximum) + { + this.maximum = maximum; + } + + public void setMinimum (int minimum) + { + this.minimum = minimum; + } + + public void setUnitIncrement (int unitIncrement) + { + this.unitIncrement = unitIncrement; + } + + public void setValue (int value) + { + this.value = value; + + if (value < minimum) + minimum = value; + + if (value > maximum) + maximum = value; + } + + public void setVisibleAmount (int visibleAmount) + { + this.visibleAmount = visibleAmount; + } + + public String paramString () + { + throw new Error ("not implemented"); + } + + /** + * Returns true if the value is in the process of changing. + * + * @since 1.4 + */ + public boolean getValueIsAdjusting () + { + return valueIsAdjusting; + } + + /** + * Sets the value of valueIsAdjusting. + * + * @since 1.4 + */ + public void setValueIsAdjusting (boolean valueIsAdjusting) + { + this.valueIsAdjusting = valueIsAdjusting; + } +} // class ScrollPaneAdjustable + diff --git a/libjava/classpath/java/awt/Scrollbar.java b/libjava/classpath/java/awt/Scrollbar.java new file mode 100644 index 0000000..6e506c7 --- /dev/null +++ b/libjava/classpath/java/awt/Scrollbar.java @@ -0,0 +1,825 @@ +/* Scrollbar.java -- AWT Scrollbar widget + Copyright (C) 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 java.awt; + +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.peer.ScrollbarPeer; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleValue; + +/** + * This class implements a scrollbar widget. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class Scrollbar extends Component implements Accessible, Adjustable +{ + // FIXME: Serialization readObject/writeObject + + /** + * Constant indicating that a scrollbar is horizontal. + */ + public static final int HORIZONTAL = 0; + + /** + * Constant indicating that a scrollbar is vertical. + */ + public static final int VERTICAL = 1; + + /** + * Serialization Constant. + */ + private static final long serialVersionUID = 8451667562882310543L; + + /** + * @serial The amount by which the value of the scrollbar is changed + * when incrementing in line mode. + */ + private int lineIncrement; + + /** + * @serial The amount by which the value of the scrollbar is changed + * when incrementing in page mode. + */ + private int pageIncrement; + + /** + * @serial The maximum value for this scrollbar + */ + private int maximum; + + /** + * @serial The minimum value for this scrollbar + */ + private int minimum; + + /** + * @serial The orientation of this scrollbar, which will be either + * the HORIZONTAL or VERTICAL constant + * from this class. + */ + private int orientation; + + /** + * @serial The current value of this scrollbar. + */ + private int value; + + /** + * @serial The width of the scrollbar's thumb, which is relative + * to the minimum and maximum value of the scrollbar. + */ + private int visibleAmount; + + /** + * List of AdjustmentListener's. + */ + private AdjustmentListener adjustment_listeners; + + /** + * true if the scrollbar is adjusting, false otherwise. + */ + private transient boolean valueIsAdjusting = false; + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_scrollbar_number; + + /** + * Initializes a new instance of Scrollbar with a + * vertical orientation and default values for all other parameters. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public Scrollbar() + { + this(VERTICAL); + } + + /** + * Initializes a new instance of Scrollbar with the + * specified orientation and default values for all other parameters. + * The orientation must be either the constant HORIZONTAL or + * VERTICAL from this class. An incorrect value will throw + * an exception. + * + * @param orientation The orientation of this scrollbar. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + * @exception IllegalArgumentException If the orientation value is not valid. + */ + public Scrollbar(int orientation) throws IllegalArgumentException + { + this(orientation, 0, 10, 0, 100); + } + + /** + * Initializes a new instance of Scrollbar with the + * specified parameters. The orientation must be either the constant + * HORIZONTAL or VERTICAL. An incorrect value + * will throw an exception. Inconsistent values for other parameters + * are silently corrected to valid values. + * + * @param orientation The orientation of this scrollbar. + * @param value The initial value of the scrollbar. + * @param visibleAmount The width of the scrollbar thumb. + * @param minimum The minimum value of the scrollbar. + * @param maximum The maximum value of the scrollbar. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + * @exception IllegalArgumentException If the orientation value is not valid. + */ + public Scrollbar(int orientation, int value, int visibleAmount, int minimum, + int maximum) throws IllegalArgumentException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + + if ((orientation != HORIZONTAL) && (orientation != VERTICAL)) + throw new IllegalArgumentException("Bad orientation value: " + + orientation); + + this.orientation = orientation; + + setValues(value, visibleAmount, minimum, maximum); + + // Default is 1 according to online docs. + lineIncrement = 1; + + // Default is 10 according to javadocs. + pageIncrement = 10; + } + + /** + * Returns the orientation constant for this object. + * + * @return The orientation constant for this object. + */ + public int getOrientation() + { + return orientation; + } + + /** + * Sets the orientation of this scrollbar to the specified value. This + * value must be either the constant HORIZONTAL or + * VERTICAL from this class or an exception will be thrown. + * + * @param orientation The new orientation value. + * + * @exception IllegalArgumentException If the orientation value is not valid. + */ + public void setOrientation(int orientation) + { + if ((orientation != HORIZONTAL) && (orientation != VERTICAL)) + throw new IllegalArgumentException("Bad orientation value: " + + orientation); + + // FIXME: Communicate to peer? Or must this be called before peer creation? + this.orientation = orientation; + } + + /** + * Returns the current value for this scrollbar. + * + * @return The current value for this scrollbar. + */ + public int getValue() + { + return value; + } + + /** + * Sets the current value for this scrollbar to the specified value. + * If this is inconsistent with the minimum and maximum values for this + * scrollbar, the value is silently adjusted. + * + * @param value The new value for this scrollbar. + */ + public void setValue(int value) + { + setValues(value, visibleAmount, minimum, maximum); + } + + /** + * Returns the maximum value for this scrollbar. + * + * @return The maximum value for this scrollbar. + */ + public int getMaximum() + { + return maximum; + } + + /** + * Sets the maximum value for this scrollbar to the specified value. + * If the value is less than the current minimum value, it is silent + * set to equal the minimum value. + * + * @param maximum The new maximum value for this scrollbar. + */ + public void setMaximum(int maximum) + { + setValues(value, visibleAmount, minimum, maximum); + } + + /** + * Returns the minimum value for this scrollbar. + * + * @return The minimum value for this scrollbar. + */ + public int getMinimum() + { + return minimum; + } + + /** + * Sets the minimum value for this scrollbar to the specified value. If + * this is not consistent with the current value and maximum, it is + * silently adjusted to be consistent. + * + * @param minimum The new minimum value for this scrollbar. + */ + public void setMinimum(int minimum) + { + setValues(value, visibleAmount, minimum, maximum); + } + + /** + * Returns the width of the scrollbar's thumb, in units relative to the + * maximum and minimum value of the scrollbar. + * + * @return The width of the scrollbar's thumb. + */ + public int getVisibleAmount() + { + return getVisible(); + } + + /** + * Returns the width of the scrollbar's thumb, in units relative to the + * maximum and minimum value of the scrollbar. + * + * @return The width of the scrollbar's thumb. + * + * @deprecated This method is deprecated in favor of + * getVisibleAmount(). + */ + public int getVisible() + { + return visibleAmount; + } + + /** + * Sets the width of the scrollbar's thumb, in units relative to the + * maximum and minimum value of the scrollbar. + * + * @param visibleAmount The new visible amount value of the scrollbar. + */ + public void setVisibleAmount(int visibleAmount) + { + setValues(value, visibleAmount, minimum, maximum); + } + + /** + * Sets the current value, visible amount, minimum, and maximum for this + * scrollbar. These values are adjusted to be internally consistent + * if necessary. + * + * @param value The new value for this scrollbar. + * @param visibleAmount The new visible amount for this scrollbar. + * @param minimum The new minimum value for this scrollbar. + * @param maximum The new maximum value for this scrollbar. + */ + public synchronized void setValues(int value, int visibleAmount, + int minimum, int maximum) + { + if (maximum < minimum) + maximum = minimum; + + if (value < minimum) + value = minimum; + + if (value > maximum) + value = maximum; + + if (visibleAmount > maximum - minimum) + visibleAmount = maximum - minimum; + + ScrollbarPeer peer = (ScrollbarPeer) getPeer(); + if (peer != null + && (this.value != value || this.visibleAmount != visibleAmount + || this.minimum != minimum || this.maximum != maximum)) + peer.setValues(value, visibleAmount, minimum, maximum); + + this.value = value; + this.visibleAmount = visibleAmount; + this.minimum = minimum; + this.maximum = maximum; + + int range = maximum - minimum; + if (lineIncrement > range) + { + if (range == 0) + lineIncrement = 1; + else + lineIncrement = range; + + if (peer != null) + peer.setLineIncrement(lineIncrement); + } + + if (pageIncrement > range) + { + if (range == 0) + pageIncrement = 1; + else + pageIncrement = range; + + if (peer != null) + peer.setPageIncrement(pageIncrement); + } + } + + /** + * Returns the value added or subtracted when the user activates the scrollbar + * scroll by a "unit" amount. + * + * @return The unit increment value. + */ + public int getUnitIncrement() + { + return getLineIncrement(); + } + + /** + * Returns the value added or subtracted when the user selects the scrollbar + * scroll by a "unit" amount control. + * + * @return The unit increment value. + * + * @deprecated This method is deprecated in favor of + * getUnitIncrement(). + */ + public int getLineIncrement() + { + return lineIncrement; + } + + /** + * Sets the value added or subtracted to the scrollbar value when the + * user selects the scroll by a "unit" amount control. + * + * @param unitIncrement The new unit increment amount. + */ + public synchronized void setUnitIncrement(int unitIncrement) + { + setLineIncrement(unitIncrement); + } + + /** + * Sets the value added or subtracted to the scrollbar value when the + * user selects the scroll by a "unit" amount control. + * + * @param lineIncrement The new unit increment amount. + * + * @deprecated This method is deprecated in favor of + * setUnitIncrement(). + */ + public void setLineIncrement(int lineIncrement) + { + if (lineIncrement < 0) + throw new IllegalArgumentException("Unit increment less than zero."); + + int range = maximum - minimum; + if (lineIncrement > range) + { + if (range == 0) + lineIncrement = 1; + else + lineIncrement = range; + } + + if (lineIncrement == this.lineIncrement) + return; + + this.lineIncrement = lineIncrement; + + ScrollbarPeer peer = (ScrollbarPeer) getPeer(); + if (peer != null) + peer.setLineIncrement(this.lineIncrement); + } + + /** + * Returns the value added or subtracted when the user activates the scrollbar + * scroll by a "block" amount. + * + * @return The block increment value. + */ + public int getBlockIncrement() + { + return getPageIncrement(); + } + + /** + * Returns the value added or subtracted when the user selects the scrollbar + * scroll by a "block" amount control. + * + * @return The block increment value. + * + * @deprecated This method is deprecated in favor of + * getBlockIncrement(). + */ + public int getPageIncrement() + { + return pageIncrement; + } + + /** + * Sets the value added or subtracted to the scrollbar value when the + * user selects the scroll by a "block" amount control. + * + * @param blockIncrement The new block increment amount. + */ + public synchronized void setBlockIncrement(int blockIncrement) + { + setPageIncrement(blockIncrement); + } + + /** + * Sets the value added or subtracted to the scrollbar value when the + * user selects the scroll by a "block" amount control. + * + * @param pageIncrement The new block increment amount. + * + * @deprecated This method is deprecated in favor of + * setBlockIncrement(). + */ + public void setPageIncrement(int pageIncrement) + { + if (pageIncrement < 0) + throw new IllegalArgumentException("Block increment less than zero."); + + int range = maximum - minimum; + if (pageIncrement > range) + { + if (range == 0) + pageIncrement = 1; + else + pageIncrement = range; + } + + if (pageIncrement == this.pageIncrement) + return; + + this.pageIncrement = pageIncrement; + + ScrollbarPeer peer = (ScrollbarPeer) getPeer(); + if (peer != null) + peer.setPageIncrement(this.pageIncrement); + } + + /** + * Notifies this object to create its native peer. + */ + public synchronized void addNotify() + { + if (peer == null) + peer = getToolkit().createScrollbar(this); + super.addNotify(); + } + + /** + * Adds a new adjustment listener to the list of registered listeners + * for this object. + * + * @param listener The listener to add. + */ + public synchronized void addAdjustmentListener(AdjustmentListener listener) + { + adjustment_listeners = AWTEventMulticaster.add(adjustment_listeners, + listener); + enableEvents(AWTEvent.ADJUSTMENT_EVENT_MASK); + } + + /** + * Removes the specified listener from the list of registered listeners + * for this object. + * + * @param listener The listener to remove. + */ + public synchronized void removeAdjustmentListener(AdjustmentListener listener) + { + adjustment_listeners = AWTEventMulticaster.remove(adjustment_listeners, + listener); + } + + /** + * Processes events for this scrollbar. It does this by calling + * processAdjustmentEvent() if the event is an instance of + * AdjustmentEvent, otherwise it calls the superclass to + * process the event. + * + * @param event The event to process. + */ + protected void processEvent(AWTEvent event) + { + if (event instanceof AdjustmentEvent) + processAdjustmentEvent((AdjustmentEvent) event); + else + super.processEvent(event); + } + + /** + * Processes adjustment events for this object by dispatching them to + * any registered listeners. Note that this method will only be called + * if adjustment events are enabled. This will happen automatically if + * any listeners are registered. Otherwise, it can be enabled by a + * call to enableEvents(). + * + * @param event The event to process. + */ + protected void processAdjustmentEvent(AdjustmentEvent event) + { + value = event.getValue(); + if (adjustment_listeners != null) + adjustment_listeners.adjustmentValueChanged(event); + } + + void dispatchEventImpl(AWTEvent e) + { + if (e.id <= AdjustmentEvent.ADJUSTMENT_LAST + && e.id >= AdjustmentEvent.ADJUSTMENT_FIRST + && (adjustment_listeners != null + || (eventMask & AWTEvent.ADJUSTMENT_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); + } + + /** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ + protected String paramString() + { + return ("value=" + getValue() + ",visibleAmount=" + getVisibleAmount() + + ",minimum=" + getMinimum() + ",maximum=" + getMaximum() + + ",pageIncrement=" + pageIncrement + ",lineIncrement=" + + lineIncrement + ",orientation=" + + (orientation == HORIZONTAL ? "HORIZONTAL" : "VERTICAL") + + super.paramString()); + } + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this Scrollbar. FooListeners are registered using the + * addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + */ + public EventListener[] getListeners(Class listenerType) + { + if (listenerType == AdjustmentListener.class) + return AWTEventMulticaster.getListeners(adjustment_listeners, + listenerType); + + return super.getListeners(listenerType); + } + + /** + * Returns an array of all registered adjustment listeners. + */ + public AdjustmentListener[] getAdjustmentListeners() + { + return (AdjustmentListener[]) getListeners(AdjustmentListener.class); + } + + /** + * Returns true if the value is in the process of changing. + * + * @since 1.4 + */ + public boolean getValueIsAdjusting() + { + return valueIsAdjusting; + } + + /** + * Sets the value of valueIsAdjusting. + * + * @since 1.4 + */ + public void setValueIsAdjusting(boolean valueIsAdjusting) + { + this.valueIsAdjusting = valueIsAdjusting; + } + + /** + * Generate a unique name for this scroll bar. + * + * @return A unique name for this scroll bar. + */ + String generateName() + { + return "scrollbar" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_scrollbar_number++; + } + + /** + * This class provides accessibility support for the + * scrollbar. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + protected class AccessibleAWTScrollBar extends AccessibleAWTComponent + implements AccessibleValue + { + /** + * Serialization constant to match JDK 1.5 + */ + private static final long serialVersionUID = -344337268523697807L; + + /** + * Returns the role of this accessible object. + * + * @return the instance of AccessibleRole, + * which describes this object. + * + * @see javax.accessibility.AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.SCROLL_BAR; + } + + /** + * Returns the state set of this accessible object. + * + * @return a set of AccessibleStates which + * represent the current state of the accessible object. + * + * @see javax.accessibility.AccessibleState + * @see javax.accessibility.AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (getOrientation() == HORIZONTAL) + states.add(AccessibleState.HORIZONTAL); + else + states.add(AccessibleState.VERTICAL); + if (getValueIsAdjusting()) + states.add(AccessibleState.BUSY); + return states; + } + + /** + * Returns an implementation of the AccessibleValue + * interface for this accessible object. In this case, the + * current instance is simply returned (with a more appropriate + * type), as it also implements the accessible value as well as + * the context. + * + * @return the accessible value associated with this context. + * + * @see javax.accessibility.AccessibleValue + */ + public AccessibleValue getAccessibleValue() + { + return this; + } + + /** + * Returns the current value of this accessible object. + * In this case, this is the same as the value for + * the scrollbar, wrapped in an Integer + * object. + * + * @return the numeric value of this scrollbar. + * + * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() + */ + public Number getCurrentAccessibleValue() + { + return new Integer(getValue()); + } + + /** + * Sets the current value of this accessible object + * to that supplied. In this case, the value of the + * scrollbar is set, and this method always returns + * true. + * + * @param number the new accessible value. + * + * @return true if the value was set. + * + * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) + */ + public boolean setCurrentAccessibleValue(Number number) + { + setValue(number.intValue()); + return true; + } + + /** + * Returns the minimum acceptable accessible value used + * by this object. In this case, this is the same as + * the minimum value of the scrollbar, wrapped in an + * object. + * + * @return the minimum value of this scrollbar. + * + * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() + */ + public Number getMinimumAccessibleValue() + { + return new Integer(getMinimum()); + } + + /** + * Returns the maximum acceptable accessible value used + * by this object. In this case, this is the same as + * the maximum value of the scrollbar, wrapped in an + * object. + * + * @return the maximum value of this scrollbar. + * + * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() + */ + public Number getMaximumAccessibleValue() + { + return new Integer(getMaximum()); + } + } + + /** + * Gets the AccessibleContext associated with this Scrollbar. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTScrollBar(); + + return accessibleContext; + } +} diff --git a/libjava/classpath/java/awt/Shape.java b/libjava/classpath/java/awt/Shape.java new file mode 100644 index 0000000..bd8a434 --- /dev/null +++ b/libjava/classpath/java/awt/Shape.java @@ -0,0 +1,203 @@ +/* Shape.java -- the classic Object-Oriented shape interface + Copyright (C) 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 java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * This interface represents an abstract shape. The shape is described by + * a {@link PathIterator}, and has callbacks for determining bounding box, + * where points and rectangles lie in relation to the shape, and tracing + * the trajectory. + * + *

A point is inside if it is completely inside, or on the boundary and + * adjacent points in the increasing x or y direction are completely inside. + * Unclosed shapes are considered as implicitly closed when performing + * contains or intersects. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see PathIterator + * @see AffineTransform + * @see java.awt.geom.FlatteningPathIterator + * @see java.awt.geom.GeneralPath + * @since 1.0 + * @status updated to 1.4 + */ +public interface Shape +{ + /** + * Returns a Rectange that bounds the shape. There is no + * guarantee that this is the minimum bounding box, particularly if + * the shape overflows the finite integer range of a bound. Generally, + * getBounds2D returns a tighter bound. + * + * @return the shape's bounding box + * @see #getBounds2D() + */ + Rectangle getBounds(); + + /** + * Returns a high precision bounding box of the shape. There is no guarantee + * that this is the minimum bounding box, but at least it never overflows. + * + * @return the shape's bounding box + * @see #getBounds() + * @since 1.2 + */ + Rectangle2D getBounds2D(); + + /** + * Test if the coordinates lie in the shape. + * + * @param x the x coordinate + * @param y the y coordinate + * @return true if (x,y) lies inside the shape + * @since 1.2 + */ + boolean contains(double x, double y); + + /** + * Test if the point lie in the shape. + * + * @param p the high-precision point + * @return true if p lies inside the shape + * @throws NullPointerException if p is null + * @since 1.2 + */ + boolean contains(Point2D p); + + /** + * Test if a high-precision rectangle intersects the shape. This is true + * if any point in the rectangle is in the shape, with the caveat that the + * operation may include high probability estimates when the actual + * calculation is prohibitively expensive. The {@link java.awt.geom.Area} + * class can be used for more precise answers. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle, undefined results if negative + * @param h the height of the rectangle, undefined results if negative + * @return true if the rectangle intersects this shape + * @see java.awt.geom.Area + * @since 1.2 + */ + boolean intersects(double x, double y, double w, double h); + + /** + * Test if a high-precision rectangle intersects the shape. This is true + * if any point in the rectangle is in the shape, with the caveat that the + * operation may include high probability estimates when the actual + * calculation is prohibitively expensive. The {@link java.awt.geom.Area} + * class can be used for more precise answers. + * + * @param r the rectangle + * @return true if the rectangle intersects this shape + * @throws NullPointerException if r is null + * @see #intersects(double, double, double, double) + * @since 1.2 + */ + boolean intersects(Rectangle2D r); + + /** + * Test if a high-precision rectangle lies completely in the shape. This is + * true if all points in the rectangle are in the shape, with the caveat + * that the operation may include high probability estimates when the actual + * calculation is prohibitively expensive. The {@link java.awt.geom.Area} + * class can be used for more precise answers. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle, undefined results if negative + * @param h the height of the rectangle, undefined results if negative + * @return true if the rectangle is contained in this shape + * @see java.awt.geom.Area + * @since 1.2 + */ + boolean contains(double x, double y, double w, double h); + + /** + * Test if a high-precision rectangle lies completely in the shape. This is + * true if all points in the rectangle are in the shape, with the caveat + * that the operation may include high probability estimates when the actual + * calculation is prohibitively expensive. The {@link java.awt.geom.Area} + * class can be used for more precise answers. + * + * @param r the rectangle + * @return true if the rectangle is contained in this shape + * @throws NullPointerException if r is null + * @see #contains(double, double, double, double) + * @since 1.2 + */ + boolean contains(Rectangle2D r); + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. Each call returns + * a new object, independent from others in use. It is recommended, but + * not required, that the Shape isolate iterations from future changes to + * the boundary, and document this fact. + * + * @param transform an optional transform to apply to the iterator + * @return a new iterator over the boundary + * @since 1.2 + */ + PathIterator getPathIterator(AffineTransform transform); + + /** + * Return an iterator along the flattened version of the shape boundary. + * Only SEG_MOVETO, SEG_LINETO, and SEG_CLOSE points are returned in the + * iterator. The flatness paramter controls how far points are allowed to + * differ from the real curve; although a limit on accuracy may cause this + * parameter to be enlarged if needed. + * + *

If the optional transform is provided, the iterator is transformed + * accordingly. Each call returns a new object, independent from others in + * use. It is recommended, but not required, that the Shape isolate + * iterations from future changes to the boundary, and document this fact. + * + * @param transform an optional transform to apply to the iterator + * @param flatness the maximum distance for deviation from the real boundary + * @return a new iterator over the boundary + * @since 1.2 + */ + PathIterator getPathIterator(AffineTransform transform, double flatness); +} // interface Shape diff --git a/libjava/classpath/java/awt/Stroke.java b/libjava/classpath/java/awt/Stroke.java new file mode 100644 index 0000000..1a4c61c --- /dev/null +++ b/libjava/classpath/java/awt/Stroke.java @@ -0,0 +1,65 @@ +/* Stroke.java -- a stroked outline of a shape + 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 java.awt; + +/** + * This interface allows a Graphics2D to grab the outline of a shape, as if + * stroked by a marking pen of appropriate size and shape. The area inked + * by the pen is the area of this stroke. Anything in the graphic which + * traces an outline will use this stroke, such as drawLine. + * Strokes must be immutable, because the graphics object does not clone + * them. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see BasicStroke + * @see Graphics2D#setStroke(Stroke) + * @since 1.1 + * @status updated to 1.4 + */ +public interface Stroke +{ + /** + * Returns a shape which outlines the boundary of the given shape, in + * effect converting the infinitely thin line into a new shape. + * + * @param s the shape to stroke + * @return the stroked outline shape + */ + Shape createStrokedShape(Shape s); +} // interface Stroke diff --git a/libjava/classpath/java/awt/SystemColor.java b/libjava/classpath/java/awt/SystemColor.java new file mode 100644 index 0000000..2ead74a --- /dev/null +++ b/libjava/classpath/java/awt/SystemColor.java @@ -0,0 +1,462 @@ +/* SystemColor.java -- access dynamic system color values + Copyright (C) 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 java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.io.Serializable; + +/** + * This class contains the various "system colors" in use by the native + * windowing system. The getRGB() method is dynamic on systems + * which support dynamic system color changes, and most methods in the + * superclass are written to use this dynamic value when reporting colors. + * However, the equals() method is not dynamic, and does not + * track the actual color of instances in this class. This means that equals + * may give surprising results; you are better off relying on getRGB. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public final class SystemColor extends Color implements Serializable +{ + // Implementation note: To be serial compatible with JDK, this class must + // violate the semantic meaning of super.value to be one of the + // NUM_COLORS constants instead of the actual RGB value. Hence there are + // a lot of ugly workarounds in Color and in this class. I would have + // designed it MUCH differently, making a separate id field in this class. + + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 4503142729533789064L; + + /** + * Array index of the desktop color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #desktop + */ + public static final int DESKTOP = 0; + + /** + * Array index of the active caption color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #activeCaption + */ + public static final int ACTIVE_CAPTION = 1; + + /** + * Array index of the active caption text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #activeCaptionText + */ + public static final int ACTIVE_CAPTION_TEXT = 2; + + /** + * Array index of the active caption border color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #activeCaptionBorder + */ + public static final int ACTIVE_CAPTION_BORDER = 3; + + /** + * Array index of the inactive caption color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #inactiveCaption + */ + public static final int INACTIVE_CAPTION = 4; + + /** + * Array index of the inactive caption text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #inactiveCaptionText + */ + public static final int INACTIVE_CAPTION_TEXT = 5; + + /** + * Array index of the inactive caption border color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #inactiveCaptionBorder + */ + public static final int INACTIVE_CAPTION_BORDER = 6; + + /** + * Array index of the window background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #window + */ + public static final int WINDOW = 7; + + /** + * Array index of the window border color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #windowBorder + */ + public static final int WINDOW_BORDER = 8; + + /** + * Array index of the window text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #windowText + */ + public static final int WINDOW_TEXT = 9; + + /** + * Array index of the menu background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #menu + */ + public static final int MENU = 10; + + /** + * Array index of the menu text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #menuText + */ + public static final int MENU_TEXT = 11; + + /** + * Array index of the text background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #text + */ + public static final int TEXT = 12; + + /** + * Array index of the text foreground color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #textText + */ + public static final int TEXT_TEXT = 13; + + /** + * Array index of the highlighted text background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #textHighlight + */ + public static final int TEXT_HIGHLIGHT = 14; + + /** + * Array index of the highlighted text foreground color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #textHighlightText + */ + public static final int TEXT_HIGHLIGHT_TEXT = 15; + + /** + * Array index of the inactive text foreground color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #textInactiveText + */ + public static final int TEXT_INACTIVE_TEXT = 16; + + /** + * Array index of the control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #control + */ + public static final int CONTROL = 17; + + /** + * Array index of the control text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlText + */ + public static final int CONTROL_TEXT = 18; + + /** + * Array index of the highlighted control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlHighlight + */ + public static final int CONTROL_HIGHLIGHT = 19; + + /** + * Array index of the lightly highlighted control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlLtHighlight + */ + public static final int CONTROL_LT_HIGHLIGHT = 20; + + /** + * Array index of the shadowed control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlShadow + */ + public static final int CONTROL_SHADOW = 21; + + /** + * Array index of the darkly shadowed control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlDkShadow + */ + public static final int CONTROL_DK_SHADOW = 22; + + /** + * Array index of the scrollbar background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #scrollbar + */ + public static final int SCROLLBAR = 23; + + /** + * Array index of the info background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #info + */ + public static final int INFO = 24; + + /** + * Array index of the info text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #infoText + */ + public static final int INFO_TEXT = 25; + + /** + * The number of system colors. Used by + * {@link Toolkit#loadSystemColors(int[])}. + */ + public static final int NUM_COLORS = 26; + + /** + * The internal array used to dynamically update getRGB(). + */ + private static final int[] colors = new int[NUM_COLORS]; + + /** The desktop color. */ + public static final SystemColor desktop + = new SystemColor(DESKTOP); + + /** The active caption background color. */ + public static final SystemColor activeCaption + = new SystemColor(ACTIVE_CAPTION); + + /** The active caption text color. */ + public static final SystemColor activeCaptionText + = new SystemColor(ACTIVE_CAPTION_TEXT); + + /** The active caption border color. */ + public static final SystemColor activeCaptionBorder + = new SystemColor(ACTIVE_CAPTION_BORDER); + + /** The inactive caption background color. */ + public static final SystemColor inactiveCaption + = new SystemColor(INACTIVE_CAPTION); + + /** The inactive caption text color. */ + public static final SystemColor inactiveCaptionText + = new SystemColor(INACTIVE_CAPTION_TEXT); + + /** The inactive caption border color. */ + public static final SystemColor inactiveCaptionBorder + = new SystemColor(INACTIVE_CAPTION_BORDER); + + /** The window background color. */ + public static final SystemColor window + = new SystemColor(WINDOW); + + /** The window border color. */ + public static final SystemColor windowBorder + = new SystemColor(WINDOW_BORDER); + + /** The window text color. */ + public static final SystemColor windowText + = new SystemColor(WINDOW_TEXT); + + /** The menu background color. */ + public static final SystemColor menu + = new SystemColor(MENU); + + /** The menu text color. */ + public static final SystemColor menuText + = new SystemColor(MENU_TEXT); + + /** The text background color. */ + public static final SystemColor text + = new SystemColor(TEXT); + + /** The text foreground color. */ + public static final SystemColor textText + = new SystemColor(TEXT_TEXT); + + /** The highlighted text background color. */ + public static final SystemColor textHighlight + = new SystemColor(TEXT_HIGHLIGHT); + + /** The highlighted text foreground color. */ + public static final SystemColor textHighlightText + = new SystemColor(TEXT_HIGHLIGHT_TEXT); + + /** The inactive text color. */ + public static final SystemColor textInactiveText + = new SystemColor(TEXT_INACTIVE_TEXT); + + /** The control background color. */ + public static final SystemColor control + = new SystemColor(CONTROL); + + /** The control text color. */ + public static final SystemColor controlText + = new SystemColor(CONTROL_TEXT); + + /** The control highlight color. */ + public static final SystemColor controlHighlight + = new SystemColor(CONTROL_HIGHLIGHT); + + /** The control light highlight color. */ + public static final SystemColor controlLtHighlight + = new SystemColor(CONTROL_LT_HIGHLIGHT); + + /** The control shadow color. */ + public static final SystemColor controlShadow + = new SystemColor(CONTROL_SHADOW); + + /** The control dark shadow color. */ + public static final SystemColor controlDkShadow + = new SystemColor(CONTROL_DK_SHADOW); + + /** The scrollbar color. */ + public static final SystemColor scrollbar + = new SystemColor(SCROLLBAR); + + /** The info text background color. */ + public static final SystemColor info + = new SystemColor(INFO); + + /** The info text foreground color. */ + public static final SystemColor infoText + = new SystemColor(INFO_TEXT); + + /** + * Construct a system color which is dynamically updated. + * + * @param id the color id + */ + private SystemColor(int id) + { + // Note: See Color#Color(int, boolean) to explain why we use this + // particular constructor. + super(id, true); + } + + /** + * Returns the RGB value for this color, in the sRGB color space. The blue + * value will be in bits 0-7, green in 8-15, red in 6-23, and the alpha + * value (bits 24-31) is 0xff. This is dynamically updated, so it may not + * match the results of getRed(), getGreen(), or + * getBlue(). + * + * @return the current RGB value + */ + public int getRGB() + { + Toolkit.getDefaultToolkit().loadSystemColors(colors); + return colors[value] | ALPHA_MASK; + } + + /** + * Returns a paint context, used for filling areas of a raster scan with + * the current value of this system color. Since the system colors may be + * dynamically updated, the returned value may not always be the same; but + * as the system color is solid, the context does not need any of the + * passed parameters to do its job. + * + * @param cm the requested color model + * @param deviceBounds the bounding box in device coordinates, ignored + * @param userBounds the bounding box in user coordinates, ignored + * @param xform the bounds transformation, ignored + * @param hints any rendering hints, ignored + * @return a context for painting this solid color + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + Toolkit.getDefaultToolkit().loadSystemColors(colors); + int color = colors[value] | ALPHA_MASK; + if (context == null || color != context.color || !context.getColorModel().equals(cm)) + context = new ColorPaintContext(cm,color); + return context; + } + + /** + * Returns a string describing this color. This is in the format + * "java.awt.SystemColor[i=" + index + ']', where index is one of the + * integer constants of this class. Unfortunately, this description + * does not describe the current value of the color; for that you should + * use new Color(syscolor.getRGB()).toString(). + * + * @return a string describing this color + */ + public String toString() + { + return "java.awt.SystemColor[i=" + value + ']'; + } +} // class SystemColor diff --git a/libjava/classpath/java/awt/TextArea.java b/libjava/classpath/java/awt/TextArea.java new file mode 100644 index 0000000..d422d33 --- /dev/null +++ b/libjava/classpath/java/awt/TextArea.java @@ -0,0 +1,629 @@ +/* TextArea.java -- A multi-line text entry component + 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 java.awt; + +import java.awt.event.KeyEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.TextAreaPeer; +import java.util.HashSet; +import java.util.Set; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleStateSet; + + +/** + * A TextArea is a text component capable of displaying multiple lines + * of user-editable text. A TextArea handles its own scrolling and + * can display vertical and horizontal scrollbars as navigation aids. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class TextArea extends TextComponent implements java.io.Serializable +{ + /** + * Display both horiztonal and vertical scroll bars. + */ + public static final int SCROLLBARS_BOTH = 0; + + /** + * Display vertical scroll bar only. + */ + public static final int SCROLLBARS_VERTICAL_ONLY = 1; + + /** + * Display horizatonal scroll bar only. + */ + public static final int SCROLLBARS_HORIZONTAL_ONLY = 2; + + /** + * Do not display scrollbars. + */ + public static final int SCROLLBARS_NONE = 3; + + /** + * Serialization constant. + */ + private static final long serialVersionUID = 3692302836626095722L; + + /** + * @serial The number of columns used in this text area's preferred + * and minimum size calculations. + */ + private int columns; + + /** + * @serial The number of rows used in this text area's preferred and + * minimum size calculations. + */ + private int rows; + + /** + * @serial The scrollbar display policy. One of SCROLLBARS_BOTH, + * SCROLLBARS_VERTICAL_ONLY, SCROLLBARS_HORIZONTAL_ONLY, + * SCROLLBARS_NONE. + */ + private int scrollbarVisibility; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_text_number; + + /** + * Initialize a new instance of TextArea that is empty. + * Conceptually the TextArea has 0 rows and 0 columns + * but its initial bounds are defined by its peer or by the + * container in which it is packed. Both horizontal and vertical + * scrollbars will be displayed. + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea () + { + this ("", 0, 0, SCROLLBARS_BOTH); + } + + /** + * Initialize a new instance of TextArea that contains + * the specified text. Conceptually the TextArea has 0 + * rows and 0 columns but its initial bounds are defined by its peer + * or by the container in which it is packed. Both horizontal and + * veritcal scrollbars will be displayed. + * + * @param text The text to display in this text area. + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea (String text) + { + this (text, 0, 0, SCROLLBARS_BOTH); + } + + /** + * Initialize a new instance of TextArea that is empty + * and can display the specified number of rows and columns of text, + * without the need to scroll. Both horizontal and vertical + * scrollbars will be displayed. + * + * @param rows The number of rows in this text area. + * @param columns The number of columns in this text area. + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea (int rows, int columns) + { + this ("", rows, columns, SCROLLBARS_BOTH); + } + + /** + * Initialize a new instance of TextArea that can + * display the specified number of rows and columns of text, without + * the need to scroll. The TextArea initially contains the + * specified text. + * + * @param text The text to display in this text area. + * @param rows The number of rows in this text area. + * @param columns The number of columns in this text area. + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea (String text, int rows, int columns) + { + this (text, rows, columns, SCROLLBARS_BOTH); + } + + /** + * Initialize a new instance of TextArea that initially + * contains the specified text. The TextArea can display the + * specified number of rows and columns of text, without the need to + * scroll. This constructor allows specification of the scroll bar + * display policy. + * + * @param text The text to display in this text area. + * @param rows The number of rows in this text area. + * @param columns The number of columns in this text area. + * @param scrollbarVisibility The scroll bar display policy. One of + * SCROLLBARS_BOTH, SCROLLBARS_VERTICAL_ONLY, + * SCROLLBARS_HORIZONTAL_ONLY, SCROLLBARS_NONE. + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea (String text, int rows, int columns, int scrollbarVisibility) + { + super (text); + + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); + + if (rows < 0 || columns < 0) + throw new IllegalArgumentException ("Bad row or column value"); + + if (scrollbarVisibility != SCROLLBARS_BOTH + && scrollbarVisibility != SCROLLBARS_VERTICAL_ONLY + && scrollbarVisibility != SCROLLBARS_HORIZONTAL_ONLY + && scrollbarVisibility != SCROLLBARS_NONE) + throw new IllegalArgumentException ("Bad scrollbar visibility value"); + + this.rows = rows; + this.columns = columns; + this.scrollbarVisibility = scrollbarVisibility; + + // TextAreas need to receive tab key events so we override the + // default forward and backward traversal key sets. + Set s = new HashSet (); + s.add (AWTKeyStroke.getAWTKeyStroke (KeyEvent.VK_TAB, + KeyEvent.CTRL_DOWN_MASK)); + setFocusTraversalKeys (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, s); + s = new HashSet (); + s.add (AWTKeyStroke.getAWTKeyStroke (KeyEvent.VK_TAB, + KeyEvent.SHIFT_DOWN_MASK + | KeyEvent.CTRL_DOWN_MASK)); + setFocusTraversalKeys (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, s); + } + + /** + * Retrieve the number of columns that this text area would prefer + * to display. This value may or may not correspond to the number + * of columns that are actually displayed. + * + * @return The preferred number of columns. + */ + public int getColumns () + { + return columns; + } + + /** + * Set the preferred number of columns for this text area. This + * method does not cause the number of columns displayed by the text + * area to be updated, if the text area is currently visible. + * + * @param columns The preferred number of columns. + * + * @exception IllegalArgumentException If columns is less than zero. + */ + public synchronized void setColumns (int columns) + { + if (columns < 0) + throw new IllegalArgumentException ("Value is less than zero: " + + columns); + + this.columns = columns; + } + + /** + * Retrieve the number of rows that this text area would prefer to + * display. This value may or may not correspond to the number of + * rows that are actually displayed. + * + * @return The preferred number of rows. + */ + public int getRows () + { + return rows; + } + + /** + * Set the preferred number of rows for this text area. This method + * does not cause the number of columns displayed by the text area + * to be updated, if the text area is currently visible. + * + * @param rows The preferred number of rows. + * + * @exception IllegalArgumentException If rows is less than zero. + */ + public synchronized void setRows (int rows) + { + if (rows < 1) + throw new IllegalArgumentException ("Value is less than one: " + rows); + + this.rows = rows; + } + + /** + * Retrieve the minimum size for this text area, considering the + * text area's current row and column values. A text area's minimum + * size depends on the number of rows and columns of text it would + * prefer to display, and on the size of the font in which the text + * would be displayed. + * + * @return The minimum size for this text field. + */ + public Dimension getMinimumSize () + { + return getMinimumSize (getRows (), getColumns ()); + } + + /** + * Retrieve the minimum size that this text area would have if its + * row and column values were equal to those specified. A text + * area's minimum size depends on the number of rows and columns of + * text it would prefer to display, and on the size of the font in + * which the text would be displayed. + * + * @param rows The number of rows to use in the minimum size + * calculation. + * @param columns The number of columns to use in the minimum size + * calculation. + * + * @return The minimum size for this text area. + */ + public Dimension getMinimumSize (int rows, int columns) + { + return minimumSize (rows, columns); + } + + /** + * Retrieve the minimum size for this text area, considering the + * text area's current row and column values. A text area's minimum + * size depends on the number of rows and columns of text it would + * prefer to display, and on the size of the font in which the text + * would be displayed. + * + * @return The minimum size for this text area. + * + * @deprecated This method is deprecated in favor of + * getMinimumSize (). + */ + public Dimension minimumSize () + { + return minimumSize (getRows (), getColumns ()); + } + + /** + * Retrieve the minimum size that this text area would have if its + * row and column values were equal to those specified. A text + * area's minimum size depends on the number of rows and columns of + * text it would prefer to display, and on the size of the font in + * which the text would be displayed. + * + * @param rows The number of rows to use in the minimum size + * calculation. + * @param columns The number of columns to use in the minimum size + * calculation. + * + * @return The minimum size for this text area. + * + * @deprecated This method is deprecated in favor of + * getMinimumSize (int, int). + */ + public Dimension minimumSize (int rows, int columns) + { + TextAreaPeer peer = (TextAreaPeer) getPeer (); + + // Sun returns Dimension (0,0) in this case. + if (peer == null) + return new Dimension (0, 0); + + return peer.getMinimumSize (rows, columns); + } + + /** + * Retrieve the preferred size for this text area, considering the + * text area's current row and column values. A text area's preferred + * size depends on the number of rows and columns of text it would + * prefer to display, and on the size of the font in which the text + * would be displayed. + * + * @return The preferred size for this text field. + */ + public Dimension getPreferredSize () + { + return getPreferredSize (getRows (), getColumns ()); + } + + /** + * Retrieve the preferred size that this text area would have if its + * row and column values were equal to those specified. A text + * area's preferred size depends on the number of rows and columns + * of text it would prefer to display, and on the size of the font + * in which the text would be displayed. + * + * @param rows The number of rows to use in the preferred size + * calculation. + * @param columns The number of columns to use in the preferred size + * calculation. + * + * @return The preferred size for this text area. + */ + public Dimension getPreferredSize (int rows, int columns) + { + return preferredSize (rows, columns); + } + + /** + * Retrieve the preferred size for this text area, considering the + * text area's current row and column values. A text area's preferred + * size depends on the number of rows and columns of text it would + * prefer to display, and on the size of the font in which the text + * would be displayed. + * + * @return The preferred size for this text field. + * + * @deprecated This method is deprecated in favor of + * getPreferredSize (). + */ + public Dimension preferredSize () + { + return preferredSize (getRows (), getColumns ()); + } + + /** + * Retrieve the preferred size that this text area would have if its + * row and column values were equal to those specified. A text + * area's preferred size depends on the number of rows and columns + * of text it would prefer to display, and on the size of the font + * in which the text would be displayed. + * + * @param rows The number of rows to use in the preferred size + * calculation. + * @param columns The number of columns to use in the preferred size + * calculation. + * + * @return The preferred size for this text area. + * + * @deprecated This method is deprecated in favor of + * getPreferredSize (int, int). + */ + public Dimension preferredSize (int rows, int columns) + { + TextAreaPeer peer = (TextAreaPeer) getPeer (); + + // Sun returns Dimension (0,0) in this case. + if (peer == null) + return new Dimension (0, 0); + + return peer.getPreferredSize (rows, columns); + } + + /** + * Retrieve the scroll bar display policy -- one of SCROLLBARS_BOTH, + * SCROLLBARS_VERTICAL_ONLY, SCROLLBARS_HORIZONTAL_ONLY, + * SCROLLBARS_NONE. + * + * @return The current scroll bar display policy. + */ + public int getScrollbarVisibility () + { + return scrollbarVisibility; + } + + /** + * Notify this object that it should create its native peer. + */ + public void addNotify () + { + if (getPeer () == null) + setPeer ((ComponentPeer) getToolkit().createTextArea (this)); + } + + /** + * Append the specified text to the end of the current text. + * + * @param str The text to append. + */ + public void append (String str) + { + appendText (str); + } + + /** + * Append the specified text to the end of the current text. + * + * @param str The text to append. + * + * @deprecated This method is deprecated in favor of + * append (). + */ + public void appendText (String str) + { + TextAreaPeer peer = (TextAreaPeer) getPeer (); + + if (peer != null) + peer.insert (str, peer.getText().length ()); + } + + /** + * Insert the specified text at the specified position. The first + * character in the text area is at position zero. + * + * @param str The text to insert. + * @param pos The position at which to insert text. + */ + public void insert (String str, int pos) + { + insertText (str, pos); + } + + /** + * Insert the specified text at the specified position. The first + * character in the text area is at position zero. + * + * @param str The text to insert. + * @param pos The position at which to insert text. + * + * @deprecated This method is deprecated in favor of + * insert (). + */ + public void insertText (String str, int pos) + { + TextAreaPeer peer = (TextAreaPeer) getPeer (); + + if (peer != null) + peer.insert (str, pos); + } + + /** + * Replace a range of characters with the specified text. The + * character at the start position will be replaced, unless start == + * end. The character at the end posistion will not be replaced. + * The first character in the text area is at position zero. The + * length of the replacement text may differ from the length of the + * text that is replaced. + * + * @param str The new text for the range. + * @param start The start position of the replacement range. + * @param end The end position of the replacement range. + */ + public void replaceRange (String str, int start, int end) + { + replaceText (str, start, end); + } + + /** + * Replace a range of characters with the specified text. The + * character at the start position will be replaced, unless start == + * end. The character at the end posistion will not be replaced. + * The first character in the text area is at position zero. The + * length of the replacement text may differ from the length of the + * text that is replaced. + * + * @param str The new text for the range. + * @param start The start position of the replacement range. + * @param end The end position of the replacement range. + * + * @deprecated This method is deprecated in favor of + * replaceRange (). + */ + public void replaceText (String str, int start, int end) + { + TextAreaPeer peer = (TextAreaPeer) getPeer (); + + if (peer != null) + peer.replaceRange (str, start, end); + } + + /** + * Retrieve a debugging string for this text area. + * + * @return A debugging string for this text area. + */ + protected String paramString () + { + String sbVisibility = ""; + + switch (scrollbarVisibility) + { + case SCROLLBARS_BOTH: + sbVisibility = "both"; + break; + case SCROLLBARS_VERTICAL_ONLY: + sbVisibility = "vertical-only"; + break; + case SCROLLBARS_HORIZONTAL_ONLY: + sbVisibility = "horizontal-only"; + break; + case SCROLLBARS_NONE: + sbVisibility = "none"; + break; + } + + String editable = ""; + if (isEditable ()) + editable = "editable,"; + + return getName () + "," + getX () + "," + getY () + "," + getWidth () + + "x" + getHeight () + "," + "text=" + getText () + "," + editable + + "selection=" + getSelectionStart () + "-" + getSelectionEnd () + + ",rows=" + rows + ",columns=" + columns + ",scrollbarVisibility=" + + sbVisibility; + } + + /** + * Generate a unique name for this text area. + * + * @return A unique name for this text area. + */ + String generateName () + { + return "text" + getUniqueLong (); + } + + private static synchronized long getUniqueLong () + { + return next_text_number++; + } + + protected class AccessibleAWTTextArea extends AccessibleAWTTextComponent + { + protected AccessibleAWTTextArea() + { + } + + public AccessibleStateSet getAccessibleStateSet() + { + return super.getAccessibleStateSet(); + } + } + + /** + * Gets the AccessibleContext associated with this TextArea. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTTextArea(); + return accessibleContext; + } +} diff --git a/libjava/classpath/java/awt/TextComponent.java b/libjava/classpath/java/awt/TextComponent.java new file mode 100644 index 0000000..9edbd88 --- /dev/null +++ b/libjava/classpath/java/awt/TextComponent.java @@ -0,0 +1,739 @@ +/* TextComponent.java -- Widgets for entering text + Copyright (C) 1999, 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 java.awt; + +import java.awt.event.TextEvent; +import java.awt.event.TextListener; +import java.awt.peer.TextComponentPeer; +import java.io.Serializable; +import java.text.BreakIterator; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleText; +import javax.swing.text.AttributeSet; + +/** + * This class provides common functionality for widgets than + * contain text. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class TextComponent extends Component + implements Serializable, Accessible +{ + +/* + * Static Variables + */ + +// Constant for serialization +private static final long serialVersionUID = -2214773872412987419L; + +/* + * Instance Variables + */ + +/** + * @serial Indicates whether or not this component is editable. + * This is package-private to avoid an accessor method. + */ +boolean editable; + +/** + * @serial The starting position of the selected text region. + * This is package-private to avoid an accessor method. + */ +int selectionStart; + +/** + * @serial The ending position of the selected text region. + * This is package-private to avoid an accessor method. + */ +int selectionEnd; + +/** + * @serial The text in the component + * This is package-private to avoid an accessor method. + */ +String text; + +/** + * A list of listeners that will receive events from this object. + */ +protected transient TextListener textListener; + + protected class AccessibleAWTTextComponent + extends AccessibleAWTComponent + implements AccessibleText, TextListener + { + // Constructor + // Adds a listener for tracking caret changes + public AccessibleAWTTextComponent() + { + TextComponent.this.addTextListener(this); + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.TEXT; + } + + public AccessibleStateSet getAccessibleStateSet() + { + // TODO: Docs say PropertyChangeEvent will fire if this state changes. + // That means that the event has to fire when editable changes. + AccessibleStateSet ss = super.getAccessibleStateSet(); + if (editable) + ss.add(AccessibleState.EDITABLE); + return ss; + } + + public AccessibleText getAccessibleText() + { + return this; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getIndexAtPoint(java.awt.Point) + */ + public int getIndexAtPoint(Point point) + { + return TextComponent.this.getIndexAtPoint(point); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getCharacterBounds(int) + */ + public Rectangle getCharacterBounds(int index) + { + return TextComponent.this.getCharacterBounds(index); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getCharCount() + */ + public int getCharCount() + { + return text.length(); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getCaretPosition() + */ + public int getCaretPosition() + { + return TextComponent.this.getCaretPosition(); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getAtIndex(int, int) + */ + public String getAtIndex(int part, int index) + { + if (index < 0 || index >= text.length()) + return null; + BreakIterator it = null; + switch (part) + { + case CHARACTER: + return text.substring(index, index + 1); + case WORD: + it = BreakIterator.getWordInstance(); + break; + case SENTENCE: + it = BreakIterator.getSentenceInstance(); + break; + default: + return null; + } + it.setText(text); + int start = index; + if (!it.isBoundary(index)) + start = it.preceding(index); + int end = it.following(index); + if (end == -1) + return text.substring(index); + else + return text.substring(index, end); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getAfterIndex(int, int) + */ + public String getAfterIndex(int part, int index) { + if (index < 0 || index >= text.length()) + return null; + BreakIterator it = null; + switch (part) + { + case CHARACTER: + return text.substring(index, index + 1); + case WORD: + it = BreakIterator.getWordInstance(); + break; + case SENTENCE: + it = BreakIterator.getSentenceInstance(); + break; + default: + return null; + } + it.setText(text); + int start = index; + if (!it.isBoundary(index)) + start = it.following(index); + // Make sure there was a complete unit. I.e. if index is in the middle + // of a word, return null if there is no word after the that one. + if (start == -1) + return null; + int end = it.following(start); + if (end == -1) + return text.substring(index); + else + return text.substring(index, end); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getBeforeIndex(int, int) + */ + public String getBeforeIndex(int part, int index) + { + if (index < 1 || index >= text.length()) + return null; + BreakIterator it = null; + switch (part) + { + case CHARACTER: + return text.substring(index - 1, index); + case WORD: + it = BreakIterator.getWordInstance(); + break; + case SENTENCE: + it = BreakIterator.getSentenceInstance(); + break; + default: + return null; + } + it.setText(text); + int end = index; + if (!it.isBoundary(index)) + end = it.preceding(index); + // Make sure there was a complete unit. I.e. if index is in the middle + // of a word, return null if there is no word before that one. + if (end == -1) + return null; + int start = it.preceding(end); + if (start == -1) + return text.substring(0, end); + else + return text.substring(start, end); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getCharacterAttribute(int) + */ + public AttributeSet getCharacterAttribute(int index) + { + // FIXME: I suspect this really gets filled in by subclasses. + return null; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getSelectionStart() + */ + public int getSelectionStart() { + // TODO Auto-generated method stub + return selectionStart; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getSelectionEnd() + */ + public int getSelectionEnd() + { + return selectionEnd; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getSelectedText() + */ + public String getSelectedText() + { + if (selectionEnd - selectionStart > 0) + return text.substring(selectionStart, selectionEnd); + else + return null; + } + + /* (non-Javadoc) + * @see java.awt.event.TextListener#textValueChanged(java.awt.event.TextEvent) + */ + public void textValueChanged(TextEvent event) + { + // TODO Auto-generated method stub + + } + + } + +/*************************************************************************/ + +/* + * Constructors + */ + +TextComponent(String text) +{ + this.text = text; + this.editable = true; +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the text in this component + * + * @return The text in this component. + */ +public synchronized String +getText() +{ + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + text = tcp.getText(); + + return(text); +} + +/*************************************************************************/ + +/** + * Sets the text in this component to the specified string. + * + * @param text The new text for this component. + */ +public synchronized void +setText(String text) +{ + if (text == null) + text = ""; + + this.text = text; + + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + tcp.setText(text); + setCaretPosition(0); +} + +/*************************************************************************/ + +/** + * Returns a string that contains the text that is currently selected. + * + * @return The currently selected text region. + */ +public synchronized String +getSelectedText() +{ + String alltext = getText(); + int start = getSelectionStart(); + int end = getSelectionEnd(); + + return(alltext.substring(start, end)); +} + +/*************************************************************************/ + +/** + * Returns the starting position of the selected text region. + * If the text is not selected then caret position is returned. + * + * @return The starting position of the selected text region. + */ +public synchronized int +getSelectionStart() +{ + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + selectionStart = tcp.getSelectionStart(); + + return(selectionStart); +} + +/*************************************************************************/ + +/** + * Sets the starting position of the selected region to the + * specified value. If the specified value is out of range, then it + * will be silently changed to the nearest legal value. + * + * @param selectionStart The new start position for selected text. + */ +public synchronized void +setSelectionStart(int selectionStart) +{ + select(selectionStart, getSelectionEnd()); +} + +/*************************************************************************/ + +/** + * Returns the ending position of the selected text region. + * If the text is not selected, then caret position is returned + * + * @return The ending position of the selected text region. + */ +public synchronized int +getSelectionEnd() +{ + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + selectionEnd = tcp.getSelectionEnd(); + + return(selectionEnd); +} + +/*************************************************************************/ + +/** + * Sets the ending position of the selected region to the + * specified value. If the specified value is out of range, then it + * will be silently changed to the nearest legal value. + * + * @param selectionEnd The new start position for selected text. + */ +public synchronized void +setSelectionEnd(int selectionEnd) +{ + select(getSelectionStart(), selectionEnd); +} + +/*************************************************************************/ + +/** + * This method sets the selected text range to the text between the + * specified start and end positions. Illegal values for these + * positions are silently fixed. + * + * @param selectionStart The new start position for the selected text. + * @param selectionEnd The new end position for the selected text. + */ +public synchronized void +select(int selectionStart, int selectionEnd) +{ + if (selectionStart < 0) + selectionStart = 0; + + if (selectionStart > getText().length()) + selectionStart = text.length(); + + if (selectionEnd > text.length()) + selectionEnd = text.length(); + + if (selectionStart > getSelectionEnd()) + selectionStart = selectionEnd; + + this.selectionStart = selectionStart; + this.selectionEnd = selectionEnd; + + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + tcp.select(selectionStart, selectionEnd); +} + +/*************************************************************************/ + +/** + * Selects all of the text in the component. + */ +public synchronized void +selectAll() +{ + select(0, getText().length()); +} + +/*************************************************************************/ + +/** + * Returns the current caret position in the text. + * + * @return The caret position in the text. + */ +public synchronized int +getCaretPosition() +{ + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + return(tcp.getCaretPosition()); + else + return(0); +} + +/*************************************************************************/ + +/** + * Sets the caret position to the specified value. + * + * @param caretPosition The new caret position. + * + * @exception IllegalArgumentException If the value supplied for position + * is less than zero. + * + * @since 1.1 + */ +public synchronized void +setCaretPosition(int caretPosition) +{ + if (caretPosition < 0) + throw new IllegalArgumentException (); + + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + tcp.setCaretPosition(caretPosition); +} + +/*************************************************************************/ + +/** + * Tests whether or not this component's text can be edited. + * + * @return true if the text can be edited, false + * otherwise. + */ +public boolean +isEditable() +{ + return(editable); +} + +/*************************************************************************/ + +/** + * Sets whether or not this component's text can be edited. + * + * @param editable true to enable editing of the text, + * false to disable it. + */ +public synchronized void +setEditable(boolean editable) +{ + this.editable = editable; + + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + tcp.setEditable(editable); +} + +/*************************************************************************/ + +/** + * Notifies the component that it should destroy its native peer. + */ +public void +removeNotify() +{ + super.removeNotify(); +} + +/*************************************************************************/ + +/** + * Adds a new listener to the list of text listeners for this + * component. + * + * @param listener The listener to be added. + */ +public synchronized void +addTextListener(TextListener listener) +{ + textListener = AWTEventMulticaster.add(textListener, listener); + + enableEvents(AWTEvent.TEXT_EVENT_MASK); +} + +/*************************************************************************/ + +/** + * Removes the specified listener from the list of listeners + * for this component. + * + * @param listener The listener to remove. + */ +public synchronized void +removeTextListener(TextListener listener) +{ + textListener = AWTEventMulticaster.remove(textListener, listener); +} + +/*************************************************************************/ + +/** + * Processes the specified event for this component. Text events are + * processed by calling the processTextEvent() method. + * All other events are passed to the superclass method. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof TextEvent) + processTextEvent((TextEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * Processes the specified text event by dispatching it to any listeners + * that are registered. Note that this method will only be called + * if text event's are enabled. This will be true if there are any + * registered listeners, or if the event has been specifically + * enabled using enableEvents(). + * + * @param event The text event to process. + */ +protected void +processTextEvent(TextEvent event) +{ + if (textListener != null) + textListener.textValueChanged(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= TextEvent.TEXT_LAST + && e.id >= TextEvent.TEXT_FIRST + && (textListener != null + || (eventMask & AWTEvent.TEXT_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debugging string. + * + * @return A debugging string. + */ +protected String +paramString() +{ + return(getClass().getName() + "(text=" + getText() + ")"); +} + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this TextComponent. FooListeners are registered using + * the addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + */ + public EventListener[] getListeners (Class listenerType) + { + if (listenerType == TextListener.class) + return AWTEventMulticaster.getListeners (textListener, listenerType); + + return super.getListeners (listenerType); + } + + /** + * Returns all text listeners registered to this object. + */ + public TextListener[] getTextListeners () + { + return (TextListener[]) getListeners (TextListener.class); + } + + /** + * Gets the AccessibleContext associated with this TextComponent. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTTextComponent(); + return accessibleContext; + } + + + /*******************************/ + // Provide AccessibleAWTTextComponent access to several peer functions that + // aren't publicly exposed. This is package-private to avoid an accessor + // method. + synchronized int + getIndexAtPoint(Point p) + { + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + return tcp.getIndexAtPoint(p.x, p.y); + return -1; + } + + synchronized Rectangle + getCharacterBounds(int i) + { + TextComponentPeer tcp = (TextComponentPeer)getPeer(); + if (tcp != null) + return tcp.getCharacterBounds(i); + return null; + } + + + + +} // class TextComponent + diff --git a/libjava/classpath/java/awt/TextField.java b/libjava/classpath/java/awt/TextField.java new file mode 100644 index 0000000..4d62d02 --- /dev/null +++ b/libjava/classpath/java/awt/TextField.java @@ -0,0 +1,541 @@ +/* TextField.java -- A one line text entry field + Copyright (C) 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 java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.peer.ComponentPeer; +import java.awt.peer.TextFieldPeer; +import java.util.EventListener; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleStateSet; + +/** + * This class implements a single line text entry field widget + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class TextField extends TextComponent +{ + +/* + * Static Variables + */ + +// Serialization constant +private static final long serialVersionUID = -2966288784432217853L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The number of columns in the text entry field. + */ +private int columns; + +/** + * @serial The character that is echoed when doing protected input + */ +private char echoChar; + +// List of registered ActionListener's for this object. +private ActionListener action_listeners; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of TextField that is empty + * and has one column. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ +public +TextField() +{ + this("", 1); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of TextField containing + * the specified text. The number of columns will be equal to the + * length of the text string. + * + * @param text The text to display in the field. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ +public +TextField(String text) +{ + this(text, text.length()); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of TextField that is empty + * and has the specified number of columns. + * + * @param columns The number of columns in the text field. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ +public +TextField(int columns) +{ + this("", columns); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of TextField with the + * specified text and number of columns. + * + * @param text The text to display in the field. + * @param columns The number of columns in the field. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ +public +TextField(String text, int columns) +{ + super(text); + this.columns = columns; + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the number of columns in the field. + * + * @return The number of columns in the field. + */ +public int +getColumns() +{ + return(columns); +} + +/*************************************************************************/ + +/** + * Sets the number of columns in this field to the specified value. + * + * @param columns The new number of columns in the field. + * + * @exception IllegalArgumentException If columns is less than zero. + */ +public synchronized void +setColumns(int columns) +{ + if (columns < 0) + throw new IllegalArgumentException("Value is less than zero: " + + columns); + + this.columns = columns; + // FIXME: How to we communicate this to our peer? +} + +/*************************************************************************/ + +/** + * Returns the character that is echoed to the screen when a text + * field is protected (such as when a password is being entered). + * + * @return The echo character for this text field. + */ +public char +getEchoChar() +{ + return(echoChar); +} + +/*************************************************************************/ + +/** + * Sets the character that is echoed when protected input such as + * a password is displayed. + * + * @param echoChar The new echo character. + */ +public void +setEchoChar(char echoChar) +{ + setEchoCharacter (echoChar); +} + +/*************************************************************************/ + +/** + * Sets the character that is echoed when protected input such as + * a password is displayed. + * + * @param echoChar The new echo character. + * + * @deprecated This method is deprecated in favor of + * setEchoChar() + */ +public void +setEchoCharacter(char echoChar) +{ + this.echoChar = echoChar; + + TextFieldPeer peer = (TextFieldPeer) getPeer (); + if (peer != null) + peer.setEchoChar (echoChar); +} + +/*************************************************************************/ + +/** + * Tests whether or not this text field has an echo character set + * so that characters the user type are not echoed to the screen. + * + * @return true if an echo character is set, + * false otherwise. + */ +public boolean +echoCharIsSet() +{ + if (echoChar == '\u0000') + return(false); + else + return(true); +} + +/*************************************************************************/ + +/** + * Returns the minimum size for this text field. + * + * @return The minimum size for this text field. + */ +public Dimension +getMinimumSize() +{ + return getMinimumSize (getColumns ()); +} + +/*************************************************************************/ + +/** + * Returns the minimum size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the minimum size for. + */ +public Dimension +getMinimumSize(int columns) +{ + return minimumSize (columns); +} + +/*************************************************************************/ + +/** + * Returns the minimum size for this text field. + * + * @return The minimum size for this text field. + * + * @deprecated This method is deprecated in favor of + * getMinimumSize(). + */ +public Dimension +minimumSize() +{ + return minimumSize (getColumns ()); +} + +/*************************************************************************/ + +/** + * Returns the minimum size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the minimum size for. + * + * @deprecated This method is deprecated in favor of + * getMinimumSize(int). + */ +public Dimension +minimumSize(int columns) +{ + TextFieldPeer peer = (TextFieldPeer) getPeer (); + if (peer == null) + return null; // FIXME: What do we do if there is no peer? + + return peer.getMinimumSize (columns); +} + +/*************************************************************************/ + +/** + * Returns the preferred size for this text field. + * + * @return The preferred size for this text field. + */ +public Dimension +getPreferredSize() +{ + return getPreferredSize (getColumns ()); +} + +/*************************************************************************/ + +/** + * Returns the preferred size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the preferred size for. + */ +public Dimension +getPreferredSize(int columns) +{ + return preferredSize (columns); +} + +/*************************************************************************/ + +/** + * Returns the preferred size for this text field. + * + * @return The preferred size for this text field. + * + * @deprecated This method is deprecated in favor of + * getPreferredSize(). + */ +public Dimension +preferredSize() +{ + return preferredSize (getColumns ()); +} + +/*************************************************************************/ + +/** + * Returns the preferred size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the preferred size for. + * + * @deprecated This method is deprecated in favor of + * getPreferredSize(int). + */ +public Dimension +preferredSize(int columns) +{ + TextFieldPeer peer = (TextFieldPeer) getPeer (); + if (peer == null) + return new Dimension (0, 0); + + return peer.getPreferredSize (columns); +} + +/*************************************************************************/ + +/** + * Notifies this object that it should create its native peer. + */ +public void +addNotify() +{ + if (getPeer() != null) + return; + + setPeer((ComponentPeer)getToolkit().createTextField(this)); +} + +/*************************************************************************/ + +/** + * Addes a new listener to the list of action listeners for this + * object. + * + * @param listener The listener to add to the list. + */ +public synchronized void +addActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.add(action_listeners, listener); + + enableEvents(AWTEvent.ACTION_EVENT_MASK); +} + +/*************************************************************************/ + +/** + * Removes the specified listener from the list of action listeners + * for this object. + * + * @param listener The listener to remove from the list. + */ +public synchronized void +removeActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.remove(action_listeners, listener); +} + +/*************************************************************************/ + +/** + * Processes the specified event. If the event is an instance of + * ActionEvent then processActionEvent() is + * called to process it, otherwise the event is sent to the + * superclass. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ActionEvent) + processActionEvent((ActionEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * Processes an action event by calling any registered listeners. + * Note to subclasses: This method is not called unless action events + * are enabled on this object. This will be true if any listeners + * are registered, or if action events were specifically enabled + * using enableEvents(). + * + * @param event The event to process. + */ +protected void +processActionEvent(ActionEvent event) +{ + if (action_listeners != null) + action_listeners.actionPerformed(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ActionEvent.ACTION_LAST + && e.id >= ActionEvent.ACTION_FIRST + && (action_listeners != null + || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debug string for this object. + * + * @return A debug string for this object. + */ +protected String +paramString() +{ + return(getClass().getName() + "(columns=" + getColumns() + ",echoChar=" + + getEchoChar()); +} + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this TextField. FooListeners are registered using the + * addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + * + * @since 1.3 + */ + public EventListener[] getListeners (Class listenerType) + { + if (listenerType == ActionListener.class) + return AWTEventMulticaster.getListeners (action_listeners, listenerType); + + return super.getListeners (listenerType); + } + + /** + * Return all ActionListeners register to this TextField object + * as an array. + * + * @since 1.4 + */ + public ActionListener[] getActionListeners () + { + return (ActionListener[]) getListeners (ActionListener.class); + } + + protected class AccessibleAWTTextField extends AccessibleAWTTextComponent + { + protected AccessibleAWTTextField() + { + } + + public AccessibleStateSet getAccessibleStateSet() + { + return super.getAccessibleStateSet(); + } + } + + public AccessibleContext getAccessibleContext() + { + return new AccessibleAWTTextField(); + } + +} // class TextField diff --git a/libjava/classpath/java/awt/TexturePaint.java b/libjava/classpath/java/awt/TexturePaint.java new file mode 100644 index 0000000..a12e384 --- /dev/null +++ b/libjava/classpath/java/awt/TexturePaint.java @@ -0,0 +1,75 @@ +/* TexturePaint.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 java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; + +/** STUB CLASS ONLY */ +public class TexturePaint implements Paint +{ + private final BufferedImage texture; + private final Rectangle2D anchor; + public TexturePaint(BufferedImage texture, Rectangle2D anchor) + { + this.texture = texture; + this.anchor = anchor; + } + public BufferedImage getImage() + { + return texture; + } + public Rectangle2D getAnchorRect() + { + return anchor; + } + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + throw new Error("not implemented"); + } + public int getTransparency() + { + throw new Error("not implemented"); + } +} // class TexturePaint diff --git a/libjava/classpath/java/awt/Toolkit.java b/libjava/classpath/java/awt/Toolkit.java new file mode 100644 index 0000000..c7c6f9f --- /dev/null +++ b/libjava/classpath/java/awt/Toolkit.java @@ -0,0 +1,995 @@ +/* Toolkit.java -- AWT Toolkit superclass + Copyright (C) 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 java.awt; + +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.peer.DragSourceContextPeer; +import java.awt.event.AWTEventListener; +import java.awt.event.KeyEvent; +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.LightweightPeer; +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.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.net.URL; +import java.util.Map; +import java.util.Properties; + +/** + * The AWT system uses a set of native peer objects to implement its + * widgets. These peers are provided by a peer toolkit, that is accessed + * via a subclass of this superclass. The system toolkit is retrieved + * by the static methods getDefaultToolkit. This method + * determines the system toolkit by examining the system property + * awt.toolkit. That property is set to the name of the + * Toolkit subclass for the specified peer set. If the + * awt.toolkit property is not set, then the default + * toolkit gnu.java.awt.peer.gtk.GtkToolkit is used. This + * toolkit creates its peers using the GTK+ toolkit. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class Toolkit +{ + /** The default toolkit name. */ + private static String default_toolkit_name + = gnu.classpath.Configuration.default_awt_peer_toolkit; + + /** + * The toolkit in use. Once we load it, we don't ever change it + * if the awt.toolkit property is set. + */ + private static Toolkit toolkit; + + /** The toolkit properties. */ + private static Properties props = new Properties(); + + protected final Map desktopProperties = new Properties(); + + protected final PropertyChangeSupport desktopPropsSupport + = new PropertyChangeSupport(this); + + /** + * Default constructor for subclasses. + */ + public Toolkit() + { + } + + /** + * Creates a peer object for the specified Button. + * + * @param target The Button to create the peer for. + * + * @return The peer for the specified Button object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ButtonPeer createButton(Button target); + + /** + * Creates a peer object for the specified TextField. + * + * @param target The TextField to create the peer for. + * + * @return The peer for the specified TextField object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract TextFieldPeer createTextField(TextField target); + + /** + * Creates a peer object for the specified Label. + * + * @param target The Label to create the peer for. + * + * @return The peer for the specified Label object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract LabelPeer createLabel(Label target); + + /** + * Creates a peer object for the specified List. + * + * @param target The List to create the peer for. + * + * @return The peer for the specified List object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ListPeer createList(List target); + + /** + * Creates a peer object for the specified Checkbox. + * + * @param target The Checkbox to create the peer for. + * + * @return The peer for the specified Checkbox object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract CheckboxPeer createCheckbox(Checkbox target); + + /** + * Creates a peer object for the specified Scrollbar. + * + * @param target The Scrollbar to create the peer for. + * + * @return The peer for the specified Scrollbar object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ScrollbarPeer createScrollbar(Scrollbar target); + + /** + * Creates a peer object for the specified ScrollPane. + * + * @param target The ScrollPane to create the peer for. + * + * @return The peer for the specified ScrollPane object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ScrollPanePeer createScrollPane(ScrollPane target); + + /** + * Creates a peer object for the specified TextArea. + * + * @param target The TextArea to create the peer for. + * + * @return The peer for the specified TextArea object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract TextAreaPeer createTextArea(TextArea target); + + /** + * Creates a peer object for the specified Choice. + * + * @param target The Choice to create the peer for. + * + * @return The peer for the specified Choice object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ChoicePeer createChoice(Choice target); + + /** + * Creates a peer object for the specified Frame. + * + * @param target The Frame to create the peer for. + * + * @return The peer for the specified Frame object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract FramePeer createFrame(Frame target); + + /** + * Creates a peer object for the specified Canvas. + * + * @param target The Canvas to create the peer for. + * + * @return The peer for the specified Canvas object. + */ + protected abstract CanvasPeer createCanvas(Canvas target); + + /** + * Creates a peer object for the specified Panel. + * + * @param target The Panel to create the peer for. + * + * @return The peer for the specified Panel object. + */ + protected abstract PanelPeer createPanel(Panel target); + + /** + * Creates a peer object for the specified Window. + * + * @param target The Window to create the peer for. + * + * @return The peer for the specified Window object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract WindowPeer createWindow(Window target); + + /** + * Creates a peer object for the specified Dialog. + * + * @param target The dialog to create the peer for + * + * @return The peer for the specified font name. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract DialogPeer createDialog(Dialog target); + + /** + * Creates a peer object for the specified MenuBar. + * + * @param target The MenuBar to create the peer for. + * + * @return The peer for the specified MenuBar object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract MenuBarPeer createMenuBar(MenuBar target); + + /** + * Creates a peer object for the specified Menu. + * + * @param target The Menu to create the peer for. + * + * @return The peer for the specified Menu object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract MenuPeer createMenu(Menu target); + + /** + * Creates a peer object for the specified PopupMenu. + * + * @param target The PopupMenu to create the peer for. + * + * @return The peer for the specified PopupMenu object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract PopupMenuPeer createPopupMenu(PopupMenu target); + + /** + * Creates a peer object for the specified MenuItem. + * + * @param target The MenuItem to create the peer for. + * + * @return The peer for the specified MenuItem object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract MenuItemPeer createMenuItem(MenuItem target); + + /** + * Creates a peer object for the specified FileDialog. + * + * @param target The FileDialog to create the peer for. + * + * @return The peer for the specified FileDialog object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract FileDialogPeer createFileDialog(FileDialog target); + + /** + * Creates a peer object for the specified CheckboxMenuItem. + * + * @param target The CheckboxMenuItem to create the peer for. + * + * @return The peer for the specified CheckboxMenuItem object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract CheckboxMenuItemPeer + createCheckboxMenuItem(CheckboxMenuItem target); + + /** + * Creates a peer object for the specified Component. The + * peer returned by this method is not a native windowing system peer + * with its own native window. Instead, this method allows the component + * to draw on its parent window as a "lightweight" widget. + * + * @param target The Component to create the peer for. + * + * @return The peer for the specified Component object. + */ + protected LightweightPeer createComponent(Component target) + { + return new gnu.java.awt.peer.GLightweightPeer (target); + } + + /** + * Creates a peer object for the specified font name. + * + * @param name The font to create the peer for. + * @param style The font style to create the peer for. + * + * @return The peer for the specified font name. + * + * @deprecated + */ + protected abstract FontPeer getFontPeer(String name, int style); + + /** + * Copies the current system colors into the specified array. This is + * the interface used by the SystemColor class. Although + * this method fills in the array with some default colors a real Toolkit + * should override this method and provide real system colors for the + * native GUI platform. + * + * @param systemColors The array to copy the system colors into. + * It must be at least 26 elements. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * + * @see java.awt.SystemColor + */ + protected void loadSystemColors(int systemColors[]) + { + systemColors[SystemColor.DESKTOP] = 0xFF005C5C; + systemColors[SystemColor.ACTIVE_CAPTION] = 0xFF000080; + systemColors[SystemColor.ACTIVE_CAPTION_TEXT] = 0xFFFFFFFF; + systemColors[SystemColor.ACTIVE_CAPTION_BORDER] = 0xFFC0C0C0; + systemColors[SystemColor.INACTIVE_CAPTION] = 0xFF808080; + systemColors[SystemColor.INACTIVE_CAPTION_TEXT] = 0xFFC0C0C0; + systemColors[SystemColor.INACTIVE_CAPTION_BORDER] = 0xFFC0C0C0; + systemColors[SystemColor.WINDOW] = 0xFFFFFFFF; + systemColors[SystemColor.WINDOW_BORDER] = 0xFF000000; + systemColors[SystemColor.WINDOW_TEXT] = 0xFF000000; + systemColors[SystemColor.MENU] = 0xFFC0C0C0; + systemColors[SystemColor.MENU_TEXT] = 0xFF000000; + systemColors[SystemColor.TEXT] = 0xFFC0C0C0; + systemColors[SystemColor.TEXT_TEXT] = 0xFF000000; + systemColors[SystemColor.TEXT_HIGHLIGHT] = 0xFF000090; + systemColors[SystemColor.TEXT_HIGHLIGHT_TEXT] = 0xFFFFFFFF; + systemColors[SystemColor.TEXT_INACTIVE_TEXT] = 0xFF808080; + systemColors[SystemColor.CONTROL] = 0xFFC0C0C0; + systemColors[SystemColor.CONTROL_TEXT] = 0xFF000000; + systemColors[SystemColor.CONTROL_HIGHLIGHT] = 0xFFFFFFFF; + systemColors[SystemColor.CONTROL_LT_HIGHLIGHT] = 0xFFE0E0E0; + systemColors[SystemColor.CONTROL_SHADOW] = 0xFF808080; + systemColors[SystemColor.CONTROL_DK_SHADOW] = 0xFF000000; + systemColors[SystemColor.SCROLLBAR] = 0xFFE0E0E0; + systemColors[SystemColor.INFO] = 0xFFE0E000; + systemColors[SystemColor.INFO_TEXT] = 0xFF000000; + } + + /** + * @since 1.4 + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public void setDynamicLayout(boolean dynamic) + { + } + + /** + * @since 1.4 + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected boolean isDynamicLayoutSet() + { + return false; + } + + /** + * @since 1.4 + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public boolean isDynamicLayoutActive() + { + return false; + } + + /** + * Returns the dimensions of the screen in pixels. + * + * @return The dimensions of the screen in pixels. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public abstract Dimension getScreenSize(); + + /** + * Returns the screen resolution in dots per square inch. + * + * @return The screen resolution in dots per square inch. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public abstract int getScreenResolution(); + + /** + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * + * @since 1.4 + */ + public Insets getScreenInsets(GraphicsConfiguration gc) + { + return null; + } + + /** + * Returns the color model of the screen. + * + * @return The color model of the screen. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public abstract ColorModel getColorModel(); + + /** + * Returns the names of the available fonts. + * + * @return The names of the available fonts. + * + * @deprecated + */ + public abstract String[] getFontList(); + + /** + * Return the font metrics for the specified font + * + * @param name The name of the font to return metrics for. + * + * @return The requested font metrics. + * + * @deprecated + */ + public abstract FontMetrics getFontMetrics(Font name); + + /** + * Flushes any buffered data to the screen so that it is in sync with + * what the AWT system has drawn to it. + */ + public abstract void sync(); + + /** + * Returns an instance of the default toolkit. The default toolkit is + * the subclass of Toolkit specified in the system property + * awt.toolkit, or gnu.java.awt.peer.gtk.GtkToolkit + * if the property is not set. + * + * @return An instance of the system default toolkit. + * + * @throws AWTError If the toolkit cannot be loaded. + */ + public static Toolkit getDefaultToolkit() + { + if (toolkit != null) + return toolkit; + String toolkit_name = System.getProperty("awt.toolkit", + default_toolkit_name); + try + { + Class cls = Class.forName(toolkit_name); + Object obj = cls.newInstance(); + if (!(obj instanceof Toolkit)) + throw new AWTError(toolkit_name + " is not a subclass of " + + "java.awt.Toolkit"); + toolkit = (Toolkit) obj; + return toolkit; + } + catch (ThreadDeath death) + { + throw death; + } + catch (Throwable t) + { + AWTError e = new AWTError("Cannot load AWT toolkit: " + toolkit_name); + throw (AWTError) e.initCause(t); + } + } + + /** + * Returns an image from the specified file, which must be in a + * recognized format. Supported formats vary from toolkit to toolkit. + * + * @return name The name of the file to read the image from. + */ + public abstract Image getImage(String name); + + /** + * Returns an image from the specified URL, which must be in a + * recognized format. Supported formats vary from toolkit to toolkit. + * + * @return url The URl to read the image from. + */ + public abstract Image getImage(URL url); + + public abstract Image createImage(String filename); + + public abstract Image createImage(URL url); + + /** + * Readies an image to be rendered on the screen. The width and height + * values can be set to the default sizes for the image by passing -1 + * in those parameters. + * + * @param image The image to prepare for rendering. + * @param width The width of the image. + * @param height The height of the image. + * @param observer The observer to receive events about the preparation + * process. + * + * @return true if the image is already prepared for rendering, + * false otherwise. + */ + public abstract boolean prepareImage(Image image, int width, int height, + ImageObserver observer); + + /** + * Checks the status of specified image as it is being readied for + * rendering. + * + * @param image The image to prepare for rendering. + * @param width The width of the image. + * @param height The height of the image. + * @param observer The observer to receive events about the preparation + * process. + * + * @return A union of the bitmasks from + * java.awt.image.ImageObserver that indicates the current + * state of the imaging readying process. + */ + public abstract int checkImage(Image image, int width, int height, + ImageObserver observer); + + /** + * Creates an image using the specified ImageProducer + * + * @param producer The ImageProducer to create the image from. + * + * @return The created image. + */ + public abstract Image createImage(ImageProducer producer); + + /** + * Creates an image from the specified byte array. The array must be in + * a recognized format. Supported formats vary from toolkit to toolkit. + * + * @param data The raw image data. + * + * @return The created image. + */ + public Image createImage(byte[] data) + { + return createImage(data, 0, data.length); + } + + /** + * Creates an image from the specified portion of the byte array passed. + * The array must be in a recognized format. Supported formats vary from + * toolkit to toolkit. + * + * @param data The raw image data. + * @param offset The offset into the data where the image data starts. + * @param len The length of the image data. + * + * @return The created image. + */ + public abstract Image createImage(byte[] data, int offset, int len); + + /** + * Returns a instance of PrintJob for the specified + * arguments. + * + * @param frame The window initiating the print job. + * @param title The print job title. + * @param props The print job properties. + * + * @return The requested print job, or null if the job + * was cancelled. + * + * @exception NullPointerException If frame is null, + * or GraphicsEnvironment.isHeadless() returns true. + * @exception SecurityException If this thread is not allowed to initiate + * a print job request. + */ + public abstract PrintJob getPrintJob(Frame frame, String title, + Properties props); + + /** + * Returns a instance of PrintJob for the specified + * arguments. + * + * @param frame The window initiating the print job. + * @param title The print job title. + * @param jobAttr A set of job attributes which will control the print job. + * @param pageAttr A set of page attributes which will control the print job. + * + * @exception NullPointerException If frame is null, and either jobAttr is null + * or jobAttr.getDialog() returns JobAttributes.DialogType.NATIVE. + * @exception IllegalArgumentException If pageAttrspecifies differing cross + * feed and feed resolutions, or when GraphicsEnvironment.isHeadless() returns + * true. + * @exception SecurityException If this thread is not allowed to initiate + * a print job request. + * + * @since 1.3 + */ + public PrintJob getPrintJob(Frame frame, String title, + JobAttributes jobAttr, PageAttributes pageAttr) + { + return null; + } + + /** + * Causes a "beep" tone to be generated. + */ + public abstract void beep(); + + /** + * Returns the system clipboard. + * + * @return THe system clipboard. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public abstract Clipboard getSystemClipboard(); + + /** + * Gets the singleton instance of the system selection as a Clipboard object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * + * @since 1.4 + */ + public Clipboard getSystemSelection() + { + return null; + } + + /** + * Returns the accelerator key mask for menu shortcuts. The default is + * Event.CTRL_MASK. A toolkit must override this method + * to change the default. + * + * @return The key mask for the menu accelerator key. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public int getMenuShortcutKeyMask() + { + return Event.CTRL_MASK; + } + + /** + * Returns whether the given locking key on the keyboard is currently in its + * "on" state. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * @exception IllegalArgumentException If keyCode is not one of the valid keys. + * @exception UnsupportedOperationException If the host system doesn't allow + * getting the state of this key programmatically, or if the keyboard doesn't + * have this key. + */ + public boolean getLockingKeyState(int keyCode) + { + if (keyCode != KeyEvent.VK_CAPS_LOCK + && keyCode != KeyEvent.VK_NUM_LOCK + && keyCode != KeyEvent.VK_SCROLL_LOCK) + throw new IllegalArgumentException(); + + throw new UnsupportedOperationException(); + } + + /** + * Sets the state of the given locking key on the keyboard. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * @exception IllegalArgumentException If keyCode is not one of the valid keys. + * @exception UnsupportedOperationException If the host system doesn't allow + * getting the state of this key programmatically, or if the keyboard doesn't + * have this key. + */ + public void setLockingKeyState(int keyCode, boolean on) + { + if (keyCode != KeyEvent.VK_CAPS_LOCK + && keyCode != KeyEvent.VK_NUM_LOCK + && keyCode != KeyEvent.VK_SCROLL_LOCK) + throw new IllegalArgumentException(); + + throw new UnsupportedOperationException(); + } + + /** + * Returns the native container object of the specified component. This + * method is necessary because the parent component might be a lightweight + * component. + * + * @param component The component to fetch the native container for. + * + * @return The native container object for this component. + */ + protected static Container getNativeContainer(Component component) + { + component = component.getParent(); + while (true) + { + if (component == null) + return null; + if (! (component instanceof Container)) + { + component = component.getParent(); + continue; + } + if (component.getPeer() instanceof LightweightPeer) + { + component = component.getParent(); + continue; + } + return (Container) component; + } + } + + /** + * Creates a new custom cursor object. + * + * @exception IndexOutOfBoundsException If the hotSpot values are outside + * the bounds of the cursor. + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Cursor createCustomCursor(Image cursor, Point hotSpot, String name) + { + // Presumably the only reason this isn't abstract is for backwards + // compatibility? FIXME? + return null; + } + + /** + * Returns the supported cursor dimension which is closest to the + * desired sizes. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) + { + return new Dimension (0,0); + } + + /** + * Returns the maximum number of colors the Toolkit supports in a custom + * cursor palette. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public int getMaximumCursorColors() + { + return 0; + } + + /** + * Returns whether Toolkit supports this state for Frames. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * + * @since 1.4 + */ + public boolean isFrameStateSupported(int state) + { + return false; + } + + /** + * Returns the value of the property with the specified name, or the + * default value if the property does not exist. + * + * @param key The name of the property to retrieve. + * @param def The default value of the property. + */ + public static String getProperty(String key, String def) + { + return props.getProperty(key, def); + } + + + /** + * Returns the event queue that is suitable for the calling context. + * + *

Despite the word “System” in the name of this + * method, a toolkit may provide different event queues for each + * applet. There is no guarantee that the same queue is shared + * system-wide. + * + *

The implementation first checks whether a + * SecurityManager has been installed. If so, its {@link + * java.lang.SecurityManager#checkAwtEventQueueAccess()} method gets + * called. The security manager will throw a SecurityException if it + * does not grant the permission to access the event queue. + * + *

Next, the call is delegated to {@link + * #getSystemEventQueueImpl()}. + * + * @return The event queue for this applet (or application). + * + * @throws SecurityException if a security manager has been + * installed, and it does not grant the permission to access the + * event queue. + */ + public final EventQueue getSystemEventQueue() + { + SecurityManager sm; + + sm = System.getSecurityManager(); + if (sm != null) + sm.checkAwtEventQueueAccess(); + + return getSystemEventQueueImpl(); + } + + + /** + * Returns the event queue that is suitable for the calling context. + * + *

Despite the word “System” in the name of this + * method, a toolkit may provide different event queues for each + * applet. There is no guarantee that the same queue is shared + * system-wide. + * + *

No security checks are performed, which is why this method + * may only be called by Toolkits. + * + * @see #getSystemEventQueue() + */ + protected abstract EventQueue getSystemEventQueueImpl(); + + + /** + * @since 1.3 + */ + public abstract DragSourceContextPeer + createDragSourceContextPeer(DragGestureEvent e); + + /** + * @since 1.3 + */ + public DragGestureRecognizer + createDragGestureRecognizer(Class recognizer, DragSource ds, + Component comp, int actions, + DragGestureListener l) + { + return null; + } + + public final Object getDesktopProperty(String propertyName) + { + return desktopProperties.get(propertyName); + } + + protected final void setDesktopProperty(String name, Object newValue) + { + Object oldValue = getDesktopProperty(name); + desktopProperties.put(name, newValue); + desktopPropsSupport.firePropertyChange(name, oldValue, newValue); + } + + protected Object lazilyLoadDesktopProperty(String name) + { + // FIXME - what is this?? + return null; + } + + protected void initializeDesktopProperties() + { + // Overridden by toolkit implementation? + } + + public void addPropertyChangeListener(String name, + PropertyChangeListener pcl) + { + desktopPropsSupport.addPropertyChangeListener(name, pcl); + } + + public void removePropertyChangeListener(String name, + PropertyChangeListener pcl) + { + desktopPropsSupport.removePropertyChangeListener(name, pcl); + } + + /** + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return desktopPropsSupport.getPropertyChangeListeners(); + } + + /** + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners(String name) + { + return desktopPropsSupport.getPropertyChangeListeners(name); + } + + public void addAWTEventListener(AWTEventListener listener, long eventMask) + { + // SecurityManager s = System.getSecurityManager(); + // if (s != null) + // s.checkPermission(AWTPermission("listenToAllAWTEvents")); + // FIXME + } + + public void removeAWTEventListener(AWTEventListener listener) + { + // FIXME + } + + /** + * @since 1.4 + */ + public AWTEventListener[] getAWTEventListeners() + { + return null; + } + + /** + * @since 1.4 + */ + public AWTEventListener[] getAWTEventListeners(long mask) + { + return null; + } + + /** + * @since 1.3 + */ + public abstract Map mapInputMethodHighlight(InputMethodHighlight highlight); +} // class Toolkit diff --git a/libjava/classpath/java/awt/Transparency.java b/libjava/classpath/java/awt/Transparency.java new file mode 100644 index 0000000..8885871 --- /dev/null +++ b/libjava/classpath/java/awt/Transparency.java @@ -0,0 +1,67 @@ +/* Transparency.java -- common transparency modes in graphics + Copyright (C) 2000, 2002, 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 java.awt; + +/** + * A common transparency mode for layering graphics. + * + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public interface Transparency +{ + /** Image data which is completely opaque, for an alpha value of 1.0. */ + int OPAQUE = 1; + + /** + * Image data which is either completely opaque or transparent, for an + * exact integer alpha value. + */ + int BITMASK = 2; + + /** Image data which is translucent, for a non-integer alpha value. */ + int TRANSLUCENT = 3; + + /** + * Return the transparency type. + * + * @return One of {@link #OPAQUE}, {@link #BITMASK}, or {@link #TRANSLUCENT}. + */ + int getTransparency(); +} // interface Transparency diff --git a/libjava/classpath/java/awt/Window.java b/libjava/classpath/java/awt/Window.java new file mode 100644 index 0000000..e26c4e3 --- /dev/null +++ b/libjava/classpath/java/awt/Window.java @@ -0,0 +1,1125 @@ +/* Window.java -- + Copyright (C) 1999, 2000, 2002, 2003, 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 java.awt; + +import java.awt.event.ComponentEvent; +import java.awt.event.FocusEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.awt.event.WindowListener; +import java.awt.event.WindowStateListener; +import java.awt.image.BufferStrategy; +import java.awt.peer.WindowPeer; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.EventListener; +import java.util.Iterator; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * This class represents a top-level window with no decorations. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class Window extends Container implements Accessible +{ + private static final long serialVersionUID = 4497834738069338734L; + + // Serialized fields, from Sun's serialization spec. + private String warningString = null; + private int windowSerializedDataVersion = 0; // FIXME + /** @since 1.2 */ + // private FocusManager focusMgr; // FIXME: what is this? + /** @since 1.2 */ + private int state = 0; + /** @since 1.4 */ + private boolean focusableWindowState = true; + + // A list of other top-level windows owned by this window. + private transient Vector ownedWindows = new Vector(); + + private transient WindowListener windowListener; + private transient WindowFocusListener windowFocusListener; + private transient WindowStateListener windowStateListener; + private transient GraphicsConfiguration graphicsConfiguration; + + private transient boolean shown; + + // This is package-private to avoid an accessor method. + transient Component windowFocusOwner; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_window_number; + + protected class AccessibleAWTWindow extends AccessibleAWTContainer + { + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.WINDOW; + } + + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (isActive()) + states.add(AccessibleState.ACTIVE); + return states; + } + } + + /** + * This (package access) constructor is used by subclasses that want + * to build windows that do not have parents. Eg. toplevel + * application frames. Subclasses cannot call super(null), since + * null is an illegal argument. + */ + Window() + { + visible = false; + // Windows are the only Containers that default to being focus + // cycle roots. + focusCycleRoot = true; + setLayout(new BorderLayout()); + + addWindowFocusListener (new WindowAdapter () + { + public void windowGainedFocus (WindowEvent event) + { + if (windowFocusOwner != null) + { + // FIXME: move this section and the other similar + // sections in Component into a separate method. + EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + synchronized (eq) + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + Component currentFocusOwner = manager.getGlobalPermanentFocusOwner (); + if (currentFocusOwner != null) + { + eq.postEvent (new FocusEvent (currentFocusOwner, FocusEvent.FOCUS_LOST, + false, windowFocusOwner)); + eq.postEvent (new FocusEvent (windowFocusOwner, FocusEvent.FOCUS_GAINED, + false, currentFocusOwner)); + } + else + eq.postEvent (new FocusEvent (windowFocusOwner, FocusEvent.FOCUS_GAINED, false)); + } + } + } + }); + } + + Window(GraphicsConfiguration gc) + { + this(); + graphicsConfiguration = gc; + } + + /** + * Initializes a new instance of Window with the specified + * parent. The window will initially be invisible. + * + * @param owner The owning Frame of this window. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null; this exception is always + * thrown when GraphicsEnvironment.isHeadless returns true. + */ + public Window(Frame owner) + { + this (owner, owner.getGraphicsConfiguration ()); + } + + /** + * Initializes a new instance of Window with the specified + * parent. The window will initially be invisible. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null; this exception is always + * thrown when GraphicsEnvironment.isHeadless returns true. + * + * @since 1.2 + */ + public Window(Window owner) + { + this (owner, owner.getGraphicsConfiguration ()); + } + + /** + * Initializes a new instance of Window with the specified + * parent. The window will initially be invisible. + * + * @exception IllegalArgumentException If owner is null or if gc is not from a + * screen device; this exception is always thrown when + * GraphicsEnvironment.isHeadless returns true. + * + * @since 1.3 + */ + public Window(Window owner, GraphicsConfiguration gc) + { + this (); + + synchronized (getTreeLock()) + { + if (owner == null) + throw new IllegalArgumentException ("owner must not be null"); + + parent = owner; + owner.ownedWindows.add(new WeakReference(this)); + } + + // FIXME: make this text visible in the window. + SecurityManager s = System.getSecurityManager(); + if (s != null && ! s.checkTopLevelWindow(this)) + warningString = System.getProperty("awt.appletWarning"); + + if (gc != null + && gc.getDevice().getType() != GraphicsDevice.TYPE_RASTER_SCREEN) + throw new IllegalArgumentException ("gc must be from a screen device"); + + if (gc == null) + graphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .getDefaultConfiguration(); + else + graphicsConfiguration = gc; + } + + GraphicsConfiguration getGraphicsConfigurationImpl() + { + if (graphicsConfiguration != null) + return graphicsConfiguration; + + return super.getGraphicsConfigurationImpl(); + } + + /** + * Creates the native peer for this window. + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit().createWindow(this); + super.addNotify(); + } + + /** + * Relays out this window's child components at their preferred size. + * + * @specnote pack() doesn't appear to be called internally by show(), so + * we duplicate some of the functionality. + */ + public void pack() + { + if (parent != null && !parent.isDisplayable()) + parent.addNotify(); + if (peer == null) + addNotify(); + + setSize(getPreferredSize()); + + validate(); + } + + /** + * Shows on-screen this window and any of its owned windows for whom + * isVisible returns true. + */ + public void show() + { + if (parent != null && !parent.isDisplayable()) + parent.addNotify(); + if (peer == null) + addNotify(); + + // Show visible owned windows. + synchronized (getTreeLock()) + { + Iterator e = ownedWindows.iterator(); + while(e.hasNext()) + { + Window w = (Window)(((Reference) e.next()).get()); + if (w != null) + { + if (w.isVisible()) + w.getPeer().setVisible(true); + } + else + // Remove null weak reference from ownedWindows. + // Unfortunately this can't be done in the Window's + // finalize method because there is no way to guarantee + // synchronous access to ownedWindows there. + e.remove(); + } + } + validate(); + super.show(); + toFront(); + + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + manager.setGlobalFocusedWindow (this); + + if (!shown) + { + FocusTraversalPolicy policy = getFocusTraversalPolicy (); + Component initialFocusOwner = null; + + if (policy != null) + initialFocusOwner = policy.getInitialComponent (this); + + if (initialFocusOwner != null) + initialFocusOwner.requestFocusInWindow (); + + shown = true; + } + } + + public void hide() + { + // Hide visible owned windows. + synchronized (getTreeLock ()) + { + Iterator e = ownedWindows.iterator(); + while(e.hasNext()) + { + Window w = (Window)(((Reference) e.next()).get()); + if (w != null) + { + if (w.isVisible() && w.getPeer() != null) + w.getPeer().setVisible(false); + } + else + e.remove(); + } + } + super.hide(); + } + + public boolean isDisplayable() + { + if (super.isDisplayable()) + return true; + return peer != null; + } + + /** + * Destroys any resources associated with this window. This includes + * all components in the window and all owned top-level windows. + */ + public void dispose() + { + hide(); + + synchronized (getTreeLock ()) + { + Iterator e = ownedWindows.iterator(); + while(e.hasNext()) + { + Window w = (Window)(((Reference) e.next()).get()); + if (w != null) + w.dispose(); + else + // Remove null weak reference from ownedWindows. + e.remove(); + } + + for (int i = 0; i < ncomponents; ++i) + component[i].removeNotify(); + this.removeNotify(); + + // Post a WINDOW_CLOSED event. + WindowEvent we = new WindowEvent(this, WindowEvent.WINDOW_CLOSED); + getToolkit().getSystemEventQueue().postEvent(we); + } + } + + /** + * Sends this window to the back so that all other windows display in + * front of it. + */ + public void toBack() + { + if (peer != null) + { + WindowPeer wp = (WindowPeer) peer; + wp.toBack(); + } + } + + /** + * Brings this window to the front so that it displays in front of + * any other windows. + */ + public void toFront() + { + if (peer != null) + { + WindowPeer wp = (WindowPeer) peer; + wp.toFront(); + } + } + + /** + * Returns the toolkit used to create this window. + * + * @return The toolkit used to create this window. + * + * @specnote Unlike Component.getToolkit, this implementation always + * returns the value of Toolkit.getDefaultToolkit(). + */ + public Toolkit getToolkit() + { + return Toolkit.getDefaultToolkit(); + } + + /** + * Returns the warning string that will be displayed if this window is + * popped up by an unsecure applet or application. + * + * @return The unsecure window warning message. + */ + public final String getWarningString() + { + return warningString; + } + + /** + * Returns the locale that this window is configured for. + * + * @return The locale this window is configured for. + */ + public Locale getLocale() + { + return locale == null ? Locale.getDefault() : locale; + } + + /* + /** @since 1.2 + public InputContext getInputContext() + { + // FIXME + } + */ + + /** + * Sets the cursor for this window to the specifiec cursor. + * + * @param cursor The new cursor for this window. + */ + public void setCursor(Cursor cursor) + { + super.setCursor(cursor); + } + + public Window getOwner() + { + return (Window) parent; + } + + /** @since 1.2 */ + public Window[] getOwnedWindows() + { + Window [] trimmedList; + synchronized (getTreeLock ()) + { + // Windows with non-null weak references in ownedWindows. + Window [] validList = new Window [ownedWindows.size()]; + + Iterator e = ownedWindows.iterator(); + int numValid = 0; + while (e.hasNext()) + { + Window w = (Window)(((Reference) e.next()).get()); + if (w != null) + validList[numValid++] = w; + else + // Remove null weak reference from ownedWindows. + e.remove(); + } + + if (numValid != validList.length) + { + trimmedList = new Window [numValid]; + System.arraycopy (validList, 0, trimmedList, 0, numValid); + } + else + trimmedList = validList; + } + return trimmedList; + } + + /** + * Adds the specified listener to the list of WindowListeners + * that will receive events for this window. + * + * @param listener The WindowListener to add. + */ + public synchronized void addWindowListener(WindowListener listener) + { + windowListener = AWTEventMulticaster.add(windowListener, listener); + } + + /** + * Removes the specified listener from the list of + * WindowListeners that will receive events for this window. + * + * @param listener The WindowListener to remove. + */ + public synchronized void removeWindowListener(WindowListener listener) + { + windowListener = AWTEventMulticaster.remove(windowListener, listener); + } + + /** + * Returns an array of all the window listeners registered on this window. + * + * @since 1.4 + */ + public synchronized WindowListener[] getWindowListeners() + { + return (WindowListener[]) + AWTEventMulticaster.getListeners(windowListener, + WindowListener.class); + } + + /** + * Returns an array of all the window focus listeners registered on this + * window. + * + * @since 1.4 + */ + public synchronized WindowFocusListener[] getWindowFocusListeners() + { + return (WindowFocusListener[]) + AWTEventMulticaster.getListeners(windowFocusListener, + WindowFocusListener.class); + } + + /** + * Returns an array of all the window state listeners registered on this + * window. + * + * @since 1.4 + */ + public synchronized WindowStateListener[] getWindowStateListeners() + { + return (WindowStateListener[]) + AWTEventMulticaster.getListeners(windowStateListener, + WindowStateListener.class); + } + + /** + * Adds the specified listener to this window. + */ + public void addWindowFocusListener (WindowFocusListener wfl) + { + windowFocusListener = AWTEventMulticaster.add (windowFocusListener, wfl); + } + + /** + * Adds the specified listener to this window. + * + * @since 1.4 + */ + public void addWindowStateListener (WindowStateListener wsl) + { + windowStateListener = AWTEventMulticaster.add (windowStateListener, wsl); + } + + /** + * Removes the specified listener from this window. + */ + public void removeWindowFocusListener (WindowFocusListener wfl) + { + windowFocusListener = AWTEventMulticaster.remove (windowFocusListener, wfl); + } + + /** + * Removes the specified listener from this window. + * + * @since 1.4 + */ + public void removeWindowStateListener (WindowStateListener wsl) + { + windowStateListener = AWTEventMulticaster.remove (windowStateListener, wsl); + } + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this Window. FooListeners are registered using the addFooListener + * method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + * + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + if (listenerType == WindowListener.class) + return getWindowListeners(); + return super.getListeners(listenerType); + } + + void dispatchEventImpl(AWTEvent e) + { + // Make use of event id's in order to avoid multiple instanceof tests. + if (e.id <= WindowEvent.WINDOW_LAST + && e.id >= WindowEvent.WINDOW_FIRST + && (windowListener != null + || windowFocusListener != null + || windowStateListener != null + || (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); + } + + /** + * Processes the specified event for this window. If the event is an + * instance of WindowEvent, then + * processWindowEvent() is called to process the event, + * otherwise the superclass version of this method is invoked. + * + * @param evt The event to process. + */ + protected void processEvent(AWTEvent evt) + { + if (evt instanceof WindowEvent) + processWindowEvent((WindowEvent) evt); + else + super.processEvent(evt); + } + + /** + * Dispatches this event to any listeners that are listening for + * WindowEvents on this window. This method only gets + * invoked if it is enabled via enableEvents() or if + * a listener has been added. + * + * @param evt The event to process. + */ + protected void processWindowEvent(WindowEvent evt) + { + int id = evt.getID(); + + if (id == WindowEvent.WINDOW_GAINED_FOCUS + || id == WindowEvent.WINDOW_LOST_FOCUS) + processWindowFocusEvent (evt); + else if (id == WindowEvent.WINDOW_STATE_CHANGED) + processWindowStateEvent (evt); + else + { + if (windowListener != null) + { + switch (evt.getID()) + { + case WindowEvent.WINDOW_ACTIVATED: + windowListener.windowActivated(evt); + break; + + case WindowEvent.WINDOW_CLOSED: + windowListener.windowClosed(evt); + break; + + case WindowEvent.WINDOW_CLOSING: + windowListener.windowClosing(evt); + break; + + case WindowEvent.WINDOW_DEACTIVATED: + windowListener.windowDeactivated(evt); + break; + + case WindowEvent.WINDOW_DEICONIFIED: + windowListener.windowDeiconified(evt); + break; + + case WindowEvent.WINDOW_ICONIFIED: + windowListener.windowIconified(evt); + break; + + case WindowEvent.WINDOW_OPENED: + windowListener.windowOpened(evt); + break; + + default: + break; + } + } + } + } + + /** + * Identifies if this window is active. The active window is a Frame or + * Dialog that has focus or owns the active window. + * + * @return true if active, else false. + * @since 1.4 + */ + public boolean isActive() + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + return manager.getActiveWindow() == this; + } + + /** + * Identifies if this window is focused. A window is focused if it is the + * focus owner or it contains the focus owner. + * + * @return true if focused, else false. + * @since 1.4 + */ + public boolean isFocused() + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + return manager.getFocusedWindow() == this; + } + + /** + * Returns the child window that has focus if this window is active. + * This method returns null if this window is not active + * or no children have focus. + * + * @return The component that has focus, or null if no + * component has focus. + */ + public Component getFocusOwner () + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + Window activeWindow = manager.getActiveWindow (); + + // The currently-focused Component belongs to the active Window. + if (activeWindow == this) + return manager.getFocusOwner (); + else + return windowFocusOwner; + } + + /** + * Set the focus owner for this window. This method is used to + * remember which component was focused when this window lost + * top-level focus, so that when it regains top-level focus the same + * child component can be refocused. + * + * @param windowFocusOwner the component in this window that owns + * the focus. + */ + void setFocusOwner (Component windowFocusOwner) + { + this.windowFocusOwner = windowFocusOwner; + } + + /** + * Post a Java 1.0 event to the event queue. + * + * @param e The event to post. + * + * @deprecated + */ + public boolean postEvent(Event e) + { + return handleEvent (e); + } + + /** + * Tests whether or not this window is visible on the screen. + * + * In contrast to the normal behaviour of Container, which is that + * a container is showing if its parent is visible and showing, a Window + * is even showing, if its parent (i.e. an invisible Frame) is not showing. + * + * @return true if this window is visible, false + * otherwise. + */ + public boolean isShowing() + { + return isVisible(); + } + + public void setLocationRelativeTo (Component c) + { + if (c == null || !c.isShowing ()) + { + int x = 0; + int y = 0; + + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment (); + Point center = ge.getCenterPoint (); + x = center.x - (width / 2); + y = center.y - (height / 2); + setLocation (x, y); + } + // FIXME: handle case where component is non-null. + } + + /** + * A BltBufferStrategy for windows. + */ + private class WindowBltBufferStrategy extends BltBufferStrategy + { + /** + * Creates a block transfer strategy for this window. + * + * @param numBuffers the number of buffers in this strategy + * @param accelerated true if the buffer should be accelerated, + * false otherwise + */ + WindowBltBufferStrategy(int numBuffers, boolean accelerated) + { + super(numBuffers, + new BufferCapabilities(new ImageCapabilities(accelerated), + new ImageCapabilities(accelerated), + BufferCapabilities.FlipContents.COPIED)); + } + } + + /** + * A FlipBufferStrategy for windows. + */ + private class WindowFlipBufferStrategy extends FlipBufferStrategy + { + /** + * Creates a flip buffer strategy for this window. + * + * @param numBuffers the number of buffers in this strategy + * + * @throws AWTException if the requested number of buffers is not + * supported + */ + WindowFlipBufferStrategy(int numBuffers) + throws AWTException + { + super(numBuffers, + new BufferCapabilities(new ImageCapabilities(true), + new ImageCapabilities(true), + BufferCapabilities.FlipContents.COPIED)); + } + } + + /** + * Creates a buffering strategy that manages how this window is + * repainted. This method attempts to create the optimum strategy + * based on the desired number of buffers. Hardware or software + * acceleration may be used. + * + * createBufferStrategy attempts different levels of optimization, + * but guarantees that some strategy with the requested number of + * buffers will be created even if it is not optimal. First it + * attempts to create a page flipping strategy, then an accelerated + * blitting strategy, then an unaccelerated blitting strategy. + * + * Calling this method causes any existing buffer strategy to be + * destroyed. + * + * @param numBuffers the number of buffers in this strategy + * + * @throws IllegalArgumentException if requested number of buffers + * is less than one + * @throws IllegalStateException if this window is not displayable + * + * @since 1.4 + */ + public void createBufferStrategy(int numBuffers) + { + if (numBuffers < 1) + throw new IllegalArgumentException("Window.createBufferStrategy: number" + + " of buffers is less than one"); + + if (!isDisplayable()) + throw new IllegalStateException("Window.createBufferStrategy: window is" + + " not displayable"); + + BufferStrategy newStrategy = null; + + // try a flipping strategy + try + { + newStrategy = new WindowFlipBufferStrategy(numBuffers); + } + catch (AWTException e) + { + } + + // fall back to an accelerated blitting strategy + if (newStrategy == null) + newStrategy = new WindowBltBufferStrategy(numBuffers, true); + + bufferStrategy = newStrategy; + } + + /** + * Creates a buffering strategy that manages how this window is + * repainted. This method attempts to create a strategy based on + * the specified capabilities and throws an exception if the + * requested strategy is not supported. + * + * Calling this method causes any existing buffer strategy to be + * destroyed. + * + * @param numBuffers the number of buffers in this strategy + * @param caps the requested buffering capabilities + * + * @throws AWTException if the requested capabilities are not + * supported + * @throws IllegalArgumentException if requested number of buffers + * is less than one or if caps is null + * + * @since 1.4 + */ + public void createBufferStrategy(int numBuffers, + BufferCapabilities caps) + { + if (numBuffers < 1) + throw new IllegalArgumentException("Window.createBufferStrategy: number" + + " of buffers is less than one"); + + if (caps == null) + throw new IllegalArgumentException("Window.createBufferStrategy:" + + " capabilities object is null"); + + // a flipping strategy was requested + if (caps.isPageFlipping()) + { + try + { + bufferStrategy = new WindowFlipBufferStrategy(numBuffers); + } + catch (AWTException e) + { + } + } + else + bufferStrategy = new WindowBltBufferStrategy(numBuffers, true); + } + + /** + * Returns the buffer strategy used by the window. + * + * @return the buffer strategy. + * @since 1.4 + */ + public BufferStrategy getBufferStrategy() + { + return bufferStrategy; + } + + /** + * @since 1.2 + * + * @deprecated + */ + public void applyResourceBundle(ResourceBundle rb) + { + throw new Error ("Not implemented"); + } + + /** + * @since 1.2 + * + * @deprecated + */ + public void applyResourceBundle(String rbName) + { + ResourceBundle rb = ResourceBundle.getBundle(rbName, Locale.getDefault(), + ClassLoader.getSystemClassLoader()); + if (rb != null) + applyResourceBundle(rb); + } + + /** + * Gets the AccessibleContext associated with this Window. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTWindow(); + return accessibleContext; + } + + /** + * Get graphics configuration. The implementation for Window will + * not ask any parent containers, since Window is a toplevel + * window and not actually embedded in the parent component. + */ + public GraphicsConfiguration getGraphicsConfiguration() + { + if (graphicsConfiguration != null) return graphicsConfiguration; + if (peer != null) return peer.getGraphicsConfiguration(); + return null; + } + + protected void processWindowFocusEvent(WindowEvent event) + { + if (windowFocusListener != null) + { + switch (event.getID ()) + { + case WindowEvent.WINDOW_GAINED_FOCUS: + windowFocusListener.windowGainedFocus (event); + break; + + case WindowEvent.WINDOW_LOST_FOCUS: + windowFocusListener.windowLostFocus (event); + break; + + default: + break; + } + } + } + + /** + * @since 1.4 + */ + protected void processWindowStateEvent(WindowEvent event) + { + if (windowStateListener != null + && event.getID () == WindowEvent.WINDOW_STATE_CHANGED) + windowStateListener.windowStateChanged (event); + } + + /** + * Returns whether this Window can get the focus or not. + * + * @since 1.4 + */ + public final boolean isFocusableWindow () + { + if (getFocusableWindowState () == false) + return false; + + if (this instanceof Dialog + || this instanceof Frame) + return true; + + // FIXME: Implement more possible cases for returning true. + + return false; + } + + /** + * Returns the value of the focusableWindowState property. + * + * @since 1.4 + */ + public boolean getFocusableWindowState () + { + return focusableWindowState; + } + + /** + * Sets the value of the focusableWindowState property. + * + * @since 1.4 + */ + public void setFocusableWindowState (boolean focusableWindowState) + { + this.focusableWindowState = focusableWindowState; + } + + // setBoundsCallback is needed so that when a user moves a window, + // the Window's location can be updated without calling the peer's + // setBounds method. When a user moves a window the peer window's + // location is updated automatically and the windowing system sends + // a message back to the application informing it of its updated + // dimensions. We must update the AWT Window class with these new + // dimensions. But we don't want to call the peer's setBounds + // method, because the peer's dimensions have already been updated. + // (Under X, having this method prevents Configure event loops when + // moving windows: Component.setBounds -> peer.setBounds -> + // postConfigureEvent -> Component.setBounds -> ... In some cases + // Configure event loops cause windows to jitter back and forth + // continuously). + void setBoundsCallback (int x, int y, int w, int h) + { + if (this.x == x && this.y == y && width == w && height == h) + return; + invalidate(); + boolean resized = width != w || height != h; + boolean moved = this.x != x || this.y != y; + this.x = x; + this.y = y; + width = w; + height = h; + if (resized && isShowing ()) + { + ComponentEvent ce = + new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED); + getToolkit().getSystemEventQueue().postEvent(ce); + } + if (moved && isShowing ()) + { + ComponentEvent ce = + new ComponentEvent(this, ComponentEvent.COMPONENT_MOVED); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + + /** + * Generate a unique name for this window. + * + * @return A unique name for this window. + */ + String generateName() + { + return "win" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_window_number++; + } +} diff --git a/libjava/classpath/java/awt/color/CMMException.java b/libjava/classpath/java/awt/color/CMMException.java new file mode 100644 index 0000000..ab328ec --- /dev/null +++ b/libjava/classpath/java/awt/color/CMMException.java @@ -0,0 +1,63 @@ +/* CMMException.java -- error in the native CMM + 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 java.awt.color; + +/** + * Thrown when there is an error in the native CMM. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class CMMException extends RuntimeException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 5775558044142994965L; + + /** + * Create a new instance with a specified detailed error message. + * + * @param message the message + */ + public CMMException(String message) + { + super(message); + } +} // class CMMException diff --git a/libjava/classpath/java/awt/color/ColorSpace.java b/libjava/classpath/java/awt/color/ColorSpace.java new file mode 100644 index 0000000..79369da --- /dev/null +++ b/libjava/classpath/java/awt/color/ColorSpace.java @@ -0,0 +1,183 @@ +/* ColorSpace.java -- transforms between color spaces + 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 java.awt.color; + +import java.io.Serializable; + +/** + * NEEDS DOCUMENTATION + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @since 1.2 + */ +public abstract class ColorSpace implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -409452704308689724L; + + public static final int TYPE_XYZ = 0; + public static final int TYPE_Lab = 1; + public static final int TYPE_Luv = 2; + public static final int TYPE_YCbCr = 3; + public static final int TYPE_Yxy = 4; + public static final int TYPE_RGB = 5; + public static final int TYPE_GRAY = 6; + public static final int TYPE_HSV = 7; + public static final int TYPE_HLS = 8; + public static final int TYPE_CMYK = 9; + // mysterious gap in the enumeration sequenece + public static final int TYPE_CMY = 11; + public static final int TYPE_2CLR = 12; + public static final int TYPE_3CLR = 13; + public static final int TYPE_4CLR = 14; + public static final int TYPE_5CLR = 15; + public static final int TYPE_6CLR = 16; + public static final int TYPE_7CLR = 17; + public static final int TYPE_8CLR = 18; + public static final int TYPE_9CLR = 19; + public static final int TYPE_ACLR = 20; + public static final int TYPE_BCLR = 21; + public static final int TYPE_CCLR = 22; + public static final int TYPE_DCLR = 23; + public static final int TYPE_ECLR = 24; + public static final int TYPE_FCLR = 25; + + public static final int CS_sRGB = 1000; + public static final int CS_LINEAR_RGB = 1004; + public static final int CS_CIEXYZ = 1001; + public static final int CS_PYCC = 1002; + public static final int CS_GRAY = 1003; + + private static final int CS_BASE = CS_sRGB; + private static final int CS_END = CS_LINEAR_RGB + 1; + private static final int CS_COUNT = CS_END - CS_BASE; + + // Instances are lazily instantiated + private static final ColorSpace[] INSTANCES = new ColorSpace[CS_COUNT]; + + /** + * @serial + */ + // Visible in subclass. + final int type; + + /** + * @serial + */ + // Visible in subclass. + final int numComponents; + + protected ColorSpace(int type, int numcomponents) + { + this.type = type; + numComponents = numcomponents; + } + + public static ColorSpace getInstance(int colorspace) + { + if ((colorspace >= CS_BASE) && (colorspace < CS_END)) + { + int instanceIndex = colorspace - CS_BASE; + if (INSTANCES[instanceIndex] == null) + { + ICC_Profile profile = new ICC_Profile(colorspace); + INSTANCES[instanceIndex] = new ICC_ColorSpace(profile); + } + return INSTANCES[instanceIndex]; + } + throw new IllegalArgumentException("unknown/unsupported colorspace"); + } + + public boolean isCS_sRGB() + { + return type == CS_sRGB; + } + + /** + * Transforms a color value assumed to be in this ColorSpace into a value in + * the default CS_sRGB color space. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at least + * the number of components in this ColorSpace. + */ + public abstract float[] toRGB(float[] colorvalue); + + public abstract float[] fromRGB(float[] rgbvalue); + + public abstract float[] toCIEXYZ(float[] colorvalue); + + public abstract float[] fromCIEXYZ(float[] colorvalue); + + public int getType() + { + return type; + } + + public int getNumComponents() + { + return numComponents; + } + + public String getName(int idx) + { + return "type " + type; + } + + /** + * @since 1.4 + */ + public float getMinValue(int idx) + { + if (idx < 0 || idx >= numComponents) + throw new IllegalArgumentException(); + return 0; + } + + /** + * @since 1.4 + */ + public float getMaxValue(int idx) + { + if (idx < 0 || idx >= numComponents) + throw new IllegalArgumentException(); + return 1; + } +} // class ColorSpace diff --git a/libjava/classpath/java/awt/color/ICC_ColorSpace.java b/libjava/classpath/java/awt/color/ICC_ColorSpace.java new file mode 100644 index 0000000..b50048c --- /dev/null +++ b/libjava/classpath/java/awt/color/ICC_ColorSpace.java @@ -0,0 +1,314 @@ +/* ICC_ColorSpace.java -- the canonical color space implementation + 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 java.awt.color; + +import gnu.java.awt.color.CieXyzConverter; +import gnu.java.awt.color.ClutProfileConverter; +import gnu.java.awt.color.ColorSpaceConverter; +import gnu.java.awt.color.GrayProfileConverter; +import gnu.java.awt.color.GrayScaleConverter; +import gnu.java.awt.color.LinearRGBConverter; +import gnu.java.awt.color.PyccConverter; +import gnu.java.awt.color.RgbProfileConverter; +import gnu.java.awt.color.SrgbConverter; + +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * ICC_ColorSpace - an implementation of ColorSpace + * + * While an ICC_Profile class abstracts the data in an ICC profile file + * an ICC_ColorSpace performs the color space conversions defined by + * an ICC_Profile instance. + * + * Typically, an ICC_Profile will either be created using getInstance, + * either from the built-in colorspaces, or from an ICC profile file. + * Then a ICC_Colorspace will be used to perform transforms from the + * device colorspace to and from the profile color space. + * + * The PCS used by ColorSpace is CIE XYZ relative a D50 white point. + * (Profiles using a CIE Lab PCS will have their input and output converted + * to D50 CIE XYZ accordingly. + * + * Note that a valid profile may not contain transforms in both directions, + * in which case the output may be undefined. + * All built-in colorspaces have bidirectional transforms, but developers + * using an ICC profile file may want to check the profile class using + * the ICC_Profile.getProfileClass() method. Input class profiles are + * guaranteed to have transforms to the PCS, output class profiles are + * guaranteed to have transforms from the PCS to device space. + * + * @author Sven de Marothy + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @since 1.2 + */ +public class ICC_ColorSpace extends ColorSpace +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 3455889114070431483L; + + /** + * @serial + */ + private ICC_Profile thisProfile; + + /** + * @serial + */ + private float[] minVal; + + /** + * @serial + */ + private float[] maxVal; + + /** + * @serial + */ + private float[] diffMinMax; + + /** + * @serial + */ + private float[] invDiffMinMax; + + /** + * @serial + */ + private boolean needScaleInit; + + /** + * Tells us if the PCS is CIE LAB (must be CIEXYZ otherwise) + */ + private transient int type; + private transient int nComponents; + private transient ColorSpaceConverter converter; + + /** + * Constructs a new ICC_ColorSpace from an ICC_Profile object. + * + * @exception IllegalArgumentException If profile is inappropriate for + * representing a ColorSpace. + */ + public ICC_ColorSpace(ICC_Profile profile) + { + super(profile.getColorSpaceType(), profile.getNumComponents()); + + converter = getConverter(profile); + thisProfile = profile; + nComponents = profile.getNumComponents(); + type = profile.getColorSpaceType(); + makeArrays(); + } + + /** + * Return the profile + */ + public ICC_Profile getProfile() + { + return thisProfile; + } + + /** + * Transforms a color value assumed to be in this ColorSpace into a value in + * the default CS_sRGB color space. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at least + * the number of components in this ColorSpace. + */ + public float[] toRGB(float[] colorvalue) + { + return converter.toRGB(colorvalue); + } + + /** + * Transforms a color value assumed to be in the default CS_sRGB color space + * into this ColorSpace. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at + * least 3. + */ + public float[] fromRGB(float[] rgbvalue) + { + return converter.fromRGB(rgbvalue); + } + + /** + * Transforms a color value assumed to be in this ColorSpace into the + * CS_CIEXYZ conversion color space. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at + * least the number of components in this ColorSpace. + */ + public float[] toCIEXYZ(float[] colorvalue) + { + return converter.toCIEXYZ(colorvalue); + } + + /** + * Transforms a color value assumed to be in the CS_CIEXYZ conversion color + * space into this ColorSpace. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at + * least 3. + */ + public float[] fromCIEXYZ(float[] colorvalue) + { + return converter.fromCIEXYZ(colorvalue); + } + + public boolean isCS_sRGB() + { + return converter instanceof SrgbConverter; + } + + /** + * Returns the minimum normalized color component value for the specified + * component. + * + * @exception IllegalArgumentException If component is less than 0 or greater + * than numComponents - 1. + * + * @since 1.4 + */ + public float getMinValue(int idx) + { + // FIXME: Not 100% certain of this. + if (type == ColorSpace.TYPE_Lab && (idx == 1 || idx == 2)) + return -128f; + + if (idx < 0 || idx >= nComponents) + throw new IllegalArgumentException(); + return 0; + } + + /** + * Returns the maximum normalized color component value for the specified + * component. + * + * @exception IllegalArgumentException If component is less than 0 or greater + * than numComponents - 1. + * + * @since 1.4 + */ + public float getMaxValue(int idx) + { + if (type == ColorSpace.TYPE_XYZ && idx >= 0 && idx <= 2) + return 1 + 32767 / 32768f; + else if (type == ColorSpace.TYPE_Lab) + { + if (idx == 0) + return 100; + if (idx == 1 || idx == 2) + return 127; + } + if (idx < 0 || idx >= nComponents) + throw new IllegalArgumentException(); + return 1; + } + + /** + * Returns a colorspace converter suitable for a given profile + */ + private ColorSpaceConverter getConverter(ICC_Profile profile) + { + ColorSpaceConverter converter; + switch (profile.isPredefined()) + { + case CS_sRGB: + converter = new SrgbConverter(); + break; + case CS_CIEXYZ: + converter = new CieXyzConverter(); + break; + case CS_GRAY: + converter = new GrayScaleConverter(); + break; + case CS_LINEAR_RGB: + converter = new LinearRGBConverter(); + break; + case CS_PYCC: + converter = new PyccConverter(); + break; + default: + if (profile instanceof ICC_ProfileRGB) + converter = new RgbProfileConverter((ICC_ProfileRGB) profile); + else if (profile instanceof ICC_ProfileGray) + converter = new GrayProfileConverter((ICC_ProfileGray) profile); + else + converter = new ClutProfileConverter(profile); + break; + } + return converter; + } + + /** + * Serialization compatibility requires these variable to be set, + * although we don't use them. Perhaps we should? + */ + private void makeArrays() + { + minVal = new float[nComponents]; + maxVal = new float[nComponents]; + + invDiffMinMax = diffMinMax = null; + for (int i = 0; i < nComponents; i++) + { + minVal[i] = getMinValue(i); + maxVal[i] = getMaxValue(i); + } + needScaleInit = true; + } + + /** + * Deserializes the object + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + // set up objects + converter = getConverter(thisProfile); + nComponents = thisProfile.getNumComponents(); + type = thisProfile.getColorSpaceType(); + } +} // class ICC_ColorSpace diff --git a/libjava/classpath/java/awt/color/ICC_Profile.java b/libjava/classpath/java/awt/color/ICC_Profile.java new file mode 100644 index 0000000..75f55a1 --- /dev/null +++ b/libjava/classpath/java/awt/color/ICC_Profile.java @@ -0,0 +1,1244 @@ +/* ICC_Profile.java -- color space profiling + 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 java.awt.color; + +import gnu.java.awt.color.ProfileHeader; +import gnu.java.awt.color.TagEntry; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.OutputStream; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * ICC Profile - represents an ICC Color profile. + * The ICC profile format is a standard file format which maps the transform + * from a device color space to a standard Profile Color Space (PCS), which + * can either be CIE L*a*b or CIE XYZ. + * (With the exception of device link profiles which map from one device space + * to another) + * + * ICC profiles calibrated to specific input/output devices are used when color + * fidelity is of importance. + * + * An instance of ICC_Profile can be created using the getInstance() methods, + * either using one of the predefined color spaces enumerated in ColorSpace, + * or from an ICC profile file, or from an input stream. + * + * An ICC_ColorSpace object can then be created to transform color values + * through the profile. + * + * The ICC_Profile class implements the version 2 format specified by + * International Color Consortium Specification ICC.1:1998-09, + * and its addendum ICC.1A:1999-04, April 1999 + * (available at www.color.org) + * + * @author Sven de Marothy + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @since 1.2 + */ +public class ICC_Profile implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -3938515861990936766L; + + /** + * ICC Profile classes + */ + public static final int CLASS_INPUT = 0; + public static final int CLASS_DISPLAY = 1; + public static final int CLASS_OUTPUT = 2; + public static final int CLASS_DEVICELINK = 3; + public static final int CLASS_COLORSPACECONVERSION = 4; + public static final int CLASS_ABSTRACT = 5; + public static final int CLASS_NAMEDCOLOR = 6; + + /** + * ICC Profile class signatures + */ + public static final int icSigInputClass = 0x73636e72; // 'scnr' + public static final int icSigDisplayClass = 0x6d6e7472; // 'mntr' + public static final int icSigOutputClass = 0x70727472; // 'prtr' + public static final int icSigLinkClass = 0x6c696e6b; // 'link' + public static final int icSigColorSpaceClass = 0x73706163; // 'spac' + public static final int icSigAbstractClass = 0x61627374; // 'abst' + public static final int icSigNamedColorClass = 0x6e6d636c; // 'nmcl' + + /** + * Color space signatures + */ + public static final int icSigXYZData = 0x58595A20; // 'XYZ ' + public static final int icSigLabData = 0x4C616220; // 'Lab ' + public static final int icSigLuvData = 0x4C757620; // 'Luv ' + public static final int icSigYCbCrData = 0x59436272; // 'YCbr' + public static final int icSigYxyData = 0x59787920; // 'Yxy ' + public static final int icSigRgbData = 0x52474220; // 'RGB ' + public static final int icSigGrayData = 0x47524159; // 'GRAY' + public static final int icSigHsvData = 0x48535620; // 'HSV ' + public static final int icSigHlsData = 0x484C5320; // 'HLS ' + public static final int icSigCmykData = 0x434D594B; // 'CMYK' + public static final int icSigCmyData = 0x434D5920; // 'CMY ' + public static final int icSigSpace2CLR = 0x32434C52; // '2CLR' + public static final int icSigSpace3CLR = 0x33434C52; // '3CLR' + public static final int icSigSpace4CLR = 0x34434C52; // '4CLR' + public static final int icSigSpace5CLR = 0x35434C52; // '5CLR' + public static final int icSigSpace6CLR = 0x36434C52; // '6CLR' + public static final int icSigSpace7CLR = 0x37434C52; // '7CLR' + public static final int icSigSpace8CLR = 0x38434C52; // '8CLR' + public static final int icSigSpace9CLR = 0x39434C52; // '9CLR' + public static final int icSigSpaceACLR = 0x41434C52; // 'ACLR' + public static final int icSigSpaceBCLR = 0x42434C52; // 'BCLR' + public static final int icSigSpaceCCLR = 0x43434C52; // 'CCLR' + public static final int icSigSpaceDCLR = 0x44434C52; // 'DCLR' + public static final int icSigSpaceECLR = 0x45434C52; // 'ECLR' + public static final int icSigSpaceFCLR = 0x46434C52; // 'FCLR' + + /** + * Rendering intents + */ + public static final int icPerceptual = 0; + public static final int icRelativeColorimetric = 1; + public static final int icSaturation = 2; + public static final int icAbsoluteColorimetric = 3; + + /** + * Tag signatures + */ + public static final int icSigAToB0Tag = 0x41324230; // 'A2B0' + public static final int icSigAToB1Tag = 0x41324231; // 'A2B1' + public static final int icSigAToB2Tag = 0x41324232; // 'A2B2' + public static final int icSigBlueColorantTag = 0x6258595A; // 'bXYZ' + public static final int icSigBlueTRCTag = 0x62545243; // 'bTRC' + public static final int icSigBToA0Tag = 0x42324130; // 'B2A0' + public static final int icSigBToA1Tag = 0x42324131; // 'B2A1' + public static final int icSigBToA2Tag = 0x42324132; // 'B2A2' + public static final int icSigCalibrationDateTimeTag = 0x63616C74; // 'calt' + public static final int icSigCharTargetTag = 0x74617267; // 'targ' + public static final int icSigCopyrightTag = 0x63707274; // 'cprt' + public static final int icSigCrdInfoTag = 0x63726469; // 'crdi' + public static final int icSigDeviceMfgDescTag = 0x646D6E64; // 'dmnd' + public static final int icSigDeviceModelDescTag = 0x646D6464; // 'dmdd' + public static final int icSigDeviceSettingsTag = 0x64657673; // 'devs' + public static final int icSigGamutTag = 0x67616D74; // 'gamt' + public static final int icSigGrayTRCTag = 0x6b545243; // 'kTRC' + public static final int icSigGreenColorantTag = 0x6758595A; // 'gXYZ' + public static final int icSigGreenTRCTag = 0x67545243; // 'gTRC' + public static final int icSigLuminanceTag = 0x6C756d69; // 'lumi' + public static final int icSigMeasurementTag = 0x6D656173; // 'meas' + public static final int icSigMediaBlackPointTag = 0x626B7074; // 'bkpt' + public static final int icSigMediaWhitePointTag = 0x77747074; // 'wtpt' + public static final int icSigNamedColor2Tag = 0x6E636C32; // 'ncl2' + public static final int icSigOutputResponseTag = 0x72657370; // 'resp' + public static final int icSigPreview0Tag = 0x70726530; // 'pre0' + public static final int icSigPreview1Tag = 0x70726531; // 'pre1' + public static final int icSigPreview2Tag = 0x70726532; // 'pre2' + public static final int icSigProfileDescriptionTag = 0x64657363; // 'desc' + public static final int icSigProfileSequenceDescTag = 0x70736571; // 'pseq' + public static final int icSigPs2CRD0Tag = 0x70736430; // 'psd0' + public static final int icSigPs2CRD1Tag = 0x70736431; // 'psd1' + public static final int icSigPs2CRD2Tag = 0x70736432; // 'psd2' + public static final int icSigPs2CRD3Tag = 0x70736433; // 'psd3' + public static final int icSigPs2CSATag = 0x70733273; // 'ps2s' + public static final int icSigPs2RenderingIntentTag = 0x70733269; // 'ps2i' + public static final int icSigRedColorantTag = 0x7258595A; // 'rXYZ' + public static final int icSigRedTRCTag = 0x72545243; // 'rTRC' + public static final int icSigScreeningDescTag = 0x73637264; // 'scrd' + public static final int icSigScreeningTag = 0x7363726E; // 'scrn' + public static final int icSigTechnologyTag = 0x74656368; // 'tech' + public static final int icSigUcrBgTag = 0x62666420; // 'bfd ' + public static final int icSigViewingCondDescTag = 0x76756564; // 'vued' + public static final int icSigViewingConditionsTag = 0x76696577; // 'view' + public static final int icSigChromaticityTag = 0x6368726D; // 'chrm' + + /** + * Non-ICC tag 'head' for use in retrieving the header with getData() + */ + public static final int icSigHead = 0x68656164; + + /** + * Header offsets + */ + public static final int icHdrSize = 0; + public static final int icHdrCmmId = 4; + public static final int icHdrVersion = 8; + public static final int icHdrDeviceClass = 12; + public static final int icHdrColorSpace = 16; + public static final int icHdrPcs = 20; + public static final int icHdrDate = 24; + public static final int icHdrMagic = 36; + public static final int icHdrPlatform = 40; + public static final int icHdrFlags = 44; + public static final int icHdrManufacturer = 48; + public static final int icHdrModel = 52; + public static final int icHdrAttributes = 56; + public static final int icHdrRenderingIntent = 64; + public static final int icHdrIlluminant = 68; + public static final int icHdrCreator = 80; + + /** + * + */ + public static final int icTagType = 0; + public static final int icTagReserved = 4; + public static final int icCurveCount = 8; + public static final int icCurveData = 12; + public static final int icXYZNumberX = 8; + + /** + * offset of the Tag table + */ + private static final int tagTableOffset = 128; + + /** + * @serial + */ + private static final int iccProfileSerializedDataVersion = 1; + + /** + * Constants related to generating profiles for + * built-in colorspace profiles + */ + /** + * Copyright notice to stick into built-in-profile files. + */ + private static final String copyrightNotice = "Generated by GNU Classpath."; + + /** + * Resolution of the TRC to use for predefined profiles. + * 1024 should suffice. + */ + private static final int TRC_POINTS = 1024; + + /** + * CIE 1931 D50 white point (in Lab coordinates) + */ + private static final float[] D50 = { 0.96422f, 1.00f, 0.82521f }; + + /** + * Color space profile ID + * Set to the predefined profile class (e.g. CS_sRGB) if a predefined + * color space is used, set to -1 otherwise. + * (or if the profile has been modified) + */ + private transient int profileID; + + /** + * The profile header data + */ + private transient ProfileHeader header; + + /** + * A hashtable containing the profile tags as TagEntry objects + */ + private transient Hashtable tagTable; + + /** + * Contructor for predefined colorspaces + */ + ICC_Profile(int profileID) + { + header = null; + tagTable = null; + createProfile(profileID); + } + + /** + * Constructs an ICC_Profile from a header and a table of loaded tags. + */ + ICC_Profile(ProfileHeader h, Hashtable tags) throws IllegalArgumentException + { + header = h; + tagTable = tags; + profileID = -1; // Not a predefined color space + } + + /** + * Constructs an ICC_Profile from a byte array of data. + */ + ICC_Profile(byte[] data) throws IllegalArgumentException + { + // get header and verify it + header = new ProfileHeader(data); + header.verifyHeader(data.length); + tagTable = createTagTable(data); + profileID = -1; // Not a predefined color space + } + + /** + * Free up the used memory. + */ + protected void finalize() + { + } + + /** + * Returns an ICC_Profile instance from a byte array of profile data. + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @throws IllegalArgumentException if the profile data is an invalid + * v2 profile. + * + * @param data - the profile data + * @return An ICC_Profile object + */ + public static ICC_Profile getInstance(byte[] data) + { + ProfileHeader header = new ProfileHeader(data); + + // verify it as a correct ICC header, including size + header.verifyHeader(data.length); + + Hashtable tags = createTagTable(data); + + if (isRGBProfile(header, tags)) + return new ICC_ProfileRGB(data); + if (isGrayProfile(header, tags)) + return new ICC_ProfileGray(data); + + return new ICC_Profile(header, tags); + } + + /** + * Returns an predefined ICC_Profile instance. + * + * This will construct an ICC_Profile instance from one of the predefined + * color spaces in the ColorSpace class. (e.g. CS_sRGB, CS_GRAY, etc) + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @return An ICC_Profile object + */ + public static ICC_Profile getInstance(int cspace) + { + if (cspace == ColorSpace.CS_sRGB || cspace == ColorSpace.CS_LINEAR_RGB) + return new ICC_ProfileRGB(cspace); + if (cspace == ColorSpace.CS_GRAY) + return new ICC_ProfileGray(cspace); + return new ICC_Profile(cspace); + } + + /** + * Returns an ICC_Profile instance from an ICC Profile file. + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @throws IllegalArgumentException if the profile data is an invalid + * v2 profile. + * @throws IOException if the file could not be read. + * + * @param filename - the file name of the profile file. + * @return An ICC_Profile object + */ + public static ICC_Profile getInstance(String filename) + throws IOException + { + return getInstance(new FileInputStream(filename)); + } + + /** + * Returns an ICC_Profile instance from an InputStream. + * + * This method can be used for reading ICC profiles embedded in files + * which support this. (JPEG and SVG for instance). + * + * The stream is treated in the following way: The profile header + * (128 bytes) is read first, and the header is validated. If the profile + * header is valid, it will then attempt to read the rest of the profile + * from the stream. The stream is not closed after reading. + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @throws IllegalArgumentException if the profile data is an invalid + * v2 profile. + * @throws IOException if the stream could not be read. + * + * @param in - the input stream to read the profile from. + * @return An ICC_Profile object + */ + public static ICC_Profile getInstance(InputStream in) + throws IOException + { + // read the header + byte[] headerData = new byte[ProfileHeader.HEADERSIZE]; + if (in.read(headerData) != ProfileHeader.HEADERSIZE) + throw new IllegalArgumentException("Invalid profile header"); + + ProfileHeader header = new ProfileHeader(headerData); + + // verify it as a correct ICC header, but do not verify the + // size as we are reading from a stream. + header.verifyHeader(-1); + + // get the size + byte[] data = new byte[header.getSize()]; + System.arraycopy(headerData, 0, data, 0, ProfileHeader.HEADERSIZE); + + // read the rest + if (in.read(data, ProfileHeader.HEADERSIZE, + header.getSize() - ProfileHeader.HEADERSIZE) != header.getSize() + - ProfileHeader.HEADERSIZE) + throw new IOException("Incorrect profile size"); + + return getInstance(data); + } + + /** + * Returns the major version number + */ + public int getMajorVersion() + { + return header.getMajorVersion(); + } + + /** + * Returns the minor version number. + * + * Only the least-significant byte contains data, in BCD form: + * the least-significant nibble is the BCD bug fix revision, + * the most-significant nibble is the BCD minor revision number. + * + * (E.g. For a v2.1.0 profile this will return 0x10) + */ + public int getMinorVersion() + { + return header.getMinorVersion(); + } + + /** + * Returns the device class of this profile, + * + * (E.g. CLASS_INPUT for a scanner profile, + * CLASS_OUTPUT for a printer) + */ + public int getProfileClass() + { + return header.getProfileClass(); + } + + /** + * Returns the color space of this profile, in terms + * of the color space constants defined in ColorSpace. + * (For example, it may be a ColorSpace.TYPE_RGB) + */ + public int getColorSpaceType() + { + return header.getColorSpace(); + } + + /** + * Returns the color space of this profile's Profile Connection Space (OCS) + * + * In terms of the color space constants defined in ColorSpace. + * This may be TYPE_XYZ or TYPE_Lab + */ + public int getPCSType() + { + return header.getProfileColorSpace(); + } + + /** + * Writes the profile data to an ICC profile file. + * @param filename - The name of the file to write + * @throws IOException if the write failed. + */ + public void write(String filename) throws IOException + { + FileOutputStream out = new FileOutputStream(filename); + write(out); + out.flush(); + out.close(); + } + + /** + * Writes the profile data in ICC profile file-format to a stream. + * This is useful for embedding ICC profiles in file formats which + * support this (such as JPEG and SVG). + * + * The stream is not closed after writing. + * @param out - The outputstream to which the profile data should be written + * @throws IOException if the write failed. + */ + public void write(OutputStream out) throws IOException + { + out.write(getData()); + } + + /** + * Returns the data corresponding to this ICC_Profile as a byte array. + * + * @return The data in a byte array, + * where the first element corresponds to first byte of the profile file. + */ + public byte[] getData() + { + int size = getSize(); + byte[] data = new byte[size]; + + // Header + System.arraycopy(header.getData(size), 0, data, 0, ProfileHeader.HEADERSIZE); + // # of tags + byte[] tt = getTagTable(); + System.arraycopy(tt, 0, data, ProfileHeader.HEADERSIZE, tt.length); + + Enumeration e = tagTable.elements(); + while (e.hasMoreElements()) + { + TagEntry tag = (TagEntry) e.nextElement(); + System.arraycopy(tag.getData(), 0, + data, tag.getOffset(), tag.getSize()); + } + return data; + } + + /** + * Returns the ICC profile tag data + * The non ICC-tag icSigHead is also permitted to request the header data. + * + * @param tagSignature The ICC signature of the requested tag + * @return A byte array containing the tag data + */ + public byte[] getData(int tagSignature) + { + if (tagSignature == icSigHead) + return header.getData(getSize()); + + TagEntry t = (TagEntry) tagTable.get(TagEntry.tagHashKey(tagSignature)); + if (t == null) + return null; + return t.getData(); + } + + /** + * Sets the ICC profile tag data. + * + * Note that an ICC profile can only contain one tag of each type, if + * a tag already exists with the given signature, it is replaced. + * + * @param tagSignature - The signature of the tag to set + * @param data - A byte array containing the tag data + */ + public void setData(int tagSignature, byte[] data) + { + profileID = -1; // Not a predefined color space if modified. + + if (tagSignature == icSigHead) + header = new ProfileHeader(data); + else + { + TagEntry t = new TagEntry(tagSignature, data); + tagTable.put(t.hashKey(), t); + } + } + + /** + * Get the number of components in the profile's device color space. + */ + public int getNumComponents() + { + int[] lookup = + { + ColorSpace.TYPE_RGB, 3, ColorSpace.TYPE_CMY, 3, + ColorSpace.TYPE_CMYK, 4, ColorSpace.TYPE_GRAY, 1, + ColorSpace.TYPE_YCbCr, 3, ColorSpace.TYPE_XYZ, 3, + ColorSpace.TYPE_Lab, 3, ColorSpace.TYPE_HSV, 3, + ColorSpace.TYPE_2CLR, 2, ColorSpace.TYPE_Luv, 3, + ColorSpace.TYPE_Yxy, 3, ColorSpace.TYPE_HLS, 3, + ColorSpace.TYPE_3CLR, 3, ColorSpace.TYPE_4CLR, 4, + ColorSpace.TYPE_5CLR, 5, ColorSpace.TYPE_6CLR, 6, + ColorSpace.TYPE_7CLR, 7, ColorSpace.TYPE_8CLR, 8, + ColorSpace.TYPE_9CLR, 9, ColorSpace.TYPE_ACLR, 10, + ColorSpace.TYPE_BCLR, 11, ColorSpace.TYPE_CCLR, 12, + ColorSpace.TYPE_DCLR, 13, ColorSpace.TYPE_ECLR, 14, + ColorSpace.TYPE_FCLR, 15 + }; + for (int i = 0; i < lookup.length; i += 2) + if (header.getColorSpace() == lookup[i]) + return lookup[i + 1]; + return 3; // should never happen. + } + + /** + * After deserializing we must determine if the class we want + * is really one of the more specialized ICC_ProfileRGB or + * ICC_ProfileGray classes. + */ + protected Object readResolve() throws ObjectStreamException + { + if (isRGBProfile(header, tagTable)) + return new ICC_ProfileRGB(getData()); + if (isGrayProfile(header, tagTable)) + return new ICC_ProfileGray(getData()); + return this; + } + + /** + * Deserializes an instance + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + String predef = (String) s.readObject(); + byte[] data = (byte[]) s.readObject(); + + if (data != null) + { + header = new ProfileHeader(data); + tagTable = createTagTable(data); + profileID = -1; // Not a predefined color space + } + + if (predef != null) + { + predef = predef.intern(); + if (predef.equals("CS_sRGB")) + createProfile(ColorSpace.CS_sRGB); + if (predef.equals("CS_LINEAR_RGB")) + createProfile(ColorSpace.CS_LINEAR_RGB); + if (predef.equals("CS_CIEXYZ")) + createProfile(ColorSpace.CS_CIEXYZ); + if (predef.equals("CS_GRAY")) + createProfile(ColorSpace.CS_GRAY); + if (predef.equals("CS_PYCC")) + createProfile(ColorSpace.CS_PYCC); + } + } + + /** + * Serializes an instance + * The format is a String and a byte array, + * The string is non-null if the instance is one of the built-in profiles. + * Otherwise the byte array is non-null and represents the profile data. + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + if (profileID == ColorSpace.CS_sRGB) + s.writeObject("CS_sRGB"); + else if (profileID == ColorSpace.CS_LINEAR_RGB) + s.writeObject("CS_LINEAR_RGB"); + else if (profileID == ColorSpace.CS_CIEXYZ) + s.writeObject("CS_CIEXYZ"); + else if (profileID == ColorSpace.CS_GRAY) + s.writeObject("CS_GRAY"); + else if (profileID == ColorSpace.CS_PYCC) + s.writeObject("CS_PYCC"); + else + { + s.writeObject(null); // null string + s.writeObject(getData()); // data + return; + } + s.writeObject(null); // null data + } + + /** + * Sorts a ICC profile byte array into TagEntry objects stored in + * a hash table. + */ + private static Hashtable createTagTable(byte[] data) + throws IllegalArgumentException + { + ByteBuffer buf = ByteBuffer.wrap(data); + int nTags = buf.getInt(tagTableOffset); + + Hashtable tagTable = new Hashtable(); + for (int i = 0; i < nTags; i++) + { + TagEntry te = new TagEntry(buf.getInt(tagTableOffset + + i * TagEntry.entrySize + 4), + buf.getInt(tagTableOffset + + i * TagEntry.entrySize + 8), + buf.getInt(tagTableOffset + + i * TagEntry.entrySize + 12), + data); + + if (tagTable.put(te.hashKey(), te) != null) + throw new IllegalArgumentException("Duplicate tag in profile:" + te); + } + return tagTable; + } + + /** + * Returns the total size of the padded, stored data + * Note: Tags must be stored on 4-byte aligned offsets. + */ + private int getSize() + { + int totalSize = ProfileHeader.HEADERSIZE; // size of header + + int tagTableSize = 4 + tagTable.size() * TagEntry.entrySize; // size of tag table + if ((tagTableSize & 0x0003) != 0) + tagTableSize += 4 - (tagTableSize & 0x0003); // pad + totalSize += tagTableSize; + + Enumeration e = tagTable.elements(); + while (e.hasMoreElements()) + { // tag data + int tagSize = ((TagEntry) e.nextElement()).getSize(); + if ((tagSize & 0x0003) != 0) + tagSize += 4 - (tagSize & 0x0003); // pad + totalSize += tagSize; + } + return totalSize; + } + + /** + * Generates the tag index table + */ + private byte[] getTagTable() + { + int tagTableSize = 4 + tagTable.size() * TagEntry.entrySize; + if ((tagTableSize & 0x0003) != 0) + tagTableSize += 4 - (tagTableSize & 0x0003); // pad + + int offset = 4; + int tagOffset = ProfileHeader.HEADERSIZE + tagTableSize; + ByteBuffer buf = ByteBuffer.allocate(tagTableSize); + buf.putInt(tagTable.size()); // number of tags + + Enumeration e = tagTable.elements(); + while (e.hasMoreElements()) + { + TagEntry tag = (TagEntry) e.nextElement(); + buf.putInt(offset, tag.getSignature()); + buf.putInt(offset + 4, tagOffset); + buf.putInt(offset + 8, tag.getSize()); + tag.setOffset(tagOffset); + int tagSize = tag.getSize(); + if ((tagSize & 0x0003) != 0) + tagSize += 4 - (tagSize & 0x0003); // pad + tagOffset += tagSize; + offset += 12; + } + return buf.array(); + } + + /** + * Returns if the criteria for an ICC_ProfileRGB are met. + * This means: + * Color space is TYPE_RGB + * (r,g,b)ColorantTags included + * (r,g,b)TRCTags included + * mediaWhitePointTag included + */ + private static boolean isRGBProfile(ProfileHeader header, Hashtable tags) + { + if (header.getColorSpace() != ColorSpace.TYPE_RGB) + return false; + if (tags.get(TagEntry.tagHashKey(icSigRedColorantTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigGreenColorantTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigBlueColorantTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigRedTRCTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigGreenTRCTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigBlueTRCTag)) == null) + return false; + return (tags.get(TagEntry.tagHashKey(icSigMediaWhitePointTag)) != null); + } + + /** + * Returns if the criteria for an ICC_ProfileGray are met. + * This means: + * Colorspace is TYPE_GRAY + * grayTRCTag included + * mediaWhitePointTag included + */ + private static boolean isGrayProfile(ProfileHeader header, Hashtable tags) + { + if (header.getColorSpace() != ColorSpace.TYPE_GRAY) + return false; + if (tags.get(TagEntry.tagHashKey(icSigGrayTRCTag)) == null) + return false; + return (tags.get(TagEntry.tagHashKey(icSigMediaWhitePointTag)) != null); + } + + /** + * Returns curve data for a 'curv'-type tag + * If it's a gamma curve, a single entry will be returned with the + * gamma value (including 1.0 for linear response) + * Otherwise the TRC table is returned. + * + * (Package private - used by ICC_ProfileRGB and ICC_ProfileGray) + */ + short[] getCurve(int signature) + { + byte[] data = getData(signature); + short[] curve; + + // can't find tag? + if (data == null) + return null; + + // not an curve type tag? + ByteBuffer buf = ByteBuffer.wrap(data); + if (buf.getInt(0) != 0x63757276) // 'curv' type + return null; + int count = buf.getInt(8); + if (count == 0) + { + curve = new short[1]; + curve[0] = 0x0100; // 1.00 in u8fixed8 + return curve; + } + if (count == 1) + { + curve = new short[1]; + curve[0] = buf.getShort(12); // other u8fixed8 gamma + return curve; + } + curve = new short[count]; + for (int i = 0; i < count; i++) + curve[i] = buf.getShort(12 + i * 2); + return curve; + } + + /** + * Returns XYZ tristimulus values for an 'XYZ ' type tag + * @return the XYZ values, or null if the tag was not an 'XYZ ' type tag. + * + * (Package private - used by ICC_ProfileXYZ and ICC_ProfileGray) + */ + float[] getXYZData(int signature) + { + byte[] data = getData(signature); + + // can't find tag? + if (data == null) + return null; + + // not an XYZData type tag? + ByteBuffer buf = ByteBuffer.wrap(data); + if (buf.getInt(0) != icSigXYZData) // 'XYZ ' type + return null; + + float[] point = new float[3]; + + // get the X,Y,Z tristimulus values + point[0] = ((float) buf.getInt(8)) / 65536f; + point[1] = ((float) buf.getInt(12)) / 65536f; + point[2] = ((float) buf.getInt(16)) / 65536f; + return point; + } + + /** + * Returns the profile ID if it's a predefined profile + * Or -1 for a profile loaded from an ICC profile + * + * (Package private - used by ICC_ColorSpace) + */ + int isPredefined() + { + return profileID; + } + + /** + * Creates a tag of XYZ-value type. + */ + private byte[] makeXYZData(float[] values) + { + ByteBuffer buf = ByteBuffer.allocate(20); + buf.putInt(0, icSigXYZData); // 'XYZ ' + buf.putInt(4, 0); + buf.putInt(8, (int) (values[0] * 65536.0)); + buf.putInt(12, (int) (values[1] * 65536.0)); + buf.putInt(16, (int) (values[2] * 65536.0)); + return buf.array(); + } + + /** + * Creates a tag of text type + */ + private byte[] makeTextTag(String text) + { + int length = text.length(); + ByteBuffer buf = ByteBuffer.allocate(8 + length + 1); + byte[] data; + try + { + data = text.getBytes("US-ASCII"); + } + catch (UnsupportedEncodingException e) + { + data = new byte[length]; // shouldn't happen + } + + buf.putInt(0, (int) 0x74657874); // 'text' + buf.putInt(4, 0); + for (int i = 0; i < length; i++) + buf.put(8 + i, data[i]); + buf.put(8 + length, (byte) 0); // null-terminate + return buf.array(); + } + + /** + * Creates a tag of textDescriptionType + */ + private byte[] makeDescTag(String text) + { + int length = text.length(); + ByteBuffer buf = ByteBuffer.allocate(90 + length + 1); + buf.putInt(0, (int) 0x64657363); // 'desc' + buf.putInt(4, 0); // reserved + buf.putInt(8, length + 1); // ASCII length, including null termination + byte[] data; + + try + { + data = text.getBytes("US-ASCII"); + } + catch (UnsupportedEncodingException e) + { + data = new byte[length]; // shouldn't happen + } + + for (int i = 0; i < length; i++) + buf.put(12 + i, data[i]); + buf.put(12 + length, (byte) 0); // null-terminate + + for (int i = 0; i < 39; i++) + buf.putShort(13 + length + (i * 2), (short) 0); // 78 bytes we can ignore + + return buf.array(); + } + + /** + * Creates a tag of TRC type (linear curve) + */ + private byte[] makeTRC() + { + ByteBuffer buf = ByteBuffer.allocate(12); + buf.putInt(0, 0x63757276); // 'curv' type + buf.putInt(4, 0); // reserved + buf.putInt(8, 0); + return buf.array(); + } + + /** + * Creates a tag of TRC type (single gamma value) + */ + private byte[] makeTRC(float gamma) + { + short gammaValue = (short) (gamma * 256f); + ByteBuffer buf = ByteBuffer.allocate(14); + buf.putInt(0, 0x63757276); // 'curv' type + buf.putInt(4, 0); // reserved + buf.putInt(8, 1); + buf.putShort(12, gammaValue); // 1.00 in u8fixed8 + return buf.array(); + } + + /** + * Creates a tag of TRC type (TRC curve points) + */ + private byte[] makeTRC(float[] trc) + { + ByteBuffer buf = ByteBuffer.allocate(12 + 2 * trc.length); + buf.putInt(0, 0x63757276); // 'curv' type + buf.putInt(4, 0); // reserved + buf.putInt(8, trc.length); // number of points + + // put the curve values + for (int i = 0; i < trc.length; i++) + buf.putShort(12 + i * 2, (short) (trc[i] * 65535f)); + + return buf.array(); + } + + /** + * Creates an identity color lookup table. + */ + private byte[] makeIdentityClut() + { + final int nIn = 3; + final int nOut = 3; + final int nInEntries = 256; + final int nOutEntries = 256; + final int gridpoints = 16; + + // gridpoints**nIn + final int clutSize = 2 * nOut * gridpoints * gridpoints * gridpoints; + final int totalSize = clutSize + 2 * nInEntries * nIn + + 2 * nOutEntries * nOut + 52; + + ByteBuffer buf = ByteBuffer.allocate(totalSize); + buf.putInt(0, 0x6D667432); // 'mft2' + buf.putInt(4, 0); // reserved + buf.put(8, (byte) nIn); // number input channels + buf.put(9, (byte) nOut); // number output channels + buf.put(10, (byte) gridpoints); // number gridpoints + buf.put(11, (byte) 0); // padding + + // identity matrix + buf.putInt(12, 65536); // = 1 in s15.16 fixed point + buf.putInt(16, 0); + buf.putInt(20, 0); + buf.putInt(24, 0); + buf.putInt(28, 65536); + buf.putInt(32, 0); + buf.putInt(36, 0); + buf.putInt(40, 0); + buf.putInt(44, 65536); + + buf.putShort(48, (short) nInEntries); // input table entries + buf.putShort(50, (short) nOutEntries); // output table entries + + // write the linear input channels, unsigned 16.16 fixed point, + // from 0.0 to FF.FF + for (int channel = 0; channel < 3; channel++) + for (int i = 0; i < nInEntries; i++) + { + short n = (short) ((i << 8) | i); // assumes 256 entries + buf.putShort(52 + (channel * nInEntries + i) * 2, n); + } + int clutOffset = 52 + nInEntries * nIn * 2; + + for (int x = 0; x < gridpoints; x++) + for (int y = 0; y < gridpoints; y++) + for (int z = 0; z < gridpoints; z++) + { + int offset = clutOffset + z * 2 * nOut + y * gridpoints * 2 * nOut + + x * gridpoints * gridpoints * 2 * nOut; + double xf = ((double) x) / ((double) gridpoints - 1.0); + double yf = ((double) y) / ((double) gridpoints - 1.0); + double zf = ((double) z) / ((double) gridpoints - 1.0); + buf.putShort(offset, (short) (xf * 65535.0)); + buf.putShort(offset + 2, (short) (yf * 65535.0)); + buf.putShort(offset + 4, (short) (zf * 65535.0)); + } + + for (int channel = 0; channel < 3; channel++) + for (int i = 0; i < nOutEntries; i++) + { + short n = (short) ((i << 8) | i); // assumes 256 entries + buf.putShort(clutOffset + clutSize + (channel * nOutEntries + i) * 2, + n); + } + + return buf.array(); + } + + /** + * Creates profile data corresponding to the built-in colorspaces. + */ + private void createProfile(int colorSpace) throws IllegalArgumentException + { + this.profileID = colorSpace; + header = new ProfileHeader(); + tagTable = new Hashtable(); + + switch (colorSpace) + { + case ColorSpace.CS_sRGB: + createRGBProfile(); + return; + case ColorSpace.CS_LINEAR_RGB: + createLinearRGBProfile(); + return; + case ColorSpace.CS_CIEXYZ: + createCIEProfile(); + return; + case ColorSpace.CS_GRAY: + createGrayProfile(); + return; + case ColorSpace.CS_PYCC: + createPyccProfile(); + return; + default: + throw new IllegalArgumentException("Not a predefined color space!"); + } + } + + /** + * Creates an ICC_Profile representing the sRGB color space + */ + private void createRGBProfile() + { + header.setColorSpace( ColorSpace.TYPE_RGB ); + header.setProfileColorSpace( ColorSpace.TYPE_XYZ ); + ICC_ColorSpace cs = new ICC_ColorSpace(this); + + float[] r = { 1f, 0f, 0f }; + float[] g = { 0f, 1f, 0f }; + float[] b = { 0f, 0f, 1f }; + float[] black = { 0f, 0f, 0f }; + + // CIE 1931 D50 white point (in Lab coordinates) + float[] white = D50; + + // Get tristimulus values (matrix elements) + r = cs.toCIEXYZ(r); + g = cs.toCIEXYZ(g); + b = cs.toCIEXYZ(b); + + // Generate the sRGB TRC curve, this is the linear->nonlinear + // RGB transform. + cs = new ICC_ColorSpace(getInstance(ICC_ColorSpace.CS_LINEAR_RGB)); + float[] points = new float[TRC_POINTS]; + float[] in = new float[3]; + for (int i = 0; i < TRC_POINTS; i++) + { + in[0] = in[1] = in[2] = ((float) i) / ((float) TRC_POINTS - 1); + in = cs.fromRGB(in); + // Note this value is the same for all components. + points[i] = in[0]; + } + + setData(icSigRedColorantTag, makeXYZData(r)); + setData(icSigGreenColorantTag, makeXYZData(g)); + setData(icSigBlueColorantTag, makeXYZData(b)); + setData(icSigMediaWhitePointTag, makeXYZData(white)); + setData(icSigMediaBlackPointTag, makeXYZData(black)); + setData(icSigRedTRCTag, makeTRC(points)); + setData(icSigGreenTRCTag, makeTRC(points)); + setData(icSigBlueTRCTag, makeTRC(points)); + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("Generic sRGB")); + this.profileID = ColorSpace.CS_sRGB; + } + + /** + * Creates an linear sRGB profile + */ + private void createLinearRGBProfile() + { + header.setColorSpace(ColorSpace.TYPE_RGB); + header.setProfileColorSpace(ColorSpace.TYPE_XYZ); + ICC_ColorSpace cs = new ICC_ColorSpace(this); + + float[] r = { 1f, 0f, 0f }; + float[] g = { 0f, 1f, 0f }; + float[] b = { 0f, 0f, 1f }; + float[] black = { 0f, 0f, 0f }; + + float[] white = D50; + + // Get tristimulus values (matrix elements) + r = cs.toCIEXYZ(r); + g = cs.toCIEXYZ(g); + b = cs.toCIEXYZ(b); + + setData(icSigRedColorantTag, makeXYZData(r)); + setData(icSigGreenColorantTag, makeXYZData(g)); + setData(icSigBlueColorantTag, makeXYZData(b)); + + setData(icSigMediaWhitePointTag, makeXYZData(white)); + setData(icSigMediaBlackPointTag, makeXYZData(black)); + + setData(icSigRedTRCTag, makeTRC()); + setData(icSigGreenTRCTag, makeTRC()); + setData(icSigBlueTRCTag, makeTRC()); + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("Linear RGB")); + this.profileID = ColorSpace.CS_LINEAR_RGB; + } + + /** + * Creates an CIE XYZ identity profile + */ + private void createCIEProfile() + { + header.setColorSpace( ColorSpace.TYPE_XYZ ); + header.setProfileColorSpace( ColorSpace.TYPE_XYZ ); + header.setProfileClass( CLASS_COLORSPACECONVERSION ); + ICC_ColorSpace cs = new ICC_ColorSpace(this); + + float[] white = D50; + + setData(icSigMediaWhitePointTag, makeXYZData(white)); + setData(icSigAToB0Tag, makeIdentityClut()); + setData(icSigBToA0Tag, makeIdentityClut()); + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("CIE XYZ identity profile")); + this.profileID = ColorSpace.CS_CIEXYZ; + } + + /** + * Creates a linear gray ICC_Profile + */ + private void createGrayProfile() + { + header.setColorSpace(ColorSpace.TYPE_GRAY); + header.setProfileColorSpace(ColorSpace.TYPE_XYZ); + + // CIE 1931 D50 white point (in Lab coordinates) + float[] white = D50; + + setData(icSigMediaWhitePointTag, makeXYZData(white)); + setData(icSigGrayTRCTag, makeTRC(1.0f)); + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("Linear grayscale")); + this.profileID = ColorSpace.CS_GRAY; + } + + /** + * XXX Implement me + */ + private void createPyccProfile() + { + header.setColorSpace(ColorSpace.TYPE_3CLR); + header.setProfileColorSpace(ColorSpace.TYPE_XYZ); + + // Create CLUTs here. :-) + + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("Photo YCC")); + this.profileID = ColorSpace.CS_PYCC; + } +} // class ICC_Profile diff --git a/libjava/classpath/java/awt/color/ICC_ProfileGray.java b/libjava/classpath/java/awt/color/ICC_ProfileGray.java new file mode 100644 index 0000000..3b5948d --- /dev/null +++ b/libjava/classpath/java/awt/color/ICC_ProfileGray.java @@ -0,0 +1,133 @@ +/* ICC_ProfileGray.java -- the ICC profile for a Gray colorspace + 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 java.awt.color; + +/** + * ICC_ProfileGray - a special case of ICC_Profiles. + * + * The ICC_Profile.getInstance() method will return an instance of the + * ICC_ProfileGray subclass when all the following conditions are met: + * The device color space of the profile is TYPE_GRAY. + * The profile contains a gray TRCTag. + * The profile contains a mediaWhitePointTag. + * + * As per the ICC specification, the color space conversion can then + * be done through the following method: + * linearGray = grayTRC[deviceGray] + * + * Note that if the profile contains a CLUT for the color space conversion, + * it should be used instead, and the TRC information ignored. + * + * @author Sven de Marothy + * @since 1.2 + */ +public class ICC_ProfileGray extends ICC_Profile +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -1124721290732002649L; + private transient float[] whitePoint; + + /** + * Package-private constructor used by ICC_ColorSpace for creating an + * ICC_ProfileGray from a predefined ColorSpace (CS_GRAY) + */ + ICC_ProfileGray(int cspace) + { + super(cspace); + whitePoint = getXYZData(icSigMediaWhitePointTag); + } + + /** + * Package-private constructor used by ICC_ColorSpace for creating an + * ICC_ProfileGray from profile data. + */ + ICC_ProfileGray(byte[] data) + { + super(data); + whitePoint = getXYZData(icSigMediaWhitePointTag); + } + + + /** + * Returns the media white point of the profile. + */ + public float[] getMediaWhitePoint() + { + float[] wp = new float[3]; + wp[0] = whitePoint[0]; + wp[1] = whitePoint[1]; + wp[2] = whitePoint[2]; + return wp; + } + + /** + * Returns the TRC gamma value. + * @throws ProfileDataException if the TRC is described by a lookup + * table and not a gamma value. + */ + public float getGamma() + { + short[] data = getCurve(icSigGrayTRCTag); + if (data == null) + throw new IllegalArgumentException("Couldn't read Gray TRC data."); + if (data.length != 1) + throw new ProfileDataException("TRC is a table, not a gamma value."); + + // convert the unsigned 7.8 fixed-point gamma to a float. + double gamma = (double) (data[0] & (0xFFFF)) / 256.0; + return (float) gamma; + } + + /** + * Returns the TRC lookup table. + * @throws ProfileDataException if the TRC is described by a gamma value + * and not a lookup table. + */ + public short[] getTRC() + { + short[] data = getCurve(icSigGrayTRCTag); + if (data == null) + throw new IllegalArgumentException("Couldn't read Gray TRC data."); + if (data.length <= 1) + throw new ProfileDataException("Gamma value, not a TRC table."); + return data; + } +} // class ICC_ProfileGray diff --git a/libjava/classpath/java/awt/color/ICC_ProfileRGB.java b/libjava/classpath/java/awt/color/ICC_ProfileRGB.java new file mode 100644 index 0000000..0039332 --- /dev/null +++ b/libjava/classpath/java/awt/color/ICC_ProfileRGB.java @@ -0,0 +1,227 @@ +/* ICC_ProfileRGB.java -- the ICC profile for a RGB colorspace + 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 java.awt.color; + +/** + * ICC_ProfileRGB - a special case of ICC_Profiles. + * + * The ICC_Profile.getInstance() method will return an instance of the + * ICC_ProfileRGB subclass when all the following conditions are met: + * The device color space of the profile is TYPE_RGB. + * The profile contains red, green and blue ColorantTags. + * The profile contains red, green and blue TRCTags. + * The profile contains a mediaWhitePointTag included. + * + * As per the ICC specification, the color space conversion can then + * be done through the following method: + * linearR = redTRC[deviceR] + * linearG = greenTRC[deviceG] + * linearB = blueTRC[deviceB] + * TRC curves are either a single gamma value, or a 1-dimensional lookup table. + * + * Followed by the matrix transform: + * PCS = M*linear + * + * Where PCS is the vector of profile color space (must be XYZ) coordinates, + * linear is the vector of linear RGB coordinates, and the matrix M is + * constructed from the ColorantTags, where the columns are red, green and + * blue respectively, and the rows are X, Y and Z. + * + * Note that if the profile contains a CLUT for the color space conversion, + * it should be used instead, and the TRC information ignored. + * + * @author Sven de Marothy + * @since 1.2 + */ +public class ICC_ProfileRGB extends ICC_Profile +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 8505067385152579334L; + + public static final int REDCOMPONENT = 0; + + public static final int GREENCOMPONENT = 1; + + public static final int BLUECOMPONENT = 2; + + private transient float[][] matrix; + + private transient float[] gamma; + + private transient float[] whitePoint; + + + /** + * Package-private constructor used by ICC_ColorSpace for creating an + * ICC_ProfileRGB from a predefined ColorSpace (CS_LINEAR_RGB and CS_sRGB) + */ + ICC_ProfileRGB(int cspace) + { + super(cspace); + matrix = createMatrix(); + whitePoint = getXYZData(icSigMediaWhitePointTag); + } + + /** + * Package-private constructor used by ICC_ColorSpace for creating an + * ICC_ProfileRGB from profile data. + */ + ICC_ProfileRGB(byte[] data) + { + super(data); + matrix = createMatrix(); + whitePoint = getXYZData(icSigMediaWhitePointTag); + } + + /** + * Returns the media white point of the profile. + */ + public float[] getMediaWhitePoint() + { + float[] wp = new float[3]; + wp[0] = whitePoint[0]; + wp[1] = whitePoint[1]; + wp[2] = whitePoint[2]; + return wp; + } + + /** + * Returns the colorant matrix of the conversion. + */ + public float[][] getMatrix() + { + float[][] mat = new float[3][3]; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + mat[i][j] = matrix[i][j]; + return mat; + } + + /** + * Returns the gamma value of a component + * @throws ProfileDataException if the TRC is described by a lookup + * table and not a gamma value. + */ + public float getGamma(int component) + { + short[] data; + switch (component) + { + case REDCOMPONENT: + data = getCurve(icSigRedTRCTag); + break; + case GREENCOMPONENT: + data = getCurve(icSigGreenTRCTag); + break; + case BLUECOMPONENT: + data = getCurve(icSigBlueTRCTag); + break; + default: + throw new IllegalArgumentException("Not a valid component"); + } + if (data == null) + throw new IllegalArgumentException("Error reading TRC"); + + if (data.length != 1) + throw new ProfileDataException("Not a single-gamma TRC"); + + // convert the unsigned 7.8 fixed-point gamma to a float. + float gamma = (float) (((int) data[0] & 0xFF00) >> 8); + double fraction = ((int) data[0] & 0x00FF) / 256.0; + gamma += (float) fraction; + return gamma; + } + + /** + * Returns the TRC lookup table for a component + * @throws ProfileDataException if the TRC is described by a gamma + * value and not a lookup table. + */ + public short[] getTRC(int component) + { + short[] data; + switch (component) + { + case REDCOMPONENT: + data = getCurve(icSigRedTRCTag); + break; + case GREENCOMPONENT: + data = getCurve(icSigGreenTRCTag); + break; + case BLUECOMPONENT: + data = getCurve(icSigBlueTRCTag); + break; + default: + throw new IllegalArgumentException("Not a valid component"); + } + if (data == null) + throw new IllegalArgumentException("Error reading TRC"); + + if (data.length <= 1) + throw new ProfileDataException("Gamma value, not a TRC table."); + + return data; + } + + /** + * Creates the colorspace conversion matrix from the RGB tristimulus + * values. + */ + private float[][] createMatrix() throws IllegalArgumentException + { + float[][] mat = new float[3][3]; + float[] r; + float[] g; + float[] b; + r = getXYZData(icSigRedColorantTag); + g = getXYZData(icSigGreenColorantTag); + b = getXYZData(icSigBlueColorantTag); + if (r == null || g == null || b == null) + throw new IllegalArgumentException("Error reading colorant tags!"); + for (int i = 0; i < 3; i++) + { + mat[i][0] = r[i]; + mat[i][1] = g[i]; + mat[i][2] = b[i]; + } + return mat; + } +} // class ICC_ProfileRGB diff --git a/libjava/classpath/java/awt/color/ProfileDataException.java b/libjava/classpath/java/awt/color/ProfileDataException.java new file mode 100644 index 0000000..1af23b1 --- /dev/null +++ b/libjava/classpath/java/awt/color/ProfileDataException.java @@ -0,0 +1,64 @@ +/* ProfileDataException.java -- error in processing an ICC_Profile + 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 java.awt.color; + +/** + * Thrown when there is an error accessing or processing an + * ICC_Profile. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class ProfileDataException extends RuntimeException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 7286140888240322498L; + + /** + * Create a new instance with a specified detailed error message. + * + * @param message the message + */ + public ProfileDataException(String message) + { + super(message); + } +} // class ProfileDataException diff --git a/libjava/classpath/java/awt/color/package.html b/libjava/classpath/java/awt/color/package.html new file mode 100644 index 0000000..9a08577 --- /dev/null +++ b/libjava/classpath/java/awt/color/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.color + + +

Classes to represent color spaces and profiles.

+ + + diff --git a/libjava/classpath/java/awt/datatransfer/Clipboard.java b/libjava/classpath/java/awt/datatransfer/Clipboard.java new file mode 100644 index 0000000..9953a72 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/Clipboard.java @@ -0,0 +1,114 @@ +/* Clipboard.java -- Class for transferring data via cut and paste. + Copyright (C) 1999, 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 java.awt.datatransfer; + +/** + * This class allows data to be transferred using a cut and paste type + * mechanism. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Clipboard +{ + /** + * The data being transferred. + */ + protected Transferable contents; + + /** + * The owner of this clipboard. + */ + protected ClipboardOwner owner; + + // The clipboard name + private String name; + + /** + * Initializes a new instance of Clipboard with the + * specified name. + * + * @param name The clipboard name. + */ + public Clipboard(String name) + { + this.name = name; + } + + /** + * Returns the name of the clipboard. + */ + public String getName() + { + return name; + } + + /** + * Returns the contents of the clipboard. + * + * @param requestor The object requesting the contents. + * + * @exception IllegalStateException If the clipboard is currently unavailable + */ + public synchronized Transferable getContents(Object requestor) + { + return contents; + } + + /** + * Sets the content and owner of this clipboard. + * If the given owner is different from the current owner + * then lostOwnership is called on the current owner. + * XXX - is this called with the old or new contents. + * + * @param contents The new clipboard contents. + * @param owner The new clipboard owner + * + * @exception IllegalStateException If the clipboard is currently unavailable + */ + public synchronized void setContents(Transferable contents, ClipboardOwner owner) + { + if (this.owner != owner) + if (this.owner != null) + this.owner.lostOwnership(this, contents); + + this.owner = owner; + this.contents = contents; + } +} + diff --git a/libjava/classpath/java/awt/datatransfer/ClipboardOwner.java b/libjava/classpath/java/awt/datatransfer/ClipboardOwner.java new file mode 100644 index 0000000..df75825 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/ClipboardOwner.java @@ -0,0 +1,57 @@ +/* ClipboardOwner.java -- Interface for clipboard providers + Copyright (C) 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 java.awt.datatransfer; + +/** + * This interface is for classes that will own a clipboard object. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface ClipboardOwner +{ + /** + * This method is called to notify this object that it no longer + * has ownership of the specified Clipboard. + * + * @param clipboard The clipboard for which ownership was lost. + * @param contents The contents of the clipboard which are no longer owned. + */ + void lostOwnership (Clipboard clipboard, Transferable contents); +} + diff --git a/libjava/classpath/java/awt/datatransfer/DataFlavor.java b/libjava/classpath/java/awt/datatransfer/DataFlavor.java new file mode 100644 index 0000000..e5fbd24 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/DataFlavor.java @@ -0,0 +1,1034 @@ +/* DataFlavor.java -- A type of data to transfer via the clipboard. + 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 java.awt.datatransfer; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Reader; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; + +/** + * This class represents a particular data format used for transferring + * data via the clipboard. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class DataFlavor implements java.io.Externalizable, Cloneable +{ + static final long serialVersionUID = 8367026044764648243L; + + // FIXME: Serialization: Need to write methods for. + +/** + * This is the data flavor used for tranferring plain text. The MIME + * type is "text/plain; charset=unicode". The representation class + * is java.io.InputStream. + * + * @deprecated The charset unicode is platform specific and InputStream + * deals with bytes not chars. Use getRederForText(). + */ +public static final DataFlavor plainTextFlavor; + +/** + * This is the data flavor used for transferring Java strings. The + * MIME type is "application/x-java-serialized-object" and the + * representation class is java.lang.String. + */ +public static final DataFlavor stringFlavor; + +/** + * This is a data flavor used for transferring lists of files. The + * representation type is a java.util.List, with each element of + * the list being a java.io.File. + */ +public static final DataFlavor javaFileListFlavor; + +/** + * This is an image flavor used for transferring images. The + * representation type is a java.awt.Image. + */ +public static final DataFlavor imageFlavor; + +/** + * This is the MIME type used for transferring a serialized object. + * The representation class is the type of object be deserialized. + */ +public static final String javaSerializedObjectMimeType = + "application/x-java-serialized-object"; + +/** + * This is the MIME type used to transfer a Java object reference within + * the same JVM. The representation class is the class of the object + * being transferred. + */ +public static final String javaJVMLocalObjectMimeType = + "application/x-java-jvm-local-objectref"; + +/** + * This is the MIME type used to transfer a link to a remote object. + * The representation class is the type of object being linked to. + */ +public static final String javaRemoteObjectMimeType = + "application/x-java-remote-object"; + +static +{ + plainTextFlavor + = new DataFlavor(java.io.InputStream.class, + "text/plain; charset=unicode", + "plain unicode text"); + + stringFlavor + = new DataFlavor(java.lang.String.class, + "Java Unicode String"); + + javaFileListFlavor + = new DataFlavor(java.util.List.class, + "Java File List"); + + // javaFileListFlavor.mimeType = "application/x-java-file-list"; + + imageFlavor + = new DataFlavor(java.awt.Image.class, + "Java Image"); +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +// The MIME type for this flavor +private final String mimeType; + +// The representation class for this flavor +private final Class representationClass; + +// The human readable name of this flavor +private String humanPresentableName; + +/*************************************************************************/ + +/* + * Static Methods + */ + +/** + * This method attempts to load the named class. The following class + * loaders are searched in order: the bootstrap class loader, the + * system class loader, the context class loader (if it exists), and + * the specified fallback class loader. + * + * @param className The name of the class to load. + * @param classLoader The class loader to use if all others fail, which + * may be null. + * + * @exception ClassNotFoundException If the class cannot be loaded. + */ +protected static final Class +tryToLoadClass(String className, ClassLoader classLoader) + throws ClassNotFoundException +{ + try + { + return(Class.forName(className)); + } + catch(Exception e) { ; } + // Commented out for Java 1.1 + /* + try + { + return(className.getClass().getClassLoader().findClass(className)); + } + catch(Exception e) { ; } + + try + { + return(ClassLoader.getSystemClassLoader().findClass(className)); + } + catch(Exception e) { ; } + */ + + // FIXME: What is the context class loader? + /* + try + { + } + catch(Exception e) { ; } + */ + + if (classLoader != null) + return(classLoader.loadClass(className)); + else + throw new ClassNotFoundException(className); +} + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Empty public constructor needed for externalization. + * Should not be used for normal instantiation. + */ +public +DataFlavor() +{ + mimeType = null; + representationClass = null; + humanPresentableName = null; +} + +/*************************************************************************/ + +/** + * Private constructor. + */ +private +DataFlavor(Class representationClass, + String mimeType, + String humanPresentableName) +{ + this.representationClass = representationClass; + this.mimeType = mimeType; + if (humanPresentableName != null) + this.humanPresentableName = humanPresentableName; + else + this.humanPresentableName = mimeType; +} + +/*************************************************************************/ + +/** + * Initializes a new instance of DataFlavor. The class + * and human readable name are specified, the MIME type will be + * "application/x-java-serialized-object". If the human readable name + * is not specified (null) then the human readable name + * will be the same as the MIME type. + * + * @param representationClass The representation class for this object. + * @param humanPresentableName The display name of the object. + */ +public +DataFlavor(Class representationClass, String humanPresentableName) +{ + this(representationClass, + "application/x-java-serialized-object" + + "; class=" + + representationClass.getName(), + humanPresentableName); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of DataFlavor with the + * specified MIME type and description. If the MIME type has a + * "class=<rep class>" parameter then the representation class will + * be the class name specified. Otherwise the class defaults to + * java.io.InputStream. If the human readable name + * is not specified (null) then the human readable name + * will be the same as the MIME type. + * + * @param mimeType The MIME type for this flavor. + * @param humanPresentableName The display name of this flavor. + * @param classLoader The class loader for finding classes if the default + * class loaders do not work. + * + * @exception IllegalArgumentException If the representation class + * specified cannot be loaded. + * @exception ClassNotFoundException If the class is not loaded. + */ +public +DataFlavor(String mimeType, String humanPresentableName, + ClassLoader classLoader) throws ClassNotFoundException +{ + this(getRepresentationClassFromMime(mimeType, classLoader), + mimeType, humanPresentableName); +} + +private static Class +getRepresentationClassFromMime(String mimeString, ClassLoader classLoader) +{ + String classname = getParameter("class", mimeString); + if (classname != null) + { + try + { + return tryToLoadClass(classname, classLoader); + } + catch(Exception e) + { + throw new IllegalArgumentException("classname: " + e.getMessage()); + } + } + else + { + return java.io.InputStream.class; + } +} + +/*************************************************************************/ + +/** + * Initializes a new instance of DataFlavor with the + * specified MIME type and description. If the MIME type has a + * "class=<rep class>" parameter then the representation class will + * be the class name specified. Otherwise the class defaults to + * java.io.InputStream. If the human readable name + * is not specified (null) then the human readable name + * will be the same as the MIME type. This is the same as calling + * new DataFlavor(mimeType, humanPresentableName, null). + * + * @param mimeType The MIME type for this flavor. + * @param humanPresentableName The display name of this flavor. + * + * @exception IllegalArgumentException If the representation class + * specified cannot be loaded. + */ +public +DataFlavor(String mimeType, String humanPresentableName) +{ + this (getRepresentationClassFromMime (mimeType, null), humanPresentableName); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of DataFlavor with the specified + * MIME type. This type can have a "class=" parameter to specify the + * representation class, and then the class must exist or an exception will + * be thrown. If there is no "class=" parameter then the representation class + * will be java.io.InputStream. This is the same as calling + * new DataFlavor(mimeType, null). + * + * @param mimeType The MIME type for this flavor. + * + * @exception IllegalArgumentException If a class is not specified in + * the MIME type. + * @exception ClassNotFoundException If the class cannot be loaded. + */ +public +DataFlavor(String mimeType) throws ClassNotFoundException +{ + this(mimeType, null); +} + +/*************************************************************************/ + +/** + * Returns the MIME type of this flavor. + * + * @return The MIME type for this flavor. + */ +public String +getMimeType() +{ + return(mimeType); +} + +/*************************************************************************/ + +/** + * Returns the representation class for this flavor. + * + * @return The representation class for this flavor. + */ +public Class +getRepresentationClass() +{ + return(representationClass); +} + +/*************************************************************************/ + +/** + * Returns the human presentable name for this flavor. + * + * @return The human presentable name for this flavor. + */ +public String +getHumanPresentableName() +{ + return(humanPresentableName); +} + +/*************************************************************************/ + +/** + * Returns the primary MIME type for this flavor. + * + * @return The primary MIME type for this flavor. + */ +public String +getPrimaryType() +{ + int idx = mimeType.indexOf("/"); + if (idx == -1) + return(mimeType); + + return(mimeType.substring(0, idx)); +} + +/*************************************************************************/ + +/** + * Returns the MIME subtype for this flavor. + * + * @return The MIME subtype for this flavor. + */ +public String +getSubType() +{ + int idx = mimeType.indexOf("/"); + if (idx == -1) + return(""); + + String subtype = mimeType.substring(idx + 1); + + idx = subtype.indexOf(" "); + if (idx == -1) + return(subtype); + else + return(subtype.substring(0, idx)); +} + +/*************************************************************************/ + +/** + * Returns the value of the named MIME type parameter, or null + * if the parameter does not exist. Given the parameter name and the mime + * string. + * + * @param paramName The name of the parameter. + * @param mimeString The mime string from where the name should be found. + * + * @return The value of the parameter or null. + */ +private static String +getParameter(String paramName, String mimeString) +{ + int idx = mimeString.indexOf(paramName + "="); + if (idx == -1) + return(null); + + String value = mimeString.substring(idx + paramName.length() + 1); + + idx = value.indexOf(" "); + if (idx == -1) + return(value); + else + return(value.substring(0, idx)); +} + +/*************************************************************************/ + +/** + * Returns the value of the named MIME type parameter, or null + * if the parameter does not exist. + * + * @param paramName The name of the paramter. + * + * @return The value of the parameter. + */ +public String +getParameter(String paramName) +{ + return getParameter(paramName, mimeType); +} + +/*************************************************************************/ + +/** + * Sets the human presentable name to the specified value. + * + * @param humanPresentableName The new display name. + */ +public void +setHumanPresentableName(String humanPresentableName) +{ + this.humanPresentableName = humanPresentableName; +} + +/*************************************************************************/ + +/** + * Tests the MIME type of this object for equality against the specified + * MIME type. + * + * @param mimeType The MIME type to test against. + * + * @return true if the MIME type is equal to this object's + * MIME type, false otherwise. + * + * @exception NullPointerException If mimeType is null. + */ +public boolean +isMimeTypeEqual(String mimeType) +{ + // FIXME: Need to handle default attributes and parameters + + return(this.mimeType.equals(mimeType)); +} + +/*************************************************************************/ + +/** + * Tests the MIME type of this object for equality against the specified + * data flavor's MIME type + * + * @param flavor The flavor to test against. + * + * @return true if the flavor's MIME type is equal to this + * object's MIME type, false otherwise. + */ +public final boolean +isMimeTypeEqual(DataFlavor flavor) +{ + return(isMimeTypeEqual(flavor.getMimeType())); +} + +/*************************************************************************/ + +/** + * Tests whether or not this flavor represents a serialized object. + * + * @return true if this flavor represents a serialized + * object, false otherwise. + */ +public boolean +isMimeTypeSerializedObject() +{ + return(mimeType.startsWith(javaSerializedObjectMimeType)); +} + +/*************************************************************************/ + +/** + * Tests whether or not this flavor has a representation class of + * java.io.InputStream. + * + * @return true if the representation class of this flavor + * is java.io.InputStream, false otherwise. + */ +public boolean +isRepresentationClassInputStream() +{ + return(representationClass.getName().equals("java.io.InputStream")); +} + +/*************************************************************************/ + +/** + * Tests whether the representation class for this flavor is + * serializable. + * + * @return true if the representation class is serializable, + * false otherwise. + */ +public boolean +isRepresentationClassSerializable() +{ + Class[] interfaces = representationClass.getInterfaces(); + + int i = 0; + while (i < interfaces.length) + { + if (interfaces[i].getName().equals("java.io.Serializable")) + return(true); + ++i; + } + + return(false); +} + +/*************************************************************************/ + +/** + * Tests whether the representation class for his flavor is remote. + * + * @return true if the representation class is remote, + * false otherwise. + */ +public boolean +isRepresentationClassRemote() +{ + // FIXME: Implement + throw new RuntimeException("Not implemented"); +} + +/*************************************************************************/ + +/** + * Tests whether or not this flavor represents a serialized object. + * + * @return true if this flavor represents a serialized + * object, false otherwise. + */ +public boolean +isFlavorSerializedObjectType() +{ + // FIXME: What is the diff between this and isMimeTypeSerializedObject? + return(mimeType.startsWith(javaSerializedObjectMimeType)); +} + +/*************************************************************************/ + +/** + * Tests whether or not this flavor represents a remote object. + * + * @return true if this flavor represents a remote object, + * false otherwise. + */ +public boolean +isFlavorRemoteObjectType() +{ + return(mimeType.startsWith(javaRemoteObjectMimeType)); +} + +/*************************************************************************/ + +/** + * Tests whether or not this flavor represents a list of files. + * + * @return true if this flavor represents a list of files, + * false otherwise. + */ +public boolean +isFlavorJavaFileListType() +{ + if (this.mimeType.equals(javaFileListFlavor.mimeType) && + this.representationClass.equals(javaFileListFlavor.representationClass)) + return(true); + + return(false); +} + +/*************************************************************************/ + +/** + * Returns a copy of this object. + * + * @return A copy of this object. + * + * @exception CloneNotSupportedException If the object's class does not support + * the Cloneable interface. Subclasses that override the clone method can also + * throw this exception to indicate that an instance cannot be cloned. + */ +public Object clone () throws CloneNotSupportedException +{ + try + { + return(super.clone()); + } + catch(Exception e) + { + return(null); + } +} + +/*************************************************************************/ + +/** + * This method test the specified DataFlavor for equality + * against this object. This will be true if the MIME type and + * representation type are the equal. + * + * @param flavor The DataFlavor to test against. + * + * @return true if the flavor is equal to this object, + * false otherwise. + */ +public boolean +equals(DataFlavor flavor) +{ + if (flavor == null) + return(false); + + if (!this.mimeType.toLowerCase().equals(flavor.mimeType.toLowerCase())) + return(false); + + if (!this.representationClass.equals(flavor.representationClass)) + return(false); + + return(true); +} + +/*************************************************************************/ + +/** + * This method test the specified Object for equality + * against this object. This will be true if the following conditions + * are met: + *

+ *

+ * + * @param obj The Object to test against. + * + * @return true if the flavor is equal to this object, + * false otherwise. + */ +public boolean +equals(Object obj) +{ + if (!(obj instanceof DataFlavor)) + return(false); + + return(equals((DataFlavor)obj)); +} + +/*************************************************************************/ + +/** + * Tests whether or not the specified string is equal to the MIME type + * of this object. + * + * @param str The string to test against. + * + * @return true if the string is equal to this object's MIME + * type, false otherwise. + * + * @deprecated Not compatible with hashCode(). + * Use isMimeTypeEqual() + */ +public boolean +equals(String str) +{ + return(isMimeTypeEqual(str)); +} + +/*************************************************************************/ + +/** + * Returns the hash code for this data flavor. + * The hash code is based on the (lower case) mime type and the + * representation class. + */ +public int +hashCode() +{ + return(mimeType.toLowerCase().hashCode()^representationClass.hashCode()); +} + +/*************************************************************************/ + +/** + * Returns true when the given DataFlavor + * matches this one. + */ +public boolean +match(DataFlavor dataFlavor) +{ + // XXX - How is this different from equals? + return(equals(dataFlavor)); +} + +/*************************************************************************/ + +/** + * This method exists for backward compatibility. It simply returns + * the same name/value pair passed in. + * + * @param name The parameter name. + * @param value The parameter value. + * + * @return The name/value pair. + * + * @deprecated + */ +protected String +normalizeMimeTypeParameter(String name, String value) +{ + return(name + "=" + value); +} + +/*************************************************************************/ + +/** + * This method exists for backward compatibility. It simply returns + * the MIME type string unchanged. + * + * @param type The MIME type. + * + * @return The MIME type. + * + * @deprecated + */ +protected String +normalizeMimeType(String type) +{ + return(type); +} + +/*************************************************************************/ + +/** + * Serialize this class. + * + * @param stream The ObjectOutput stream to serialize to. + * + * @exception IOException If an error occurs. + */ +public void +writeExternal(ObjectOutput stream) throws IOException +{ + // FIXME: Implement me +} + +/*************************************************************************/ + +/** + * De-serialize this class. + * + * @param stream The ObjectInput stream to deserialize from. + * + * @exception IOException If an error ocurs. + * @exception ClassNotFoundException If the class for an object being restored + * cannot be found. + */ +public void +readExternal(ObjectInput stream) throws IOException, ClassNotFoundException +{ + // FIXME: Implement me +} + +/*************************************************************************/ + +/** + * Returns a string representation of this DataFlavor. Including the + * representation class name, MIME type and human presentable name. + */ +public String +toString() +{ + return("DataFlavor[representationClass=" + + representationClass.getName() + + ",mimeType=" + + mimeType + + "humanPresentableName=" + + humanPresentableName); +} + +/*************************************************************************/ + +/** + * XXX - Currently returns plainTextFlavor. + */ +public static final DataFlavor +getTextPlainUnicodeFlavor() +{ + return(plainTextFlavor); +} + +/*************************************************************************/ + +/** + * XXX - Currently returns java.io.InputStream. + * + * @since 1.3 + */ +public final Class +getDefaultRepresentationClass() +{ + return(java.io.InputStream.class); +} +/*************************************************************************/ + +/** + * XXX - Currently returns java.io.InputStream. + */ +public final String +getDefaultRepresentationClassAsString() +{ + return(getDefaultRepresentationClass().getName()); +} + +/*************************************************************************/ + +/** + * Selects the best supported text flavor on this implementation. + * Returns null when none of the given flavors is liked. + * + * The DataFlavor returned the first data flavor in the + * array that has either a representation class which is (a subclass of) + * Reader or String, or has a representation + * class which is (a subclass of) InputStream and has a + * primary MIME type of "text" and has an supported encoding. + */ +public static final DataFlavor +selectBestTextFlavor(DataFlavor[] availableFlavors) +{ + for(int i=0; iReader for a given Transferable. + * + * If the representation class is a (subclass of) Reader + * then an instance of the representation class is returned. If the + * representatation class is a String then a + * StringReader is returned. And if the representation class + * is a (subclass of) InputStream and the primary MIME type + * is "text" then a InputStreamReader for the correct charset + * encoding is returned. + * + * @param transferable The Transferable for which a text + * Reader is requested. + * + * @exception IllegalArgumentException If the representation class is not one + * of the seven listed above or the Transferable has null data. + * @exception NullPointerException If the Transferable is null. + * @exception UnsupportedFlavorException when the transferable doesn't + * support this DataFlavor. Or if the representable class + * isn't a (subclass of) Reader, String, + * InputStream and/or the primary MIME type isn't "text". + * @exception IOException when any IOException occurs. + * @exception UnsupportedEncodingException if the "charset" isn't supported + * on this platform. + */ +public Reader getReaderForText(Transferable transferable) + throws UnsupportedFlavorException, IOException +{ + if (!transferable.isDataFlavorSupported(this)) + throw new UnsupportedFlavorException(this); + + if (Reader.class.isAssignableFrom(representationClass)) + return((Reader)transferable.getTransferData(this)); + + if (String.class.isAssignableFrom(representationClass)) + return(new StringReader((String)transferable.getTransferData(this))); + + if (InputStream.class.isAssignableFrom(representationClass) + && "text".equals(getPrimaryType())) + { + InputStream in = (InputStream)transferable.getTransferData(this); + String encoding = getParameter("charset"); + if (encoding == null) + encoding = "us-ascii"; + return(new InputStreamReader(in, encoding)); + } + + throw new UnsupportedFlavorException(this); +} + + /** + * Returns whether the representation class for this DataFlavor is + * @see java.nio.ByteBuffer or a subclass thereof. + * + * @since 1.4 + */ + public boolean isRepresentationClassByteBuffer () + { + return ByteBuffer.class.isAssignableFrom (representationClass); + } + + /** + * Returns whether the representation class for this DataFlavor is + * @see java.nio.CharBuffer or a subclass thereof. + * + * @since 1.4 + */ + public boolean isRepresentationClassCharBuffer () + { + return CharBuffer.class.isAssignableFrom (representationClass); + } + + /** + * Returns whether the representation class for this DataFlavor is + * @see java.io.Reader or a subclass thereof. + * + * @since 1.4 + */ + public boolean isRepresentationClassReader () + { + return Reader.class.isAssignableFrom (representationClass); + } + +} // class DataFlavor + diff --git a/libjava/classpath/java/awt/datatransfer/FlavorMap.java b/libjava/classpath/java/awt/datatransfer/FlavorMap.java new file mode 100644 index 0000000..59718c4 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/FlavorMap.java @@ -0,0 +1,75 @@ +/* FlavorMap.java -- Maps between flavor names and MIME types. + Copyright (C) 1999, 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 java.awt.datatransfer; + +import java.util.Map; + +/** + * This interface maps between native platform type names and DataFlavors. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface FlavorMap +{ + /** + * Maps the specified DataFlavor objects to the native + * data type name. The returned Map has keys that are + * the data flavors and values that are strings. The returned map + * may be modified. This can be useful for implementing nested mappings. + * + * @param flavors An array of data flavors to map + * or null for all data flavors. + * + * @return A Map of native data types. + */ + Map getNativesForFlavors (DataFlavor[] flavors); + + /** + * Maps the specified native type names to DataFlavor's. + * The returned Map has keys that are strings and values + * that are DataFlavor's. The returned map may be + * modified. This can be useful for implementing nested mappings. + * + * @param natives An array of native types to map + * or null for all native types. + * + * @return A Map of data flavors. + */ + Map getFlavorsForNatives (String[] natives); +} diff --git a/libjava/classpath/java/awt/datatransfer/FlavorTable.java b/libjava/classpath/java/awt/datatransfer/FlavorTable.java new file mode 100644 index 0000000..11cdda0 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/FlavorTable.java @@ -0,0 +1,73 @@ +/* FlavorTable.java -- A relaxed mapping between flavors + 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 java.awt.datatransfer; + +import java.util.List; + +/** + * A FlavorMap which no longer requires a 1-to-1 mapping between flavors. Any + * native can map to multiple flavors, and any flavor can map to multiple + * natives; although the mappings are usually symmetric. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public interface FlavorTable extends FlavorMap +{ + /** + * Returns a list of String natives corresponding to the given flavor. The + * list should be sorted from best to worst. The list must be modifiable + * without affecting this table. + * + * @param flavor the flavor to look up, or null to return all natives + * @return the sorted list of natives + */ + List getNativesForFlavor(DataFlavor flavor); + + /** + * Returns a list of flavors corresponding to the given String native. The + * list should be sorted from best to worst. The list must be modifiable + * without affecting this table. + * + * @param name the native name to look up, or null to return all flavors + * @return the sorted list of flavors + */ + List getFlavorsForNative(String name); +} diff --git a/libjava/classpath/java/awt/datatransfer/MimeTypeParseException.java b/libjava/classpath/java/awt/datatransfer/MimeTypeParseException.java new file mode 100644 index 0000000..6113ab7 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/MimeTypeParseException.java @@ -0,0 +1,70 @@ +/* MimeTypeParseException.java -- thrown when MIME string couldn't be parsed + Copyright (C) 2001, 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 java.awt.datatransfer; + +/** + * MIME string couldn't be parsed correctly. + * + * @author Mark Wielaard (mark@klomp.org) + * @status updated to 1.4 + */ +public class MimeTypeParseException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -5604407764691570741L; + + /** + * Create a new instance without any message. + */ + public MimeTypeParseException() + { + } + + /** + * Create a new instance with a specified detailed error message. + * + * @param message the message + */ + public MimeTypeParseException(String message) + { + super(message); + } +} // class MimeTypeParseException diff --git a/libjava/classpath/java/awt/datatransfer/StringSelection.java b/libjava/classpath/java/awt/datatransfer/StringSelection.java new file mode 100644 index 0000000..b74f2fa --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/StringSelection.java @@ -0,0 +1,158 @@ +/* StringSelection.java -- Clipboard handler for text. + 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 java.awt.datatransfer; + +import java.io.IOException; +import java.io.StringReader; + +/** + * This class transfers a string as plain text using the clipboard. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class StringSelection implements Transferable, ClipboardOwner +{ + +/* + * Class Variables + */ + +// List of flavors we support +// XXX: DataFlavor.plainTextFlavor is deprecated. +static final DataFlavor[] supported_flavors + = { DataFlavor.stringFlavor, + DataFlavor.plainTextFlavor }; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +// This is the data to transfer +private String data; + + /** + * Transfer the specfied string as text. + * + * @param data the data for the string selection + */ + public StringSelection(String data) + { + this.data = data; + } + +/** + * Returns a list of supported data flavors. + * + * @return A list of supported data flavors. + */ +public DataFlavor[] +getTransferDataFlavors() +{ + return(supported_flavors); +} + +/*************************************************************************/ + +/** + * Tests whether or not the specified data flavor is supported. + * + * @param flavor The data flavor to test. + * + * @return true if the data flavor is supported, + * false otherwise. + */ +public boolean +isDataFlavorSupported(DataFlavor flavor) +{ + for (int i = 0; i < supported_flavors.length; i++) + if (supported_flavors[i].equals(flavor)) + return(true); + + return(false); +} + +/*************************************************************************/ + +/** + * This method returns the data in the requested format. + * + * @param flavor The desired data flavor. + * + * @return The transferred data. + * + * @exception UnsupportedFlavorException If the specified flavor is not + * supported. + * @exception IOException If any other error occurs. + */ +public Object +getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, + IOException +{ + if (!isDataFlavorSupported(flavor)) + throw new UnsupportedFlavorException(flavor); + + if (DataFlavor.plainTextFlavor == flavor) + /* The behavior of this method for DataFlavor.plainTextFlavor and + equivalent DataFlavors is inconsistent with the definition of + DataFlavor.plainTextFlavor. We choose to do like Sun's implementation + and return a Reader instead of an InputString. */ + /* return(new StringBufferInputStream(data)); */ + return(new StringReader(data)); + else // DataFlavor.stringFlavor + return data; +} + +/*************************************************************************/ + +/** + * Called when ownership of the clipboard object is lost. + * + * @param clipboard The affected clipboard. + * @param contents The clipboard contents. + */ +public void +lostOwnership(Clipboard clipboard, Transferable contents) +{ + // FIXME: What does this do? +} + +} // class StringSelection + diff --git a/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java new file mode 100644 index 0000000..f6530f5 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java @@ -0,0 +1,169 @@ +/* SystemFlavorMap.java -- Maps between native flavor names and MIME types. + 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 java.awt.datatransfer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class maps between native platform type names and DataFlavors. + * + * XXX - The current implementation does no mapping at all. + * + * @author Mark Wielaard (mark@klomp.org) + * + * @since 1.2 + */ +public final class SystemFlavorMap implements FlavorMap, FlavorTable +{ + /** + * The default (instance) flavor map. + */ + private static FlavorMap defaultFlavorMap; + + /** + * Private constructor. + */ + private SystemFlavorMap () + { + } + + /** + * Maps the specified DataFlavor objects to the native + * data type name. The returned Map has keys that are + * the data flavors and values that are strings. The returned map + * may be modified. This can be useful for implementing nested mappings. + * + * @param flavors An array of data flavors to map + * or null for all data flavors. + * + * @return A Map of native data types to data flavors. + */ + public Map getNativesForFlavors (DataFlavor[] flavors) + { + return new HashMap(); + } + + /** + * Maps the specified native type names to DataFlavor's. + * The returned Map has keys that are strings and values + * that are DataFlavor's. The returned map may be + * modified. This can be useful for implementing nested mappings. + * + * @param natives An array of native types to map + * or null for all native types. + * + * @return A Map of data flavors to native type names. + */ + public Map getFlavorsForNatives (String[] natives) + { + return new HashMap(); + } + + /** + * Returns the default (instance) (System)FlavorMap. + */ + public static FlavorMap getDefaultFlavorMap () + { + if (defaultFlavorMap == null) + defaultFlavorMap = new SystemFlavorMap (); + + return defaultFlavorMap; + } + + /** + * Returns the native type name for the given java mime type. + */ + public static String encodeJavaMIMEType (String mime) + { + return null; + } + + /** + * Returns the native type name for the given data flavor. + */ + public static String encodeDataFlavor (DataFlavor df) + { + return null; + } + + /** + * Returns true if the native type name can be represented as + * a java mime type. + */ + public static boolean isJavaMIMEType (String name) + { + return false; + } + + /** + * Returns the java mime type for the given the native type name. + */ + public static String decodeJavaMIMEType (String name) + { + return null; + } + + /** + * Returns the data flavor given the native type name + * or null when no such data flavor exists. + */ + public static DataFlavor decodeDataFlavor (String name) + throws ClassNotFoundException + { + String javaMIMEType = decodeJavaMIMEType (name); + + if (javaMIMEType != null) + return new DataFlavor (javaMIMEType); + else + return null; + } + + public List getFlavorsForNative (String nat) + { + throw new Error ("Not implemented"); + } + + public List getNativesForFlavor (DataFlavor flav) + { + throw new Error ("Not implemented"); + } + +} // class SystemFlavorMap diff --git a/libjava/classpath/java/awt/datatransfer/Transferable.java b/libjava/classpath/java/awt/datatransfer/Transferable.java new file mode 100644 index 0000000..8075392 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/Transferable.java @@ -0,0 +1,83 @@ +/* Transferable.java -- Data transfer source + Copyright (C) 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 java.awt.datatransfer; + +import java.io.IOException; + +/** + * This interface is implemented by classes that can transfer data. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public interface Transferable +{ + /** + * This method returns a list of available data flavors for the data being + * transferred. The array returned will be sorted from most preferred + * flavor at the beginning to least preferred at the end. + * + * @return adA list of data flavors for this data + */ + DataFlavor[] getTransferDataFlavors(); + + /** + * Tests whether or not this data can be delivered in the specified data + * flavor. + * + * @param flavor the data flavor to test + * @return true if the data flavor is supported + */ + boolean isDataFlavorSupported(DataFlavor flavor); + + /** + * Returns the data in the specified DataFlavor. + * + * @param flavor the data flavor to return + * @return the data in the appropriate flavor + * @throws UnsupportedFlavorException if the flavor is not supported + * @throws IOException if the data is not available + * @see DataFlavor#getRepresentationClass + */ + Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException; + +} // interface Transferable + diff --git a/libjava/classpath/java/awt/datatransfer/UnsupportedFlavorException.java b/libjava/classpath/java/awt/datatransfer/UnsupportedFlavorException.java new file mode 100644 index 0000000..1c1da03 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/UnsupportedFlavorException.java @@ -0,0 +1,65 @@ +/* UnsupportedFlavorException.java -- ata flavor is not valid + Copyright (C) 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 java.awt.datatransfer; + +/** + * The data flavor requested is not supported for the transfer data. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Transferable#getTransferData(DataFlavor) + * @status updated to 1.4 + */ +public class UnsupportedFlavorException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5383814944251665601L; + + /** + * Initializes a new instance of UnsupportedDataFlavor + * for the specified data flavor. + * + * @param flavor the data flavor that is not supported + */ + public UnsupportedFlavorException(DataFlavor flavor) + { + super(flavor == null ? null : flavor.getHumanPresentableName()); + } +} // class UnsupportedFlavorException diff --git a/libjava/classpath/java/awt/datatransfer/package.html b/libjava/classpath/java/awt/datatransfer/package.html new file mode 100644 index 0000000..5ab860c --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - java.awt.datatransfer + + +

Classes to represent different flavors of data for transferring native +and system types through for example a clipboard.

+ + + diff --git a/libjava/classpath/java/awt/dnd/Autoscroll.java b/libjava/classpath/java/awt/dnd/Autoscroll.java new file mode 100644 index 0000000..ba4d447 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/Autoscroll.java @@ -0,0 +1,70 @@ +/* Autoscroll.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 java.awt.dnd; + +import java.awt.Insets; +import java.awt.Point; + +/** + * During DnD operations it is possible that a user may wish to drop the + * subject of the operation on a region of a scrollable GUI control that + * is not currently visible to the user. + * + * @author Michael Koch (konqueror@gmx.de) + * @since 1.2 + * @status updated to 1.4 + */ +public interface Autoscroll +{ + /** + * This method returns the Insets describing the autoscrolling region or + * border relative to the geometry of the implementing Component + */ + Insets getAutoscrollInsets (); + + /** + * Notify the Component to autoscroll + * + * @param location A Point indicating the location of the cursor that + * triggered this operation + */ + void autoscroll (Point location); + +} // interface Autoscroll + diff --git a/libjava/classpath/java/awt/dnd/DnDConstants.java b/libjava/classpath/java/awt/dnd/DnDConstants.java new file mode 100644 index 0000000..85c9c05 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DnDConstants.java @@ -0,0 +1,77 @@ +/* DnDConstants.java -- constants for drag-and-drop operations + 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 java.awt.dnd; + +/** + * This class contains various constants used in drag-and-drop operations. + * Why it is not an interface is beyond me. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public final class DnDConstants +{ + /** No action takes place. */ + public static final int ACTION_NONE = 0; + + /** The copy action. */ + public static final int ACTION_COPY = 1; + + /** The move action. */ + public static final int ACTION_MOVE = 2; + + /** Either a copy or a move. */ + public static final int ACTION_COPY_OR_MOVE = 3; + + /** + * A link action. This does not copy or move, but creates a reference back + * to the original. However, since platforms differ on how a reference should + * behave, this action is not recommended for common use. + */ + public static final int ACTION_LINK = 1073741824; + + /** A synonym for {@link #ACTION_LINK}. */ + public static final int ACTION_REFERENCE = ACTION_LINK; + + private DnDConstants() + { + // Do nothing here. + } +} diff --git a/libjava/classpath/java/awt/dnd/DnDEventMulticaster.java b/libjava/classpath/java/awt/dnd/DnDEventMulticaster.java new file mode 100644 index 0000000..d9f5ec0 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DnDEventMulticaster.java @@ -0,0 +1,74 @@ +/* DnDEventMulticaster.java -- helper class for listener chains in java.awt.dnd + 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 java.awt.dnd; + +import java.awt.AWTEventMulticaster; +import java.util.EventListener; + +class DnDEventMulticaster extends AWTEventMulticaster +{ + protected DnDEventMulticaster (EventListener a, EventListener b) + { + super (a, b); + } + + public static DragSourceListener add (DragSourceListener a, + DragSourceListener b) + { + return (DragSourceListener) addInternal (a, b); + } + + public static DragSourceMotionListener add (DragSourceMotionListener a, + DragSourceMotionListener b) + { + return (DragSourceMotionListener) addInternal (a, b); + } + + public static DragSourceListener remove (DragSourceListener a, + DragSourceListener b) + { + return (DragSourceListener) removeInternal (a, b); + } + + public static DragSourceMotionListener remove (DragSourceMotionListener a, + DragSourceMotionListener b) + { + return (DragSourceMotionListener) removeInternal (a, b); + } +} diff --git a/libjava/classpath/java/awt/dnd/DragGestureEvent.java b/libjava/classpath/java/awt/dnd/DragGestureEvent.java new file mode 100644 index 0000000..9f2bc7c --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragGestureEvent.java @@ -0,0 +1,156 @@ +/* DragGestureEvent.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 java.awt.dnd; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; +import java.awt.datatransfer.Transferable; +import java.awt.event.InputEvent; +import java.util.EventObject; +import java.util.Iterator; +import java.util.List; + +/** + * STUBBED + * @see DragGestureRecognizer + * @see DragGestureListener + * @see DragSource + * @since 1.2 + */ +public class DragGestureEvent extends EventObject +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 9080172649166731306L; + + private DragSource dragSource; + private Component component; + private final Point origin; + private final int action; + + public DragGestureEvent(DragGestureRecognizer dgr, int action, Point origin, + List events) + { + super(dgr); + if (origin == null || events == null) + throw new IllegalArgumentException(); + this.origin = origin; + this.action = action; + } + + public DragGestureRecognizer getSourceAsDragGestureRecognizer() + { + return (DragGestureRecognizer) source; + } + public Component getComponent() + { + return null; + } + public DragSource getDragSource() + { + return null; + } + public Point getDragOrigin() + { + return origin; + } + public Iterator iterator() + { + return null; + } + public Object[] toArray() + { + return null; + } + public Object[] toArray(Object[] array) + { + return array; + } + public int getDragAction() + { + return 0; + } + public InputEvent getTriggerEvent() + { + return null; + } + + /** + * Starts the drag given the initial Cursor to display, the Transferable + * object, and the DragSourceListener to use. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(Cursor dragCursor, Transferable trans) + { + startDrag(dragCursor, null, null, trans, null); + } + + /** + * Starts the drag given the initial Cursor to display, the Transferable + * object, and the DragSourceListener to use. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(Cursor dragCursor, Transferable trans, + DragSourceListener l) + { + startDrag(dragCursor, null, null, trans, l); + } + + /** + * Starts the drag given the initial Cursor to display, the Transferable + * object, and the DragSourceListener to use. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(Cursor dragCursor, Image dragImage, Point imageOffset, + Transferable trans, DragSourceListener l) + { + } +} // class DragGestureEvent diff --git a/libjava/classpath/java/awt/dnd/DragGestureListener.java b/libjava/classpath/java/awt/dnd/DragGestureListener.java new file mode 100644 index 0000000..e8befe8 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragGestureListener.java @@ -0,0 +1,63 @@ +/* DragGestureListener.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 java.awt.dnd; + +import java.util.EventListener; + +/** + * This is a listener for starting a drag-and-drop gesture. Upon receiving + * notification, the implementor then starts the drag operation. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see DragGestureRecognizer + * @see DragGestureEvent + * @see DragSource + * @since 1.2 + * @status updated to 1.4 + */ +public interface DragGestureListener extends EventListener +{ + /** + * Called when the native platform notifies the virtual machine that a + * drag-and-drop has been initiated. + * + * @param e the event + */ + void dragGestureRecognized(DragGestureEvent e); +} // interface DragGestureListener diff --git a/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java b/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java new file mode 100644 index 0000000..07b822e --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java @@ -0,0 +1,179 @@ +/* DragGestureRecognizer.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 java.awt.dnd; + +import java.awt.Component; +import java.awt.Point; +import java.awt.event.InputEvent; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.TooManyListenersException; + +/** + * STUBBED + * @since 1.2 + */ +public abstract class DragGestureRecognizer implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 8996673345831063337L; + + protected DragSource dragSource; + protected Component component; + protected transient DragGestureListener dragGestureListener; + protected int sourceActions; + protected ArrayList events = new ArrayList(); + + protected DragGestureRecognizer(DragSource ds, Component c, int sa, + DragGestureListener dgl) + { + if (ds == null) + throw new IllegalArgumentException(); + dragSource = ds; + component = c; + sourceActions = sa; + dragGestureListener = dgl; + } + + protected DragGestureRecognizer(DragSource ds, Component c, int sa) + { + this(ds, c, sa, null); + } + + protected DragGestureRecognizer(DragSource ds, Component c) + { + this(ds, c, 0, null); + } + + protected DragGestureRecognizer(DragSource ds) + { + this(ds, null, 0, null); + } + + protected abstract void registerListeners(); + + protected abstract void unregisterListeners(); + + public DragSource getDragSource() + { + return dragSource; + } + + public Component getComponent() + { + return component; + } + + public void setComponent(Component c) + { + component = c; + } + + public int getSourceActions() + { + return sourceActions; + } + + public void setSourceActions(int sa) + { + sourceActions = sa; + } + + public InputEvent getTriggerEvent() + { + return events.size() > 0 ? (InputEvent) events.get(0) : null; + } + + public void resetRecognizer() + { + throw new Error("not implemented"); + } + + /** + * Register a new DragGestureListener. + * + * @exception TooManyListenersException If a DragGestureListener has already + * been added. + */ + public void addDragGestureListener(DragGestureListener dgl) + throws TooManyListenersException + { + if (dragGestureListener != null) + throw new TooManyListenersException(); + dragGestureListener = dgl; + } + + public void removeDragGestureListener(DragGestureListener dgl) + { + if (dragGestureListener != dgl) + throw new IllegalArgumentException(); + dragGestureListener = null; + } + + protected void fireDragGestureRecognized(int dragAction, Point p) + { + throw new Error("not implemented"); + } + + protected void appendEvent(InputEvent e) + { + if (e == null) + return; + events.add(e); + } + + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject(); + dragGestureListener = (DragGestureListener) s.readObject(); + } + + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + s.writeObject(dragGestureListener instanceof Serializable + ? dragGestureListener : null); + } +} // class DragGestureRecognizer diff --git a/libjava/classpath/java/awt/dnd/DragSource.java b/libjava/classpath/java/awt/dnd/DragSource.java new file mode 100644 index 0000000..13ffc96 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSource.java @@ -0,0 +1,257 @@ +/* DragSource.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 java.awt.dnd; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Point; +import java.awt.Toolkit; +import java.awt.datatransfer.FlavorMap; +import java.awt.datatransfer.SystemFlavorMap; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.io.Serializable; +import java.util.EventListener; + +/** + * @since 1.2 + */ +public class DragSource implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 6236096958971414066L; + + public static final Cursor DefaultCopyDrop = null; + public static final Cursor DefaultMoveDrop = null; + public static final Cursor DefaultLinkDrop = null; + public static final Cursor DefaultCopyNoDrop = null; + public static final Cursor DefaultMoveNoDrop = null; + public static final Cursor DefaultLinkNoDrop = null; + + private transient FlavorMap flavorMap = SystemFlavorMap.getDefaultFlavorMap (); + + private transient DragSourceListener dragSourceListener; + private transient DragSourceMotionListener dragSourceMotionListener; + + /** + * Initializes the drag source. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public DragSource() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); + } + + /** + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public static DragSource getDefaultDragSource() + { + return null; + } + + public static boolean isDragImageSupported() + { + return false; + } + + /** + * Start a drag, given the DragGestureEvent that initiated the drag. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(DragGestureEvent trigger, Cursor dragCursor, + Image dragImage, Point imageOffset, + Transferable trans, DragSourceListener dsl, + FlavorMap map) + { + } + + /** + * Start a drag, given the DragGestureEvent that initiated the drag. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(DragGestureEvent trigger, Cursor dragCursor, + Transferable trans, DragSourceListener dsl, + FlavorMap map) + { + startDrag(trigger, dragCursor, null, null, trans, dsl, map); + } + + /** + * Start a drag, given the DragGestureEvent that initiated the drag. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(DragGestureEvent trigger, Cursor dragCursor, + Image dragImage, Point imageOffset, + Transferable trans, DragSourceListener dsl) + { + startDrag(trigger, dragCursor, dragImage, imageOffset, trans, dsl, null); + } + + /** + * Start a drag, given the DragGestureEvent that initiated the drag. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(DragGestureEvent trigger, Cursor dragCursor, + Transferable trans, DragSourceListener dsl) + { + startDrag(trigger, dragCursor, null, null, trans, dsl, null); + } + + /** + * Creates the DragSourceContext to handle this drag. + * + * @exception IllegalArgumentException FIXME + * @exception NullPointerException If dscp, dgl, dragImage or t is null. + */ + protected DragSourceContext + createDragSourceContext(DragSourceContextPeer peer, DragGestureEvent dge, + Cursor cursor, Image image, Point offset, + Transferable t, DragSourceListener dsl) + { + return null; + } + + public FlavorMap getFlavorMap() + { + return flavorMap; + } + + public DragGestureRecognizer + createDragGestureRecognizer(Class recognizer, Component c, int actions, + DragGestureListener dgl) + { + return Toolkit.getDefaultToolkit () + .createDragGestureRecognizer (recognizer, this, c, actions, + dgl); + } + + public DragGestureRecognizer + createDefaultDragGestureRecognizer(Component c, int actions, + DragGestureListener dgl) + { + return createDragGestureRecognizer (MouseDragGestureRecognizer.class, c, + actions, dgl); + } + + /** + * @since 1.4 + */ + public void addDragSourceListener(DragSourceListener l) + { + DnDEventMulticaster.add (dragSourceListener, l); + } + + /** + * @since 1.4 + */ + public void removeDragSourceListener(DragSourceListener l) + { + DnDEventMulticaster.remove (dragSourceListener, l); + } + + /** + * @since 1.4 + */ + public DragSourceListener[] getDragSourceListeners() + { + return (DragSourceListener[]) getListeners (DragSourceListener.class); + } + + /** + * @since 1.4 + */ + public void addDragSourceMotionListener(DragSourceMotionListener l) + { + DnDEventMulticaster.add (dragSourceMotionListener, l); + } + + /** + * @since 1.4 + */ + public void removeDragSourceMotionListener(DragSourceMotionListener l) + { + DnDEventMulticaster.remove (dragSourceMotionListener, l); + } + + /** + * @since 1.4 + */ + public DragSourceMotionListener[] getDragSourceMotionListeners () + { + return (DragSourceMotionListener[]) getListeners + (DragSourceMotionListener.class); + } + + /** + * @since 1.4 + */ + public EventListener[] getListeners (Class listenerType) + { + if (listenerType == DragSourceListener.class) + return DnDEventMulticaster.getListeners (dragSourceListener, + listenerType); + + if (listenerType == DragSourceMotionListener.class) + return DnDEventMulticaster.getListeners (dragSourceMotionListener, + listenerType); + + // Return an empty EventListener array. + return new EventListener [0]; + } +} // class DragSource diff --git a/libjava/classpath/java/awt/dnd/DragSourceAdapter.java b/libjava/classpath/java/awt/dnd/DragSourceAdapter.java new file mode 100644 index 0000000..90d9a69 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceAdapter.java @@ -0,0 +1,126 @@ +/* DragSourceAdapter.java -- drag-and-drop listener adapter + 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 java.awt.dnd; + +/** + * This class implements DragSourceListener and + * DragSourceMotionListener, and implements all methods + * with empty bodies. This allows a listener interested in implementing only + * a subset of these interfaces to extend this class and override only the + * desired methods. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see DragSourceEvent + * @see DragSourceListener + * @see DragSourceMotionListener + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class DragSourceAdapter + implements DragSourceListener, DragSourceMotionListener +{ + /** + * Default constructor. + */ + public DragSourceAdapter() + { + } + + /** + * Called when the cursor hotspot enters a drop site which will accept the + * drag. + * + * @param e the event + */ + public void dragEnter(DragSourceDragEvent e) + { + } + + /** + * Called when the cursor hotspot moves inside of a drop site which will + * accept the drag. + * + * @param e the event + */ + public void dragOver(DragSourceDragEvent e) + { + } + + /** + * Called whenever the mouse is moved during a drag-and-drop operation. + * + * @param e the event + */ + public void dragMouseMoved(DragSourceDragEvent e) + { + } + + /** + * Called when the user modifies the drop gesture. This is often the case + * when additional mouse or key events are received during the drag. + * + * @param e the event + */ + public void dropActionChanged(DragSourceDragEvent e) + { + } + + /** + * Called when the cursor hotspot moves outside of a drop site which will + * accept the drag. This could also happen if the drop site is no longer + * active, or no longer accepts the drag. + * + * @param e the event + */ + public void dragExit(DragSourceEvent e) + { + } + + /** + * Called when the drag and drop operation is complete. After this event, + * getDropSuccess of the event is valid, and + * getDropAction holds the action requested by the drop site. + * Furthermore, the DragSourceContext is invalidated. + * + * @param e the event + */ + public void dragDropEnd(DragSourceDropEvent e) + { + } +} // class DragSourceAdapter diff --git a/libjava/classpath/java/awt/dnd/DragSourceContext.java b/libjava/classpath/java/awt/dnd/DragSourceContext.java new file mode 100644 index 0000000..2cf0d6d --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceContext.java @@ -0,0 +1,200 @@ +/* DragSourceContext.java -- + Copyright (C) 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 java.awt.dnd; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.io.Serializable; +import java.util.TooManyListenersException; + +/** + * @since 1.2 + */ +public class DragSourceContext + implements DragSourceListener, DragSourceMotionListener, Serializable +{ + /** + * Compatible with JDK 1.2+ + */ + static final long serialVersionUID = -115407898692194719L; + + protected static final int DEFAULT = 0; + protected static final int ENTER = 1; + protected static final int OVER = 2; + protected static final int CHANGED = 3; + + private DragSourceContextPeer peer; + private Cursor cursor; + private Transferable transferable; + private DragGestureEvent trigger; + private DragSourceListener dragSourceListener; + private boolean useCustomCursor; // FIXME: currently unused but needed for serialization. + private int sourceActions; // FIXME: currently unused but needed for serialization. + private Image image; + private Point offset; + + /** + * Initializes a drag source context. + * + * @exception IllegalArgumentException If Component or DragSource of trigger + * are null, the drag action for the trigger event is DnDConstants.ACTION_NONE + * or if the source actions for the DragGestureRecognizer associated with the + * trigger event are equal to DnDConstants.ACTION_NONE. + * @exception NullPointerException If peer or trigger is null. + */ + public DragSourceContext (DragSourceContextPeer peer, + DragGestureEvent trigger, Cursor cursor, + Image image, Point offset, Transferable trans, + DragSourceListener dsl) + { + if (peer == null + || trigger == null) + throw new NullPointerException (); + + if (trigger.getComponent () == null + || trigger.getDragSource () == null + || trigger.getDragAction () == DnDConstants.ACTION_NONE + || trigger.getSourceAsDragGestureRecognizer () + .getSourceActions () == DnDConstants.ACTION_NONE) + throw new IllegalArgumentException (); + + this.peer = peer; + this.trigger = trigger; + this.cursor = cursor; + this.image = image; + this.offset = offset; + this.transferable = trans; + this.dragSourceListener = dsl; + + throw new Error ("not implemented"); + } + + public DragSource getDragSource() + { + return trigger.getDragSource (); + } + + public Component getComponent() + { + return trigger.getComponent (); + } + + public DragGestureEvent getTrigger() + { + return trigger; + } + + public int getSourceActions() + { + return trigger.getSourceAsDragGestureRecognizer ().getSourceActions (); + } + + public void setCursor (Cursor cursor) + { + this.cursor = cursor; + // FIXME: Check if we need to do more here + } + + public Cursor getCursor() + { + return cursor; + } + + /** + * Adds a DragSourceListener. + * + * @exception TooManyListenersException If a DragSourceListener + * has already been added. + */ + public void addDragSourceListener (DragSourceListener dsl) + throws TooManyListenersException + { + if (dragSourceListener != null) + throw new TooManyListenersException (); + + dragSourceListener = dsl; + } + + public void removeDragSourceListener (DragSourceListener dsl) + { + if (dragSourceListener == dsl) + dragSourceListener = null; + } + + public void transferablesFlavorsChanged() + { + } + + public void dragEnter(DragSourceDragEvent e) + { + } + + public void dragOver(DragSourceDragEvent e) + { + } + + public void dragExit(DragSourceEvent e) + { + } + + public void dropActionChanged(DragSourceDragEvent e) + { + } + + public void dragDropEnd(DragSourceDropEvent e) + { + } + + public void dragMouseMoved(DragSourceDragEvent e) + { + } + + public Transferable getTransferable() + { + return transferable; + } + + protected void updateCurrentCursor(int dropOp, int targetAct, int status) + { + } +} // class DragSourceContext diff --git a/libjava/classpath/java/awt/dnd/DragSourceDragEvent.java b/libjava/classpath/java/awt/dnd/DragSourceDragEvent.java new file mode 100644 index 0000000..511700b --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceDragEvent.java @@ -0,0 +1,102 @@ +/* DragSourceDragEvent.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 java.awt.dnd; + +import gnu.java.awt.EventModifier; + +/** + * @author Michael Koch + * @since 1.2 + */ +public class DragSourceDragEvent extends DragSourceEvent +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = 481346297933902471L; + + private final int dropAction; + private final int targetActions; + private final int gestureModifiers; + + public DragSourceDragEvent(DragSourceContext context, int dropAction, + int actions, int modifiers) + { + super(context); + this.dropAction = dropAction; + targetActions = actions; + gestureModifiers = EventModifier.extend(modifiers); + } + + public DragSourceDragEvent(DragSourceContext context, int dropAction, + int actions, int modifiers, int x, int y) + { + super(context, x, y); + this.dropAction = dropAction; + targetActions = actions; + gestureModifiers = EventModifier.extend(modifiers); + } + + public int getTargetActions() + { + return targetActions; + } + + public int getGestureModifiers() + { + return EventModifier.revert(gestureModifiers); + } + + public int getGestureModifiersEx() + { + return gestureModifiers; + } + + public int getUserAction() + { + return dropAction; + } + + public int getDropAction() + { + return (dropAction + & targetActions + & ((DragSourceContext) source).getSourceActions()); + } +} // class DragSourceDragEvent diff --git a/libjava/classpath/java/awt/dnd/DragSourceDropEvent.java b/libjava/classpath/java/awt/dnd/DragSourceDropEvent.java new file mode 100644 index 0000000..7621262 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceDropEvent.java @@ -0,0 +1,89 @@ +/* DragSourceDragEvent.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 java.awt.dnd; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.2 + * + * Written using JDK 1.4.1 Online API + * Status: JDK 1.4 complete + */ +public class DragSourceDropEvent extends DragSourceEvent +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = -5571321229470821891L; + + private final int dropAction; + private final boolean dropSuccess; + + public DragSourceDropEvent (DragSourceContext context) + { + super (context); + this.dropAction = 0; + this.dropSuccess = false; + } + + public DragSourceDropEvent (DragSourceContext context, int dropAction, + boolean dropSuccess) + { + super (context); + this.dropAction = dropAction; + this.dropSuccess = dropSuccess; + } + + public DragSourceDropEvent (DragSourceContext context, int dropAction, + boolean dropSuccess, int x, int y) + { + super (context, x, y); + this.dropAction = dropAction; + this.dropSuccess = dropSuccess; + } + + public int getDropAction() + { + return dropAction & ((DragSourceContext) source).getSourceActions(); + } + + public boolean getDropSuccess() + { + return dropSuccess; + } +} // class DragSourceDropEvent diff --git a/libjava/classpath/java/awt/dnd/DragSourceEvent.java b/libjava/classpath/java/awt/dnd/DragSourceEvent.java new file mode 100644 index 0000000..c5cd42a --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceEvent.java @@ -0,0 +1,93 @@ +/* DragSourceEvent.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 java.awt.dnd; + +import java.awt.Point; +import java.util.EventObject; + +/** + * @since 1.2 + */ +public class DragSourceEvent extends EventObject +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = -763287114604032641L; + + private final boolean locationSpecified; + private final int x; + private final int y; + + public DragSourceEvent(DragSourceContext context) + { + super(context); + locationSpecified = false; + x = 0; + y = 0; + } + + public DragSourceEvent(DragSourceContext context, int x, int y) + { + super(context); + locationSpecified = true; + this.x = x; + this.y = y; + } + + public DragSourceContext getDragSourceContext() + { + return (DragSourceContext) source; + } + + public Point getLocation() + { + return locationSpecified ? new Point(x, y) : null; + } + + public int getX() + { + return x; + } + + public int getY() + { + return y; + } +} // class DragSourceEvent diff --git a/libjava/classpath/java/awt/dnd/DragSourceListener.java b/libjava/classpath/java/awt/dnd/DragSourceListener.java new file mode 100644 index 0000000..aac6e94 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceListener.java @@ -0,0 +1,97 @@ +/* DragSourceListener.java -- listen to events during the drag + 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 java.awt.dnd; + +import java.util.EventListener; + +/** + * This class allows an object to listen for drag and drop events. It can + * be used to provide appropriate feedback for "drag over" actions. You can + * also use a DragSourceAdapter to filter the events you are + * interested in. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public interface DragSourceListener extends EventListener +{ + /** + * Called when the cursor hotspot enters a drop site which will accept the + * drag. + * + * @param e the drag source drag event + */ + void dragEnter(DragSourceDragEvent e); + + /** + * Called when the cursor hotspot moves inside of a drop site which will + * accept the drag. + * + * @param e the drag source drag event + */ + void dragOver(DragSourceDragEvent e); + + /** + * Called when the user modifies the drop gesture. This is often the case + * when additional mouse or key events are received during the drag. + * + * @param e the drag source drag event + */ + void dropActionChanged(DragSourceDragEvent e); + + /** + * Called when the cursor hotspot moves outside of a drop site which will + * accept the drag. This could also happen if the drop site is no longer + * active, or no longer accepts the drag. + * + * @param e the drag source drag event + */ + void dragExit(DragSourceEvent e); + + /** + * Called when the drag and drop operation is complete. After this event, + * getDropSuccess of the event is valid, and + * getDropAction holds the action requested by the drop site. + * Furthermore, the DragSourceContext is invalidated. + * + * @param e the drag source drag event + */ + void dragDropEnd(DragSourceDropEvent e); +} // interface DragSourceListener diff --git a/libjava/classpath/java/awt/dnd/DragSourceMotionListener.java b/libjava/classpath/java/awt/dnd/DragSourceMotionListener.java new file mode 100644 index 0000000..5d04c22 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceMotionListener.java @@ -0,0 +1,64 @@ +/* DragSourceMotionListener.java -- tracks motion in the drag source + 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 java.awt.dnd; + +import java.util.EventListener; + +/** + * This is a listener for mouse motion in the drag source before the drop + * event occurs. You can also use a DragSourceAdapter to filter + * the events you are interested in. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see DragSourceDragEvent + * @see DragSource + * @see DragSourceListener + * @see DragSourceAdapter + * @since 1.4 + * @status updated to 1.4 + */ +public interface DragSourceMotionListener extends EventListener +{ + /** + * Called whenever the mouse is moved during a drag-and-drop operation. + * + * @param e the event + */ + void dragMouseMoved(DragSourceDragEvent e); +} // interface DragSourceMotionListener diff --git a/libjava/classpath/java/awt/dnd/DropTarget.java b/libjava/classpath/java/awt/dnd/DropTarget.java new file mode 100644 index 0000000..9fd7ef8 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTarget.java @@ -0,0 +1,293 @@ +/* DropTarget.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 java.awt.dnd; + +import java.awt.Component; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Point; +import java.awt.datatransfer.FlavorMap; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.Serializable; +import java.util.EventListener; +import java.util.TooManyListenersException; + +/** + * @author Michael Koch + * @since 1.2 + */ +public class DropTarget + implements DropTargetListener, EventListener, Serializable +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = -6283860791671019047L; + + /** @specnote According to the online documentation, this is + * protected, but in reality it is public. */ + public static class DropTargetAutoScroller + implements ActionListener + { + private Component component; + private Point point; + + protected DropTargetAutoScroller (Component c, Point p) + { + component = c; + point = p; + } + + protected void updateLocation (Point newLocn) + { + point = newLocn; + } + + protected void stop () + { + } + + public void actionPerformed (ActionEvent e) + { + } + } + + private Component component; + private FlavorMap flavorMap; + private int actions; + private DropTargetContext dropTargetContext; + private DropTargetListener dropTargetListener; + private boolean active = true; + + /** + * Creates a DropTarget object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget () + { + this (null, 0, null, true, null); + } + + /** + * Creates a DropTarget object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget (Component c, DropTargetListener dtl) + { + this (c, 0, dtl, true, null); + } + + /** + * Creates a DropTarget object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget (Component c, int i, DropTargetListener dtl) + { + this (c, i, dtl, true, null); + } + + /** + * Creates a DropTarget object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget (Component c, int i, DropTargetListener dtl, boolean b) + { + this (c, i, dtl, b, null); + } + + /** + * Creates a DropTarget object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget (Component c, int i, DropTargetListener dtl, boolean b, + FlavorMap fm) + { + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); + + component = c; + actions = i; + dropTargetListener = dtl; + flavorMap = fm; + + setActive (b); + } + + /** + * Sets the component associated with this drop target object. + */ + public void setComponent (Component c) + { + component = c; + } + + /** + * Returns the component associated with this drop target object. + */ + public Component getComponent () + { + return component; + } + + /** + * Sets the default actions. + */ + public void setDefaultActions (int ops) + { + actions = ops; + } + + /** + * Returns the default actions. + */ + public int getDefaultActions () + { + return actions; + } + + public void setActive (boolean active) + { + this.active = active; + } + + public boolean isActive() + { + return active; + } + + /** + * Adds a new DropTargetListener. + * + * @exception TooManyListenersException Sun's JDK does not, despite + * documentation, throw this exception here when you install an additional + * DropTargetListener. So to be compatible, we do the same + * thing. + */ + public void addDropTargetListener (DropTargetListener dtl) + throws TooManyListenersException + { + dropTargetListener = dtl; + } + + public void removeDropTargetListener(DropTargetListener dtl) + { + // FIXME: Do we need to do something with dtl ? + dropTargetListener = null; + } + + public void dragEnter(DropTargetDragEvent dtde) + { + } + + public void dragOver(DropTargetDragEvent dtde) + { + } + + public void dropActionChanged(DropTargetDragEvent dtde) + { + } + + public void dragExit(DropTargetEvent dte) + { + } + + public void drop(DropTargetDropEvent dtde) + { + } + + public FlavorMap getFlavorMap() + { + return flavorMap; + } + + public void setFlavorMap(FlavorMap fm) + { + flavorMap = fm; + } + + public void addNotify(java.awt.peer.ComponentPeer peer) + { + } + + public void removeNotify(java.awt.peer.ComponentPeer peer) + { + } + + public DropTargetContext getDropTargetContext() + { + if (dropTargetContext == null) + dropTargetContext = createDropTargetContext (); + + return dropTargetContext; + } + + protected DropTargetContext createDropTargetContext() + { + return new DropTargetContext (this); + } + + protected DropTarget.DropTargetAutoScroller createDropTargetAutoScroller + (Component c, Point p) + { + return new DropTarget.DropTargetAutoScroller (c, p); + } + + protected void initializeAutoscrolling(Point p) + { + } + + protected void updateAutoscroll(Point dragCursorLocn) + { + } + + protected void clearAutoscroll() + { + } +} // class DropTarget diff --git a/libjava/classpath/java/awt/dnd/DropTargetAdapter.java b/libjava/classpath/java/awt/dnd/DropTargetAdapter.java new file mode 100644 index 0000000..13c6b9f --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetAdapter.java @@ -0,0 +1,100 @@ +/* DragSourceAdapter.java -- drag-and-drop listener adapter + 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 java.awt.dnd; + +/** + * This class implements DropTargetListener, and implements all methods + * with empty bodies. This allows a listener interested in implementing only + * a subset of these interfaces to extend this class and override only the + * desired methods. + * + * @author Michael Koch (konqueror@gmx.de) + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class DropTargetAdapter + implements DropTargetListener +{ + /** + * Default constructor. + */ + public DropTargetAdapter() + { + } + + /** + * Called when the cursor hotspot enters a drop site which will accept the + * drag. + * + * @param e the event + */ + public void dragEnter (DropTargetDragEvent e) + { + } + + /** + * Called when the cursor hotspot moves inside of a drop site which will + * accept the drag. + * + * @param e the event + */ + public void dragOver (DropTargetDragEvent e) + { + } + + /** + * Called when the user modifies the drop gesture. This is often the case + * when additional mouse or key events are received during the drag. + * + * @param e the event + */ + public void dropActionChanged (DropTargetDragEvent e) + { + } + + /** + * Called when the cursor hotspot moves outside of a drop site which will + * accept the drag. This could also happen if the drop site is no longer + * active, or no longer accepts the drag. + * + * @param e the event + */ + public void dragExit(DropTargetEvent e) + { + } +} // class DropTargetAdapter diff --git a/libjava/classpath/java/awt/dnd/DropTargetContext.java b/libjava/classpath/java/awt/dnd/DropTargetContext.java new file mode 100644 index 0000000..d1fb66e --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetContext.java @@ -0,0 +1,188 @@ +/* DropTargetContext.java -- + Copyright (C) 2002, 2003, 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 java.awt.dnd; + +import java.awt.Component; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; +import java.io.Serializable; +import java.util.Arrays; +import java.util.List; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.2 + */ +public class DropTargetContext implements Serializable +{ + static final long serialVersionUID = -634158968993743371L; + + /** @specnote According to the online documentation, this is + * protected, but in reality it is public. */ + public class TransferableProxy implements Transferable + { + protected boolean isLocal; + protected Transferable transferable; + + TransferableProxy (Transferable t, boolean local) + { + this.transferable = t; + this.isLocal = local; + } + + public DataFlavor[] getTransferDataFlavors () + { + return transferable.getTransferDataFlavors (); + } + + public boolean isDataFlavorSupported (DataFlavor flavor) + { + return transferable.isDataFlavorSupported (flavor); + } + + public Object getTransferData (DataFlavor flavor) + throws UnsupportedFlavorException, IOException + { + return transferable.getTransferData (flavor); + } + } + + private DropTarget dropTarget; + private int targetActions; + private java.awt.dnd.peer.DropTargetContextPeer dtcp; + + // package private + DropTargetContext (DropTarget dropTarget) + { + this.dropTarget = dropTarget; + } + + public DropTarget getDropTarget () + { + return dropTarget; + } + + public Component getComponent () + { + return dropTarget.getComponent (); + } + + public void addNotify (java.awt.dnd.peer.DropTargetContextPeer dtcp) + { + this.dtcp = dtcp; + } + + public void removeNotify () + { + this.dtcp = null; + } + + protected void setTargetActions (int actions) + { + targetActions = actions; + } + + protected int getTargetActions() + { + return targetActions; + } + + /** + * Signals that the drop is completed. + * + * @exception InvalidDnDOperationException If a drop is not outstanding. + */ + public void dropComplete (boolean success) + { + // FIXME: implement this + } + + protected void acceptDrag (int dragOperation) + { + // FIXME: implement this + } + + protected void rejectDrag () + { + // FIXME: implement this + } + + protected void acceptDrop (int dropOperation) + { + // FIXME: implement this + } + + protected void rejectDrop () + { + // FIXME: implement this + } + + protected DataFlavor[] getCurrentDataFlavors () + { + // FIXME: implement this + return null; + } + + protected List getCurrentDataFlavorsAsList () + { + return Arrays.asList (getCurrentDataFlavors ()); + } + + protected boolean isDataFlavorSupported (DataFlavor flavor) + { + return getCurrentDataFlavorsAsList ().contains (flavor); + } + + /** + * Return the Transferable operandof this operation. + * + * @exception InvalidDnDOperationException If a drag is not outstanding. + */ + protected Transferable getTransferable() throws InvalidDnDOperationException + { + // FIXME: implement this + return null; + } + + protected Transferable createTransferableProxy(Transferable t, boolean local) + { + return new TransferableProxy (t, local); + } +} // class DropTargetContext diff --git a/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java b/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java new file mode 100644 index 0000000..6cdc3a2 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java @@ -0,0 +1,140 @@ +/* DropTargetDragEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.awt.Point; +import java.awt.datatransfer.DataFlavor; +import java.util.List; + +/** + * @since 1.2 + */ +public class DropTargetDragEvent extends DropTargetEvent +{ + /** + * Compatible with 1.2+ + */ + private static final long serialVersionUID = -8422265619058953682L; + + private final int dropAction; + private final int srcActions; + private final Point location; + + /** + * Initializes a DropTargetDragEvent. + * + * @exception IllegalArgumentException If dropAction is not one of DnDConstants, + * srcActions is not a bitwise mask of DnDConstants, or dtc is null. + * @exception NullPointerException If location is null. + */ + public DropTargetDragEvent (DropTargetContext context, Point location, + int dropAction, int srcActions) + { + super (context); + + if (location == null) + throw new NullPointerException (); + + if (context == null) + throw new IllegalArgumentException (); + + if (dropAction != DnDConstants.ACTION_NONE + && dropAction != DnDConstants.ACTION_COPY + && dropAction != DnDConstants.ACTION_MOVE + && dropAction != DnDConstants.ACTION_COPY_OR_MOVE + && dropAction != DnDConstants.ACTION_LINK + && dropAction != DnDConstants.ACTION_REFERENCE) + throw new IllegalArgumentException (); + + int srcActionsMask = DnDConstants.ACTION_NONE + | DnDConstants.ACTION_COPY + | DnDConstants.ACTION_MOVE + | DnDConstants.ACTION_COPY_OR_MOVE + | DnDConstants.ACTION_LINK + | DnDConstants.ACTION_REFERENCE; + + if (~(srcActions ^ srcActionsMask) != 0) + throw new IllegalArgumentException (); + + this.dropAction = dropAction; + this.srcActions = srcActions; + this.location = location; + } + + public void acceptDrag (int dragOperation) + { + context.acceptDrag (dragOperation); + } + + public DataFlavor[] getCurrentDataFlavors () + { + return context.getCurrentDataFlavors (); + } + + public List getCurrentDataFlavorsAsList () + { + return context.getCurrentDataFlavorsAsList (); + } + + public int getDropAction() + { + return 0; + //return dropAction & ((DropTargetContext) source).getTargetActions(); + } + + public Point getLocation () + { + return location; + } + + public int getSourceActions () + { + return srcActions; + } + + public boolean isDataFlavorSupported (DataFlavor df) + { + return context.isDataFlavorSupported (df); + } + + public void rejectDrag () + { + context.rejectDrag (); + } +} // class DropTargetDragEvent diff --git a/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java b/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java new file mode 100644 index 0000000..0c0777f --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java @@ -0,0 +1,170 @@ +/* DropTargetDropEvent.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 java.awt.dnd; + +import java.awt.Point; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.util.List; + +/** + * @since 1.2 + */ +public class DropTargetDropEvent extends DropTargetEvent +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = -1721911170440459322L; + + private final int dropAction; + private final int actions; + private final Point location; + private final boolean isLocalTx; + + /** + * Initializes a DropTargetDropEvent. By default this constructor + * assumes that the target is not int same JVM. + * + * @exception IllegalArgumentException If dropAction is not one of DnDConstants, + * actions is not a bitwise mask of DnDConstants, or dtc is null. + * @exception NullPointerException If location is null. + */ + public DropTargetDropEvent (DropTargetContext dtc, Point location, + int dropAction, int actions) + { + this (dtc, location, dropAction, actions, false); + } + + /** + * Initializes a DropTargetDropEvent. + * + * @exception IllegalArgumentException If dropAction is not one of DnDConstants, + * actions is not a bitwise mask of DnDConstants, or dtc is null. + * @exception NullPointerException If location is null. + */ + public DropTargetDropEvent (DropTargetContext dtc, Point location, + int dropAction, int actions, boolean isLocalTx) + { + super (dtc); + + if (location == null) + throw new NullPointerException (); + + if (dtc == null) + throw new IllegalArgumentException (); + + if (dropAction != DnDConstants.ACTION_NONE + && dropAction != DnDConstants.ACTION_COPY + && dropAction != DnDConstants.ACTION_MOVE + && dropAction != DnDConstants.ACTION_COPY_OR_MOVE + && dropAction != DnDConstants.ACTION_LINK + && dropAction != DnDConstants.ACTION_REFERENCE) + throw new IllegalArgumentException (); + + int actionsMask = DnDConstants.ACTION_NONE + | DnDConstants.ACTION_COPY + | DnDConstants.ACTION_MOVE + | DnDConstants.ACTION_COPY_OR_MOVE + | DnDConstants.ACTION_LINK + | DnDConstants.ACTION_REFERENCE; + + if (~(actions ^ actionsMask) != 0) + throw new IllegalArgumentException (); + + this.dropAction = dropAction; + this.actions = actions; + this.location = location; + this.isLocalTx = isLocalTx; + } + + public Point getLocation () + { + return location; + } + + public DataFlavor[] getCurrentDataFlavors () + { + return context.getCurrentDataFlavors (); + } + + public List getCurrentDataFlavorsAsList () + { + return context.getCurrentDataFlavorsAsList (); + } + + public boolean isDataFlavorSupported (DataFlavor flavor) + { + return context.isDataFlavorSupported (flavor); + } + + public int getSourceActions () + { + return actions; + } + + public int getDropAction () + { + return dropAction; + } + + public Transferable getTransferable () + { + return context.getTransferable (); + } + + public void acceptDrop (int dropAction) + { + context.acceptDrop (dropAction); + } + + public void rejectDrop () + { + context.rejectDrop (); + } + + public void dropComplete (boolean success) + { + // FIXME: implement this + } + + public boolean isLocalTransfer() + { + return isLocalTx; + } +} // class DropTargetDropEvent diff --git a/libjava/classpath/java/awt/dnd/DropTargetEvent.java b/libjava/classpath/java/awt/dnd/DropTargetEvent.java new file mode 100644 index 0000000..56a4d48 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetEvent.java @@ -0,0 +1,56 @@ +/* DropTarget.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 java.awt.dnd; + +import java.util.EventObject; + +public class DropTargetEvent extends EventObject +{ + protected DropTargetContext context; + + public DropTargetEvent (DropTargetContext context) + { + super (context); + this.context = context; + } + + public DropTargetContext getDropTargetContext () + { + return context; + } +} diff --git a/libjava/classpath/java/awt/dnd/DropTargetListener.java b/libjava/classpath/java/awt/dnd/DropTargetListener.java new file mode 100644 index 0000000..ceb839b --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetListener.java @@ -0,0 +1,89 @@ +/* DropTargetListener.java -- listen to events during the drop + 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 java.awt.dnd; + +import java.util.EventListener; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.2 + * @status updated to 1.4 + */ +public interface DropTargetListener extends EventListener +{ + /** + * Called when the cursor hotspot enters a drop site which will accept the + * drag. + * + * @param e the drag source drag event + */ + void dragEnter (DropTargetDragEvent e); + + /** + * Called when the cursor hotspot moves inside of a drop site which will + * accept the drag. + * + * @param e the drag source drag event + */ + void dragOver (DropTargetDragEvent e); + + /** + * Called when the user modifies the drop gesture. This is often the case + * when additional mouse or key events are received during the drag. + * + * @param e the drag source drag event + */ + void dropActionChanged (DropTargetDragEvent e); + + /** + * Called when the cursor hotspot moves outside of a drop site which will + * accept the drag. This could also happen if the drop site is no longer + * active, or no longer accepts the drag. + * + * @param e the drag source drag event + */ + void dragExit (DropTargetEvent e); + + /** + * Called when the drag operation has terminated with a drop. + * + * @param e the drag source drag event + */ + void drop (DropTargetDropEvent e); +} // interface DropTargetListener diff --git a/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java b/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java new file mode 100644 index 0000000..2fd9767 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java @@ -0,0 +1,73 @@ +/* InvalidDnDOperationException.java -- thrown when drag-and-drop fails + 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 java.awt.dnd; + +/** + * Thrown when a method in the java.awt.dnd package is unable to perform a + * requested operation, usually because the underlying DnD system is in the + * wrong state. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public class InvalidDnDOperationException extends IllegalStateException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -6062568741193956678L; + + /** + * Create an exception without a message. + */ + public InvalidDnDOperationException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public InvalidDnDOperationException(String s) + { + super(s); + } +} // class InvalidDnDOperationException diff --git a/libjava/classpath/java/awt/dnd/MouseDragGestureRecognizer.java b/libjava/classpath/java/awt/dnd/MouseDragGestureRecognizer.java new file mode 100644 index 0000000..9a2a7bc --- /dev/null +++ b/libjava/classpath/java/awt/dnd/MouseDragGestureRecognizer.java @@ -0,0 +1,131 @@ +/* MouseDragGestureRecognizer.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 java.awt.dnd; + +import java.awt.Component; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; + +/** + * @author Michael Koch (konqueror@gmx.de) + */ +public abstract class MouseDragGestureRecognizer + extends DragGestureRecognizer + implements MouseListener, MouseMotionListener +{ + /** + * Creates a MouseDragGestureRecognizer object. + */ + protected MouseDragGestureRecognizer (DragSource ds, Component c, int act, + DragGestureListener dgl) + { + super (ds, c, act, dgl); + } + + /** + * Creates a MouseDragGestureRecognizer object. + */ + protected MouseDragGestureRecognizer (DragSource ds, Component c, int act) + { + super (ds, c, act); + } + + /** + * Creates a MouseDragGestureRecognizer object. + */ + protected MouseDragGestureRecognizer (DragSource ds, Component c) + { + super (ds, c); + } + + /** + * Creates a MouseDragGestureRecognizer object. + */ + protected MouseDragGestureRecognizer (DragSource ds) + { + super (ds); + } + + protected void registerListeners () + { + component.addMouseListener (this); + component.addMouseMotionListener (this); + } + + protected void unregisterListeners () + { + component.removeMouseListener (this); + component.removeMouseMotionListener (this); + } + + public void mouseClicked (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mousePressed (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseReleased (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseEntered (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseExited (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseDragged (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseMoved (MouseEvent e) + { + // Do nothing in here by default. + } +} // class MouseDragGestureRecognizer diff --git a/libjava/classpath/java/awt/dnd/package.html b/libjava/classpath/java/awt/dnd/package.html new file mode 100644 index 0000000..d1ae521 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.dnd + + +

Events and listeners for drag and drop sources and targets.

+ + + diff --git a/libjava/classpath/java/awt/dnd/peer/DragSourceContextPeer.java b/libjava/classpath/java/awt/dnd/peer/DragSourceContextPeer.java new file mode 100644 index 0000000..8c134b6 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/peer/DragSourceContextPeer.java @@ -0,0 +1,57 @@ +/* DragSourceContextPeer.java -- interface for drag-and-drop peers + 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 java.awt.dnd.peer; + +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; +import java.awt.dnd.DragSourceContext; +import java.awt.dnd.InvalidDnDOperationException; + +/** + * STUBBED + */ +public interface DragSourceContextPeer +{ + void startDrag(DragSourceContext context, Cursor c, Image i, Point p) + throws InvalidDnDOperationException; + Cursor getCursor(); + void setCursor(Cursor c) throws InvalidDnDOperationException; + void transferablesFlavorsChanged(); +} // interface DragSourceContextPeer diff --git a/libjava/classpath/java/awt/dnd/peer/DropTargetContextPeer.java b/libjava/classpath/java/awt/dnd/peer/DropTargetContextPeer.java new file mode 100644 index 0000000..6eae29b --- /dev/null +++ b/libjava/classpath/java/awt/dnd/peer/DropTargetContextPeer.java @@ -0,0 +1,68 @@ +/* DropTargetContextPeer.java -- interface for drag-and-drop peers + 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 java.awt.dnd.peer; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DropTarget; +import java.awt.dnd.InvalidDnDOperationException; + + +/** + * Used to control state of recipient protocol from the + * DropTargetListener. Occurs when a Component + * with an associated DropTarget and visible geometry is first + * intersected by a logical cursor. + * + * @author Michael Koch (konqueror@gmx.de) + */ +public interface DropTargetContextPeer +{ + void setTargetActions(int actions); + int getTargetActions(); + DropTarget getDropTarget(); + DataFlavor[] getTransferDataFlavors(); + Transferable getTransferable() throws InvalidDnDOperationException; + boolean isTransferableJVMLocal(); + void acceptDrag(int dragAction); + void rejectDrag(); + void acceptDrop(int dropAction); + void rejectDrop(); + void dropComplete(boolean success); +} diff --git a/libjava/classpath/java/awt/dnd/peer/DropTargetPeer.java b/libjava/classpath/java/awt/dnd/peer/DropTargetPeer.java new file mode 100644 index 0000000..ec17cbe --- /dev/null +++ b/libjava/classpath/java/awt/dnd/peer/DropTargetPeer.java @@ -0,0 +1,48 @@ +/* DropTargetPeer.java -- interface for drag-and-drop peers + 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 java.awt.dnd.peer; + +import java.awt.dnd.DropTarget; + +/** + */ +public interface DropTargetPeer +{ + void addDropTarget (DropTarget target); + void removeDropTarget (DropTarget target); +} // interface DropTargetContextPeer diff --git a/libjava/classpath/java/awt/dnd/peer/package.html b/libjava/classpath/java/awt/dnd/peer/package.html new file mode 100644 index 0000000..52ec19c --- /dev/null +++ b/libjava/classpath/java/awt/dnd/peer/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.dnd.peer + + +

Interfaces for using native interface components.

+ + + diff --git a/libjava/classpath/java/awt/event/AWTEventListener.java b/libjava/classpath/java/awt/event/AWTEventListener.java new file mode 100644 index 0000000..079a91d --- /dev/null +++ b/libjava/classpath/java/awt/event/AWTEventListener.java @@ -0,0 +1,65 @@ +/* AWTEventListener.java -- listen for all events in the AWT system + Copyright (C) 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Toolkit; +import java.util.EventListener; + +/** + * This listener is for classes that need to listen to all events in the AWT + * system. In general, this should not be used except for classes like + * javax.accessibility or by event recorders. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see AWTEvent + * @see Toolkit#addAWTEventListener(AWTEventListener, long) + * @see Toolkit#removeAWTEventListener(AWTEventListener) + * @since 1.2 + * @status updated to 1.4 + */ +public interface AWTEventListener extends EventListener +{ + /** + * This method is called when any event in the AWT system is dispatched. + * + * @param event the AWTEvent that was dispatched + */ + void eventDispatched(AWTEvent event); +} // interface AWTEventListener diff --git a/libjava/classpath/java/awt/event/AWTEventListenerProxy.java b/libjava/classpath/java/awt/event/AWTEventListenerProxy.java new file mode 100644 index 0000000..3d9958b --- /dev/null +++ b/libjava/classpath/java/awt/event/AWTEventListenerProxy.java @@ -0,0 +1,155 @@ +/* AWTEventListenerProxy.java -- wrapper/filter for AWTEventListener + 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Toolkit; +import java.util.EventListenerProxy; + +/** + * This class allows adding an AWTEventListener which only pays attention to + * a specific event mask. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Toolkit + * @see EventListenerProxy + * @since 1.4 + * @status updated to 1.4 + */ +public class AWTEventListenerProxy extends EventListenerProxy + implements AWTEventListener +{ + /** The event mask. */ + private final long mask; + + /** + * Construct an AWT Event Listener which only listens to events in the given + * mask, passing the work on to the real listener. + * + * @param eventMask the mask of events to listen to + * @param listener the wrapped listener + */ + public AWTEventListenerProxy(long eventMask, AWTEventListener listener) + { + super(listener); + mask = eventMask; + } + + /** + * Forwards events on to the delegate if they meet the event mask. + * + * @param event the property change event to filter + * @throws NullPointerException if the delegate this was created with is null + */ + public void eventDispatched(AWTEvent event) + { + int id = event == null ? 0 : event.getID(); + if (((mask & AWTEvent.ACTION_EVENT_MASK) != 0 + && event instanceof ActionEvent) + || ((mask & AWTEvent.ADJUSTMENT_EVENT_MASK) != 0 + && event instanceof AdjustmentEvent) + || ((mask & AWTEvent.COMPONENT_EVENT_MASK) != 0 + && event instanceof ComponentEvent + && (id >= ComponentEvent.COMPONENT_FIRST + && id <= ComponentEvent.COMPONENT_LAST)) + || ((mask & AWTEvent.CONTAINER_EVENT_MASK) != 0 + && event instanceof ContainerEvent) + || ((mask & AWTEvent.FOCUS_EVENT_MASK) != 0 + && event instanceof FocusEvent) + || ((mask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 + && event instanceof HierarchyEvent + && (id == HierarchyEvent.ANCESTOR_MOVED + || id == HierarchyEvent.ANCESTOR_RESIZED)) + || ((mask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 + && event instanceof HierarchyEvent + && id == HierarchyEvent.HIERARCHY_CHANGED) + || ((mask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0 + && event instanceof InputMethodEvent) + || ((mask & AWTEvent.INVOCATION_EVENT_MASK) != 0 + && event instanceof InvocationEvent) + || ((mask & AWTEvent.ITEM_EVENT_MASK) != 0 + && event instanceof ItemEvent) + || ((mask & AWTEvent.KEY_EVENT_MASK) != 0 + && event instanceof KeyEvent) + || ((mask & AWTEvent.MOUSE_EVENT_MASK) != 0 + && event instanceof MouseEvent + && (id == MouseEvent.MOUSE_PRESSED + || id == MouseEvent.MOUSE_RELEASED + || id == MouseEvent.MOUSE_CLICKED + || id == MouseEvent.MOUSE_ENTERED + || id == MouseEvent.MOUSE_EXITED)) + || ((mask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0 + && event instanceof MouseEvent + && (id == MouseEvent.MOUSE_MOVED + || id == MouseEvent.MOUSE_DRAGGED)) + || ((mask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 + && event instanceof MouseWheelEvent) + || ((mask & AWTEvent.PAINT_EVENT_MASK) != 0 + && event instanceof PaintEvent) + || ((mask & AWTEvent.TEXT_EVENT_MASK) != 0 + && event instanceof TextEvent) + || ((mask & AWTEvent.WINDOW_EVENT_MASK) != 0 + && event instanceof WindowEvent + && (id == WindowEvent.WINDOW_OPENED + || id == WindowEvent.WINDOW_CLOSING + || id == WindowEvent.WINDOW_CLOSED + || id == WindowEvent.WINDOW_ICONIFIED + || id == WindowEvent.WINDOW_DEICONIFIED + || id == WindowEvent.WINDOW_ACTIVATED + || id == WindowEvent.WINDOW_DEACTIVATED)) + || ((mask & AWTEvent.WINDOW_FOCUS_EVENT_MASK) != 0 + && event instanceof WindowEvent + && (id == WindowEvent.WINDOW_GAINED_FOCUS + || id == WindowEvent.WINDOW_LOST_FOCUS)) + || ((mask & AWTEvent.WINDOW_STATE_EVENT_MASK) != 0 + && event instanceof WindowEvent + && id == WindowEvent.WINDOW_STATE_CHANGED)) + ((AWTEventListener) getListener()).eventDispatched(event); + } + + /** + * This returns the event mask associated with this listener. + * + * @return the event mask + */ + public long getEventMask() + { + return mask; + } +} // class AWTEventListenerProxy diff --git a/libjava/classpath/java/awt/event/ActionEvent.java b/libjava/classpath/java/awt/event/ActionEvent.java new file mode 100644 index 0000000..4bce7d4 --- /dev/null +++ b/libjava/classpath/java/awt/event/ActionEvent.java @@ -0,0 +1,226 @@ +/* ActionEvent.java -- an action has been triggered + Copyright (C) 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.EventQueue; + +/** + * This event is generated when an action on a component (such as a + * button press) occurs. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ActionListener + * @since 1.1 + * @status updated to 1.4 + */ +public class ActionEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -7671078796273832149L; + + /** Bit mask indicating the shift key was pressed. */ + public static final int SHIFT_MASK = InputEvent.SHIFT_MASK; + + /** Bit mask indicating the control key was pressed. */ + public static final int CTRL_MASK = InputEvent.CTRL_MASK; + + /** Bit mask indicating the that meta key was pressed. */ + public static final int META_MASK = InputEvent.META_MASK; + + /** Bit mask indicating that the alt key was pressed. */ + public static final int ALT_MASK = InputEvent.ALT_MASK; + + /** The first id number in the range of action id's. */ + public static final int ACTION_FIRST = 1001; + + /** The last id number in the range of action id's. */ + public static final int ACTION_LAST = 1001; + + /** An event id indicating that an action has occurred. */ + public static final int ACTION_PERFORMED = 1001; + + /** + * A nonlocalized string that gives more specific details of the event cause. + * + * @see #getActionCommand() + * @serial the command for this event + */ + private final String actionCommand; + + /** + * The bitmask of the modifiers that were pressed during the action. + * + * @see #getModifiers() + * @serial modifiers for this event + */ + private final int modifiers; + + /** + * The timestamp of this event; usually the same as the underlying input + * event. + * + * @see #getWhen() + * @serial the timestamp of the event + * @since 1.4 + */ + private final long when; + + /** + * Initializes a new instance of ActionEvent with the + * specified source, id, and command. Note that an invalid id leads to + * unspecified results. + * + * @param source the event source + * @param id the event id + * @param command the command string for this action + * @throws IllegalArgumentException if source is null + */ + public ActionEvent(Object source, int id, String command) + { + this(source, id, command, EventQueue.getMostRecentEventTime(), 0); + } + + /** + * Initializes a new instance of ActionEvent with the + * specified source, id, command, and modifiers. Note that an invalid id + * leads to unspecified results. + * + * @param source the event source + * @param id the event id + * @param command the command string for this action + * @param modifiers the bitwise or of modifier keys down during the action + * @throws IllegalArgumentException if source is null + */ + public ActionEvent(Object source, int id, String command, int modifiers) + { + this(source, id, command, EventQueue.getMostRecentEventTime(), modifiers); + } + + /** + * Initializes a new instance of ActionEvent with the + * specified source, id, command, and modifiers, and timestamp. Note that + * an invalid id leads to unspecified results. + * + * @param source the event source + * @param id the event id + * @param command the command string for this action + * @param when the timestamp of the event + * @param modifiers the bitwise or of modifier keys down during the action + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public ActionEvent(Object source, int id, String command, long when, + int modifiers) + { + super(source, id); + actionCommand = command; + this.when = when; + this.modifiers = modifiers; + } + + /** + * Returns the command string associated with this action. + * + * @return the command string associated with this action + */ + public String getActionCommand() + { + return actionCommand; + } + + /** + * Gets the timestamp of when this action took place. Usually, this + * corresponds to the timestamp of the underlying InputEvent. + * + * @return the timestamp of this action + * @since 1.4 + */ + public long getWhen() + { + return when; + } + + /** + * Returns the keys held down during the action. This value will be a + * combination of the bit mask constants defined in this class, or 0 if no + * modifiers were pressed. + * + * @return the modifier bits + */ + public int getModifiers() + { + return modifiers; + } + + /** + * Returns a string that identifies the action event. This is in the format + * "ACTION_PERFORMED,cmd=" + getActionCommand() + ",when=" + getWhen() + * + ",modifiers=" + <modifier string>, where the modifier + * string is in the order "Meta", "Ctrl", "Alt", "Shift", "Alt Graph", and + * "Button1", separated by '+', according to the bits set in getModifiers(). + * + * @return a string identifying the event + */ + public String paramString() + { + StringBuffer s = new StringBuffer(id == ACTION_PERFORMED + ? "ACTION_PERFORMED,cmd=" + : "unknown type,cmd="); + s.append(actionCommand).append(",when=").append(when).append(",modifiers"); + int len = s.length(); + s.setLength(len + 1); + if ((modifiers & META_MASK) != 0) + s.append("+Meta"); + if ((modifiers & CTRL_MASK) != 0) + s.append("+Ctrl"); + if ((modifiers & ALT_MASK) != 0) + s.append("+Alt"); + if ((modifiers & SHIFT_MASK) != 0) + s.append("+Shift"); + if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) + s.append("+Alt Graph"); + if ((modifiers & InputEvent.BUTTON1_MASK) != 0) + s.append("+Button1"); + s.setCharAt(len, '='); + return s.toString(); + } +} // class ActionEvent diff --git a/libjava/classpath/java/awt/event/ActionListener.java b/libjava/classpath/java/awt/event/ActionListener.java new file mode 100644 index 0000000..4c302cc --- /dev/null +++ b/libjava/classpath/java/awt/event/ActionListener.java @@ -0,0 +1,59 @@ +/* ActionListener.java -- listens for action events + Copyright (C) 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that listen for action events. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ActionEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface ActionListener extends EventListener +{ + /** + * This method is invoked when an action occurs. + * + * @param event the ActionEvent that occurred + */ + void actionPerformed(ActionEvent event); +} diff --git a/libjava/classpath/java/awt/event/AdjustmentEvent.java b/libjava/classpath/java/awt/event/AdjustmentEvent.java new file mode 100644 index 0000000..867c577 --- /dev/null +++ b/libjava/classpath/java/awt/event/AdjustmentEvent.java @@ -0,0 +1,222 @@ +/* AdjustmentEvent.java -- an adjustable value was changed + Copyright (C) 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Adjustable; + +/** + * This class represents an event that is generated when an adjustable + * value is changed. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Adjustable + * @see AdjustmentListener + * @since 1.1 + * @status updated to 1.4 + */ +public class AdjustmentEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5700290645205279921L; + + /** This is the first id in the range of ids used by adjustment events. */ + public static final int ADJUSTMENT_FIRST = 601; + + /** This is the last id in the range of ids used by adjustment events. */ + public static final int ADJUSTMENT_LAST = 601; + + /** This is the id indicating an adjustment value changed. */ + public static final int ADJUSTMENT_VALUE_CHANGED = 601; + + /** Adjustment type for unit increments. */ + public static final int UNIT_INCREMENT = 1; + + /** Adjustment type for unit decrements. */ + public static final int UNIT_DECREMENT = 2; + + /** Adjustment type for block decrements. */ + public static final int BLOCK_DECREMENT = 3; + + /** Adjustment type for block increments. */ + public static final int BLOCK_INCREMENT = 4; + + /** Adjustment type for tracking adjustments. */ + public static final int TRACK = 5; + + /** + * The adjustable object that caused the event. + * + * @see #getAdjustable() + * @serial the cause + */ + private final Adjustable adjustable; + + /** + * The type of adjustment, one of {@link #UNIT_INCREMENT}, + * {@link #UNIT_DECREMENT}, {@link #BLOCK_INCREMENT}, + * {@link #BLOCK_DECREMENT}, or {@link #TRACK}. + * + * @see #getAdjustmentType() + * @serial the adjustment type + */ + private final int adjustmentType; + + /** + * The new value of the adjustable; it should be in the range of the + * adjustable cause. + * + * @see #getValue() + * @serial the adjustment value + */ + private final int value; + + /** + * True if this is in a series of multiple adjustment events. + * + * @see #getValueIsAdjusting() + * @serial true if this is not the last adjustment + * @since 1.4 + */ + private final boolean isAdjusting; + + /** + * Initializes an instance of AdjustmentEvent with the + * specified source, id, type, and value. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param type the event type, one of the constants of this class + * @param value the value of the adjustment + * @throws IllegalArgumentException if source is null + */ + public AdjustmentEvent(Adjustable source, int id, int type, int value) + { + this(source, id, type, value, false); + } + + /** + * Initializes an instance of AdjustmentEvent with the + * specified source, id, type, and value. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param type the event type, one of the constants of this class + * @param value the value of the adjustment + * @param isAdjusting if this event is in a chain of adjustments + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public AdjustmentEvent(Adjustable source, int id, int type, int value, + boolean isAdjusting) + { + super(source, id); + this.adjustmentType = type; + this.value = value; + adjustable = source; + this.isAdjusting = isAdjusting; + } + + /** + * This method returns the source of the event as an Adjustable. + * + * @return the Adjustable source of the event + */ + public Adjustable getAdjustable() + { + return adjustable; + } + + /** + * Returns the new value of the adjustable object. + * + * @return the value of the event + */ + public int getValue() + { + return value; + } + + /** + * Returns the type of the event, which will be one of + * {@link #UNIT_INCREMENT}, {@link #UNIT_DECREMENT}, + * {@link #BLOCK_INCREMENT}, {@link #BLOCK_DECREMENT}, or {@link #TRACK}. + * + * @return the type of the event + */ + public int getAdjustmentType() + { + return adjustmentType; + } + + /** + * Test if this event is part of a sequence of multiple adjustements. + * + * @return true if this is not the last adjustment + * @since 1.4 + */ + public boolean getValueIsAdjusting() + { + return isAdjusting; + } + + /** + * Returns a string that describes the event. This is in the format + * "ADJUSTMENT_VALUE_CHANGED,adjType=" + <type> + ",value=" + * + getValue() + ",isAdjusting=" + getValueIsAdjusting(), where + * type is the name of the constant returned by getAdjustmentType(). + * + * @return a string that describes the event + */ + public String paramString() + { + return (id == ADJUSTMENT_VALUE_CHANGED + ? "ADJUSTMENT_VALUE_CHANGED,adjType=" : "unknown type,adjType=") + + (adjustmentType == UNIT_INCREMENT ? "UNIT_INCREMENT,value=" + : adjustmentType == UNIT_DECREMENT ? "UNIT_DECREMENT,value=" + : adjustmentType == BLOCK_INCREMENT ? "BLOCK_INCREMENT,value=" + : adjustmentType == BLOCK_DECREMENT ? "BLOCK_DECREMENT,value=" + : adjustmentType == TRACK ? "TRACK,value=" : "unknown type,value=") + + value + ",isAdjusting=" + isAdjusting; + } +} // class AdjustmentEvent diff --git a/libjava/classpath/java/awt/event/AdjustmentListener.java b/libjava/classpath/java/awt/event/AdjustmentListener.java new file mode 100644 index 0000000..1eb2e3b --- /dev/null +++ b/libjava/classpath/java/awt/event/AdjustmentListener.java @@ -0,0 +1,58 @@ +/* AdjustmentListener.java -- listen for adjustment events + Copyright (C) 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 java.awt.event; + +import java.util.EventListener; + +/** + * Interface for classes that listen for adjustment events. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public interface AdjustmentListener extends EventListener +{ + /** + * This method is called when an adjustable value changes. + * + * @param event the AdjustmentEvent that occurred + */ + void adjustmentValueChanged(AdjustmentEvent event); +} // interface AdjustmentListener diff --git a/libjava/classpath/java/awt/event/ComponentAdapter.java b/libjava/classpath/java/awt/event/ComponentAdapter.java new file mode 100644 index 0000000..6b4893f --- /dev/null +++ b/libjava/classpath/java/awt/event/ComponentAdapter.java @@ -0,0 +1,97 @@ +/* ComponentAdapter.java -- convenience class for writing component listeners + Copyright (C) 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 java.awt.event; + +/** + * This class implements ComponentListener and implements + * all methods with empty bodies. This allows a listener interested in + * implementing only a subset of the ComponentListener + * interface to extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ComponentEvent + * @see ComponentListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class ComponentAdapter implements ComponentListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public ComponentAdapter() + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentResized(ComponentEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentMoved(ComponentEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentShown(ComponentEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentHidden(ComponentEvent event) + { + } +} // class ComponentAdapter diff --git a/libjava/classpath/java/awt/event/ComponentEvent.java b/libjava/classpath/java/awt/event/ComponentEvent.java new file mode 100644 index 0000000..ba9c2a5 --- /dev/null +++ b/libjava/classpath/java/awt/event/ComponentEvent.java @@ -0,0 +1,137 @@ +/* ComponentEvent.java -- notification of events for components + Copyright (C) 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Component; + +/** + * This class is for events generated when a component is moved, resized, + * hidden, or shown. These events normally do not need to be handled by the + * application, since the AWT system automatically takes care of them. This + * is also the superclass for other events on components, but + * ComponentListeners ignore such subclasses. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ComponentAdapter + * @see ComponentListener + * @since 1.1 + * @status updated to 1.4 + */ +public class ComponentEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 8101406823902992965L; + + /** This is the first id in the range of ids used by this class. */ + public static final int COMPONENT_FIRST = 100; + + /** This is the last id in the range of ids used by this class. */ + public static final int COMPONENT_LAST = 103; + + /** This id indicates that a component was moved. */ + public static final int COMPONENT_MOVED = 100; + + /** This id indicates that a component was resized. */ + public static final int COMPONENT_RESIZED = 101; + + /** This id indicates that a component was shown. */ + public static final int COMPONENT_SHOWN = 102; + + /** This id indicates that a component was hidden. */ + public static final int COMPONENT_HIDDEN = 103; + + /** + * Initializes a new instance of ComponentEvent with the + * specified source and id. Note that an invalid id leads to unspecified + * results. + * + * @param source the source of the event + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public ComponentEvent(Component source, int id) + { + super(source, id); + } + + /** + * This method returns the event source as a Component. If the + * source has subsequently been modified to a non-Component, this returns + * null. + * + * @return the event source as a Component, or null + */ + public Component getComponent() + { + return source instanceof Component ? (Component) source : null; + } + + /** + * This method returns a string identifying this event. This is the field + * name of the id type, and for COMPONENT_MOVED or COMPONENT_RESIZED, the + * new bounding box of the component. + * + * @return a string identifying this event + */ + public String paramString() + { + // Unlike Sun, we don't throw NullPointerException or ClassCastException + // when source was illegally changed. + switch (id) + { + case COMPONENT_MOVED: + return "COMPONENT_MOVED " + + (source instanceof Component + ? ((Component) source).getBounds() : (Object) ""); + case COMPONENT_RESIZED: + return "COMPONENT_RESIZED " + + (source instanceof Component + ? ((Component) source).getBounds() : (Object) ""); + case COMPONENT_SHOWN: + return "COMPONENT_SHOWN"; + case COMPONENT_HIDDEN: + return "COMPONENT_HIDDEN"; + default: + return "unknown type"; + } + } +} // class ComponentEvent diff --git a/libjava/classpath/java/awt/event/ComponentListener.java b/libjava/classpath/java/awt/event/ComponentListener.java new file mode 100644 index 0000000..b43faae --- /dev/null +++ b/libjava/classpath/java/awt/event/ComponentListener.java @@ -0,0 +1,84 @@ +/* ComponentListener.java -- receive all events for a component + Copyright (C) 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that receive all events from a component. + * Normally it is not necessary to process these events since the AWT + * handles them internally, taking all appropriate actions. To watch a subset + * of these events, use a ComponentAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ComponentAdapter + * @see ComponentEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface ComponentListener extends EventListener +{ + /** + * This method is called when the component is resized. + * + * @param event the ComponentEvent indicating the resize + */ + void componentResized(ComponentEvent event); + + /** + * This method is called when the component is moved. + * + * @param event the ComponentEvent indicating the move + */ + void componentMoved(ComponentEvent event); + + /** + * This method is called when the component is made visible. + * + * @param event the ComponentEvent indicating the visibility + */ + void componentShown(ComponentEvent event); + + /** + * This method is called when the component is hidden. + * + * @param event the ComponentEvent indicating the visibility + */ + void componentHidden(ComponentEvent event); +} // interface ComponentListener diff --git a/libjava/classpath/java/awt/event/ContainerAdapter.java b/libjava/classpath/java/awt/event/ContainerAdapter.java new file mode 100644 index 0000000..c847adf --- /dev/null +++ b/libjava/classpath/java/awt/event/ContainerAdapter.java @@ -0,0 +1,79 @@ +/* ContainerAdapter.java -- convenience class for writing container listeners + Copyright (C) 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 java.awt.event; + +/** + * This class implements ContainerListener and implements + * all methods with empty bodies. This allows a listener interested in + * implementing only a subset of the ContainerListener + * interface to extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ContainerEvent + * @see ContainerListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class ContainerAdapter implements ContainerListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public ContainerAdapter() + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentAdded(ContainerEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentRemoved(ContainerEvent event) + { + } +} // class ContainerAdapter diff --git a/libjava/classpath/java/awt/event/ContainerEvent.java b/libjava/classpath/java/awt/event/ContainerEvent.java new file mode 100644 index 0000000..3c401fe --- /dev/null +++ b/libjava/classpath/java/awt/event/ContainerEvent.java @@ -0,0 +1,135 @@ +/* ContainerEvent.java -- components added/removed from a container + Copyright (C) 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 java.awt.event; + +import java.awt.Component; +import java.awt.Container; + +/** + * This event is generated when a component is added or removed from a + * container. Applications do not ordinarily need to handle these events + * since the AWT system handles them internally. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ContainerAdapter + * @see ContainerListener + * @since 1.1 + * @status updated to 1.4 + */ +public class ContainerEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -4114942250539772041L; + + /** This is the first id in the id range used by this class. */ + public static final int CONTAINER_FIRST = 300; + + /** This is the last id in the id range used by this class. */ + public static final int CONTAINER_LAST = 301; + + /** This id indicates a component was added to the container. */ + public static final int COMPONENT_ADDED = 300; + + /** This id indicates a component was removed from the container. */ + public static final int COMPONENT_REMOVED = 301; + + /** + * The non-null child component that was added or removed. + * + * @serial the child component that changed + */ + private final Component child; + + /** + * Initializes a new instance of ContainerEvent with the + * specified source and id. Additionally, the affected child component + * is also passed as a parameter. Note that an invalid id leads to + * unspecified results. + * + * @param source the source container of the event + * @param id the event id + * @param child the child component affected by this event + * @throws IllegalArgumentException if source is null + */ + public ContainerEvent(Component source, int id, Component child) + { + super(source, id); + this.child = child; + } + + /** + * Returns the source of this event as a Container. + * + * @return the source of the event + * @throws ClassCastException if the source is changed to a non-Container + */ + public Container getContainer() + { + return (Container) source; + } + + /** + * This method returns the child object that was added or removed from + * the container. + * + * @return the child object added or removed + */ + public Component getChild() + { + return child; + } + + /** + * This method returns a string identifying this event. It is formatted as: + * (getID() == COMPONENT_ADDED ? "COMPONENT_ADDED" + * : "COMPONENT_REMOVED") + ",child=" + getChild().getName(). + * + * @return a string identifying this event + */ + public String paramString() + { + // Unlike Sun, we don't throw NullPointerException if child is illegally + // null. + return (id == COMPONENT_ADDED ? "COMPONENT_ADDED,child=" + : id == COMPONENT_REMOVED ? "COMPONENT_REMOVED,child=" + : "unknown type,child=") + (child == null ? "" : child.getName()); + } +} // class ContainerEvent diff --git a/libjava/classpath/java/awt/event/ContainerListener.java b/libjava/classpath/java/awt/event/ContainerListener.java new file mode 100644 index 0000000..b37d434 --- /dev/null +++ b/libjava/classpath/java/awt/event/ContainerListener.java @@ -0,0 +1,70 @@ +/* ContainerListener.java -- listen for container events + Copyright (C) 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to listen for all events from + * container objects. This is normally not necessary since the AWT system + * listens for and processes these events. To watch a subset of these events, + * use a ContainerAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ContainerAdapter + * @see ContainerEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface ContainerListener extends EventListener +{ + /** + * This method is called when a component is added to the container. + * + * @param event the ContainerEvent indicating component addition + */ + void componentAdded(ContainerEvent event); + + /** + * This method is called when a component is removed from the container. + * + * @param event the ContainerEvent indicating component removal + */ + void componentRemoved(ContainerEvent event); +} // interface ContainerListener diff --git a/libjava/classpath/java/awt/event/FocusAdapter.java b/libjava/classpath/java/awt/event/FocusAdapter.java new file mode 100644 index 0000000..fb0532a --- /dev/null +++ b/libjava/classpath/java/awt/event/FocusAdapter.java @@ -0,0 +1,79 @@ +/* FocusAdapter.java -- convenience class for writing focus listeners + Copyright (C) 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 java.awt.event; + +/** + * This class implements FocusListener and implements all + * methods with empty bodies. This allows a listener interested in + * implementing only a subset of the FocusListener interface to + * extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see FocusEvent + * @see FocusListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class FocusAdapter implements FocusListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public FocusAdapter() + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void focusGained(FocusEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void focusLost(FocusEvent event) + { + } +} // class FocusAdapter diff --git a/libjava/classpath/java/awt/event/FocusEvent.java b/libjava/classpath/java/awt/event/FocusEvent.java new file mode 100644 index 0000000..a44284a --- /dev/null +++ b/libjava/classpath/java/awt/event/FocusEvent.java @@ -0,0 +1,181 @@ +/* FocusEvent.java -- generated for a focus change + Copyright (C) 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 java.awt.event; + +import java.awt.Component; + +/** + * This class represents an event generated when a focus change occurs for a + * component. There are both temporary changes, such as when focus is stolen + * during a sroll then returned, and permanent changes, such as when the user + * TABs through focusable components. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see FocusAdapter + * @see FocusListener + * @since 1.1 + * @status updated to 1.4 + */ +public class FocusEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 523753786457416396L; + + /** This is the first id in the range of ids used by this class. */ + public static final int FOCUS_FIRST = 1004; + + /** This is the last id in the range of ids used by this class. */ + public static final int FOCUS_LAST = 1005; + + /** This is the event id for a focus gained event. */ + public static final int FOCUS_GAINED = 1004; + + /** This is the event id for a focus lost event. */ + public static final int FOCUS_LOST = 1005; + + /** + * Indicates whether or not the focus change is temporary. + * + * @see #isTemporary() + * @serial true if the focus change is temporary + */ + private final boolean temporary; + + /** + * The other component which is giving up or stealing focus from this + * component, if known. + * + * @see #getOppositeComponent() + * @serial the component with the opposite focus event, or null + * @since 1.4 + */ + private final Component opposite; + + /** + * Initializes a new instance of FocusEvent with the + * specified source, id, temporary status, and opposite counterpart. Note + * that an invalid id leads to unspecified results. + * + * @param source the component that is gaining or losing focus + * @param id the event id + * @param temporary true if the focus change is temporary + * @param opposite the component receiving the opposite focus event, or null + * @throws IllegalArgumentException if source is null + */ + public FocusEvent(Component source, int id, boolean temporary, + Component opposite) + { + super(source, id); + this.temporary = temporary; + this.opposite = opposite; + } + + /** + * Initializes a new instance of FocusEvent with the + * specified source, id, and temporary status. Note that an invalid id + * leads to unspecified results. + * + * @param source the component that is gaining or losing focus + * @param id the event id + * @param temporary true if the focus change is temporary + * @throws IllegalArgumentException if source is null + */ + public FocusEvent(Component source, int id, boolean temporary) + { + this(source, id, temporary, null); + } + + /** + * Initializes a new instance of FocusEvent with the + * specified source and id. Note that an invalid id leads to unspecified + * results. + * + * @param source the component that is gaining or losing focus + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public FocusEvent(Component source, int id) + { + this(source, id, false, null); + } + + /** + * This method tests whether or not the focus change is temporary or + * permanent. + * + * @return true if the focus change is temporary + */ + public boolean isTemporary() + { + return temporary; + } + + /** + * Returns the component which received the opposite focus event. If this + * component gained focus, the opposite lost focus; likewise if this + * component is giving up focus, the opposite is gaining it. If this + * information is unknown, perhaps because the opposite is a native + * application, this returns null. + * + * @return the component with the focus opposite, or null + * @since 1.4 + */ + public Component getOppositeComponent() + { + return opposite; + } + + /** + * Returns a string identifying this event. This is formatted as: + * (getID() == FOCUS_GAINED ? "FOCUS_GAINED" : "FOCUS_LOST") + * + (isTemporary() ? ",temporary," : ",permanent,") + "opposite=" + * + getOppositeComponent(). + * + * @return a string identifying this event + */ + public String paramString() + { + return (id == FOCUS_GAINED ? "FOCUS_GAINED" + : id == FOCUS_LOST ? "FOCUS_LOST" : "unknown type") + + (temporary ? ",temporary,opposite=" : ",permanent,opposite=") + + opposite; + } +} // class FocusEvent diff --git a/libjava/classpath/java/awt/event/FocusListener.java b/libjava/classpath/java/awt/event/FocusListener.java new file mode 100644 index 0000000..1f72018 --- /dev/null +++ b/libjava/classpath/java/awt/event/FocusListener.java @@ -0,0 +1,69 @@ +/* FocusListener.java -- listen for focus changes + Copyright (C) 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to be notified of changes of + * keyboard focus for a component. To watch a subset of these events, use a + * FocusAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see FocusAdapter + * @see FocusEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface FocusListener extends EventListener +{ + /** + * This method is called when a component gains the keyboard focus. + * + * @param event the FocusEvent indicating that focus was gained + */ + void focusGained(FocusEvent event); + + /** + * This method is invoked when a component loses the keyboard focus. + * + * @param event the FocusEvent indicating that focus was lost + */ + void focusLost(FocusEvent event); +} // interface FocusListener diff --git a/libjava/classpath/java/awt/event/HierarchyBoundsAdapter.java b/libjava/classpath/java/awt/event/HierarchyBoundsAdapter.java new file mode 100644 index 0000000..340cf01 --- /dev/null +++ b/libjava/classpath/java/awt/event/HierarchyBoundsAdapter.java @@ -0,0 +1,78 @@ +/* HierarchyBoundsAdapter.java -- convenience class for writing listeners + 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 java.awt.event; + +/** + * This class implements HierarchyBoundsListener and implements + * all methods with empty bodies. This allows a listener interested in + * implementing only a subset of the HierarchyBoundsListener + * interface to extend this class and override only the desired methods. + * + * @author Bryce McKinlay + * @see HierarchyBoundsListener + * @see HierarchyEvent + * @since 1.3 + * @status updated to 1.4 + */ +public abstract class HierarchyBoundsAdapter implements HierarchyBoundsListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public HierarchyBoundsAdapter() + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void ancestorMoved(HierarchyEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void ancestorResized(HierarchyEvent event) + { + } +} diff --git a/libjava/classpath/java/awt/event/HierarchyBoundsListener.java b/libjava/classpath/java/awt/event/HierarchyBoundsListener.java new file mode 100644 index 0000000..6896237 --- /dev/null +++ b/libjava/classpath/java/awt/event/HierarchyBoundsListener.java @@ -0,0 +1,70 @@ +/* HierarchyBoundsListener.java -- listens to bounds changes of parents + 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 java.awt.event; + +import java.util.EventListener; + +/** + * This listens for changes in an ancestors size or location. Normally it is + * not necessary to process these events since the AWT handles them + * internally, taking all appropriate actions. To watch a subset of these + * events, use a HierarchyBoundsAdapter. + * + * @author Bryce McKinlay + * @see HierarchyBoundsAdapter + * @see HierarchyEvent + * @since 1.3 + * @status updated to 1.4 + */ +public interface HierarchyBoundsListener extends EventListener +{ + /** + * Called when an ancestor component of the source is moved. + * + * @param e the event describing the ancestor's motion + */ + void ancestorMoved(HierarchyEvent e); + + /** + * Called when an ancestor component is resized. + * + * @param e the event describing the ancestor's resizing + */ + void ancestorResized(HierarchyEvent e); +} // interface HierarchyBoundsListener diff --git a/libjava/classpath/java/awt/event/HierarchyEvent.java b/libjava/classpath/java/awt/event/HierarchyEvent.java new file mode 100644 index 0000000..e10cefb --- /dev/null +++ b/libjava/classpath/java/awt/event/HierarchyEvent.java @@ -0,0 +1,253 @@ +/* HierarchyEvent.java -- generated for a change in hierarchy + 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Container; + +/** + * This class represents an event generated for an ancestor component which + * may affect this component. These events normally do not need to be handled + * by the application, since the AWT system automatically takes care of them. + * + *

There are two types of hierarchy events. The first type is handled by + * HierarchyListener, and includes addition or removal of an ancestor, or + * an ancestor changing its on-screen status (visible and/or displayble). The + * second type is handled by HierarchyBoundsListener, and includes resizing + * or moving of an ancestor. + * + * @author Bryce McKinlay + * @see HierarchyListener + * @see HierarchyBoundsAdapter + * @see HierarchyBoundsListener + * @since 1.3 + * @status updated to 1.4 + */ +public class HierarchyEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.3+. + */ + private static final long serialVersionUID = -5337576970038043990L; + + /** This is the first id in the range of ids used by this class. */ + public static final int HIERARCHY_FIRST = 1400; + + /** This id indicates that the hierarchy tree changed. */ + public static final int HIERARCHY_CHANGED = 1400; + + /** This id indicates that an ancestor was moved. */ + public static final int ANCESTOR_MOVED = 1401; + + /** This id indicates that an ancestor was resized. */ + public static final int ANCESTOR_RESIZED = 1402; + + /** This is the last id in the range of ids used by this class. */ + public static final int HIERARCHY_LAST = 1402; + + /** This indicates that the HIERARCHY_CHANGED is a changed parent. */ + public static final int PARENT_CHANGED = 1; + + /** + * This indicates that the HIERARCHY_CHANGED is caused by a change in + * displayability. + * + * @see Component#isDisplayable() + * @see Component#addNotify() + * @see Component#removeNotify() + */ + public static final int DISPLAYABILITY_CHANGED = 2; + + /** + * This indicates that the HIERARCHY_CHANGED is a changed visibility. + * + * @see Component#isShowing() + * @see Component#addNotify() + * @see Component#removeNotify() + * @see Component#show() + * @see Component#hide() + */ + public static final int SHOWING_CHANGED = 4; + + /** + * The component at the top of the changed hierarchy. + * + * @serial the top component changed + */ + private final Component changed; + + /** + * The parent of this component, either before or after the change depending + * on the type of change. + * + * @serial the parent component changed + */ + private final Container changedParent; + + /** + * The bitmask of HIERARCHY_CHANGED event types. + * + * @serial the change flags + */ + private final long changeFlags; + + /** + * Initializes a new instance of HierarchyEvent with the + * specified parameters. Note that an invalid id leads to unspecified + * results. + * + * @param source the component whose hierarchy changed + * @param id the event id + * @param changed the top component in the tree of changed hierarchy + * @param changedParent the updated parent of this object + * @throws IllegalArgumentException if source is null + */ + public HierarchyEvent(Component source, int id, Component changed, + Container changedParent) + { + this(source, id, changed, changedParent, 0); + } + + /** + * Initializes a new instance of HierarchyEvent with the + * specified parameters. Note that an invalid id leads to unspecified + * results. + * + * @param source the component whose hierarchy changed + * @param id the event id + * @param changed the top component in the tree of changed hierarchy + * @param changedParent the updated parent of this object + * @param changeFlags the bitmask of specific HIERARCHY_CHANGED events + * @throws IllegalArgumentException if source is null + */ + public HierarchyEvent(Component source, int id, Component changed, + Container changedParent, long changeFlags) + { + super(source, id); + this.changed = changed; + this.changedParent = changedParent; + this.changeFlags = changeFlags; + } + + /** + * This method returns the event source as a Component. If the + * source has subsequently been modified to a non-Component, this returns + * null. + * + * @return the event source as a Component, or null + */ + public Component getComponent() + { + return source instanceof Component ? (Component) source : null; + } + + /** + * Returns the component at the top of the hierarchy which changed. + * + * @return the top changed component + */ + public Component getChanged() + { + return changed; + } + + /** + * Returns the parent of the component listed in getChanged(). + * If the cause of this event was Container.add, this is the + * new parent; if the cause was Container.remove, this is the + * old parent; otherwise it is the unchanged parent. + * + * @return the parent container of the changed component + */ + public Container getChangedParent() + { + return changedParent; + } + + /** + * If this is a HIERARCHY_CHANGED event, this returns a bitmask of the + * types of changes that took place. + * + * @return the bitwise or of hierarchy change types, or 0 + * @see #PARENT_CHANGED + * @see #DISPLAYABILITY_CHANGED + * @see #SHOWING_CHANGED + */ + public long getChangeFlags() + { + return changeFlags; + } + + /** + * This method returns a string identifying this event. This is the field + * name of the id type, followed by a parenthesized listing of the changed + * component and its parent container. In addition, if the type is + * HIERARCHY_CHANGED, the flags preceed the changed component, in the + * order PARENT_CHANGED, DISPLAYABILITY_CHANGED, and SHOWING_CHANGED. + * + * @return a string identifying this event + */ + public String paramString() + { + StringBuffer r = new StringBuffer(); + switch (id) + { + case HIERARCHY_CHANGED: + r.append("HIERARCHY_CHANGED ("); + if ((changeFlags & PARENT_CHANGED) != 0) + r.append("PARENT_CHANGED,"); + if ((changeFlags & DISPLAYABILITY_CHANGED) != 0) + r.append("DISPLAYABILITY_CHANGED,"); + if ((changeFlags & SHOWING_CHANGED) != 0) + r.append("SHOWING_CHANGED,"); + break; + case ANCESTOR_MOVED: + r.append("ANCESTOR_MOVED ("); + break; + case ANCESTOR_RESIZED: + r.append("ANCESTOR_RESIZED ("); + break; + default: + return "unknown type"; + } + r.append(changed).append(',').append(changedParent).append(')'); + return r.toString(); + } +} // class HierarchyEvent diff --git a/libjava/classpath/java/awt/event/HierarchyListener.java b/libjava/classpath/java/awt/event/HierarchyListener.java new file mode 100644 index 0000000..f90414b --- /dev/null +++ b/libjava/classpath/java/awt/event/HierarchyListener.java @@ -0,0 +1,62 @@ +/* HierarchyListener.java -- listens to changes in the component hierarchy + 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 java.awt.event; + +import java.util.EventListener; + +/** + * This listens for changes in the hierarchy tree of components. Normally it is + * not necessary to process these events since the AWT handles them + * internally, taking all appropriate actions. + * + * @author Bryce McKinlay + * @see HierarchyEvent + * @since 1.3 + * @status updated to 1.4 + */ +public interface HierarchyListener extends EventListener +{ + /** + * Called when the hierarchy of this component changes. Use + * getChangeFlags() on the event to see what exactly changed. + * + * @param e the event describing the change + */ + void hierarchyChanged(HierarchyEvent e); +} // interface HierarchyListener diff --git a/libjava/classpath/java/awt/event/InputEvent.java b/libjava/classpath/java/awt/event/InputEvent.java new file mode 100644 index 0000000..8f9aed6 --- /dev/null +++ b/libjava/classpath/java/awt/event/InputEvent.java @@ -0,0 +1,381 @@ +/* InputEvent.java -- common superclass of component input events + Copyright (C) 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 java.awt.event; + +import gnu.java.awt.EventModifier; + +import java.awt.Component; + +/** + * This is the common superclass for all component input classes. These are + * passed to listeners before the component, so that listeners can consume + * the event before it does its default behavior. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see KeyEvent + * @see KeyAdapter + * @see MouseEvent + * @see MouseAdapter + * @see MouseMotionAdapter + * @see MouseWheelEvent + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class InputEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -2482525981698309786L; + + /** + * This is the bit mask which indicates the shift key is down. It is + * recommended that SHIFT_DOWN_MASK be used instead. + * + * @see #SHIFT_DOWN_MASK + */ + public static final int SHIFT_MASK = 1; + + /** + * This is the bit mask which indicates the control key is down. It is + * recommended that CTRL_DOWN_MASK be used instead. + * + * @see #CTRL_DOWN_MASK + */ + public static final int CTRL_MASK = 2; + + /** + * This is the bit mask which indicates the meta key is down. It is + * recommended that META_DOWN_MASK be used instead. + * + * @see #META_DOWN_MASK + */ + public static final int META_MASK = 4; + + /** + * This is the bit mask which indicates the alt key is down. It is + * recommended that ALT_DOWN_MASK be used instead. + * + * @see #ALT_DOWN_MASK + */ + public static final int ALT_MASK = 8; + + /** + * This is the bit mask which indicates the alt-graph modifier is in effect. + * It is recommended that ALT_GRAPH_DOWN_MASK be used instead. + * + * @see #ALT_GRAPH_DOWN_MASK + */ + public static final int ALT_GRAPH_MASK = 0x20; + + /** + * This bit mask indicates mouse button one is down. It is recommended that + * BUTTON1_DOWN_MASK be used instead. + * + * @see #BUTTON1_DOWN_MASK + */ + public static final int BUTTON1_MASK = 0x10; + + /** + * This bit mask indicates mouse button two is down. It is recommended that + * BUTTON2_DOWN_MASK be used instead. + * + * @see #BUTTON2_DOWN_MASK + */ + public static final int BUTTON2_MASK = 8; + + /** + * This bit mask indicates mouse button three is down. It is recommended + * that BUTTON3_DOWN_MASK be used instead. + * + * @see #BUTTON3_DOWN_MASK + */ + public static final int BUTTON3_MASK = 4; + + /** + * The SHIFT key extended modifier. + * + * @since 1.4 + */ + public static final int SHIFT_DOWN_MASK = 0x0040; + + /** + * The CTRL key extended modifier. + * + * @since 1.4 + */ + public static final int CTRL_DOWN_MASK = 0x0080; + + /** + * The META key extended modifier. + * + * @since 1.4 + */ + public static final int META_DOWN_MASK = 0x0100; + + /** + * The ALT key extended modifier. + * + * @since 1.4 + */ + public static final int ALT_DOWN_MASK = 0x0200; + + /** + * The mouse button1 key extended modifier. + * + * @since 1.4 + */ + public static final int BUTTON1_DOWN_MASK = 0x0400; + + /** + * The mouse button2 extended modifier. + * + * @since 1.4 + */ + public static final int BUTTON2_DOWN_MASK = 0x0800; + + /** + * The mouse button3 extended modifier. + * + * @since 1.4 + */ + public static final int BUTTON3_DOWN_MASK = 0x1000; + + /** + * The ALT_GRAPH key extended modifier. + * + * @since 1.4 + */ + public static final int ALT_GRAPH_DOWN_MASK = 0x2000; + + /** The mask to convert new to old, package visible for use in subclasses. */ + static final int CONVERT_MASK + = EventModifier.NEW_MASK & ~(BUTTON2_DOWN_MASK | BUTTON3_DOWN_MASK); + + /** + * The timestamp when this event occurred. + * + * @see #getWhen() + * @serial the timestamp + */ + private final long when; + + /** + * The modifiers in effect for this event. Package visible for use by + * subclasses. The old style (bitmask 0x3f) should not be mixed with the + * new style (bitmasks 0xffffffc0). + * + * @see #getModifiers() + * @see MouseEvent + * @serial the modifier state, stored in the new style + */ + int modifiers; + + /** + * Initializes a new instance of InputEvent with the specified + * source, id, timestamp, and modifiers. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param when the timestamp when the event occurred + * @param modifiers the modifiers in effect for this event, old or new style + * @throws IllegalArgumentException if source is null + */ + InputEvent(Component source, int id, long when, int modifiers) + { + super(source, id); + this.when = when; + this.modifiers = EventModifier.extend(modifiers); + } + + /** + * This method tests whether or not the shift key was down during the event. + * + * @return true if the shift key is down + */ + public boolean isShiftDown() + { + return (modifiers & SHIFT_DOWN_MASK) != 0; + } + + /** + * This method tests whether or not the control key was down during the + * event. + * + * @return true if the control key is down + */ + public boolean isControlDown() + { + return (modifiers & CTRL_DOWN_MASK) != 0; + } + + /** + * This method tests whether or not the meta key was down during the event. + * + * @return true if the meta key is down + */ + public boolean isMetaDown() + { + return (modifiers & META_DOWN_MASK) != 0; + } + + /** + * This method tests whether or not the alt key was down during the event. + * + * @return true if the alt key is down + */ + public boolean isAltDown() + { + return (modifiers & ALT_DOWN_MASK) != 0; + } + + /** + * This method tests whether or not the alt-graph modifier was in effect + * during the event. + * + * @return true if the alt-graph modifier is down + */ + public boolean isAltGraphDown() + { + return (modifiers & ALT_GRAPH_DOWN_MASK) != 0; + } + + /** + * This method returns the timestamp when this event occurred. + * + * @return the timestamp when this event occurred + */ + public long getWhen() + { + return when; + } + + /** + * This method returns the old-style modifiers in effect for this event. + * Note that this is ambiguous between button2 and alt, and between + * button3 and meta. Also, code which generated these modifiers tends to + * only list the modifier that just changed, even if others were down at + * the time. Consider using getModifiersEx instead. This will be a union + * of the bit masks defined in this class that are applicable to the event. + * + * @return the modifiers in effect for this event + * @see #getModifiersEx() + */ + public int getModifiers() + { + return EventModifier.revert(modifiers); + } + + /** + * Returns the extended modifiers (new-style) for this event. This represents + * the state of all modal keys and mouse buttons at the time of the event, + * and does not suffer from the problems mentioned in getModifiers. + * + *

For an example of checking multiple modifiers, this code will return + * true only if SHIFT and BUTTON1 were pressed and CTRL was not: + *

+   * int onmask = InputEvent.SHIFT_DOWN_MASK | InputEvent.BUTTON1_DOWN_MASK;
+   * int offmask = InputEvent.CTRL_DOWN_MASK;
+   * return (event.getModifiersEx() & (onmask | offmask)) == onmask;
+   * 
+ * + * @return the bitwise or of all modifiers pressed during the event + * @since 1.4 + */ + public int getModifiersEx() + { + return modifiers; + } + + /** + * Consumes this event. A consumed event is not processed further by the AWT + * system. + */ + public void consume() + { + consumed = true; + } + + /** + * This method tests whether or not this event has been consumed. + * + * @return true if this event has been consumed + */ + public boolean isConsumed() + { + return consumed; + } + + /** + * Convert the extended modifier bitmask into a String, such as "Shift" or + * "Ctrl+Button1". + * + * XXX Sun claims this can be localized via the awt.properties file - how + * do we implement that? + * + * @param modifiers the modifiers + * @return a string representation of the modifiers in this bitmask + * @since 1.4 + */ + public static String getModifiersExText(int modifiers) + { + modifiers &= EventModifier.NEW_MASK; + if (modifiers == 0) + return ""; + StringBuffer s = new StringBuffer(); + if ((modifiers & META_DOWN_MASK) != 0) + s.append("Meta+"); + if ((modifiers & CTRL_DOWN_MASK) != 0) + s.append("Ctrl+"); + if ((modifiers & ALT_DOWN_MASK) != 0) + s.append("Alt+"); + if ((modifiers & SHIFT_DOWN_MASK) != 0) + s.append("Shift+"); + if ((modifiers & ALT_GRAPH_DOWN_MASK) != 0) + s.append("Alt Graph+"); + if ((modifiers & BUTTON1_DOWN_MASK) != 0) + s.append("Button1+"); + if ((modifiers & BUTTON2_DOWN_MASK) != 0) + s.append("Button2+"); + if ((modifiers & BUTTON3_DOWN_MASK) != 0) + s.append("Button3+"); + return s.substring(0, s.length() - 1); + } +} // class InputEvent diff --git a/libjava/classpath/java/awt/event/InputMethodEvent.java b/libjava/classpath/java/awt/event/InputMethodEvent.java new file mode 100644 index 0000000..f6711a8 --- /dev/null +++ b/libjava/classpath/java/awt/event/InputMethodEvent.java @@ -0,0 +1,303 @@ +/* InputMethodEvent.java -- events from a text input method + Copyright (C) 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.font.TextHitInfo; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.text.AttributedCharacterIterator; + +/** + * This class is for event generated by change in a text input method. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see InputMethodListener + * @since 1.2 + * @status updated to 1.4 + */ +public class InputMethodEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 4727190874778922661L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int INPUT_METHOD_FIRST = 1100; + + /** This event id indicates that the text in the input method has changed. */ + public static final int INPUT_METHOD_TEXT_CHANGED = 1100; + + /** This event id indicates that the input method curor point has changed. */ + public static final int CARET_POSITION_CHANGED = 1101; + + /** This is the last id in the range of event ids used by this class. */ + public static final int INPUT_METHOD_LAST = 1101; + + /** + * The timestamp when this event was created. + * + * @serial the timestamp + * @since 1.4 + */ + private long when; + + /** The input method text. */ + private final transient AttributedCharacterIterator text; + + /** The number of committed characters in the text. */ + private final transient int committedCharacterCount; + + /** The caret. */ + private final transient TextHitInfo caret; + + /** The most important position to be visible. */ + private final transient TextHitInfo visiblePosition; + + /** + * Initializes a new instance of InputMethodEvent with the + * specified source, id, timestamp, text, char count, caret, and visible + * position. + * + * @param source the source that generated the event + * @param id the event id + * @param when the timestamp of the event + * @param text the input text + * @param committedCharacterCount the number of committed characters + * @param caret the caret position + * @param visiblePosition the position most important to make visible + * @throws IllegalArgumentException if source is null, id is invalid, id is + * CARET_POSITION_CHANGED and text is non-null, or if + * committedCharacterCount is out of range + * @since 1.4 + */ + public InputMethodEvent(Component source, int id, long when, + AttributedCharacterIterator text, + int committedCharacterCount, TextHitInfo caret, + TextHitInfo visiblePosition) + { + super(source, id); + this.when = when; + this.text = text; + this.committedCharacterCount = committedCharacterCount; + this.caret = caret; + this.visiblePosition = visiblePosition; + if (id < INPUT_METHOD_FIRST || id > INPUT_METHOD_LAST + || (id == CARET_POSITION_CHANGED && text != null) + || committedCharacterCount < 0 + || (committedCharacterCount + > (text == null ? 0 : text.getEndIndex() - text.getBeginIndex()))) + throw new IllegalArgumentException(); + } + + /** + * Initializes a new instance of InputMethodEvent with the + * specified source, id, text, char count, caret, and visible position. + * + * @param source the source that generated the event + * @param id the event id + * @param text the input text + * @param committedCharacterCount the number of committed characters + * @param caret the caret position + * @param visiblePosition the position most important to make visible + * @throws IllegalArgumentException if source is null, id is invalid, id is + * CARET_POSITION_CHANGED and text is non-null, or if + * committedCharacterCount is out of range + * @since 1.4 + */ + public InputMethodEvent(Component source, int id, + AttributedCharacterIterator text, + int committedCharacterCount, TextHitInfo caret, + TextHitInfo visiblePosition) + { + this(source, id, EventQueue.getMostRecentEventTime(), text, + committedCharacterCount, caret, visiblePosition); + } + + /** + * Initializes a new instance of InputMethodEvent with the + * specified source, id, caret, and visible position, and with a null + * text and char count. + * + * @param source the source that generated the event + * @param id the event id + * @param caret the caret position + * @param visiblePosition the position most important to make visible + * @throws IllegalArgumentException if source is null or id is invalid + * @since 1.4 + */ + public InputMethodEvent(Component source, int id, TextHitInfo caret, + TextHitInfo visiblePosition) + { + this(source, id, EventQueue.getMostRecentEventTime(), null, 0, caret, + visiblePosition); + } + + /** + * This method returns the input method text. This can be null, + * and will always be null for CARET_POSITION_CHANGED events. + * Characters from 0 to getCommittedCharacterCount()-1 have + * been committed, the remaining characters are composed text. + * + * @return the input method text, or null + */ + public AttributedCharacterIterator getText() + { + return text; + } + + /** + * Returns the number of committed characters in the input method text. + * + * @return the number of committed characters in the input method text + */ + public int getCommittedCharacterCount() + { + return committedCharacterCount; + } + + /** + * Returns the caret position. The caret offset is relative to the composed + * text of the most recent INPUT_METHOD_TEXT_CHANGED event. + * + * @return the caret position, or null + */ + public TextHitInfo getCaret() + { + return caret; + } + + /** + * Returns the position that is most important to be visible, or null if + * such a hint is not necessary. The caret offset is relative to the composed + * text of the most recent INPUT_METHOD_TEXT_CHANGED event. + * + * @return the position that is most important to be visible + */ + public TextHitInfo getVisiblePosition() + { + return visiblePosition; + } + + /** + * This method consumes the event. A consumed event is not processed + * in the default manner by the component that generated it. + */ + public void consume() + { + consumed = true; + } + + /** + * This method tests whether or not this event has been consumed. + * + * @return true if the event has been consumed + */ + public boolean isConsumed() + { + return consumed; + } + + /** + * Return the timestamp of this event. + * + * @return the timestamp + * @since 1.4 + */ + public long getWhen() + { + return when; + } + + /** + * This method returns a string identifying the event. This contains the + * event ID, the committed and composed characters separated by '+', the + * number of committed characters, the caret, and the visible position. + * + * @return a string identifying the event + */ + public String paramString() + { + StringBuffer s + = new StringBuffer(80 + (text == null ? 0 + : text.getEndIndex() - text.getBeginIndex())); + s.append(id == INPUT_METHOD_TEXT_CHANGED ? "INPUT_METHOD_TEXT_CHANGED, " + : "CARET_POSITION_CHANGED, "); + if (text == null) + s.append("no text, 0 characters committed, caret: "); + else + { + s.append('"'); + int i = text.getBeginIndex(); + int j = committedCharacterCount; + while (--j >= 0) + s.append(text.setIndex(i++)); + s.append("\" + \""); + j = text.getEndIndex() - i; + while (--j >= 0) + s.append(text.setIndex(i++)); + s.append("\", ").append(committedCharacterCount) + .append(" characters committed, caret: "); + } + s.append(caret == null ? (Object) "no caret" : caret).append(", ") + .append(visiblePosition == null ? (Object) "no visible position" + : visiblePosition); + return s.toString(); + } + + /** + * Reads in the object from a serial stream, updating when to + * {@link EventQueue#getMostRecentEventTime()} if necessary. + * + * @param s the stream to read from + * @throws IOException if deserialization fails + * @throws ClassNotFoundException if deserialization fails + * @serialData default, except for updating when + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + if (when == 0) + when = EventQueue.getMostRecentEventTime(); + } +} // class InputMethodEvent diff --git a/libjava/classpath/java/awt/event/InputMethodListener.java b/libjava/classpath/java/awt/event/InputMethodListener.java new file mode 100644 index 0000000..e2f6a4e --- /dev/null +++ b/libjava/classpath/java/awt/event/InputMethodListener.java @@ -0,0 +1,70 @@ +/* InputMethodListener.java -- listen for input method events + Copyright (C) 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 java.awt.event; + +import java.awt.im.InputMethodRequests; +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive events from an input + * method. For a text component to use input methods, it must also install + * an InputMethodRequests handler. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see InputMethodEvent + * @see InputMethodRequests + * @since 1.2 + * @status updated to 1.4 + */ +public interface InputMethodListener extends EventListener +{ + /** + * This method is called when the text is changed. + * + * @param event the InputMethodEvent indicating the text change + */ + void inputMethodTextChanged(InputMethodEvent event); + + /** + * This method is called when the cursor position within the text is changed. + * + * @param event the InputMethodEvent indicating the change + */ + void caretPositionChanged(InputMethodEvent event); +} // interface InputMethodListener diff --git a/libjava/classpath/java/awt/event/InvocationEvent.java b/libjava/classpath/java/awt/event/InvocationEvent.java new file mode 100644 index 0000000..75feb62 --- /dev/null +++ b/libjava/classpath/java/awt/event/InvocationEvent.java @@ -0,0 +1,237 @@ +/* InvocationEvent.java -- call a runnable when dispatched + Copyright (C) 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.ActiveEvent; +import java.awt.EventQueue; + +/** + * This event executes {@link Runnable#run()} of a target object when it is + * dispatched. This class is used by calls to invokeLater and + * invokeAndWait, so client code can use this fact to avoid + * writing special-casing AWTEventListener objects. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ActiveEvent + * @see EventQueue#invokeLater(Runnable) + * @see EventQueue#invokeAndWait(Runnable) + * @see AWTEventListener + * @since 1.2 + * @status updated to 1.4 + */ +public class InvocationEvent extends AWTEvent implements ActiveEvent +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 436056344909459450L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int INVOCATION_FIRST = 1200; + + /** This is the default id for this event type. */ + public static final int INVOCATION_DEFAULT = 1200; + + /** This is the last id in the range of event ids used by this class. */ + public static final int INVOCATION_LAST = 1200; + + /** + * This is the Runnable object to call when dispatched. + * + * @serial the runnable to execute + */ + protected Runnable runnable; + + /** + * This is the object to call notifyAll() on when + * the call to run() returns, or null if no + * object is to be notified. + * + * @serial the object to notify + */ + protected Object notifier; + + /** + * This variable is set to true if exceptions are caught + * and stored in a variable during the call to run(), otherwise + * exceptions are ignored and propagate up. + * + * @serial true to catch exceptions + */ + protected boolean catchExceptions; + + /** + * This is the caught exception thrown in the run() method. It + * is null if exceptions are ignored, the run method hasn't completed, or + * there were no exceptions. + * + * @serial the caught exception, if any + */ + private Exception exception; + + /** + * The timestamp when this event was created. + * + * @see #getWhen() + * @serial the timestamp + * @since 1.4 + */ + private final long when = EventQueue.getMostRecentEventTime(); + + /** + * Initializes a new instance of InvocationEvent with the + * specified source and runnable. + * + * @param source the source of the event + * @param runnable the Runnable object to invoke + * @throws IllegalArgumentException if source is null + */ + public InvocationEvent(Object source, Runnable runnable) + { + this(source, INVOCATION_DEFAULT, runnable, null, false); + } + + /** + * Initializes a new instance of InvocationEvent with the + * specified source, runnable, and notifier. It will also catch exceptions + * if specified. If notifier is non-null, this will call notifyAll() on + * the object when the runnable is complete. If catchExceptions is true, + * this traps any exception in the runnable, otherwise it lets the exception + * propagate up the Event Dispatch thread. + * + * @param source the source of the event + * @param runnable the Runnable object to invoke + * @param notifier the object to notify, or null + * @param catchExceptions true to catch exceptions from the runnable + */ + public InvocationEvent(Object source, Runnable runnable, Object notifier, + boolean catchExceptions) + { + this(source, INVOCATION_DEFAULT, runnable, notifier, catchExceptions); + } + + /** + * Initializes a new instance of InvocationEvent with the + * specified source, runnable, and notifier. It will also catch exceptions + * if specified. If notifier is non-null, this will call notifyAll() on + * the object when the runnable is complete. If catchExceptions is true, + * this traps any exception in the runnable, otherwise it lets the exception + * propagate up the Event Dispatch thread. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param runnable the Runnable object to invoke + * @param notifier the object to notify, or null + * @param catchExceptions true to catch exceptions from the runnable + */ + protected InvocationEvent(Object source, int id, Runnable runnable, + Object notifier, boolean catchExceptions) + { + super(source, id); + this.runnable = runnable; + this.notifier = notifier; + this.catchExceptions = catchExceptions; + } + + /** + * This method calls the run() method of the runnable, traps + * exceptions if instructed to do so, and calls notifyAll() + * on any notifier if all worked successfully. + */ + public void dispatch() + { + if (catchExceptions) + try + { + runnable.run(); + } + catch (Exception e) + { + exception = e; + } + else + runnable.run(); + + Object o = notifier; + if (o != null) + synchronized(o) + { + o.notifyAll(); + } + } + + /** + * This method returns the exception that occurred during the execution of + * the runnable, or null if not exception was thrown or + * exceptions were not caught. + * + * @return the exception thrown by the runnable + */ + public Exception getException() + { + return exception; + } + + /** + * Gets the timestamp of when this event was created. + * + * @return the timestamp of this event + * @since 1.4 + */ + public long getWhen() + { + return when; + } + + /** + * This method returns a string identifying this event. This is formatted as: + * "INVOCATION_DEFAULT,runnable=" + runnable + ",notifier=" + notifier + * + ",catchExceptions=" + catchExceptions + ",when=" + getWhen(). + * + * @return a string identifying this event + */ + public String paramString() + { + return (id == INVOCATION_DEFAULT ? "INVOCATION_DEFAULT,runnable=" + : "unknown type,runnable=") + runnable + ",notifier=" + notifier + + ",catchExceptions=" + catchExceptions + ",when=" + when; + } +} // class InvocationEvent diff --git a/libjava/classpath/java/awt/event/ItemEvent.java b/libjava/classpath/java/awt/event/ItemEvent.java new file mode 100644 index 0000000..467815b --- /dev/null +++ b/libjava/classpath/java/awt/event/ItemEvent.java @@ -0,0 +1,155 @@ +/* ItemEvent.java -- event for item state changes + Copyright (C) 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.ItemSelectable; + +/** + * This event is generated when a selection item changes state. This is an + * abstraction that distills a large number of individual mouse or keyboard + * events into a simpler "item selected" and "item deselected" events. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ItemSelectable + * @see ItemListener + * @since 1.1 + * @status updated to 1.4 + */ +public class ItemEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -608708132447206933L; + + /** This is the first id in the event id range used by this class. */ + public static final int ITEM_FIRST = 701; + + /** This is the last id in the event id range used by this class. */ + public static final int ITEM_LAST = 701; + + /** This event id indicates a state change occurred. */ + public static final int ITEM_STATE_CHANGED = 701; + + /** This type indicates that the item was selected. */ + public static final int SELECTED = 1; + + /** This type indicates that the item was deselected. */ + public static final int DESELECTED = 2; + + /** + * The item affected by this event. + * + * @serial the item of the selection + */ + private final Object item; + + /** + * The state change direction, one of {@link #SELECTED} or + * {@link #DESELECTED}. + * + * @serial the selection state + */ + private final int stateChange; + + /** + * Initializes a new instance of ItemEvent with the specified + * source, id, and state change constant. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param item the item affected by the state change + * @param stateChange one of {@link #SELECTED} or {@link #DESELECTED} + */ + public ItemEvent(ItemSelectable source, int id, Object item, int stateChange) + { + super(source, id); + this.item = item; + this.stateChange = stateChange; + } + + /** + * This method returns the event source as an ItemSelectable. + * + * @return the event source as an ItemSelected + * @throws ClassCastException if source is changed to a non-ItemSelectable + */ + public ItemSelectable getItemSelectable() + { + return (ItemSelectable) source; + } + + /** + * Returns the item affected by this state change. + * + * @return the item affected by this state change + */ + public Object getItem() + { + return item; + } + + /** + * Returns the type of state change, either {@link #SELECTED} or + * {@link #DESELECTED}. + * + * @return the type of state change + */ + public int getStateChange() + { + return stateChange; + } + + /** + * Returns a string identifying this event. This is in the format: + * "ITEM_STATE_CHANGED,item=" + item + ",stateChange=" + * + (getStateChange() == DESELECTED ? "DESELECTED" : "SELECTED"). + * + * @return a string identifying this event + */ + public String paramString() + { + return (id == ITEM_STATE_CHANGED ? "ITEM_STATE_CHANGED,item=" + : "unknown type,item=") + item + ",stateChange=" + + (stateChange == SELECTED ? "SELECTED" + : stateChange == DESELECTED ? "DESELECTED" : "unknown type"); + } +} // class ItemEvent diff --git a/libjava/classpath/java/awt/event/ItemListener.java b/libjava/classpath/java/awt/event/ItemListener.java new file mode 100644 index 0000000..fa5f3aa --- /dev/null +++ b/libjava/classpath/java/awt/event/ItemListener.java @@ -0,0 +1,62 @@ +/* ItemListener.java -- listen for item events + Copyright (C) 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 java.awt.event; + +import java.awt.ItemSelectable; +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive events when an + * item's selection state changes. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ItemSelectable + * @see ItemEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface ItemListener extends EventListener +{ + /** + * This method is called when an item's state is changed. + * + * @param event the ItemEvent indicating the change + */ + void itemStateChanged(ItemEvent event); +} // interface ItemListener diff --git a/libjava/classpath/java/awt/event/KeyAdapter.java b/libjava/classpath/java/awt/event/KeyAdapter.java new file mode 100644 index 0000000..c01d61f --- /dev/null +++ b/libjava/classpath/java/awt/event/KeyAdapter.java @@ -0,0 +1,88 @@ +/* KeyAdapter.java -- convenience class for writing key listeners + Copyright (C) 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 java.awt.event; + +/** + * This class implements KeyListener and implements all methods + * with empty bodies. This allows a listener interested in implementing only + * a subset of the KeyListener interface to extend this class + * and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see KeyEvent + * @see KeyListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class KeyAdapter implements KeyListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public KeyAdapter() + { + } + + /** + * Implements this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void keyTyped(KeyEvent event) + { + } + + /** + * Implements this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void keyPressed(KeyEvent event) + { + } + + /** + * Implements this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void keyReleased(KeyEvent event) + { + } +} // class KeyAdapter diff --git a/libjava/classpath/java/awt/event/KeyEvent.java b/libjava/classpath/java/awt/event/KeyEvent.java new file mode 100644 index 0000000..a40a8e1 --- /dev/null +++ b/libjava/classpath/java/awt/event/KeyEvent.java @@ -0,0 +1,1740 @@ +/* KeyEvent.java -- event for key presses + Copyright (C) 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 java.awt.event; + +import gnu.java.awt.EventModifier; + +import java.awt.Component; +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * This event is generated when a key is pressed or released. There are two + * categories of key events: + * + *

"Key typed" events are higher-level, and have already + * compensated for modifiers and keyboard layout to generate a single Unicode + * character. It may take several key press events to generate one key typed. + * The getKeyCode method will return VK_UNDEFINED, + * and getKeyChar will return a valid Unicode character or + * CHAR_UNDEFINED. + * + *

"Key pressed" and "key released" events are lower-level, and + * are platform and keyboard dependent. They correspond to the actaul motion + * on a keyboard, and return a virtual key code which labels the key that was + * pressed. The getKeyCode method will return one of the + * VK_* constants (except VK_UNDEFINED), and the + * getKeyChar method is undefined. + * + *

Some keys do not generate key typed events, such as the F1 or HELP keys. + * Not all keyboards can generate all virtual keys, and no attempt is made to + * simulate the ones that can't be typed. Virtual keys correspond to the + * keyboard layout, so for example, VK_Q in English is VK_A in French. Also, + * there are some additional virtual keys to ease handling of actions, such + * as VK_ALL_CANDIDATES in place of ALT+VK_CONVERT. Do not rely on the value + * of the VK_* constants, except for VK_ENTER, VK_BACK_SPACE, and VK_TAB. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see KeyAdapter + * @see KeyListener + * @since 1.1 + * @status updated to 1.4 + */ +public class KeyEvent extends InputEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -2352130953028126954L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int KEY_FIRST = 400; + + /** This is the last id in the range of event ids used by this class. */ + public static final int KEY_LAST = 402; + + /** + * This event id indicates a key was typed, which is a key press followed + * by a key release to generate an actual Unicode character. It may take + * several key presses to generate one key typed event, and some action + * keys have no corresponding key typed. + */ + public static final int KEY_TYPED = 400; + + /** This event id indicates a key was pressed. */ + public static final int KEY_PRESSED = 401; + + /** This event it indicates a key was released. */ + public static final int KEY_RELEASED = 402; + + /** The virtual key Enter, which will always map to '\n'. */ + public static final int VK_ENTER = '\n'; + + /** The virtual key Backspace, which will always map to '\b'. */ + public static final int VK_BACK_SPACE = '\b'; + + /** The virtual key Tab, which will always map to '\t'. */ + public static final int VK_TAB = '\t'; + + /** The virtual key Cancel. */ + public static final int VK_CANCEL = 3; + + /** The virtual key VK_CLEAR. */ + public static final int VK_CLEAR = 12; + + /** The virtual key VK_SHIFT. */ + public static final int VK_SHIFT = 16; + + /** The virtual key VK_CONTROL. */ + public static final int VK_CONTROL = 17; + + /** The virtual key VK_ALT. */ + public static final int VK_ALT = 18; + + /** The virtual key VK_PAUSE. */ + public static final int VK_PAUSE = 19; + + /** The virtual key VK_CAPS_LOCK. */ + public static final int VK_CAPS_LOCK = 20; + + /** The virtual key VK_ESCAPE. */ + public static final int VK_ESCAPE = 27; + + /** The virtual key VK_SPACE. */ + public static final int VK_SPACE = ' '; + + /** The virtual key VK_PAGE_UP. */ + public static final int VK_PAGE_UP = 33; + + /** The virtual key VK_PAGE_DOWN. */ + public static final int VK_PAGE_DOWN = 34; + + /** The virtual key VK_END. */ + public static final int VK_END = 35; + + /** The virtual key VK_HOME. */ + public static final int VK_HOME = 36; + + /** + * The virtual key for the non-numpad VK_LEFT. + * + * @see #VK_KP_LEFT + */ + public static final int VK_LEFT = 37; + + /** + * The virtual key for the non-numpad VK_UP. + * + * @see #VK_KP_UP + */ + public static final int VK_UP = 38; + + /** + * The virtual key for the non-numpad VK_RIGHT. + * + * @see #VK_KP_RIGHT + */ + public static final int VK_RIGHT = 39; + + /** + * The virtual key for the non-numpad VK_DOWN. + * + * @see #VK_KP_DOWN + */ + public static final int VK_DOWN = 40; + + /** The virtual key VK_COMMA. */ + public static final int VK_COMMA = ','; + + /** + * The virtual key VK_MINUS. + * + * @since 1.2 + */ + public static final int VK_MINUS = '-'; + + /** The virtual key VK_PERIOD. */ + public static final int VK_PERIOD = '.'; + + /** The virtual key VK_SLASH. */ + public static final int VK_SLASH = '/'; + + /** The virtual key VK_0. */ + public static final int VK_0 = '0'; + + /** The virtual key VK_1. */ + public static final int VK_1 = '1'; + + /** The virtual key VK_2. */ + public static final int VK_2 = '2'; + + /** The virtual key VK_3. */ + public static final int VK_3 = '3'; + + /** The virtual key VK_4. */ + public static final int VK_4 = '4'; + + /** The virtual key VK_5. */ + public static final int VK_5 = '5'; + + /** The virtual key VK_6. */ + public static final int VK_6 = '6'; + + /** The virtual key VK_7. */ + public static final int VK_7 = '7'; + + /** The virtual key VK_8. */ + public static final int VK_8 = '8'; + + /** The virtual key VK_9. */ + public static final int VK_9 = '9'; + + /** The virtual key VK_SEMICOLON. */ + public static final int VK_SEMICOLON = ';'; + + /** The virtual key VK_EQUALS. */ + public static final int VK_EQUALS = '='; + + /** The virtual key VK_A. */ + public static final int VK_A = 'A'; + + /** The virtual key VK_B. */ + public static final int VK_B = 'B'; + + /** The virtual key VK_C. */ + public static final int VK_C = 'C'; + + /** The virtual key VK_D. */ + public static final int VK_D = 'D'; + + /** The virtual key VK_E. */ + public static final int VK_E = 'E'; + + /** The virtual key VK_F. */ + public static final int VK_F = 'F'; + + /** The virtual key VK_G. */ + public static final int VK_G = 'G'; + + /** The virtual key VK_H. */ + public static final int VK_H = 'H'; + + /** The virtual key VK_I. */ + public static final int VK_I = 'I'; + + /** The virtual key VK_J. */ + public static final int VK_J = 'J'; + + /** The virtual key VK_K. */ + public static final int VK_K = 'K'; + + /** The virtual key VK_L. */ + public static final int VK_L = 'L'; + + /** The virtual key VK_M. */ + public static final int VK_M = 'M'; + + /** The virtual key VK_N. */ + public static final int VK_N = 'N'; + + /** The virtual key VK_O. */ + public static final int VK_O = 'O'; + + /** The virtual key VK_P. */ + public static final int VK_P = 'P'; + + /** The virtual key VK_Q. */ + public static final int VK_Q = 'Q'; + + /** The virtual key VK_R. */ + public static final int VK_R = 'R'; + + /** The virtual key VK_S. */ + public static final int VK_S = 'S'; + + /** The virtual key VK_T. */ + public static final int VK_T = 'T'; + + /** The virtual key VK_U. */ + public static final int VK_U = 'U'; + + /** The virtual key VK_V. */ + public static final int VK_V = 'V'; + + /** The virtual key VK_W. */ + public static final int VK_W = 'W'; + + /** The virtual key VK_X. */ + public static final int VK_X = 'X'; + + /** The virtual key VK_Y. */ + public static final int VK_Y = 'Y'; + + /** The virtual key VK_Z. */ + public static final int VK_Z = 'Z'; + + /** The virtual key VK_OPEN_BRACKET. */ + public static final int VK_OPEN_BRACKET = '['; + + /** The virtual key VK_BACK_SLASH. */ + public static final int VK_BACK_SLASH = '\\'; + + /** The virtual key VK_CLOSE_BRACKET. */ + public static final int VK_CLOSE_BRACKET = ']'; + + /** The virtual key VK_NUMPAD0. */ + public static final int VK_NUMPAD0 = 96; + + /** The virtual key VK_NUMPAD1. */ + public static final int VK_NUMPAD1 = 97; + + /** The virtual key VK_NUMPAD2. */ + public static final int VK_NUMPAD2 = 98; + + /** The virtual key VK_NUMPAD3. */ + public static final int VK_NUMPAD3 = 99; + + /** The virtual key VK_NUMPAD4. */ + public static final int VK_NUMPAD4 = 100; + + /** The virtual key VK_NUMPAD5. */ + public static final int VK_NUMPAD5 = 101; + + /** The virtual key VK_NUMPAD6. */ + public static final int VK_NUMPAD6 = 102; + + /** The virtual key VK_NUMPAD7. */ + public static final int VK_NUMPAD7 = 103; + + /** The virtual key VK_NUMPAD8. */ + public static final int VK_NUMPAD8 = 104; + + /** The virtual key VK_NUMPAD9. */ + public static final int VK_NUMPAD9 = 105; + + /** The virtual key VK_MULTIPLY. */ + public static final int VK_MULTIPLY = 106; + + /** The virtual key VK_ADD. */ + public static final int VK_ADD = 107; + + /** + * The virtual key VK_SEPARATOR, handily mispelled for those who can't + * figure it out. + * + * @deprecated use {@link #VK_SEPARATOR} + */ + public static final int VK_SEPARATER = 108; + + /** + * The virtual key VK_SEPARATOR. + * + * @since 1.4 + */ + public static final int VK_SEPARATOR = 108; + + /** The virtual key VK_SUBTRACT. */ + public static final int VK_SUBTRACT = 109; + + /** The virtual key VK_DECIMAL. */ + public static final int VK_DECIMAL = 110; + + /** The virtual key VK_DIVIDE. */ + public static final int VK_DIVIDE = 111; + + /** The virtual key VK_DELETE. */ + public static final int VK_DELETE = 127; + + /** The virtual key VK_NUM_LOCK. */ + public static final int VK_NUM_LOCK = 144; + + /** The virtual key VK_SCROLL_LOCK. */ + public static final int VK_SCROLL_LOCK = 145; + + /** The virtual key VK_F1. */ + public static final int VK_F1 = 112; + + /** The virtual key VK_F2. */ + public static final int VK_F2 = 113; + + /** The virtual key VK_F3. */ + public static final int VK_F3 = 114; + + /** The virtual key VK_F4. */ + public static final int VK_F4 = 115; + + /** The virtual key VK_F5. */ + public static final int VK_F5 = 116; + + /** The virtual key VK_F6. */ + public static final int VK_F6 = 117; + + /** The virtual key VK_F7. */ + public static final int VK_F7 = 118; + + /** The virtual key VK_F8. */ + public static final int VK_F8 = 119; + + /** The virtual key VK_F9. */ + public static final int VK_F9 = 120; + + /** The virtual key VK_F10. */ + public static final int VK_F10 = 121; + + /** The virtual key VK_F11. */ + public static final int VK_F11 = 122; + + /** The virtual key VK_F12. */ + public static final int VK_F12 = 123; + + /** + * The virtual key VK_F13. + * + * @since 1.2 + */ + public static final int VK_F13 = 61440; + + /** + * The virtual key VK_F14. + * + * @since 1.2 + */ + public static final int VK_F14 = 61441; + + /** + * The virtual key VK_F15. + * + * @since 1.2 + */ + public static final int VK_F15 = 61442; + + /** + * The virtual key VK_F16. + * + * @since 1.2 + */ + public static final int VK_F16 = 61443; + + /** + * The virtual key VK_F17. + * + * @since 1.2 + */ + public static final int VK_F17 = 61444; + + /** + * The virtual key VK_F18. + * + * @since 1.2 + */ + public static final int VK_F18 = 61445; + + /** + * The virtual key VK_F19. + * + * @since 1.2 + */ + public static final int VK_F19 = 61446; + + /** + * The virtual key VK_F20. + * + * @since 1.2 + */ + public static final int VK_F20 = 61447; + + /** + * The virtual key VK_F21. + * + * @since 1.2 + */ + public static final int VK_F21 = 61448; + + /** + * The virtual key VK_F22. + * + * @since 1.2 + */ + public static final int VK_F22 = 61449; + + /** + * The virtual key VK_F23. + * + * @since 1.2 + */ + public static final int VK_F23 = 61450; + + /** + * The virtual key VK_F24. + * + * @since 1.2 + */ + public static final int VK_F24 = 61451; + + /** The virtual key VK_PRINTSCREEN. */ + public static final int VK_PRINTSCREEN = 154; + + /** The virtual key VK_INSERT. */ + public static final int VK_INSERT = 155; + + /** The virtual key VK_HELP. */ + public static final int VK_HELP = 156; + + /** The virtual key VK_META. */ + public static final int VK_META = 157; + + /** The virtual key VK_BACK_QUOTE. */ + public static final int VK_BACK_QUOTE = 192; + + /** The virtual key VK_QUOTE. */ + public static final int VK_QUOTE = 222; + + /** + * The virtual key for the numpad VK_KP_UP. + * + * @see #VK_UP + * @since 1.2 + */ + public static final int VK_KP_UP = 224; + + /** + * The virtual key for the numpad VK_KP_DOWN. + * + * @see #VK_DOWN + * @since 1.2 + */ + public static final int VK_KP_DOWN = 225; + + /** + * The virtual key for the numpad VK_KP_LEFT. + * + * @see #VK_LEFT + * @since 1.2 + */ + public static final int VK_KP_LEFT = 226; + + /** + * The virtual key for the numpad VK_KP_RIGHT. + * + * @see #VK_RIGHT + * @since 1.2 + */ + public static final int VK_KP_RIGHT = 227; + + /** + * The virtual key VK_DEAD_GRAVE. + * + * @since 1.2 + */ + public static final int VK_DEAD_GRAVE = 128; + + /** + * The virtual key VK_DEAD_ACUTE. + * + * @since 1.2 + */ + public static final int VK_DEAD_ACUTE = 129; + + /** + * The virtual key VK_DEAD_CIRCUMFLEX. + * + * @since 1.2 + */ + public static final int VK_DEAD_CIRCUMFLEX = 130; + + /** + * The virtual key VK_DEAD_TILDE. + * + * @since 1.2 + */ + public static final int VK_DEAD_TILDE = 131; + + /** + * The virtual key VK_DEAD_MACRON. + * + * @since 1.2 + */ + public static final int VK_DEAD_MACRON = 132; + + /** + * The virtual key VK_DEAD_BREVE. + * + * @since 1.2 + */ + public static final int VK_DEAD_BREVE = 133; + + /** + * The virtual key VK_DEAD_ABOVEDOT. + * + * @since 1.2 + */ + public static final int VK_DEAD_ABOVEDOT = 134; + + /** + * The virtual key VK_DEAD_DIAERESIS. + * + * @since 1.2 + */ + public static final int VK_DEAD_DIAERESIS = 135; + + /** + * The virtual key VK_DEAD_ABOVERING. + * + * @since 1.2 + */ + public static final int VK_DEAD_ABOVERING = 136; + + /** + * The virtual key VK_DEAD_DOUBLEACUTE. + * + * @since 1.2 + */ + public static final int VK_DEAD_DOUBLEACUTE = 137; + + /** + * The virtual key VK_DEAD_CARON. + * + * @since 1.2 + */ + public static final int VK_DEAD_CARON = 138; + + /** + * The virtual key VK_DEAD_CEDILLA. + * + * @since 1.2 + */ + public static final int VK_DEAD_CEDILLA = 139; + + /** + * The virtual key VK_DEAD_OGONEK. + * + * @since 1.2 + */ + public static final int VK_DEAD_OGONEK = 140; + + /** + * The virtual key VK_DEAD_IOTA. + * + * @since 1.2 + */ + public static final int VK_DEAD_IOTA = 141; + + /** + * The virtual key VK_DEAD_VOICED_SOUND. + * + * @since 1.2 + */ + public static final int VK_DEAD_VOICED_SOUND = 142; + + /** + * The virtual key VK_DEAD_SEMIVOICED_SOUND. + * + * @since 1.2 + */ + public static final int VK_DEAD_SEMIVOICED_SOUND = 143; + + /** + * The virtual key VK_AMPERSAND. + * + * @since 1.2 + */ + public static final int VK_AMPERSAND = 150; + + /** + * The virtual key VK_ASTERISK. + * + * @since 1.2 + */ + public static final int VK_ASTERISK = 151; + + /** + * The virtual key VK_QUOTEDBL. + * + * @since 1.2 + */ + public static final int VK_QUOTEDBL = 152; + + /** + * The virtual key VK_LESS. + * + * @since 1.2 + */ + public static final int VK_LESS = 153; + + /** + * The virtual key VK_GREATER. + * + * @since 1.2 + */ + public static final int VK_GREATER = 160; + + /** + * The virtual key VK_BRACELEFT. + * + * @since 1.2 + */ + public static final int VK_BRACELEFT = 161; + + /** + * The virtual key VK_BRACERIGHT. + * + * @since 1.2 + */ + public static final int VK_BRACERIGHT = 162; + + /** + * The virtual key VK_AT. + * + * @since 1.2 + */ + public static final int VK_AT = 512; + + /** + * The virtual key VK_COLON. + * + * @since 1.2 + */ + public static final int VK_COLON = 513; + + /** + * The virtual key VK_CIRCUMFLEX. + * + * @since 1.2 + */ + public static final int VK_CIRCUMFLEX = 514; + + /** + * The virtual key VK_DOLLAR. + * + * @since 1.2 + */ + public static final int VK_DOLLAR = 515; + + /** + * The virtual key VK_EURO_SIGN. + * + * @since 1.2 + */ + public static final int VK_EURO_SIGN = 516; + + /** + * The virtual key VK_EXCLAMATION_MARK. + * + * @since 1.2 + */ + public static final int VK_EXCLAMATION_MARK = 517; + + /** + * The virtual key VK_INVERTED_EXCLAMATION_MARK. + * + * @since 1.2 + */ + public static final int VK_INVERTED_EXCLAMATION_MARK = 518; + + /** + * The virtual key VK_LEFT_PARENTHESIS. + * + * @since 1.2 + */ + public static final int VK_LEFT_PARENTHESIS = 519; + + /** + * The virtual key VK_NUMBER_SIGN. + * + * @since 1.2 + */ + public static final int VK_NUMBER_SIGN = 520; + + /** + * The virtual key VK_PLUS. + * + * @since 1.2 + */ + public static final int VK_PLUS = 521; + + /** + * The virtual key VK_RIGHT_PARENTHESIS. + * + * @since 1.2 + */ + public static final int VK_RIGHT_PARENTHESIS = 522; + + /** + * The virtual key VK_UNDERSCORE. + * + * @since 1.2 + */ + public static final int VK_UNDERSCORE = 523; + + /** The virtual key VK_FINAL. */ + public static final int VK_FINAL = 24; + + /** The virtual key VK_CONVERT. */ + public static final int VK_CONVERT = 28; + + /** The virtual key VK_NONCONVERT. */ + public static final int VK_NONCONVERT = 29; + + /** The virtual key VK_ACCEPT. */ + public static final int VK_ACCEPT = 30; + + /** The virtual key VK_MODECHANGE. */ + public static final int VK_MODECHANGE = 31; + + /** The virtual key VK_KANA. */ + public static final int VK_KANA = 21; + + /** The virtual key VK_KANJI. */ + public static final int VK_KANJI = 25; + + /** + * The virtual key VK_ALPHANUMERIC. + * + * @since 1.2 + */ + public static final int VK_ALPHANUMERIC = 240; + + /** + * The virtual key VK_KATAKANA. + * + * @since 1.2 + */ + public static final int VK_KATAKANA = 241; + + /** + * The virtual key VK_HIRAGANA. + * + * @since 1.2 + */ + public static final int VK_HIRAGANA = 242; + + /** + * The virtual key VK_FULL_WIDTH. + * + * @since 1.2 + */ + public static final int VK_FULL_WIDTH = 243; + + /** + * The virtual key VK_HALF_WIDTH. + * + * @since 1.2 + */ + public static final int VK_HALF_WIDTH = 244; + + /** + * The virtual key VK_ROMAN_CHARACTERS. + * + * @since 1.2 + */ + public static final int VK_ROMAN_CHARACTERS = 245; + + /** + * The virtual key VK_ALL_CANDIDATES. + * + * @since 1.2 + */ + public static final int VK_ALL_CANDIDATES = 256; + + /** + * The virtual key VK_PREVIOUS_CANDIDATE. + * + * @since 1.2 + */ + public static final int VK_PREVIOUS_CANDIDATE = 257; + + /** + * The virtual key VK_CODE_INPUT. + * + * @since 1.2 + */ + public static final int VK_CODE_INPUT = 258; + + /** + * The virtual key VK_JAPANESE_KATAKANA. + * + * @since 1.2 + */ + public static final int VK_JAPANESE_KATAKANA = 259; + + /** + * The virtual key VK_JAPANESE_HIRAGANA. + * + * @since 1.2 + */ + public static final int VK_JAPANESE_HIRAGANA = 260; + + /** + * The virtual key VK_JAPANESE_ROMAN. + * + * @since 1.2 + */ + public static final int VK_JAPANESE_ROMAN = 261; + + /** + * The virtual key VK_KANA_LOCK. + * + * @since 1.3 + */ + public static final int VK_KANA_LOCK = 262; + + /** + * The virtual key VK_INPUT_METHOD_ON_OFF. + * + * @since 1.3 + */ + public static final int VK_INPUT_METHOD_ON_OFF = 263; + + /** + * The virtual key VK_CUT. + * + * @since 1.2 + */ + public static final int VK_CUT = 65489; + + /** + * The virtual key VK_COPY. + * + * @since 1.2 + */ + public static final int VK_COPY = 65485; + + /** + * The virtual key VK_PASTE. + * + * @since 1.2 + */ + public static final int VK_PASTE = 65487; + + /** + * The virtual key VK_UNDO. + * + * @since 1.2 + */ + public static final int VK_UNDO = 65483; + + /** + * The virtual key VK_AGAIN. + * + * @since 1.2 + */ + public static final int VK_AGAIN = 65481; + + /** + * The virtual key VK_FIND. + * + * @since 1.2 + */ + public static final int VK_FIND = 65488; + + /** + * The virtual key VK_PROPS. + * + * @since 1.2 + */ + public static final int VK_PROPS = 65482; + + /** + * The virtual key VK_STOP. + * + * @since 1.2 + */ + public static final int VK_STOP = 65480; + + /** + * The virtual key VK_COMPOSE. + * + * @since 1.2 + */ + public static final int VK_COMPOSE = 65312; + + /** + * The virtual key VK_ALT_GRAPH. + * + * @since 1.2 + */ + public static final int VK_ALT_GRAPH = 65406; + + /** + * The virtual key VK_UNDEFINED. This is used for key typed events, which + * do not have a virtual key. + */ + public static final int VK_UNDEFINED = 0; + + /** + * The only char with no valid Unicode interpretation. This is used for + * key pressed and key released events which do not have a valid keyChar. + */ + public static final char CHAR_UNDEFINED = '\uffff'; + + /** + * Indicates unknown or irrelavent key location. This is also used for + * key typed events, which do not need a location. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_UNKNOWN = 0; + + /** + * Indicates a standard key location, with no left/right variants and not + * on the numeric pad. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_STANDARD = 1; + + /** + * Indicates the key is on the left side of the keyboard, such as the left + * shift. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_LEFT = 2; + + /** + * Indicates the key is on the right side of the keyboard, such as the right + * shift. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_RIGHT = 3; + + /** + * Indicates the key is on the numeric pad, such as the numpad 0. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_NUMPAD = 4; + + /** + * The code assigned to the physical keyboard location (as adjusted by the + * keyboard layout). Use the symbolic VK_* names instead of numbers. + * + * @see #getKeyCode() + * @serial the VK_ code for this key + */ + private int keyCode; + + /** + * The Unicode character produced by the key type event. This has no meaning + * for key pressed and key released events. + * + * @see #getKeyChar() + * @serial the Unicode value for this key + */ + private char keyChar; + + /** + * The keyboard location of the key. One of {@link #KEY_LOCATION_UNKNOWN}, + * {@link #KEY_LOCATION_STANDARD}, {@link #KEY_LOCATION_LEFT}, + * {@link #KEY_LOCATION_RIGHT}, or {@link #KEY_LOCATION_NUMPAD}. + * + * @see #getKeyLocation() + * @serial the key location + * @since 1.4 + */ + private final int keyLocation; + + /** + * Stores the state of the native event dispatching system, to correctly + * dispatch in Component#dispatchEventImpl when a proxy is active. + * + * XXX Does this matter in Classpath? + * + * @serial whether the proxy is active + */ + private boolean isProxyActive; + + + /** + * Initializes a new instance of KeyEvent with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the component that generated this event + * @param id the event id + * @param when the timestamp when the even occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param keyCode the integer constant for the virtual key type + * @param keyChar the Unicode value of the key + * @param keyLocation the location of the key + * @throws IllegalArgumentException if source is null, if keyLocation is + * invalid, or if (id == KEY_TYPED && (keyCode != VK_UNDEFINED + * || keyChar == CHAR_UNDEFINED)) + */ + public KeyEvent(Component source, int id, long when, int modifiers, + int keyCode, char keyChar, int keyLocation) + { + super(source, id, when, modifiers); + this.keyCode = keyCode; + this.keyChar = keyChar; + this.keyLocation = keyLocation; + if ((id == KEY_TYPED && (keyCode != VK_UNDEFINED + || keyChar == CHAR_UNDEFINED)) + || keyLocation < KEY_LOCATION_UNKNOWN + || keyLocation > KEY_LOCATION_NUMPAD) + throw new IllegalArgumentException(); + } + + /** + * Initializes a new instance of KeyEvent with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the component that generated this event + * @param id the event id + * @param when the timestamp when the even occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param keyCode the integer constant for the virtual key type + * @param keyChar the Unicode value of the key + * @throws IllegalArgumentException if source is null, or if + * (id == KEY_TYPED && (keyCode != VK_UNDEFINED + * || keyChar == CHAR_UNDEFINED)) + */ + public KeyEvent(Component source, int id, long when, int modifiers, + int keyCode, char keyChar) + { + this(source, id, when, modifiers, keyCode, keyChar, KEY_LOCATION_UNKNOWN); + } + + /** + * Initializes a new instance of KeyEvent with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the component that generated this event + * @param id the event id + * @param when the timestamp when the even occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param keyCode the integer constant for the virtual key type + * @throws IllegalArgumentException if source is null, or if + * id == KEY_TYPED but keyCode != VK_UNDEFINED + * + * @deprecated + */ + public KeyEvent(Component source, int id, long when, int modifiers, + int keyCode) + { + this(source, id, when, modifiers, keyCode, '\0', KEY_LOCATION_UNKNOWN); + } + + /** + * Returns the key code for the event key. This will be one of the + * VK_* constants defined in this class. If the event type is + * KEY_TYPED, the result will be VK_UNDEFINED. + * + * @return the key code for this event + */ + public int getKeyCode() + { + return keyCode; + } + + /** + * Sets the key code for this event. This must be one of the + * VK_* constants defined in this class. + * + * @param keyCode the new key code for this event + */ + public void setKeyCode(int keyCode) + { + this.keyCode = keyCode; + } + + /** + * Returns the Unicode value for the event key. This will be + * CHAR_UNDEFINED if there is no Unicode equivalent for + * this key, usually when this is a KEY_PRESSED or KEY_RELEASED event. + * + * @return the Unicode character for this event + */ + public char getKeyChar() + { + return keyChar; + } + + /** + * Sets the Unicode character for this event to the specified value. + * + * @param keyChar the new Unicode character for this event + */ + public void setKeyChar(char keyChar) + { + this.keyChar = keyChar; + } + + /** + * Sets the modifier keys to the specified value. This should be a union + * of the bit mask constants from InputEvent. The use of this + * method is not recommended, particularly for KEY_TYPED events, which do + * not check if the modifiers were changed. + * + * @param modifiers the new modifier value, in either old or new style + * @see InputEvent + * + * @deprecated + */ + public void setModifiers(int modifiers) + { + this.modifiers = EventModifier.extend(modifiers); + } + + /** + * Returns the keyboard location of the key that generated this event. This + * provides a way to distinguish between keys like left and right shift + * which share a common key code. The result will be one of + * {@link #KEY_LOCATION_UNKNOWN}, {@link #KEY_LOCATION_STANDARD}, + * {@link #KEY_LOCATION_LEFT}, {@link #KEY_LOCATION_RIGHT}, or + * {@link #KEY_LOCATION_NUMPAD}. + * + * @return the key location + * @since 1.4 + */ + public int getKeyLocation() + { + return keyLocation; + } + + /** + * Returns the text name of key code, such as "HOME", "F1", or "A". + * + * XXX Sun claims this can be localized via the awt.properties file - how + * do we implement that? + * + * @return the text name of the key code + */ + public static String getKeyText(int keyCode) + { + switch (keyCode) + { + case VK_CANCEL: + return "Cancel"; + case VK_BACK_SPACE: + return "Backspace"; + case VK_TAB: + return "Tab"; + case VK_ENTER: + return "Enter"; + case VK_CLEAR: + return "Clear"; + case VK_SHIFT: + return "Shift"; + case VK_CONTROL: + return "Ctrl"; + case VK_ALT: + return "Alt"; + case VK_PAUSE: + return "Pause"; + case VK_CAPS_LOCK: + return "Caps Lock"; + case VK_KANA: + return "Kana"; + case VK_FINAL: + return "Final"; + case VK_KANJI: + return "Kanji"; + case VK_ESCAPE: + return "Escape"; + case VK_CONVERT: + return "Convert"; + case VK_NONCONVERT: + return "No Convert"; + case VK_ACCEPT: + return "Accept"; + case VK_MODECHANGE: + return "Mode Change"; + case VK_SPACE: + return "Space"; + case VK_PAGE_UP: + return "Page Up"; + case VK_PAGE_DOWN: + return "Page Down"; + case VK_END: + return "End"; + case VK_HOME: + return "Home"; + case VK_LEFT: + case VK_KP_LEFT: + return "Left"; + case VK_UP: + case VK_KP_UP: + return "Up"; + case VK_RIGHT: + case VK_KP_RIGHT: + return "Right"; + case VK_DOWN: + case VK_KP_DOWN: + return "Down"; + case VK_MINUS: + return "Minus"; + case VK_MULTIPLY: + return "NumPad *"; + case VK_ADD: + return "NumPad +"; + case VK_SEPARATOR: + return "NumPad ,"; + case VK_SUBTRACT: + return "NumPad -"; + case VK_DECIMAL: + return "NumPad ."; + case VK_DIVIDE: + return "NumPad /"; + case VK_DELETE: + return "Delete"; + case VK_DEAD_GRAVE: + return "Dead Grave"; + case VK_DEAD_ACUTE: + return "Dead Acute"; + case VK_DEAD_CIRCUMFLEX: + return "Dead Circumflex"; + case VK_DEAD_TILDE: + return "Dead Tilde"; + case VK_DEAD_MACRON: + return "Dead Macron"; + case VK_DEAD_BREVE: + return "Dead Breve"; + case VK_DEAD_ABOVEDOT: + return "Dead Above Dot"; + case VK_DEAD_DIAERESIS: + return "Dead Diaeresis"; + case VK_DEAD_ABOVERING: + return "Dead Above Ring"; + case VK_DEAD_DOUBLEACUTE: + return "Dead Double Acute"; + case VK_DEAD_CARON: + return "Dead Caron"; + case VK_DEAD_CEDILLA: + return "Dead Cedilla"; + case VK_DEAD_OGONEK: + return "Dead Ogonek"; + case VK_DEAD_IOTA: + return "Dead Iota"; + case VK_DEAD_VOICED_SOUND: + return "Dead Voiced Sound"; + case VK_DEAD_SEMIVOICED_SOUND: + return "Dead Semivoiced Sound"; + case VK_NUM_LOCK: + return "Num Lock"; + case VK_SCROLL_LOCK: + return "Scroll Lock"; + case VK_AMPERSAND: + return "Ampersand"; + case VK_ASTERISK: + return "Asterisk"; + case VK_QUOTEDBL: + return "Double Quote"; + case VK_LESS: + return "Less"; + case VK_PRINTSCREEN: + return "Print Screen"; + case VK_INSERT: + return "Insert"; + case VK_HELP: + return "Help"; + case VK_META: + return "Meta"; + case VK_GREATER: + return "Greater"; + case VK_BRACELEFT: + return "Left Brace"; + case VK_BRACERIGHT: + return "Right Brace"; + case VK_BACK_QUOTE: + return "Back Quote"; + case VK_QUOTE: + return "Quote"; + case VK_ALPHANUMERIC: + return "Alphanumeric"; + case VK_KATAKANA: + return "Katakana"; + case VK_HIRAGANA: + return "Hiragana"; + case VK_FULL_WIDTH: + return "Full-Width"; + case VK_HALF_WIDTH: + return "Half-Width"; + case VK_ROMAN_CHARACTERS: + return "Roman Characters"; + case VK_ALL_CANDIDATES: + return "All Candidates"; + case VK_PREVIOUS_CANDIDATE: + return "Previous Candidate"; + case VK_CODE_INPUT: + return "Code Input"; + case VK_JAPANESE_KATAKANA: + return "Japanese Katakana"; + case VK_JAPANESE_HIRAGANA: + return "Japanese Hiragana"; + case VK_JAPANESE_ROMAN: + return "Japanese Roman"; + case VK_KANA_LOCK: + return "Kana Lock"; + case VK_INPUT_METHOD_ON_OFF: + return "Input Method On/Off"; + case VK_AT: + return "At"; + case VK_COLON: + return "Colon"; + case VK_CIRCUMFLEX: + return "Circumflex"; + case VK_DOLLAR: + return "Dollar"; + case VK_EURO_SIGN: + return "Euro"; + case VK_EXCLAMATION_MARK: + return "Exclamation Mark"; + case VK_INVERTED_EXCLAMATION_MARK: + return "Inverted Exclamation Mark"; + case VK_LEFT_PARENTHESIS: + return "Left Parenthesis"; + case VK_NUMBER_SIGN: + return "Number Sign"; + case VK_PLUS: + return "Plus"; + case VK_RIGHT_PARENTHESIS: + return "Right Parenthesis"; + case VK_UNDERSCORE: + return "Underscore"; + case VK_COMPOSE: + return "Compose"; + case VK_ALT_GRAPH: + return "Alt Graph"; + case VK_STOP: + return "Stop"; + case VK_AGAIN: + return "Again"; + case VK_PROPS: + return "Props"; + case VK_UNDO: + return "Undo"; + case VK_COPY: + return "Copy"; + case VK_PASTE: + return "Paste"; + case VK_FIND: + return "Find"; + case VK_CUT: + return "Cut"; + case VK_COMMA: + case VK_PERIOD: + case VK_SLASH: + case VK_0: + case VK_1: + case VK_2: + case VK_3: + case VK_4: + case VK_5: + case VK_6: + case VK_7: + case VK_8: + case VK_9: + case VK_SEMICOLON: + case VK_EQUALS: + case VK_A: + case VK_B: + case VK_C: + case VK_D: + case VK_E: + case VK_F: + case VK_G: + case VK_H: + case VK_I: + case VK_J: + case VK_K: + case VK_L: + case VK_M: + case VK_N: + case VK_O: + case VK_P: + case VK_Q: + case VK_R: + case VK_S: + case VK_T: + case VK_U: + case VK_V: + case VK_W: + case VK_X: + case VK_Y: + case VK_Z: + case VK_OPEN_BRACKET: + case VK_BACK_SLASH: + case VK_CLOSE_BRACKET: + return "" + (char) keyCode; + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + return "NumPad-" + (keyCode - VK_NUMPAD0); + case VK_F1: + case VK_F2: + case VK_F3: + case VK_F4: + case VK_F5: + case VK_F6: + case VK_F7: + case VK_F8: + case VK_F9: + case VK_F10: + case VK_F11: + case VK_F12: + return "F" + (keyCode - (VK_F1 - 1)); + case VK_F13: + case VK_F14: + case VK_F15: + case VK_F16: + case VK_F17: + case VK_F18: + case VK_F19: + case VK_F20: + case VK_F21: + case VK_F22: + case VK_F23: + case VK_F24: + return "F" + (keyCode - (VK_F13 - 13)); + default: + // This is funky on negative numbers, but that's Sun's fault. + return "Unknown keyCode: 0x" + (keyCode < 0 ? "-" : "") + + Integer.toHexString(Math.abs(keyCode)); + } + } + + /** + * Returns a string describing the modifiers, such as "Shift" or + * "Ctrl+Button1". + * + * XXX Sun claims this can be localized via the awt.properties file - how + * do we implement that? + * + * @param modifiers the old-style modifiers to convert to text + * @return a string representation of the modifiers in this bitmask + */ + public static String getKeyModifiersText(int modifiers) + { + return getModifiersExText(EventModifier.extend(modifiers + & EventModifier.OLD_MASK)); + } + + /** + * Tests whether or not this key is an action key. An action key typically + * does not fire a KEY_TYPED event, and is not a modifier. + * + * @return true if this is an action key + */ + public boolean isActionKey() + { + switch (keyCode) + { + case VK_PAUSE: + case VK_CAPS_LOCK: + case VK_KANA: + case VK_FINAL: + case VK_KANJI: + case VK_CONVERT: + case VK_NONCONVERT: + case VK_ACCEPT: + case VK_MODECHANGE: + case VK_PAGE_UP: + case VK_PAGE_DOWN: + case VK_END: + case VK_HOME: + case VK_LEFT: + case VK_UP: + case VK_RIGHT: + case VK_DOWN: + case VK_F1: + case VK_F2: + case VK_F3: + case VK_F4: + case VK_F5: + case VK_F6: + case VK_F7: + case VK_F8: + case VK_F9: + case VK_F10: + case VK_F11: + case VK_F12: + case VK_NUM_LOCK: + case VK_SCROLL_LOCK: + case VK_PRINTSCREEN: + case VK_INSERT: + case VK_HELP: + case VK_KP_UP: + case VK_KP_DOWN: + case VK_KP_LEFT: + case VK_KP_RIGHT: + case VK_ALPHANUMERIC: + case VK_KATAKANA: + case VK_HIRAGANA: + case VK_FULL_WIDTH: + case VK_HALF_WIDTH: + case VK_ROMAN_CHARACTERS: + case VK_ALL_CANDIDATES: + case VK_PREVIOUS_CANDIDATE: + case VK_CODE_INPUT: + case VK_JAPANESE_KATAKANA: + case VK_JAPANESE_HIRAGANA: + case VK_JAPANESE_ROMAN: + case VK_KANA_LOCK: + case VK_INPUT_METHOD_ON_OFF: + case VK_F13: + case VK_F14: + case VK_F15: + case VK_F16: + case VK_F17: + case VK_F18: + case VK_F19: + case VK_F20: + case VK_F21: + case VK_F22: + case VK_F23: + case VK_F24: + case VK_STOP: + case VK_AGAIN: + case VK_PROPS: + case VK_UNDO: + case VK_COPY: + case VK_PASTE: + case VK_FIND: + case VK_CUT: + return true; + default: + return false; + } + } + + /** + * Returns a string identifying the event. This is formatted as the + * field name of the id type, followed by the keyCode, then the + * keyChar, modifiers (if any), extModifiers (if any), and + * keyLocation. + * + * @return a string identifying the event + */ + public String paramString() + { + StringBuffer s = new StringBuffer(); + + switch (id) + { + case KEY_PRESSED: + s.append("KEY_PRESSED"); + break; + case KEY_RELEASED: + s.append("KEY_RELEASED"); + break; + case KEY_TYPED: + s.append("KEY_TYPED"); + break; + default: + s.append("unknown type"); + } + + s.append(",keyCode=").append(keyCode); + + s.append(",keyText=").append(getKeyText(keyCode)); + + s.append(",keyChar="); + if (isActionKey() + || keyCode == VK_SHIFT + || keyCode == VK_CONTROL + || keyCode == VK_ALT) + s.append("Undefined keyChar"); + else + { + /* This output string must be selected by examining keyChar + * rather than keyCode, because key code information is not + * included in KEY_TYPED events. + */ + if (keyChar == VK_BACK_SPACE + || keyChar == VK_TAB + || keyChar == VK_ENTER + || keyChar == VK_ESCAPE + || keyChar == VK_DELETE) + s.append(getKeyText(keyChar)); + else + s.append("'").append(keyChar).append("'"); + } + + if ((modifiers & CONVERT_MASK) != 0) + s.append(",modifiers=").append(getModifiersExText(modifiers + & CONVERT_MASK)); + if (modifiers != 0) + s.append(",extModifiers=").append(getModifiersExText(modifiers)); + + s.append(",keyLocation=KEY_LOCATION_"); + switch (keyLocation) + { + case KEY_LOCATION_UNKNOWN: + s.append("UNKNOWN"); + break; + case KEY_LOCATION_STANDARD: + s.append("STANDARD"); + break; + case KEY_LOCATION_LEFT: + s.append("LEFT"); + break; + case KEY_LOCATION_RIGHT: + s.append("RIGHT"); + break; + case KEY_LOCATION_NUMPAD: + s.append("NUMPAD"); + } + + return s.toString(); + } + + /** + * Reads in the object from a serial stream. + * + * @param s the stream to read from + * @throws IOException if deserialization fails + * @throws ClassNotFoundException if deserialization fails + * @serialData default, except that the modifiers are converted to new style + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + modifiers = EventModifier.extend(modifiers); + } +} // class KeyEvent diff --git a/libjava/classpath/java/awt/event/KeyListener.java b/libjava/classpath/java/awt/event/KeyListener.java new file mode 100644 index 0000000..5c0a640 --- /dev/null +++ b/libjava/classpath/java/awt/event/KeyListener.java @@ -0,0 +1,77 @@ +/* KeyListener.java -- listen for keyboard presses + Copyright (C) 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive keyboard events. To + * watch a subset of these events, use a KeyAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see KeyAdapter + * @see KeyEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface KeyListener extends EventListener +{ + /** + * This method is called when a key is typed. A key is considered typed + * when it and all modifiers have been pressed and released, mapping to + * a single virtual key. + * + * @param event the KeyEvent indicating that a key was typed + */ + void keyTyped(KeyEvent event); + + /** + * This method is called when a key is pressed. + * + * @param event the KeyEvent indicating the key press + */ + void keyPressed(KeyEvent event); + + /** + * This method is called when a key is released. + * + * @param event the KeyEvent indicating the key release + */ + void keyReleased(KeyEvent event); +} // interface KeyListener diff --git a/libjava/classpath/java/awt/event/MouseAdapter.java b/libjava/classpath/java/awt/event/MouseAdapter.java new file mode 100644 index 0000000..9f40c28 --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseAdapter.java @@ -0,0 +1,106 @@ +/* MouseAdapter.java -- convenience class for writing mouse listeners + Copyright (C) 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 java.awt.event; + +/** + * This class implements MouseListener and implements all methods + * with empty bodies. This allows a listener interested in implementing only + * a subset of the MouseListener interface to extend this class + * and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see MouseEvent + * @see MouseListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class MouseAdapter implements MouseListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public MouseAdapter() + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mouseClicked(MouseEvent event) + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mousePressed(MouseEvent event) + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mouseReleased(MouseEvent event) + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mouseEntered(MouseEvent event) + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mouseExited(MouseEvent event) + { + } +} // class MouseAdapter diff --git a/libjava/classpath/java/awt/event/MouseEvent.java b/libjava/classpath/java/awt/event/MouseEvent.java new file mode 100644 index 0000000..249c3d1 --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseEvent.java @@ -0,0 +1,432 @@ +/* MouseEvent.java -- a mouse event + Copyright (C) 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 java.awt.event; + +import gnu.java.awt.EventModifier; + +import java.awt.Component; +import java.awt.Point; +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * This event is generated for a mouse event. There are three main categories + * of mouse events: Regular events include pressing, releasing, and clicking + * buttons, as well as moving over the boundary of the unobscured portion of + * a component. Motion events include movement and dragging. Wheel events are + * covered separately by the subclass MouseWheelEvent. + * + *

A mouse event is tied to the unobstructed visible component that the + * mouse cursor was over at the time of the action. The button that was + * most recently pressed is the only one that shows up in + * getModifiers, and is returned by getButton, + * while all buttons that are down show up in getModifiersEx. + * + *

Drag events may be cut short if native drag-and-drop operations steal + * the event. Likewise, if a mouse drag exceeds the bounds of a window or + * virtual device, some platforms may clip the path to fit in the bounds of + * the component. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see MouseAdapter + * @see MouseListener + * @see MouseMotionAdapter + * @see MouseMotionListener + * @see MouseWheelListener + * @since 1.1 + * @status updated to 1.4 + */ +public class MouseEvent extends InputEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -991214153494842848L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int MOUSE_FIRST = 500; + + /** This is the last id in the range of event ids used by this class. */ + public static final int MOUSE_LAST = 507; + + /** This event id indicates that the mouse was clicked. */ + public static final int MOUSE_CLICKED = 500; + + /** This event id indicates that the mouse was pressed. */ + public static final int MOUSE_PRESSED = 501; + + /** This event id indicates that the mouse was released. */ + public static final int MOUSE_RELEASED = 502; + + /** This event id indicates that the mouse was moved. */ + public static final int MOUSE_MOVED = 503; + + /** This event id indicates that the mouse entered a component. */ + public static final int MOUSE_ENTERED = 504; + + /** This event id indicates that the mouse exited a component. */ + public static final int MOUSE_EXITED = 505; + + /** + * This indicates that no button changed state. + * + * @see #getButton() + * @since 1.4 + */ + public static final int NOBUTTON = 0; + + /** + * This indicates that button 1 changed state. + * + * @see #getButton() + * @since 1.4 + */ + public static final int BUTTON1 = 1; + + /** + * This indicates that button 2 changed state. + * + * @see #getButton() + * @since 1.4 + */ + public static final int BUTTON2 = 2; + + /** + * This indicates that button 3 changed state. + * + * @see #getButton() + * @since 1.4 + */ + public static final int BUTTON3 = 3; + + /** This event id indicates that the mouse was dragged over a component. */ + public static final int MOUSE_DRAGGED = 506; + + /** + * This event id indicates that the mouse wheel was rotated. + * + * @since 1.4 + */ + public static final int MOUSE_WHEEL = 507; + + /** + * The X coordinate of the mouse cursor at the time of the event. + * + * @see #getX() + * @serial the x coordinate + */ + private int x; + + /** + * The Y coordinate of the mouse cursor at the time of the event. + * + * @see #getY() + * @serial the y coordinate + */ + private int y; + + /** + * The number of clicks that took place. For MOUSE_CLICKED, MOUSE_PRESSED, + * and MOUSE_RELEASED, this will be at least 1; otherwise it is 0. + * + * see #getClickCount() + * @serial the number of clicks + */ + private final int clickCount; + + /** + * Indicates which mouse button changed state. Can only be one of + * {@link #NOBUTTON}, {@link #BUTTON1}, {@link #BUTTON2}, or + * {@link #BUTTON3}. + * + * @see #getButton() + * @since 1.4 + */ + private int button; + + /** + * Whether or not this event should trigger a popup menu. + * + * @see PopupMenu + * @see #isPopupTrigger() + * @serial true if this is a popup trigger + */ + private final boolean popupTrigger; + + /** + * Initializes a new instance of MouseEvent with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param when the timestamp of when the event occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param x the X coordinate of the mouse point + * @param y the Y coordinate of the mouse point + * @param clickCount the number of mouse clicks for this event + * @param popupTrigger true if this event triggers a popup menu + * @param button the most recent mouse button to change state + * @throws IllegalArgumentException if source is null or button is invalid + * @since 1.4 + */ + public MouseEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger, + int button) + { + super(source, id, when, modifiers); + this.x = x; + this.y = y; + this.clickCount = clickCount; + this.popupTrigger = popupTrigger; + this.button = button; + if (button < NOBUTTON || button > BUTTON3) + throw new IllegalArgumentException(); + if ((modifiers & EventModifier.OLD_MASK) != 0) + { + if ((modifiers & BUTTON1_MASK) != 0) + this.button = BUTTON1; + else if ((modifiers & BUTTON2_MASK) != 0) + this.button = BUTTON2; + else if ((modifiers & BUTTON3_MASK) != 0) + this.button = BUTTON3; + } + } + + /** + * Initializes a new instance of MouseEvent with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param when the timestamp of when the event occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param x the X coordinate of the mouse point + * @param y the Y coordinate of the mouse point + * @param clickCount the number of mouse clicks for this event + * @param popupTrigger true if this event triggers a popup menu + * @throws IllegalArgumentException if source is null + */ + public MouseEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger) + { + this(source, id, when, modifiers, x, y, clickCount, popupTrigger, + NOBUTTON); + } + + /** + * This method returns the X coordinate of the mouse position. This is + * relative to the source component. + * + * @return the x coordinate + */ + public int getX() + { + return x; + } + + /** + * This method returns the Y coordinate of the mouse position. This is + * relative to the source component. + * + * @return the y coordinate + */ + public int getY() + { + return y; + } + + /** + * This method returns a Point for the x,y position of + * the mouse pointer. This is relative to the source component. + * + * @return a Point for the event position + */ + public Point getPoint() + { + return new Point(x, y); + } + + /** + * Translates the event coordinates by the specified x and y offsets. + * + * @param dx the value to add to the X coordinate of this event + * @param dy the value to add to the Y coordiante of this event + */ + public void translatePoint(int dx, int dy) + { + x += dx; + y += dy; + } + + /** + * This method returns the number of mouse clicks associated with this + * event. + * + * @return the number of mouse clicks for this event + */ + public int getClickCount() + { + return clickCount; + } + + /** + * Returns which button, if any, was the most recent to change state. This + * will be one of {@link #NOBUTTON}, {@link #BUTTON1}, {@link #BUTTON2}, or + * {@link #BUTTON3}. + * + * @return the button that changed state + * @since 1.4 + */ + public int getButton() + { + return button; + } + + /** + * This method tests whether or not the event is a popup menu trigger. This + * should be checked in both MousePressed and MouseReleased to be + * cross-platform compatible, as different systems have different popup + * triggers. + * + * @return true if the event is a popup menu trigger + */ + public boolean isPopupTrigger() + { + return popupTrigger; + } + + /** + * Returns a string describing the modifiers, such as "Shift" or + * "Ctrl+Button1". + * + * XXX Sun claims this can be localized via the awt.properties file - how + * do we implement that? + * + * @param modifiers the old-style modifiers to convert to text + * @return a string representation of the modifiers in this bitmask + */ + public static String getMouseModifiersText(int modifiers) + { + modifiers &= EventModifier.OLD_MASK; + if ((modifiers & BUTTON2_MASK) != 0) + modifiers |= BUTTON2_DOWN_MASK; + if ((modifiers & BUTTON3_MASK) != 0) + modifiers |= BUTTON3_DOWN_MASK; + return getModifiersExText(EventModifier.extend(modifiers)); + } + + /** + * Returns a string identifying this event. This is formatted as the field + * name of the id type, followed by the (x,y) point, the most recent button + * changed, modifiers (if any), extModifiers (if any), and clickCount. + * + * @return a string identifying this event + */ + public String paramString() + { + StringBuffer s = new StringBuffer(); + switch (id) + { + case MOUSE_CLICKED: + s.append("MOUSE_CLICKED,("); + break; + case MOUSE_PRESSED: + s.append("MOUSE_PRESSED,("); + break; + case MOUSE_RELEASED: + s.append("MOUSE_RELEASED,("); + break; + case MOUSE_MOVED: + s.append("MOUSE_MOVED,("); + break; + case MOUSE_ENTERED: + s.append("MOUSE_ENTERED,("); + break; + case MOUSE_EXITED: + s.append("MOUSE_EXITED,("); + break; + case MOUSE_DRAGGED: + s.append("MOUSE_DRAGGED,("); + break; + case MOUSE_WHEEL: + s.append("MOUSE_WHEEL,("); + break; + default: + s.append("unknown type,("); + } + s.append(x).append(',').append(y).append("),button=").append(button); + if ((modifiers & EventModifier.NEW_MASK) != 0) + { + int mod = modifiers; + if ((mod & (ALT_DOWN_MASK | BUTTON2_DOWN_MASK)) != 0) + mod |= ALT_DOWN_MASK | BUTTON2_DOWN_MASK; + if ((mod & (META_DOWN_MASK | BUTTON3_DOWN_MASK)) != 0) + mod |= META_DOWN_MASK | BUTTON3_DOWN_MASK; + s.append(",modifiers=").append(getModifiersExText(mod)); + } + if (modifiers != 0) + s.append(",extModifiers=").append(getModifiersExText(modifiers)); + return s.append(",clickCount=").append(clickCount).toString(); + } + + /** + * Reads in the object from a serial stream. + * + * @param s the stream to read from + * @throws IOException if deserialization fails + * @throws ClassNotFoundException if deserialization fails + * @serialData default, except that the modifiers are converted to new style + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + if ((modifiers & EventModifier.OLD_MASK) != 0) + { + if ((modifiers & BUTTON1_MASK) != 0) + button = BUTTON1; + else if ((modifiers & BUTTON2_MASK) != 0) + button = BUTTON2; + else if ((modifiers & BUTTON3_MASK) != 0) + button = BUTTON3; + modifiers = EventModifier.extend(modifiers); + } + } +} // class MouseEvent diff --git a/libjava/classpath/java/awt/event/MouseListener.java b/libjava/classpath/java/awt/event/MouseListener.java new file mode 100644 index 0000000..4508019 --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseListener.java @@ -0,0 +1,94 @@ +/* MouseListener.java -- listen for mouse clicks and crossing component edges + Copyright (C) 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive mouse events other than + * simple motion events. This includes clicks (but not mouse wheel events), + * and crossing component boundaries without change in button status. To + * track moves and drags, use MouseMotionListener, and to track wheel events, + * use MouseWheelListener. To watch a subset of these events, use a + * MouseAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see MouseAdapter + * @see MouseEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface MouseListener extends EventListener +{ + /** + * This method is called when the mouse is clicked (pressed and released + * in short succession) on a component. + * + * @param event the MouseEvent indicating the click + */ + void mouseClicked(MouseEvent event); + + /** + * This method is called when the mouse is pressed over a component. + * + * @param event the MouseEvent for the press + */ + void mousePressed(MouseEvent event); + + /** + * This method is called when the mouse is released over a component. + * + * @param event the MouseEvent for the release + */ + void mouseReleased(MouseEvent event); + + /** + * This method is called when the mouse enters a component. + * + * @param event the MouseEvent for the entry + */ + void mouseEntered(MouseEvent event); + + /** + * This method is called when the mouse exits a component. + * + * @param event the MouseEvent for the exit + */ + void mouseExited(MouseEvent event); +} // interface MouseListener diff --git a/libjava/classpath/java/awt/event/MouseMotionAdapter.java b/libjava/classpath/java/awt/event/MouseMotionAdapter.java new file mode 100644 index 0000000..8a295f6 --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseMotionAdapter.java @@ -0,0 +1,79 @@ +/* MouseMotionAdapter.java -- convenience class for mouse motion listeners + Copyright (C) 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 java.awt.event; + +/** + * This class implements MouseMotionListener and implements all + * methods with empty bodies. This allows a listener interested in + * implementing only a subset of the MouseMotionListener + * interface to extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see MouseEvent + * @see MouseMotionListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class MouseMotionAdapter implements MouseMotionListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public MouseMotionAdapter() + { + } + + /** + * Implement this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void mouseDragged(MouseEvent event) + { + } + + /** + * Implement this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void mouseMoved(MouseEvent event) + { + } +} // class MouseMotionAdapter diff --git a/libjava/classpath/java/awt/event/MouseMotionListener.java b/libjava/classpath/java/awt/event/MouseMotionListener.java new file mode 100644 index 0000000..ba2c569 --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseMotionListener.java @@ -0,0 +1,72 @@ +/* MouseMotionListener.java -- listen to mouse motion events + Copyright (C) 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to be notified of mouse movements. + * This includes moves and drags, but not crossing component boundaries. To + * track other mouse events, use MouseListener or MouseWheelListener. To + * watch a subset of these events, use a MouseMotionAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see MouseMotionAdapter + * @see MouseEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface MouseMotionListener extends EventListener +{ + /** + * This method is called when the mouse is moved over a component + * while a button has been pressed. + * + * @param event the MouseEvent indicating the motion + */ + void mouseDragged(MouseEvent event); + + /** + * This method is called when the mouse is moved over a component + * while no button is pressed. + * + * @param event the MouseEvent indicating the motion + */ + void mouseMoved(MouseEvent event); +} // interface MouseMotionListener diff --git a/libjava/classpath/java/awt/event/MouseWheelEvent.java b/libjava/classpath/java/awt/event/MouseWheelEvent.java new file mode 100644 index 0000000..bc603aa --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseWheelEvent.java @@ -0,0 +1,232 @@ +/* MouseWheelEvent.java -- a mouse wheel event + 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 java.awt.event; + +import java.awt.Adjustable; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.ScrollPane; + +import javax.swing.JScrollPane; +import javax.swing.Scrollable; + +/** + * This event is generated for a mouse wheel rotation. The wheel (the middle + * mouse button on most modern mice) can be rotated towards or away from the + * user, and is ofteh used for scrolling. + * + *

Because of the special use for scrolling components, MouseWheelEvents + * often affect a different component than the one located at the point of + * the event. If the component under the mouse cursor does not accept wheel + * events, the event is passed to the first ancestor container which does. This + * is often a ScrollPane, which knows how to scroll. If an AWT component is + * built from a native widget that knows how to use mouse wheel events, that + * component will consume the event. + * + *

The two most common scroll types are "units" (lines at a time) or + * "blocks" (pages at a time). The initial setting is taken from the platform, + * although the user can adjust the setting at any time. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see MouseWheelListener + * @see ScrollPane + * @see ScrollPane#setWheelScrollingEnabled(boolean) + * @see JScrollPane + * @see JScrollPane#setWheelScrollingEnabled(boolean) + * @since 1.4 + * @status updated to 1.4 + */ +public class MouseWheelEvent extends MouseEvent +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 6459879390515399677L; + + /** + * Indicates scrolling by units (lines). + * + * @see #getScrollType() + */ + public static final int WHEEL_UNIT_SCROLL = 0; + + /** + * Indicates scrolling by blocks (pages). + * + * @see #getScrollType() + */ + public static final int WHEEL_BLOCK_SCROLL = 1; + + /** + * Indicates what scroll type should take place. This should be limited + * to {@link #WHEEL_UNIT_SCROLL} and {@link #WHEEL_BLOCK_SCROLL}. + * + * @serial the scroll type + */ + private final int scrollType; + + /** + * Indicates the scroll amount. This is only meaningful if scrollType is + * WHEEL_UNIT_SCROLL. + * + * @serial the number of lines to scroll + */ + private final int scrollAmount; + + /** + * Indicates how far the mouse wheel was rotated. + * + * @serial the rotation amount + */ + private final int wheelRotation; + + /** + * Initializes a new instance of MouseWheelEvent with the + * specified information. Note that an invalid id leads to unspecified + * results. + * + * @param source the source of the event + * @param id the event id + * @param when the timestamp of when the event occurred + * @param modifiers any modifier bits for this event + * @param x the X coordinate of the mouse point + * @param y the Y coordinate of the mouse point + * @param clickCount the number of mouse clicks for this event + * @param popupTrigger true if this event triggers a popup menu + * @param scrollType one of {@link #WHEEL_UNIT_SCROLL}, + * {@link #WHEEL_BLOCK_SCROLL} + * @param scrollAmount the number of units to scroll, ignored for block type + * @param wheelRotation the number of rotation "clicks" + * @throws IllegalArgumentException if source is null + * @see MouseEvent#MouseEvent(Component, int, long, int, int, int, int, + * boolean) + */ + public MouseWheelEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger, + int scrollType, int scrollAmount, int wheelRotation) + { + super(source, id, when, modifiers, x, y, clickCount, popupTrigger); + this.scrollType = scrollType; + this.scrollAmount = scrollAmount; + this.wheelRotation = wheelRotation; + } + + /** + * This method returns the scrolling pattern this event requests. Legal + * values are {@link #WHEEL_UNIT_SCROLL} and {@link #WHEEL_BLOCK_SCROLL}. + * + * @return the scroll type + * @see Adjustable#getUnitIncrement() + * @see Adjustable#getBlockIncrement() + * @see Scrollable#getScrollableUnitIncrement(Rectangle, int, int) + * @see Scrollable#getScrollableBlockIncrement(Rectangle, int, int) + */ + public int getScrollType() + { + return scrollType; + } + + /** + * Returns the number of units to scroll in response to this event. This + * only makes sense when the scroll type is WHEEL_UNIT_SCROLL. + * + * @return the number of scroll units, if defined + * @see #getScrollType() + */ + public int getScrollAmount() + { + return scrollAmount; + } + + /** + * Gets the number of "clicks" the wheel was rotated. Negative values move + * up (away) from the user, positive values move down (towards) the user. + * + * @return the number of rotation clicks + */ + public int getWheelRotation() + { + return wheelRotation; + } + + /** + * This is a convenience method which aids in a common listener for scrolling + * a scrollpane (although this is already built into ScrollPane and + * JScrollPane). This method only makes sense when getScrollType() returns + * WHEEL_UNIT_SCROLL. + * + *

This accounts for direction of scroll and amount of wheel movement, as + * interpreted by the platform settings. + * + * @return the number of units to scroll + * @see #getScrollType() + * @see #getScrollAmount() + * @see MouseWheelListener + * @see Adjustable + * @see Adjustable#getUnitIncrement() + * @see Scrollable + * @see Scrollable#getScrollableUnitIncrement(Rectangle, int, int) + * @see ScrollPane + * @see ScrollPane#setWheelScrollingEnabled(boolean) + * @see JScrollPane + * @see JScrollPane#setWheelScrollingEnabled(boolean) + */ + public int getUnitsToScroll() + { + return wheelRotation * scrollAmount; + } + + /** + * Returns a string identifying this event. For mouse wheel events, this + * is super.paramString() + ",scrollType=WHEEL_" + + * (getScrollType() == WHEEL_UNIT_SCROLL ? "UNIT" : "BLOCK") + * + "_SCROLL,scrollAmount=" + getScrollAmount() + ",wheelRotation=" + * + getWheelRotation(). + * + * @return a string identifying this event + */ + public String paramString() + { + return super.paramString() + ",scrollType=" + + (scrollType == WHEEL_UNIT_SCROLL ? "WHEEL_UNIT_SCROLL" + : scrollType == WHEEL_BLOCK_SCROLL ? "WHEEL_BLOCK_SCROLL" + : "unknown scroll type") + + ",scrollAmount=" + scrollAmount + ",wheelRotation=" + wheelRotation; + } +} // class MouseWheelEvent diff --git a/libjava/classpath/java/awt/event/MouseWheelListener.java b/libjava/classpath/java/awt/event/MouseWheelListener.java new file mode 100644 index 0000000..1125582 --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseWheelListener.java @@ -0,0 +1,60 @@ +/* MouseWheelListener.java -- listen for mouse wheel events + 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive mouse wheel events. For + * other events, use MouseListener or MouseMotionListener. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see MouseWheelEvent + * @since 1.4 + * @status updated to 1.4 + */ +public interface MouseWheelListener extends EventListener +{ + /** + * This method is called when the mouse wheel is rotated. + * + * @param event the MouseWheelEvent indicating the rotation + */ + void mouseWheelMoved(MouseWheelEvent event); +} // interface MouseWheelListener diff --git a/libjava/classpath/java/awt/event/PaintEvent.java b/libjava/classpath/java/awt/event/PaintEvent.java new file mode 100644 index 0000000..bb89c37 --- /dev/null +++ b/libjava/classpath/java/awt/event/PaintEvent.java @@ -0,0 +1,127 @@ +/* PaintEvent.java -- an area of the screen needs to be repainted + Copyright (C) 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 java.awt.event; + +import java.awt.Component; +import java.awt.Rectangle; + +/** + * This event is generated when an area of the screen needs to be painted. + * This event is not meant for users, but exists to allow proper serialization + * behavior in the EventQueue with user-accessible events. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class PaintEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 1267492026433337593L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int PAINT_FIRST = 800; + + /** This is the last id in the range of event ids used by this class. */ + public static final int PAINT_LAST = 801; + + /** This id is for paint event types. */ + public static final int PAINT = 800; + + /** This id is for update event types. */ + public static final int UPDATE = 801; + + /** + * This is the rectange to be painted or updated. + * + * @see #getUpdateRect() + * @see #setUpdateRect(Rectangle) + * @serial the non-null rectangle to be painted + */ + private Rectangle updateRect; + + /** + * Initializes a new instance of PaintEvent with the specified + * source, id, and update region. Note that an invalid id leads to + * unspecified results. + * + * @param source the event source + * @param id the event id + * @param updateRect the rectangle to repaint + * @throws IllegalArgumentException if source is null + */ + public PaintEvent(Component source, int id, Rectangle updateRect) + { + super(source, id); + this.updateRect = updateRect; + } + + /** + * Returns the rectange to be updated for this event. + * + * @return the rectangle to update + */ + public Rectangle getUpdateRect() + { + return updateRect; + } + + /** + * Sets the rectangle to be updated for this event. + * + * @param updateRect the new update rectangle for this event + */ + public void setUpdateRect(Rectangle updateRect) + { + this.updateRect = updateRect; + } + + /** + * Returns a string identifying this event. + * + * @return a string identifying this event + */ + public String paramString() + { + return (id == PAINT ? "PAINT,updateRect=" : id == UPDATE + ? "UPDATE,updateRect=" : "unknown type,updateRect=") + updateRect; + } +} // class PaintEvent diff --git a/libjava/classpath/java/awt/event/TextEvent.java b/libjava/classpath/java/awt/event/TextEvent.java new file mode 100644 index 0000000..0288abb --- /dev/null +++ b/libjava/classpath/java/awt/event/TextEvent.java @@ -0,0 +1,93 @@ +/* TextEvent.java -- event for text changes + Copyright (C) 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 java.awt.event; + +import java.awt.AWTEvent; +import java.awt.TextComponent; + +/** + * This event is generated when a text box changes contents. This is an + * abstraction that distills a large number of individual mouse or keyboard + * events into a simpler "text changed" event. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see TextComponent + * @see TextListener + * @since 1.1 + * @status updated to 1.4 + */ +public class TextEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 6269902291250941179L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int TEXT_FIRST = 900; + + /** This is the last id in the range of event ids used by this class. */ + public static final int TEXT_LAST = 900; + + /** This event id indicates that the text of an object has changed. */ + public static final int TEXT_VALUE_CHANGED = 900; + + /** + * Initializes a new instance of TextEvent with the specified + * source and id. Note that an invalid id leads to unspecified results. + * + * @param source the (TextComponent) object that generated this event + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public TextEvent(Object source, int id) + { + super(source, id); + } + + /** + * Returns a string identifying this event. This is "TEXT_VALUE_CHANGED". + * + * @return a string identifying this event + */ + public String paramString() + { + return id == TEXT_VALUE_CHANGED ? "TEXT_VALUE_CHANGED" : "unknown type"; + } +} // class TextEvent diff --git a/libjava/classpath/java/awt/event/TextListener.java b/libjava/classpath/java/awt/event/TextListener.java new file mode 100644 index 0000000..bcdd7fa --- /dev/null +++ b/libjava/classpath/java/awt/event/TextListener.java @@ -0,0 +1,60 @@ +/* TextListener.java -- listen for text changes + Copyright (C) 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to be notified when text changes + * in a component. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see TextEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface TextListener extends EventListener +{ + /** + * This method is called when the text being monitored changes. + * + * @param event the TextEvent indicating the change + */ + void textValueChanged(TextEvent event); +} // interface TextListener diff --git a/libjava/classpath/java/awt/event/WindowAdapter.java b/libjava/classpath/java/awt/event/WindowAdapter.java new file mode 100644 index 0000000..708de58 --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowAdapter.java @@ -0,0 +1,156 @@ +/* WindowAdapter.java -- convenience class for writing window listeners + Copyright (C) 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 java.awt.event; + +/** + * This class implements WindowListener, + * WindowStateListener, and WindowFocusListener, and + * implements all methods with empty bodies. This allows a listener + * interested in listening to only a subset of any WindowEvent + * actions to extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ComponentEvent + * @see ComponentListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class WindowAdapter + implements WindowListener, WindowStateListener, WindowFocusListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public WindowAdapter() + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowOpened(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowClosing(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowClosed(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowIconified(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowDeiconified(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowActivated(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowDeactivated(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + * @since 1.4 + */ + public void windowStateChanged(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + * @since 1.4 + */ + public void windowGainedFocus(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + * @since 1.4 + */ + public void windowLostFocus(WindowEvent event) + { + } +} // class WindowAdapter diff --git a/libjava/classpath/java/awt/event/WindowEvent.java b/libjava/classpath/java/awt/event/WindowEvent.java new file mode 100644 index 0000000..2186889 --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowEvent.java @@ -0,0 +1,312 @@ +/* WindowEvent.java -- window change event + Copyright (C) 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 java.awt.event; + +import java.awt.Frame; +import java.awt.Window; + +/** + * This event is generated when there is a change in a window. This includes + * creation, closing, iconification, activation, and focus changes. There + * are three listeners, for three types of events: WindowListeners deal with + * the lifecycle of a window, WindowStateListeners deal with window state + * like maximization, and WindowFocusListeners deal with focus switching to + * or from a window. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see WindowAdapter + * @see WindowListener + * @see WindowFocusListener + * @see WindowStateListener + * @since 1.1 + * @status updated to 1.4 + */ +public class WindowEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -1567959133147912127L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int WINDOW_FIRST = 200; + + /** This is the id for a window that is opened. */ + public static final int WINDOW_OPENED = 200; + + /** This is the id for a window that is about to close. */ + public static final int WINDOW_CLOSING = 201; + + /** This is the id for a window that finished closing. */ + public static final int WINDOW_CLOSED = 202; + + /** This is the id for a window that is iconified. */ + public static final int WINDOW_ICONIFIED = 203; + + /** This is the id for a window that is de-iconified. */ + public static final int WINDOW_DEICONIFIED = 204; + + /** This is the id for a window that is activated. */ + public static final int WINDOW_ACTIVATED = 205; + + /** This is the id for a window that is de-activated. */ + public static final int WINDOW_DEACTIVATED = 206; + + /** + * This is the id for a window becoming the focused window. + * + * @since 1.4 + */ + public static final int WINDOW_GAINED_FOCUS = 207; + + /** + * This is the id for a window losing all focus. + * + * @since 1.4 + */ + public static final int WINDOW_LOST_FOCUS = 208; + + /** + * This is the id for a window state change, such as maximization. + * + * @since 1.4 + */ + public static final int WINDOW_STATE_CHANGED = 209; + + /** This is the last id in the range of event ids used by this class. */ + public static final int WINDOW_LAST = 209; + + /** + * The other Window involved in a focus or activation change. For + * WINDOW_ACTIVATED and WINDOW_GAINED_FOCUS events, this is the window that + * lost focus; for WINDOW_DEACTIVATED and WINDOW_LOST_FOCUS, this is the + * window that stole focus; and for other events (or when native + * implementation does not have the data available), this is null. + * + * @see #getOppositeWindow() + * @serial the opposite window, or null + * @since 1.4 + */ + private final Window opposite; + + /** + * The former state of the window. + * + * @serial bitmask of the old window state + * @since 1.4 + */ + private final int oldState; + + /** + * The present state of the window. + * + * @serial bitmask of the new window state + * @since 1.4 + */ + private final int newState; + + /** + * Initializes a new instance of WindowEvent with the specified + * parameters. Note that an invalid id leads to unspecified results. + * + * @param source the window that generated this event + * @param id the event id + * @param opposite the window that received the opposite event, or null + * @param oldState the previous state of this window + * @param newState the new state of this window + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public WindowEvent(Window source, int id, Window opposite, + int oldState, int newState) + { + super(source, id); + this.opposite = opposite; + this.oldState = oldState; + this.newState = newState; + } + + /** + * Initializes a new instance of WindowEvent with the specified + * parameters. Note that an invalid id leads to unspecified results. + * + * @param source the window that generated this event + * @param id the event id + * @param opposite the window that received the opposite event, or null + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public WindowEvent(Window source, int id, Window opposite) + { + this(source, id, opposite, 0, 0); + } + + /** + * Initializes a new instance of WindowEvent with the specified + * parameters. Note that an invalid id leads to unspecified results. + * + * @param source the window that generated this event + * @param id the event id + * @param oldState the previous state of this window + * @param newState the new state of this window + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public WindowEvent(Window source, int id, int oldState, int newState) + { + this(source, id, null, oldState, newState); + } + + /** + * Initializes a new instance of WindowEvent with the specified + * parameters. Note that an invalid id leads to unspecified results. + * + * @param source the window that generated this event + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public WindowEvent(Window source, int id) + { + this(source, id, null, 0, 0); + } + + /** + * Returns the event source as a Window. If the source has + * subsequently been modified to a non-Window, this returns null. + * + * @return the event source as a Window + */ + public Window getWindow() + { + return source instanceof Window ? (Window) source : null; + } + + /** + * Returns the opposite window if this window was involved in an activation + * or focus change. For WINDOW_ACTIVATED and WINDOW_GAINED_FOCUS events, + * this is the window that lost focus; for WINDOW_DEACTIVATED and + * WINDOW_LOST_FOCUS, this is the window that stole focus; and for other + * events (or when native implementation does not have the data available), + * this is null. + * + * @return the opposite window, or null + * @since 1.4 + */ + public Window getOppositeWindow() + { + return opposite; + } + + /** + * Returns the state of this window before the event. This is the bitwise + * or of fields in Frame: NORMAL, ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT, + * and MAXIMIZED_BOTH. + * + * @return the former state + * @see Frame#getExtendedState() + * @since 1.4 + */ + public int getOldState() + { + return oldState; + } + + /** + * Returns the state of this window after the event. This is the bitwise + * or of fields in Frame: NORMAL, ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT, + * and MAXIMIZED_BOTH. + * + * @return the updated state + * @see Frame#getExtendedState() + * @since 1.4 + */ + public int getNewState() + { + return newState; + } + + /** + * Returns a string that identifies this event. This is formatted as the + * field name of the id, followed by the opposite window, old state, and + * new state. + * + * @return a string that identifies this event + */ + public String paramString() + { + StringBuffer s = new StringBuffer(); + switch (id) + { + case WINDOW_OPENED: + s.append("WINDOW_OPENED,opposite="); + break; + case WINDOW_CLOSING: + s.append("WINDOW_CLOSING,opposite="); + break; + case WINDOW_CLOSED: + s.append("WINDOW_CLOSED,opposite="); + break; + case WINDOW_ICONIFIED: + s.append("WINDOW_ICONIFIED,opposite="); + break; + case WINDOW_DEICONIFIED: + s.append("WINDOW_DEICONIFIED,opposite="); + break; + case WINDOW_ACTIVATED: + s.append("WINDOW_ACTIVATED,opposite="); + break; + case WINDOW_DEACTIVATED: + s.append("WINDOW_DEACTIVATED,opposite="); + break; + case WINDOW_GAINED_FOCUS: + s.append("WINDOW_GAINED_FOCUS,opposite="); + break; + case WINDOW_LOST_FOCUS: + s.append("WINDOW_LOST_FOCUS,opposite="); + break; + case WINDOW_STATE_CHANGED: + s.append("WINDOW_STATE_CHANGED,opposite="); + break; + default: + s.append("unknown type,opposite="); + } + return s.append(opposite).append(",oldState=").append(oldState) + .append(",newState=").append(newState).toString(); + } +} // class WindowEvent diff --git a/libjava/classpath/java/awt/event/WindowFocusListener.java b/libjava/classpath/java/awt/event/WindowFocusListener.java new file mode 100644 index 0000000..7384253 --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowFocusListener.java @@ -0,0 +1,68 @@ +/* WindowFocusListener.java -- listens for window focus events + 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to monitor events for window + * focus changes. To watch a subset of these events, use a WindowAdapter. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see WindowAdapter + * @see WindowEvent + * @since 1.4 + * @status updated to 1.4 + */ +public interface WindowFocusListener extends EventListener +{ + /** + * This method is called when a window gains focus. + * + * @param event the WindowEvent indicating the focus change + */ + void windowGainedFocus(WindowEvent event); + + /** + * This method is called when a window loses focus. + * + * @param event the WindowEvent indicating the focus change + */ + void windowLostFocus(WindowEvent event); +} // interface WindowFocusListener diff --git a/libjava/classpath/java/awt/event/WindowListener.java b/libjava/classpath/java/awt/event/WindowListener.java new file mode 100644 index 0000000..52213eb --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowListener.java @@ -0,0 +1,109 @@ +/* WindowListener.java -- listens for window events + Copyright (C) 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 java.awt.event; + +import java.awt.Frame; +import java.awt.Image; +import java.util.EventListener; + +/** + * This interface is for classes that wish to monitor events for window + * changes. To watch a subset of these events, use a WindowAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see WindowAdapter + * @see WindowEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface WindowListener extends EventListener +{ + /** + * This method is called when the window is made visible. + * + * @param event the WindowEvent indicating the change + */ + void windowOpened(WindowEvent event); + + /** + * This method is called when the user calls the system menu close + * function, giving the program a chance to cancel the close. + * + * @param event the WindowEvent indicating the close attempt + */ + void windowClosing(WindowEvent event); + + /** + * This method is called when the window is closed. + * + * @param event the WindowEvent indicating the dispose + */ + void windowClosed(WindowEvent event); + + /** + * This method is called when the window is iconified. + * + * @param event the WindowEvent indicating the iconification + * @see Frame#setIconImage(Image) + */ + void windowIconified(WindowEvent event); + + /** + * This method is called when the window is deiconified. + * + * @param event the WindowEvent indicating the deiconification + */ + void windowDeiconified(WindowEvent event); + + /** + * This method is called when a window is activated. Only Frames and Dialogs + * can be active, and the active window always contains the component with + * focus. + * + * @param event the WindowEvent indicating the activation + */ + void windowActivated(WindowEvent event); + + /** + * This method is called when the window is deactivated. + * + * @param event the WindowEvent indicating the deactivation + */ + void windowDeactivated(WindowEvent event); +} // interface WindowListener diff --git a/libjava/classpath/java/awt/event/WindowStateListener.java b/libjava/classpath/java/awt/event/WindowStateListener.java new file mode 100644 index 0000000..9bc6174 --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowStateListener.java @@ -0,0 +1,62 @@ +/* WindowStateListener.java -- listens for window state changes + 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 java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to monitor events for window + * state changes. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see WindowAdapter + * @see WindowEvent + * @since 1.4 + * @status updated to 1.4 + */ +public interface WindowStateListener extends EventListener +{ + /** + * This method is called when the window state is changed, because of + * iconification or maximization. + * + * @param event the WindowEvent indicating the change + */ + void windowStateChanged(WindowEvent event); +} // interface WindowStateListener diff --git a/libjava/classpath/java/awt/event/package.html b/libjava/classpath/java/awt/event/package.html new file mode 100644 index 0000000..77662a3 --- /dev/null +++ b/libjava/classpath/java/awt/event/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.event + + +

Listeners and adapters for different kinds of AWT events.

+ + + diff --git a/libjava/classpath/java/awt/font/FontRenderContext.java b/libjava/classpath/java/awt/font/FontRenderContext.java new file mode 100644 index 0000000..78564a6 --- /dev/null +++ b/libjava/classpath/java/awt/font/FontRenderContext.java @@ -0,0 +1,126 @@ +/* FontRenderContext.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 java.awt.font; + +import java.awt.geom.AffineTransform; + +/** + * @author Michael Koch + */ +public class FontRenderContext +{ + private AffineTransform affineTransform; + private boolean isAntiAliased; + private boolean usesFractionalMetrics; + + /** + * Construct a new FontRenderContext. + */ + protected FontRenderContext() + { + // Do nothing here. + } + + /** + * Construct a new FontRenderContext. + */ + public FontRenderContext (AffineTransform tx, boolean isAntiAliased, + boolean usesFractionalMetrics) + { + if (tx != null + && !tx.isIdentity ()) + { + this.affineTransform = new AffineTransform (tx); + } + + this.isAntiAliased = isAntiAliased; + this.usesFractionalMetrics = usesFractionalMetrics; + } + + public boolean equals (Object obj) + { + if (! (obj instanceof FontRenderContext)) + return false; + + return equals ((FontRenderContext) obj); + } + + public boolean equals (FontRenderContext rhs) + { + return (affineTransform.equals (rhs.getTransform ()) + && isAntiAliased == rhs.isAntiAliased () + && usesFractionalMetrics == rhs.usesFractionalMetrics ()); + } + + + /** + * Retrieves the affine transform for scaling typographical points + * to raster pixels. + * + * @return a clone of the transform object. + */ + public AffineTransform getTransform () + { + if (affineTransform == null) + return new AffineTransform (); + else + return new AffineTransform (affineTransform); + } + + + /** + * Returns the hash code of the font render context. + */ + public int hashCode () + { + // FIXME: check what SUN does here. + return affineTransform == null ? 0 : affineTransform.hashCode (); + } + + public boolean isAntiAliased () + { + return isAntiAliased; + } + + public boolean usesFractionalMetrics () + { + return usesFractionalMetrics; + } +} + diff --git a/libjava/classpath/java/awt/font/GlyphJustificationInfo.java b/libjava/classpath/java/awt/font/GlyphJustificationInfo.java new file mode 100644 index 0000000..5f45fd5 --- /dev/null +++ b/libjava/classpath/java/awt/font/GlyphJustificationInfo.java @@ -0,0 +1,77 @@ +/* GlyphJustificationInfo.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 java.awt.font; + +/** + * @author Michael Koch + */ +public final class GlyphJustificationInfo +{ + public static final int PRIORITY_KASHIDA = 0; + public static final int PRIORITY_WHITESPACE = 1; + public static final int PRIORITY_INTERCHAR = 2; + public static final int PRIORITY_NONE = 3; + + public final float weight; + public final int growPriority; + public final boolean growAbsorb; + public final float growLeftLimit; + public final float growRightLimit; + public final int shrinkPriority; + public final boolean shrinkAbsorb; + public final float shrinkLeftLimit; + public final float shrinkRightLimit; + + public GlyphJustificationInfo (float weight, boolean growAbsorb, + int growPriority, float growLeftLimit, + float growRightLimit, boolean shrinkAbsorb, + int shrinkPriority, float shrinkLeftLimit, + float shrinkRightLimit) + { + this.weight = weight; + this.growAbsorb = growAbsorb; + this.growPriority = growPriority; + this.growLeftLimit = growLeftLimit; + this.growRightLimit = growRightLimit; + this.shrinkAbsorb = shrinkAbsorb; + this.shrinkPriority = shrinkPriority; + this.shrinkLeftLimit = shrinkLeftLimit; + this.shrinkRightLimit = shrinkRightLimit; + } +} diff --git a/libjava/classpath/java/awt/font/GlyphMetrics.java b/libjava/classpath/java/awt/font/GlyphMetrics.java new file mode 100644 index 0000000..28b2088 --- /dev/null +++ b/libjava/classpath/java/awt/font/GlyphMetrics.java @@ -0,0 +1,134 @@ +/* GlyphMetrics.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 java.awt.font; + +import java.awt.geom.Rectangle2D; + +/** + * @author Michael Koch + */ +public final class GlyphMetrics +{ + public static final byte COMBINING = 2; + public static final byte COMPONENT = 3; + public static final byte LIGATURE = 1; + public static final byte STANDARD = 0; + public static final byte WHITESPACE = 4; + + private boolean horizontal; + private float advanceX; + private float advanceY; + private Rectangle2D bounds; + private byte glyphType; + + public GlyphMetrics (boolean horizontal, float advanceX, float advanceY, + Rectangle2D bounds, byte glyphType) + { + this.horizontal = horizontal; + this.advanceX = advanceX; + this.advanceY = advanceY; + this.bounds = bounds; + this.glyphType = glyphType; + } + + public GlyphMetrics (float advance, Rectangle2D bounds, byte glyphType) + { + this (true, advance, advance, bounds, glyphType); + } + + public float getAdvance () + { + return horizontal ? advanceX : advanceY; + } + + public float getAdvanceX () + { + return advanceX; + } + + public float getAdvanceY () + { + return advanceY; + } + + public Rectangle2D getBounds2D () + { + return bounds; + } + + public float getLSB () + { + throw new Error ("not implemented"); + } + + public float getRSB () + { + throw new Error ("not implemented"); + } + + public int getType () + { + return glyphType; + } + + public boolean isCombining () + { + return (glyphType == COMBINING); + } + + public boolean isComponent () + { + return (glyphType == COMPONENT); + } + + public boolean isLigature() + { + return (glyphType == LIGATURE); + } + + public boolean isStandard() + { + return (glyphType == STANDARD); + } + + public boolean isWhitespace() + { + return (glyphType == WHITESPACE); + } +} diff --git a/libjava/classpath/java/awt/font/GlyphVector.java b/libjava/classpath/java/awt/font/GlyphVector.java new file mode 100644 index 0000000..57e2581 --- /dev/null +++ b/libjava/classpath/java/awt/font/GlyphVector.java @@ -0,0 +1,145 @@ +/* GlyphVector.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 java.awt.font; + +import java.awt.Font; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * @author Michael Koch + */ +public abstract class GlyphVector implements Cloneable +{ + public static final int FLAG_COMPLEX_GLYPHS = 8; + public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2; + public static final int FLAG_HAS_TRANSFORMS = 1; + public static final int FLAG_MASK = 15; + public static final int FLAG_RUN_RTL = 4; + + /** + * Constructs a GlyphVector object. + */ + public GlyphVector () + { + } + + public abstract boolean equals (GlyphVector set); + + public abstract Font getFont (); + + public abstract FontRenderContext getFontRenderContext (); + + public int getGlyphCharIndex (int glyphIndex) + { + throw new Error ("not implemented"); + } + + public int[] getGlyphCharIndices (int beginGlyphIndex, int numEntries, + int[] codeReturn) + { + throw new Error ("not implemented"); + } + + public abstract int getGlyphCode (int glyphIndex); + + public abstract int[] getGlyphCodes (int beginGlyphIndex, int numEntries, + int[] codeReturn); + + public abstract GlyphJustificationInfo getGlyphJustificationInfo + (int glyphIndex); + + public abstract Shape getGlyphLogicalBounds (int glyphIndex); + + public abstract GlyphMetrics getGlyphMetrics (int glyphIndex); + + public abstract Shape getGlyphOutline (int glyphIndex); + + public Shape getGlyphOutline (int glyphIndex, float x, float y) + { + throw new Error ("not implemented"); + } + + public Rectangle getGlyphPixelBounds (int index, FontRenderContext renderFRC, + float x, float y) + { + throw new Error ("not implemented"); + } + + public abstract Point2D getGlyphPosition (int glyphIndex); + + public abstract float[] getGlyphPositions (int beginGlyphIndex, + int numEntries, + float[] positionReturn); + + public abstract AffineTransform getGlyphTransform (int glyphIndex); + + public abstract Shape getGlyphVisualBounds (int glyphIndex); + + public int getLayoutFlags () + { + throw new Error ("not implemented"); + } + + public abstract Rectangle2D getLogicalBounds (); + + public abstract int getNumGlyphs (); + + public abstract Shape getOutline (); + + public abstract Shape getOutline (float x, float y); + + public Rectangle getPixelBounds (FontRenderContext renderFRC, + float x, float y) + { + throw new Error ("not implemented"); + } + + public abstract Rectangle2D getVisualBounds (); + + public abstract void performDefaultLayout (); + + public abstract void setGlyphPosition (int glyphIndex, Point2D newPos); + + public abstract void setGlyphTransform (int glyphIndex, + AffineTransform newTX); +} diff --git a/libjava/classpath/java/awt/font/GraphicAttribute.java b/libjava/classpath/java/awt/font/GraphicAttribute.java new file mode 100644 index 0000000..79eae99 --- /dev/null +++ b/libjava/classpath/java/awt/font/GraphicAttribute.java @@ -0,0 +1,84 @@ +/* GraphicAttribute.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 java.awt.font; + +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +/** + * @author Michael Koch + */ +public abstract class GraphicAttribute +{ + public static final int BOTTOM_ALIGNMENT = -2; + public static final int CENTER_BASELINE = 1; + public static final int HANGING_BASELINE = 2; + public static final int ROMAN_BASELINE = 0; + public static final int TOP_ALIGNMENT = -1; + + private int alignment; + + protected GraphicAttribute (int alignment) + { + this.alignment = alignment; + } + + public abstract void draw (Graphics2D graphics, float x, float y); + + public abstract float getAdvance (); + + public final int getAlignment () + { + return alignment; + } + + public abstract float getAscent (); + + public Rectangle2D getBounds () + { + throw new Error ("not implemented"); + } + + public abstract float getDescent (); + + public GlyphJustificationInfo getJustificationInfo () + { + throw new Error ("not implemented"); + } +} diff --git a/libjava/classpath/java/awt/font/ImageGraphicAttribute.java b/libjava/classpath/java/awt/font/ImageGraphicAttribute.java new file mode 100644 index 0000000..77413f9 --- /dev/null +++ b/libjava/classpath/java/awt/font/ImageGraphicAttribute.java @@ -0,0 +1,109 @@ +/* ImageGraphicAttribute.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 java.awt.font; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.geom.Rectangle2D; + +/** + * @author Michael Koch + */ +public final class ImageGraphicAttribute extends GraphicAttribute +{ + private Image image; + + public ImageGraphicAttribute (Image image, int alignment) + { + super (alignment); + this.image = image; + } + + public ImageGraphicAttribute (Image image, int alignment, float originX, + float originY) + { + super (alignment); + this.image = image; + + throw new Error ("not implemented"); + } + + public void draw (Graphics2D graphics, float x, float y) + { + throw new Error ("not implemented"); + } + + public boolean equals (Object obj) + { + if (! (obj instanceof ImageGraphicAttribute)) + return false; + + return equals ((ImageGraphicAttribute) obj); + } + + public boolean equals (ImageGraphicAttribute rhs) + { + throw new Error ("not implemented"); + } + + public float getAdvance () + { + throw new Error ("not implemented"); + } + + public float getAscent () + { + throw new Error ("not implemented"); + } + + public Rectangle2D getBounds () + { + throw new Error ("not implemented"); + } + + public float getDescent () + { + throw new Error ("not implemented"); + } + + public int hashCode () + { + throw new Error ("not implemented"); + } +} diff --git a/libjava/classpath/java/awt/font/LineBreakMeasurer.java b/libjava/classpath/java/awt/font/LineBreakMeasurer.java new file mode 100644 index 0000000..0a6a969 --- /dev/null +++ b/libjava/classpath/java/awt/font/LineBreakMeasurer.java @@ -0,0 +1,113 @@ +/* LineBreakMeasurer.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 java.awt.font; + +import java.text.AttributedCharacterIterator; +import java.text.BreakIterator; + +public final class LineBreakMeasurer +{ + private AttributedCharacterIterator ci; + private FontRenderContext frc; + private BreakIterator bi; + + /** + * Constructs a LineBreakMeasurer object. + */ + public LineBreakMeasurer (AttributedCharacterIterator text, + FontRenderContext frc) + { + this (text, null, frc); + } + + /** + * Constructs a LineBreakMeasurer object. + */ + public LineBreakMeasurer (AttributedCharacterIterator text, + BreakIterator breakIter, FontRenderContext frc) + { + this.ci = text; + this.bi = breakIter; + this.frc = frc; + } + + public void deleteChar (AttributedCharacterIterator newParagraph, + int deletePos) + { + throw new Error ("not implemented"); + } + + public int getPosition () + { + return ci.getIndex (); + } + + public void insertChar (AttributedCharacterIterator newParagraph, + int insertPos) + { + throw new Error ("not implemented"); + } + + public TextLayout nextLayout (float wrappingWidth) + { + throw new Error ("not implemented"); + } + + public TextLayout nextLayout (float wrappingWidth, int offsetLimit, + boolean requireNextWord) + { + throw new Error ("not implemented"); + } + + public int nextOffset (float wrappingWidth) + { + throw new Error ("not implemented"); + } + + public int nextOffset (float wrappingWidth, int offsetLimit, + boolean requireNextWord) + { + throw new Error ("not implemented"); + } + + public void setPosition (int newPosition) + { + ci.setIndex (newPosition); + } +} diff --git a/libjava/classpath/java/awt/font/LineMetrics.java b/libjava/classpath/java/awt/font/LineMetrics.java new file mode 100644 index 0000000..3c45ad1 --- /dev/null +++ b/libjava/classpath/java/awt/font/LineMetrics.java @@ -0,0 +1,67 @@ +/* LineMetrics.java -- Information about about a line display characteristics + 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 java.awt.font; + +/** + * @author Michael Koch + */ +public abstract class LineMetrics +{ + public abstract float getAscent(); + + public abstract int getBaselineIndex(); + + public abstract float[] getBaselineOffsets(); + + public abstract float getDescent(); + + public abstract float getHeight(); + + public abstract float getLeading(); + + public abstract int getNumChars(); + + public abstract float getStrikethroughOffset(); + + public abstract float getStrikethroughThickness(); + + public abstract float getUnderlineOffset(); + + public abstract float getUnderlineThickness(); +} diff --git a/libjava/classpath/java/awt/font/MultipleMaster.java b/libjava/classpath/java/awt/font/MultipleMaster.java new file mode 100644 index 0000000..57417ea --- /dev/null +++ b/libjava/classpath/java/awt/font/MultipleMaster.java @@ -0,0 +1,61 @@ +/* MultipleMaster.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 java.awt.font; + +import java.awt.Font; + +/** + * @author Michael Koch + */ +public interface MultipleMaster +{ + Font deriveMMFont (float[] axes); + + Font deriveMMFont (float[] glyphWidths, float avgStemWidth, + float typicalCapHeight, float typicalXHeight, + float italicAngle); + + float[] getDesignAxisDefaults(); + + String[] getDesignAxisNames(); + + float[] getDesignAxisRanges(); + + int getNumDesignAxes(); +} diff --git a/libjava/classpath/java/awt/font/NumericShaper.java b/libjava/classpath/java/awt/font/NumericShaper.java new file mode 100644 index 0000000..efbdcd4 --- /dev/null +++ b/libjava/classpath/java/awt/font/NumericShaper.java @@ -0,0 +1,137 @@ +/* NumericShaper.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 java.awt.font; + +import java.io.Serializable; + +/** + * @author Michael Koch + * @since 1.4 + */ +public final class NumericShaper implements Serializable +{ + private static final long serialVersionUID = -8022764705923730308L; + + public static final int ALL_RANGES = 524287; + public static final int ARABIC = 2; + public static final int BENGALI = 16; + public static final int DEVANAGARI = 8; + public static final int EASTERN_ARABIC = 4; + public static final int ETHIOPIC = 65536; + public static final int EUROPEAN = 1; + public static final int GUJARATI = 64; + public static final int GURMUKHI = 32; + public static final int KANNADA = 1024; + public static final int KHMER = 131072; + public static final int LAO = 8192; + public static final int MALAYALAM = 2048; + public static final int MONGOLIAN = 262144; + public static final int MYANMAR = 32768; + public static final int ORIYA = 128; + public static final int TAMIL = 256; + public static final int TELUGU = 512; + public static final int THAI = 4096; + public static final int TIBETAN = 16384; + + private int ranges; + private int context; + + private NumericShaper (int ranges, int context) + { + this.ranges = ranges; + this.context = context; + } + + public boolean equals (Object obj) + { + if (! (obj instanceof NumericShaper)) + return false; + + NumericShaper tmp = (NumericShaper) obj; + + return (ranges == tmp.ranges + && context == tmp.context); + } + + public static NumericShaper getContextualShaper (int ranges) + { + throw new Error ("not implemented"); + } + + public static NumericShaper getContextualShaper (int ranges, + int defaultContext) + { + throw new Error ("not implemented"); + } + + public int getRanges () + { + return ranges; + } + + public static NumericShaper getShaper (int singleRange) + { + throw new Error ("not implemented"); + } + + public int hashCode () + { + throw new Error ("not implemented"); + } + + public boolean isContextual () + { + throw new Error ("not implemented"); + } + + public void shape (char[] text, int start, int count) + { + shape (text, start, count, context); + } + + public void shape (char[] text, int start, int count, int context) + { + throw new Error ("not implemented"); + } + + public String toString () + { + throw new Error ("not implemented"); + } +} diff --git a/libjava/classpath/java/awt/font/OpenType.java b/libjava/classpath/java/awt/font/OpenType.java new file mode 100644 index 0000000..ece3279 --- /dev/null +++ b/libjava/classpath/java/awt/font/OpenType.java @@ -0,0 +1,111 @@ +/* OpenType.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 java.awt.font; + +/** + * @author Michael Koch + */ +public interface OpenType +{ + int TAG_ACNT = 1633906292; + int TAG_AVAR = 1635148146; + int TAG_BASE = 1111577413; + int TAG_BDAT = 1650745716; + int TAG_BLOC = 1651273571; + int TAG_BSLN = 1651731566; + int TAG_CFF = 1128678944; + int TAG_CMAP = 1668112752; + int TAG_CVAR = 1668702578; + int TAG_CVT = 1668707360; + int TAG_DSIG = 1146308935; + int TAG_EBDT = 1161970772; + int TAG_EBLC = 1161972803; + int TAG_EBSC = 1161974595; + int TAG_FDSC = 1717859171; + int TAG_FEAT = 1717920116; + int TAG_FMTX = 1718449272; + int TAG_FPGM = 1718642541; + int TAG_FVAR = 1719034226; + int TAG_GASP = 1734439792; + int TAG_GDEF = 1195656518; + int TAG_GLYF = 1735162214; + int TAG_GPOS = 1196445523; + int TAG_GSUB = 1196643650; + int TAG_GVAR = 1735811442; + int TAG_HDMX = 1751412088; + int TAG_HEAD = 1751474532; + int TAG_HHEA = 1751672161; + int TAG_HMTX = 1752003704; + int TAG_JSTF = 1246975046; + int TAG_JUST = 1786082164; + int TAG_KERN = 1801810542; + int TAG_LCAR = 1818452338; + int TAG_LOCA = 1819239265; + int TAG_LTSH = 1280594760; + int TAG_MAXP = 1835104368; + int TAG_MMFX = 1296909912; + int TAG_MMSD = 1296913220; + int TAG_MORT = 1836020340; + int TAG_NAME = 1851878757; + int TAG_OPBD = 1836020340; + int TAG_OS2 = 1330851634; + int TAG_PCLT = 1346587732; + int TAG_POST = 1886352244; + int TAG_PREP = 1886545264; + int TAG_PROP = 1886547824; + int TAG_TRAK = 1953653099; + int TAG_TYP1 = 1954115633; + int TAG_VDMX = 1447316824; + int TAG_VHEA = 1986553185; + int TAG_VMTX = 1986884728; + + byte[] getFontTable (int sfntTag); + + byte[] getFontTable (int sfntTag, int offset, int count); + + byte[] getFontTable (String strSfntTag); + + byte[] getFontTable (String strSfntTag, int offset, int count); + + int getFontTableSize (int sfntTag); + + int getFontTableSize (String strSfntTag); + + int getVersion (); +} diff --git a/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java b/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java new file mode 100644 index 0000000..6d64dec --- /dev/null +++ b/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java @@ -0,0 +1,105 @@ +/* ShapeGraphicAttribute.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 java.awt.font; + +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; + +public final class ShapeGraphicAttribute extends GraphicAttribute +{ + public static final boolean FILL = false; + public static final boolean STROKE = true; + + private Shape shape; + private boolean stroke; + + public ShapeGraphicAttribute (Shape shape, int alignment, boolean stroke) + { + super (alignment); + this.shape = shape; + this.stroke = stroke; + } + + public void draw (Graphics2D graphics, float x, float y) + { + throw new Error ("not implemented"); + } + + public boolean equals (Object obj) + { + if (! (obj instanceof ShapeGraphicAttribute)) + return false; + + return equals ((ShapeGraphicAttribute) obj); + } + + public boolean equals (ShapeGraphicAttribute rhs) + { + return (shape.equals (rhs.shape) + && getAlignment () == rhs.getAlignment () + && stroke == rhs.stroke); + } + + public float getAdvance () + { + throw new Error ("not implemented"); + } + + public float getAscent () + { + throw new Error ("not implemented"); + } + + public Rectangle2D getBounds () + { + return shape.getBounds2D (); + } + + public float getDescent () + { + throw new Error ("not implemented"); + } + + public int hashCode () + { + // FIXME: Check what SUN does here + return shape.hashCode (); + } +} diff --git a/libjava/classpath/java/awt/font/TextAttribute.java b/libjava/classpath/java/awt/font/TextAttribute.java new file mode 100644 index 0000000..6f5ed59 --- /dev/null +++ b/libjava/classpath/java/awt/font/TextAttribute.java @@ -0,0 +1,309 @@ +/* TextAttribute.java -- + 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 java.awt.font; + +import java.io.InvalidObjectException; +import java.text.AttributedCharacterIterator; + +/** + * Attributes (and associated values) that can be used to define an + * {@link java.text.AttributedString}. + */ +public final class TextAttribute extends AttributedCharacterIterator.Attribute +{ + private static final long serialVersionUID = 7744112784117861702L; + + /** A key for the background paint attribute. */ + public static final TextAttribute BACKGROUND = + new TextAttribute("background"); + + /** A key for the BIDI_EMBEDDING attribute. */ + public static final TextAttribute BIDI_EMBEDDING = + new TextAttribute("bidi_embedding"); + + /** A key for the CHAR_REPLACEMENT attribute. */ + public static final TextAttribute CHAR_REPLACEMENT = + new TextAttribute("char_replacement"); + + /** A key for the FAMILY attribute. */ + public static final TextAttribute FAMILY = new TextAttribute("family"); + + /** A key for the font attribute. */ + public static final TextAttribute FONT = new TextAttribute("font"); + + /** A key for the foreground paint attribute. */ + public static final TextAttribute FOREGROUND = + new TextAttribute("foreground"); + + /** A key for the INPUT_METHOD_HIGHLIGHT attribute. */ + public static final TextAttribute INPUT_METHOD_HIGHLIGHT = + new TextAttribute("input method highlight"); + + /** A key for the INPUT_METHOD_UNDERLINE attribute. */ + public static final TextAttribute INPUT_METHOD_UNDERLINE = + new TextAttribute("input method underline"); + + /** A key for the text justification attribute. */ + public static final TextAttribute JUSTIFICATION = + new TextAttribute("justification"); + + /** + * A value that can be used with the {@link #JUSTIFICATION} attribute to + * indicate full justification of the text. + */ + public static final Float JUSTIFICATION_FULL = new Float(1.0); + + /** + * A value that can be used with the {@link #JUSTIFICATION} attribute to + * indicate no justification of the text. + */ + public static final Float JUSTIFICATION_NONE = new Float(0.0); + + /** A key for the NUMERIC_SHAPING attribute. */ + public static final TextAttribute NUMERIC_SHAPING = + new TextAttribute("numeric_shaping"); + + /** A key for the POSTURE attribute. */ + public static final TextAttribute POSTURE = new TextAttribute("posture"); + + /** A value that can be used with the {@link #POSTURE} attribute. */ + public static final Float POSTURE_OBLIQUE = new Float(0.2); + + /** A value that can be used with the {@link #POSTURE} attribute. */ + public static final Float POSTURE_REGULAR = new Float(0.0); + + /** A key for the RUN_DIRECTION attribute. */ + public static final TextAttribute RUN_DIRECTION = + new TextAttribute("run_direction"); + + /** A value that can be used with the {@link #RUN_DIRECTION} attribute. */ + public static final Boolean RUN_DIRECTION_LTR = Boolean.FALSE; + + /** A value that can be used with the {@link #RUN_DIRECTION} attribute. */ + public static final Boolean RUN_DIRECTION_RTL = Boolean.TRUE; + + /** A key for the text size attribute. */ + public static final TextAttribute SIZE = new TextAttribute("size"); + + /** A key for the STRIKETHROUGH attribute. */ + public static final TextAttribute STRIKETHROUGH = + new TextAttribute("strikethrough"); + + /** A value that can be used with the {@link #STRIKETHROUGH} attribute. */ + public static final Boolean STRIKETHROUGH_ON = Boolean.TRUE; + + /** A key for the SUPERSCRIPT attribute. */ + public static final TextAttribute SUPERSCRIPT = + new TextAttribute("superscript"); + + /** A value that can be used with the {@link #SUPERSCRIPT} attribute. */ + public static final Integer SUPERSCRIPT_SUB = new Integer(-1); + + /** A value that can be used with the {@link #SUPERSCRIPT} attribute. */ + public static final Integer SUPERSCRIPT_SUPER = new Integer(1); + + /** A key for the SWAP_COLORS attribute. */ + public static final TextAttribute SWAP_COLORS = + new TextAttribute("swap_colors"); + + /** A value that can be used with the {@link #SWAP_COLORS} attribute. */ + public static final Boolean SWAP_COLORS_ON = Boolean.TRUE; + + /** A key for the TRANFORM attribute. */ + public static final TextAttribute TRANSFORM = new TextAttribute("transform"); + + /** A key for the UNDERLINE attribute. */ + public static final TextAttribute UNDERLINE = new TextAttribute("underline"); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_DASHED = new Integer(5); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_DOTTED = new Integer(3); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_GRAY = new Integer(4); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_ONE_PIXEL = new Integer(1); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_TWO_PIXEL = new Integer(2); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_ON = new Integer(0); + + /** A key for the WEIGHT attribute. */ + public static final TextAttribute WEIGHT = new TextAttribute("weight"); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_BOLD = new Float(2.0); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_DEMIBOLD = new Float(1.75); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_DEMILIGHT = new Float(0.875); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_EXTRA_LIGHT = new Float(0.5); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_EXTRABOLD = new Float(2.5); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_HEAVY = new Float(2.25); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_LIGHT = new Float(0.75); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_MEDIUM = new Float(1.5); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_REGULAR = new Float(1.0); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_SEMIBOLD = new Float(1.25); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_ULTRABOLD = new Float(2.75); + + /** A key for the WIDTH attribute. */ + public static final TextAttribute WIDTH = new TextAttribute("width"); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_CONDENSED = new Float(0.75); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_EXTENDED = new Float(1.5); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_REGULAR = new Float(1.0); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_SEMI_CONDENSED = new Float(0.875); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_SEMI_EXTENDED = new Float(1.25); + + /** + * Creates a new attribute. + * + * @param name the name. + */ + protected TextAttribute(String name) + { + super(name); + } + + /** + * After deserialization, this method ensures that only one instance of + * each attribute is used. + * + * @return The (single) attribute instance. + * + * @throws InvalidObjectException if the attribute is not recognised. + */ + protected Object readResolve() + throws InvalidObjectException + { + if (this.getName().equals("background")) + return BACKGROUND; + + if (this.getName().equals("bidi_embedding")) + return BIDI_EMBEDDING; + + if (this.getName().equals("char_replacement")) + return CHAR_REPLACEMENT; + + if (this.getName().equals("family")) + return FAMILY; + + if (this.getName().equals("font")) + return FONT; + + if (this.getName().equals("foreground")) + return FOREGROUND; + + if (this.getName().equals("input method highlight")) + return INPUT_METHOD_HIGHLIGHT; + + if (this.getName().equals("input method underline")) + return INPUT_METHOD_UNDERLINE; + + if (this.getName().equals("justification")) + return JUSTIFICATION; + + if (this.getName().equals("numeric_shaping")) + return NUMERIC_SHAPING; + + if (this.getName().equals("posture")) + return POSTURE; + + if (this.getName().equals("run_direction")) + return RUN_DIRECTION; + + if (this.getName().equals("size")) + return SIZE; + + if (this.getName().equals("strikethrough")) + return STRIKETHROUGH; + + if (this.getName().equals("superscript")) + return SUPERSCRIPT; + + if (this.getName().equals("swap_colors")) + return SWAP_COLORS; + + if (this.getName().equals("transform")) + return TRANSFORM; + + if (this.getName().equals("underline")) + return UNDERLINE; + + if (this.getName().equals("weight")) + return WEIGHT; + + if (this.getName().equals("width")) + return WIDTH; + + throw new InvalidObjectException("Can't resolve Attribute: " + getName()); + } +} diff --git a/libjava/classpath/java/awt/font/TextHitInfo.java b/libjava/classpath/java/awt/font/TextHitInfo.java new file mode 100644 index 0000000..2b23e19 --- /dev/null +++ b/libjava/classpath/java/awt/font/TextHitInfo.java @@ -0,0 +1,125 @@ +/* TextHitInfo.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 java.awt.font; + +/** + * @author John Leuner (jewel@debian.org) + */ +public final class TextHitInfo +{ + private int charIndex; + private boolean leadingEdge; + + TextHitInfo (int charIndex, boolean leadingEdge) + { + this.charIndex = charIndex; + this.leadingEdge = leadingEdge; + } + + public int getCharIndex() + { + return charIndex; + } + + public boolean isLeadingEdge() + { + return leadingEdge; + } + + public int getInsertionIndex() + { + return (leadingEdge ? charIndex : charIndex + 1); + } + + public int hashCode() + { + return charIndex; + } + + public boolean equals(Object obj) + { + if(obj instanceof TextHitInfo) + return this.equals((TextHitInfo) obj); + + return false; + } + + public boolean equals(TextHitInfo hitInfo) + { + return (charIndex == hitInfo.getCharIndex ()) + && (leadingEdge == hitInfo.isLeadingEdge ()); + } + + public static TextHitInfo leading(int charIndex) + { + return new TextHitInfo (charIndex, true); + } + + public static TextHitInfo trailing(int charIndex) + { + return new TextHitInfo (charIndex, false); + } + + public static TextHitInfo beforeOffset(int offset) + { + return new TextHitInfo (offset, false); + } + + public static TextHitInfo afterOffset(int offset) + { + return new TextHitInfo (offset, true); + } + + public TextHitInfo getOtherHit() + { + return (leadingEdge ? trailing (charIndex - 1) : leading (charIndex + 1)); + } + + public TextHitInfo getOffsetHit(int offset) + { + return new TextHitInfo (charIndex + offset, leadingEdge); + } + + public String toString() + { + return "TextHitInfo[" + + charIndex + + (leadingEdge ? "L" : "T" ) + + "]"; + } +} diff --git a/libjava/classpath/java/awt/font/TextLayout.java b/libjava/classpath/java/awt/font/TextLayout.java new file mode 100644 index 0000000..bb64161 --- /dev/null +++ b/libjava/classpath/java/awt/font/TextLayout.java @@ -0,0 +1,332 @@ +/* TextLayout.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 java.awt.font; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.peer.ClasspathTextLayoutPeer; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.util.Map; + +/** + * @author Michael Koch + */ +public final class TextLayout implements Cloneable +{ + public static final CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy (); + ClasspathTextLayoutPeer peer; + + public static class CaretPolicy + { + public CaretPolicy () + { + // Do nothing here. + } + + public TextHitInfo getStrongCaret (TextHitInfo hit1, TextHitInfo hit2, + TextLayout layout) + { + return layout.peer.getStrongCaret(hit1, hit2); + } + } + + public TextLayout (AttributedCharacterIterator text, FontRenderContext frc) + { + AttributedString as = new AttributedString (text); + ClasspathToolkit tk = (ClasspathToolkit)(Toolkit.getDefaultToolkit ()); + peer = tk.getClasspathTextLayoutPeer(as, frc); + } + + public TextLayout (String string, Font font, FontRenderContext frc) + { + AttributedString as = new AttributedString (string); + as.addAttribute (TextAttribute.FONT, font); + ClasspathToolkit tk = (ClasspathToolkit)(Toolkit.getDefaultToolkit ()); + peer = tk.getClasspathTextLayoutPeer(as, frc); + } + + public TextLayout (String string, Map attributes, FontRenderContext frc) + { + AttributedString as = new AttributedString (string, attributes); + ClasspathToolkit tk = (ClasspathToolkit)(Toolkit.getDefaultToolkit ()); + peer = tk.getClasspathTextLayoutPeer(as, frc); + } + + protected Object clone () + { + try + { + TextLayout tl = (TextLayout) super.clone (); + tl.peer = (ClasspathTextLayoutPeer) this.peer.clone(); + return tl; + } + catch (CloneNotSupportedException e) + { + // This should never occur + throw new InternalError (); + } + } + + + public void draw (Graphics2D g2, float x, float y) + { + peer.draw(g2, x, y); + } + + public boolean equals (Object obj) + { + if (! (obj instanceof TextLayout)) + return false; + + return equals ((TextLayout) obj); + } + + public boolean equals (TextLayout tl) + { + return this.peer.equals(tl.peer); + } + + public float getAdvance () + { + return peer.getAdvance(); + } + + public float getAscent () + { + return peer.getAscent(); + } + + public byte getBaseline () + { + return peer.getBaseline(); + } + + public float[] getBaselineOffsets () + { + return peer.getBaselineOffsets(); + } + + public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint) + { + return peer.getBlackBoxBounds(firstEndpoint, secondEndpoint); + } + + public Rectangle2D getBounds() + { + return peer.getBounds(); + } + + public float[] getCaretInfo (TextHitInfo hit) + { + return getCaretInfo(hit, getBounds()); + } + + public float[] getCaretInfo (TextHitInfo hit, Rectangle2D bounds) + { + return peer.getCaretInfo(hit, bounds); + } + + public Shape getCaretShape (TextHitInfo hit) + { + return getCaretShape(hit, getBounds()); + } + + public Shape getCaretShape (TextHitInfo hit, Rectangle2D bounds) + { + return peer.getCaretShape(hit, bounds); + } + + public Shape[] getCaretShapes (int offset) + { + return getCaretShapes(offset, getBounds()); + } + + public Shape[] getCaretShapes (int offset, Rectangle2D bounds) + { + return getCaretShapes(offset, getBounds(), DEFAULT_CARET_POLICY); + } + + public Shape[] getCaretShapes (int offset, Rectangle2D bounds, + TextLayout.CaretPolicy policy) + { + return peer.getCaretShapes(offset, bounds, policy); + } + + public int getCharacterCount () + { + return peer.getCharacterCount(); + } + + public byte getCharacterLevel (int index) + { + return peer.getCharacterLevel(index); + } + + public float getDescent () + { + return peer.getDescent(); + } + + public TextLayout getJustifiedLayout (float justificationWidth) + { + return peer.getJustifiedLayout(justificationWidth); + } + + public float getLeading () + { + return peer.getLeading(); + } + + public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint) + { + return getLogicalHighlightShape (firstEndpoint, secondEndpoint, getBounds()); + } + + public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint, + Rectangle2D bounds) + { + return peer.getLogicalHighlightShape(firstEndpoint, secondEndpoint, bounds); + } + + public int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint, + TextHitInfo secondEndpoint) + { + return peer.getLogicalRangesForVisualSelection(firstEndpoint, secondEndpoint); + } + + public TextHitInfo getNextLeftHit (int offset) + { + return getNextLeftHit(offset, DEFAULT_CARET_POLICY); + } + + public TextHitInfo getNextLeftHit (int offset, TextLayout.CaretPolicy policy) + { + return peer.getNextLeftHit(offset, policy); + } + + public TextHitInfo getNextLeftHit (TextHitInfo hit) + { + return getNextLeftHit(hit.getCharIndex()); + } + + public TextHitInfo getNextRightHit (int offset) + { + return getNextRightHit(offset, DEFAULT_CARET_POLICY); + } + + public TextHitInfo getNextRightHit (int offset, TextLayout.CaretPolicy policy) + { + return peer.getNextRightHit(offset, policy); + } + + public TextHitInfo getNextRightHit (TextHitInfo hit) + { + return getNextRightHit(hit.getCharIndex()); + } + + public Shape getOutline (AffineTransform tx) + { + return peer.getOutline(tx); + } + + public float getVisibleAdvance () + { + return peer.getVisibleAdvance(); + } + + public Shape getVisualHighlightShape (TextHitInfo firstEndpoint, + TextHitInfo secondEndpoint) + { + return getVisualHighlightShape(firstEndpoint, secondEndpoint, getBounds()); + } + + public Shape getVisualHighlightShape (TextHitInfo firstEndpoint, + TextHitInfo secondEndpoint, + Rectangle2D bounds) + { + return peer.getVisualHighlightShape(firstEndpoint, secondEndpoint, bounds); + } + + public TextHitInfo getVisualOtherHit (TextHitInfo hit) + { + return peer.getVisualOtherHit(hit); + } + + protected void handleJustify (float justificationWidth) + { + peer.handleJustify(justificationWidth); + } + + public int hashCode () + { + return peer.hashCode(); + } + + public TextHitInfo hitTestChar (float x, float y) + { + return hitTestChar(x, y, getBounds()); + } + + public TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds) + { + return peer.hitTestChar(x, y, bounds); + } + + public boolean isLeftToRight () + { + return peer.isLeftToRight(); + } + + public boolean isVertical () + { + return peer.isVertical(); + } + + public String toString () + { + return peer.toString(); + } +} diff --git a/libjava/classpath/java/awt/font/TextMeasurer.java b/libjava/classpath/java/awt/font/TextMeasurer.java new file mode 100644 index 0000000..7fcdc87 --- /dev/null +++ b/libjava/classpath/java/awt/font/TextMeasurer.java @@ -0,0 +1,97 @@ +/* TextMeasurer.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 java.awt.font; + +import java.text.AttributedCharacterIterator; + +/** + * @author Michael Koch + * @since 1.3 + */ +public final class TextMeasurer implements Cloneable +{ + private AttributedCharacterIterator ci; + private FontRenderContext frc; + + public TextMeasurer (AttributedCharacterIterator text, FontRenderContext frc) + { + this.ci = text; + this.frc = frc; + } + + protected Object clone () + { + try + { + return super.clone (); + } + catch (CloneNotSupportedException e) + { + // This may never occur + throw new InternalError (); + } + } + + public void deleteChar (AttributedCharacterIterator newParagraph, + int deletePos) + { + throw new Error ("not implemented"); + } + + public float getAdvanceBetween (int start, int limit) + { + throw new Error ("not implemented"); + } + + public TextLayout getLayout (int start, int limit) + { + throw new Error ("not implemented"); + } + + public int getLineBreakIndex (int start, float maxAdvance) + { + throw new Error ("not implemented"); + } + + public void insertChar (AttributedCharacterIterator newParagraph, + int insertPos) + { + throw new Error ("not implemented"); + } +} diff --git a/libjava/classpath/java/awt/font/TransformAttribute.java b/libjava/classpath/java/awt/font/TransformAttribute.java new file mode 100644 index 0000000..977cafa --- /dev/null +++ b/libjava/classpath/java/awt/font/TransformAttribute.java @@ -0,0 +1,100 @@ +/* TransformAttribute.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 java.awt.font; + +import java.awt.geom.AffineTransform; +import java.io.Serializable; + +/** + * This class provides a mechanism for using an {@link AffineTransform} as + * an immutable attribute (for example, in the + * {@link java.text.AttributedString} class). Any transform passed to + * this class is copied before being stored, and any transform handed out + * by this class is a copy of the stored transform. In this way, it is + * not possible to modify the stored transform. + * + * @author Michael Koch + */ +public final class TransformAttribute implements Serializable +{ + private static final long serialVersionUID = 3356247357827709530L; + + private AffineTransform affineTransform; + + /** + * Creates a new attribute that contains a copy of the given transform. + * + * @param transform the transform (null not permitted). + * + * @throws IllegalArgumentException if transform is + * null. + */ + public TransformAttribute (AffineTransform transform) + { + if (transform == null) + { + throw new IllegalArgumentException("Null 'transform' not permitted."); + } + this.affineTransform = new AffineTransform (transform); + } + + /** + * Returns a copy of the transform contained by this attribute. + * + * @return A copy of the transform. + */ + public AffineTransform getTransform () + { + return (AffineTransform) affineTransform.clone(); + } + + /** + * Returns true if the transform contained by this attribute is + * an identity transform, and false otherwise. + * + * @return true if the transform contained by this attribute is + * an identity transform, and false otherwise. + * + * @since 1.4 + */ + public boolean isIdentity () + { + return (affineTransform == null ? false : affineTransform.isIdentity ()); + } +} diff --git a/libjava/classpath/java/awt/font/package.html b/libjava/classpath/java/awt/font/package.html new file mode 100644 index 0000000..8c3c61a --- /dev/null +++ b/libjava/classpath/java/awt/font/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.font + + +

Representations of different kind of characters and fonts.

+ + + diff --git a/libjava/classpath/java/awt/geom/AffineTransform.java b/libjava/classpath/java/awt/geom/AffineTransform.java new file mode 100644 index 0000000..4d1a4d6 --- /dev/null +++ b/libjava/classpath/java/awt/geom/AffineTransform.java @@ -0,0 +1,1487 @@ +/* AffineTransform.java -- transform coordinates between two 2-D spaces + Copyright (C) 2000, 2001, 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 java.awt.geom; + +import java.awt.Shape; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; + +/** + * This class represents an affine transformation between two coordinate + * spaces in 2 dimensions. Such a transform preserves the "straightness" + * and "parallelness" of lines. The transform is built from a sequence of + * translations, scales, flips, rotations, and shears. + * + *

The transformation can be represented using matrix math on a 3x3 array. + * Given (x,y), the transformation (x',y') can be found by: + *

+ * [ x']   [ m00 m01 m02 ] [ x ]   [ m00*x + m01*y + m02 ]
+ * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10*x + m11*y + m12 ]
+ * [ 1 ]   [  0   0   1  ] [ 1 ]   [          1          ]
+ * 
+ * The bottom row of the matrix is constant, so a transform can be uniquely + * represented (as in {@link #toString()}) by + * "[[m00, m01, m02], [m10, m11, m12]]". + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status partially updated to 1.4, still has some problems + */ +public class AffineTransform implements Cloneable, Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 1330973210523860834L; + + /** + * The transformation is the identity (x' = x, y' = y). All other transforms + * have either a combination of the appropriate transform flag bits for + * their type, or the type GENERAL_TRANSFORM. + * + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #getType() + */ + public static final int TYPE_IDENTITY = 0; + + /** + * The transformation includes a translation - shifting in the x or y + * direction without changing length or angles. + * + * @see #TYPE_IDENTITY + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #getType() + */ + public static final int TYPE_TRANSLATION = 1; + + /** + * The transformation includes a uniform scale - length is scaled in both + * the x and y directions by the same amount, without affecting angles. + * This is mutually exclusive with TYPE_GENERAL_SCALE. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #TYPE_MASK_SCALE + * @see #getType() + */ + public static final int TYPE_UNIFORM_SCALE = 2; + + /** + * The transformation includes a general scale - length is scaled in either + * or both the x and y directions, but by different amounts; without + * affecting angles. This is mutually exclusive with TYPE_UNIFORM_SCALE. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #TYPE_MASK_SCALE + * @see #getType() + */ + public static final int TYPE_GENERAL_SCALE = 4; + + /** + * This constant checks if either variety of scale transform is performed. + * + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + */ + public static final int TYPE_MASK_SCALE = 6; + + /** + * The transformation includes a flip about an axis, swapping between + * right-handed and left-handed coordinate systems. In a right-handed + * system, the positive x-axis rotates counter-clockwise to the positive + * y-axis; in a left-handed system it rotates clockwise. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #getType() + */ + public static final int TYPE_FLIP = 64; + + /** + * The transformation includes a rotation of a multiple of 90 degrees (PI/2 + * radians). Angles are rotated, but length is preserved. This is mutually + * exclusive with TYPE_GENERAL_ROTATION. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #TYPE_MASK_ROTATION + * @see #getType() + */ + public static final int TYPE_QUADRANT_ROTATION = 8; + + /** + * The transformation includes a rotation by an arbitrary angle. Angles are + * rotated, but length is preserved. This is mutually exclusive with + * TYPE_QUADRANT_ROTATION. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #TYPE_MASK_ROTATION + * @see #getType() + */ + public static final int TYPE_GENERAL_ROTATION = 16; + + /** + * This constant checks if either variety of rotation is performed. + * + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + */ + public static final int TYPE_MASK_ROTATION = 24; + + /** + * The transformation is an arbitrary conversion of coordinates which + * could not be decomposed into the other TYPEs. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #getType() + */ + public static final int TYPE_GENERAL_TRANSFORM = 32; + + /** + * The X coordinate scaling element of the transform matrix. + * + * @serial matrix[0,0] + */ + private double m00; + + /** + * The Y coordinate shearing element of the transform matrix. + * + * @serial matrix[1,0] + */ + private double m10; + + /** + * The X coordinate shearing element of the transform matrix. + * + * @serial matrix[0,1] + */ + private double m01; + + /** + * The Y coordinate scaling element of the transform matrix. + * + * @serial matrix[1,1] + */ + private double m11; + + /** + * The X coordinate translation element of the transform matrix. + * + * @serial matrix[0,2] + */ + private double m02; + + /** + * The Y coordinate translation element of the transform matrix. + * + * @serial matrix[1,2] + */ + private double m12; + + /** The type of this transform. */ + private transient int type; + + /** + * Construct a new identity transform: + *
+   * [ 1 0 0 ]
+   * [ 0 1 0 ]
+   * [ 0 0 1 ]
+   * 
+ */ + public AffineTransform() + { + m00 = m11 = 1; + } + + /** + * Create a new transform which copies the given one. + * + * @param tx the transform to copy + * @throws NullPointerException if tx is null + */ + public AffineTransform(AffineTransform tx) + { + setTransform(tx); + } + + /** + * Construct a transform with the given matrix entries: + *
+   * [ m00 m01 m02 ]
+   * [ m10 m11 m12 ]
+   * [  0   0   1  ]
+   * 
+ * + * @param m00 the x scaling component + * @param m10 the y shearing component + * @param m01 the x shearing component + * @param m11 the y scaling component + * @param m02 the x translation component + * @param m12 the y translation component + */ + public AffineTransform(float m00, float m10, + float m01, float m11, + float m02, float m12) + { + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m11 = m11; + this.m02 = m02; + this.m12 = m12; + updateType(); + } + + /** + * Construct a transform from a sequence of float entries. The array must + * have at least 4 entries, which has a translation factor of 0; or 6 + * entries, for specifying all parameters: + *
+   * [ f[0] f[2] (f[4]) ]
+   * [ f[1] f[3] (f[5]) ]
+   * [  0     0    1    ]
+   * 
+ * + * @param f the matrix to copy from, with at least 4 (6) entries + * @throws NullPointerException if f is null + * @throws ArrayIndexOutOfBoundsException if f is too small + */ + public AffineTransform(float[] f) + { + m00 = f[0]; + m10 = f[1]; + m01 = f[2]; + m11 = f[3]; + if (f.length >= 6) + { + m02 = f[4]; + m12 = f[5]; + } + updateType(); + } + + /** + * Construct a transform with the given matrix entries: + *
+   * [ m00 m01 m02 ]
+   * [ m10 m11 m12 ]
+   * [  0   0   1  ]
+   * 
+ * + * @param m00 the x scaling component + * @param m10 the y shearing component + * @param m01 the x shearing component + * @param m11 the y scaling component + * @param m02 the x translation component + * @param m12 the y translation component + */ + public AffineTransform(double m00, double m10, double m01, + double m11, double m02, double m12) + { + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m11 = m11; + this.m02 = m02; + this.m12 = m12; + updateType(); + } + + /** + * Construct a transform from a sequence of double entries. The array must + * have at least 4 entries, which has a translation factor of 0; or 6 + * entries, for specifying all parameters: + *
+   * [ d[0] d[2] (d[4]) ]
+   * [ d[1] d[3] (d[5]) ]
+   * [  0     0    1    ]
+   * 
+ * + * @param d the matrix to copy from, with at least 4 (6) entries + * @throws NullPointerException if d is null + * @throws ArrayIndexOutOfBoundsException if d is too small + */ + public AffineTransform(double[] d) + { + m00 = d[0]; + m10 = d[1]; + m01 = d[2]; + m11 = d[3]; + if (d.length >= 6) + { + m02 = d[4]; + m12 = d[5]; + } + updateType(); + } + + /** + * Returns a translation transform: + *
+   * [ 1 0 tx ]
+   * [ 0 1 ty ]
+   * [ 0 0 1  ]
+   * 
+ * + * @param tx the x translation distance + * @param ty the y translation distance + * @return the translating transform + */ + public static AffineTransform getTranslateInstance(double tx, double ty) + { + AffineTransform t = new AffineTransform(); + t.setToTranslation(tx, ty); + return t; + } + + /** + * Returns a rotation transform. A positive angle (in radians) rotates + * the positive x-axis to the positive y-axis: + *
+   * [ cos(theta) -sin(theta) 0 ]
+   * [ sin(theta)  cos(theta) 0 ]
+   * [     0           0      1 ]
+   * 
+ * + * @param theta the rotation angle + * @return the rotating transform + */ + public static AffineTransform getRotateInstance(double theta) + { + AffineTransform t = new AffineTransform(); + t.setToRotation(theta); + return t; + } + + /** + * Returns a rotation transform about a point. A positive angle (in radians) + * rotates the positive x-axis to the positive y-axis. This is the same + * as calling: + *
+   * AffineTransform tx = new AffineTransform();
+   * tx.setToTranslation(x, y);
+   * tx.rotate(theta);
+   * tx.translate(-x, -y);
+   * 
+ * + *

The resulting matrix is: + *

+   * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
+   * [ sin(theta)  cos(theta) y-x*sin-y*cos ]
+   * [     0           0            1       ]
+   * 
+ * + * @param theta the rotation angle + * @param x the x coordinate of the pivot point + * @param y the y coordinate of the pivot point + * @return the rotating transform + */ + public static AffineTransform getRotateInstance(double theta, + double x, double y) + { + AffineTransform t = new AffineTransform(); + t.setToTranslation(x, y); + t.rotate(theta); + t.translate(-x, -y); + return t; + } + + /** + * Returns a scaling transform: + *
+   * [ sx 0  0 ]
+   * [ 0  sy 0 ]
+   * [ 0  0  1 ]
+   * 
+ * + * @param sx the x scaling factor + * @param sy the y scaling factor + * @return the scaling transform + */ + public static AffineTransform getScaleInstance(double sx, double sy) + { + AffineTransform t = new AffineTransform(); + t.setToScale(sx, sy); + return t; + } + + /** + * Returns a shearing transform (points are shifted in the x direction based + * on a factor of their y coordinate, and in the y direction as a factor of + * their x coordinate): + *
+   * [  1  shx 0 ]
+   * [ shy  1  0 ]
+   * [  0   0  1 ]
+   * 
+ * + * @param shx the x shearing factor + * @param shy the y shearing factor + * @return the shearing transform + */ + public static AffineTransform getShearInstance(double shx, double shy) + { + AffineTransform t = new AffineTransform(); + t.setToShear(shx, shy); + return t; + } + + /** + * Returns the type of this transform. The result is always valid, although + * it may not be the simplest interpretation (in other words, there are + * sequences of transforms which reduce to something simpler, which this + * does not always detect). The result is either TYPE_GENERAL_TRANSFORM, + * or a bit-wise combination of TYPE_TRANSLATION, the mutually exclusive + * TYPE_*_ROTATIONs, and the mutually exclusive TYPE_*_SCALEs. + * + * @return The type. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + */ + public int getType() + { + return type; + } + + /** + * Return the determinant of this transform matrix. If the determinant is + * non-zero, the transform is invertible; otherwise operations which require + * an inverse throw a NoninvertibleTransformException. A result very near + * zero, due to rounding errors, may indicate that inversion results do not + * carry enough precision to be meaningful. + * + *

If this is a uniform scale transformation, the determinant also + * represents the squared value of the scale. Otherwise, it carries little + * additional meaning. The determinant is calculated as: + *

+   * | m00 m01 m02 |
+   * | m10 m11 m12 | = m00 * m11 - m01 * m10
+   * |  0   0   1  |
+   * 
+ * + * @return the determinant + * @see #createInverse() + */ + public double getDeterminant() + { + return m00 * m11 - m01 * m10; + } + + /** + * Return the matrix of values used in this transform. If the matrix has + * fewer than 6 entries, only the scale and shear factors are returned; + * otherwise the translation factors are copied as well. The resulting + * values are: + *
+   * [ d[0] d[2] (d[4]) ]
+   * [ d[1] d[3] (d[5]) ]
+   * [  0     0    1    ]
+   * 
+ * + * @param d the matrix to store the results into; with 4 (6) entries + * @throws NullPointerException if d is null + * @throws ArrayIndexOutOfBoundsException if d is too small + */ + public void getMatrix(double[] d) + { + d[0] = m00; + d[1] = m10; + d[2] = m01; + d[3] = m11; + if (d.length >= 6) + { + d[4] = m02; + d[5] = m12; + } + } + + /** + * Returns the X coordinate scaling factor of the matrix. + * + * @return m00 + * @see #getMatrix(double[]) + */ + public double getScaleX() + { + return m00; + } + + /** + * Returns the Y coordinate scaling factor of the matrix. + * + * @return m11 + * @see #getMatrix(double[]) + */ + public double getScaleY() + { + return m11; + } + + /** + * Returns the X coordinate shearing factor of the matrix. + * + * @return m01 + * @see #getMatrix(double[]) + */ + public double getShearX() + { + return m01; + } + + /** + * Returns the Y coordinate shearing factor of the matrix. + * + * @return m10 + * @see #getMatrix(double[]) + */ + public double getShearY() + { + return m10; + } + + /** + * Returns the X coordinate translation factor of the matrix. + * + * @return m02 + * @see #getMatrix(double[]) + */ + public double getTranslateX() + { + return m02; + } + + /** + * Returns the Y coordinate translation factor of the matrix. + * + * @return m12 + * @see #getMatrix(double[]) + */ + public double getTranslateY() + { + return m12; + } + + /** + * Concatenate a translation onto this transform. This is equivalent, but + * more efficient than + * concatenate(AffineTransform.getTranslateInstance(tx, ty)). + * + * @param tx the x translation distance + * @param ty the y translation distance + * @see #getTranslateInstance(double, double) + * @see #concatenate(AffineTransform) + */ + public void translate(double tx, double ty) + { + m02 += tx * m00 + ty * m01; + m12 += tx * m10 + ty * m11; + updateType(); + } + + /** + * Concatenate a rotation onto this transform. This is equivalent, but + * more efficient than + * concatenate(AffineTransform.getRotateInstance(theta)). + * + * @param theta the rotation angle + * @see #getRotateInstance(double) + * @see #concatenate(AffineTransform) + */ + public void rotate(double theta) + { + double c = Math.cos(theta); + double s = Math.sin(theta); + double n00 = m00 * c + m01 * s; + double n01 = m00 * -s + m01 * c; + double n10 = m10 * c + m11 * s; + double n11 = m10 * -s + m11 * c; + m00 = n00; + m01 = n01; + m10 = n10; + m11 = n11; + updateType(); + } + + /** + * Concatenate a rotation about a point onto this transform. This is + * equivalent, but more efficient than + * concatenate(AffineTransform.getRotateInstance(theta, x, y)). + * + * @param theta the rotation angle + * @param x the x coordinate of the pivot point + * @param y the y coordinate of the pivot point + * @see #getRotateInstance(double, double, double) + * @see #concatenate(AffineTransform) + */ + public void rotate(double theta, double x, double y) + { + translate(x, y); + rotate(theta); + translate(-x, -y); + } + + /** + * Concatenate a scale onto this transform. This is equivalent, but more + * efficient than + * concatenate(AffineTransform.getScaleInstance(sx, sy)). + * + * @param sx the x scaling factor + * @param sy the y scaling factor + * @see #getScaleInstance(double, double) + * @see #concatenate(AffineTransform) + */ + public void scale(double sx, double sy) + { + m00 *= sx; + m01 *= sy; + m10 *= sx; + m11 *= sy; + updateType(); + } + + /** + * Concatenate a shearing onto this transform. This is equivalent, but more + * efficient than + * concatenate(AffineTransform.getShearInstance(sx, sy)). + * + * @param shx the x shearing factor + * @param shy the y shearing factor + * @see #getShearInstance(double, double) + * @see #concatenate(AffineTransform) + */ + public void shear(double shx, double shy) + { + double n00 = m00 + (shy * m01); + double n01 = m01 + (shx * m00); + double n10 = m10 + (shy * m11); + double n11 = m11 + (shx * m10); + m00 = n00; + m01 = n01; + m10 = n10; + m11 = n11; + updateType(); + } + + /** + * Reset this transform to the identity (no transformation): + *
+   * [ 1 0 0 ]
+   * [ 0 1 0 ]
+   * [ 0 0 1 ]
+   * 
+ */ + public void setToIdentity() + { + m00 = m11 = 1; + m01 = m02 = m10 = m12 = 0; + type = TYPE_IDENTITY; + } + + /** + * Set this transform to a translation: + *
+   * [ 1 0 tx ]
+   * [ 0 1 ty ]
+   * [ 0 0 1  ]
+   * 
+ * + * @param tx the x translation distance + * @param ty the y translation distance + */ + public void setToTranslation(double tx, double ty) + { + m00 = m11 = 1; + m01 = m10 = 0; + m02 = tx; + m12 = ty; + type = (tx == 0 && ty == 0) ? TYPE_UNIFORM_SCALE : TYPE_TRANSLATION; + } + + /** + * Set this transform to a rotation. A positive angle (in radians) rotates + * the positive x-axis to the positive y-axis: + *
+   * [ cos(theta) -sin(theta) 0 ]
+   * [ sin(theta)  cos(theta) 0 ]
+   * [     0           0      1 ]
+   * 
+ * + * @param theta the rotation angle + */ + public void setToRotation(double theta) + { + double c = Math.cos(theta); + double s = Math.sin(theta); + m00 = c; + m01 = -s; + m02 = 0; + m10 = s; + m11 = c; + m12 = 0; + type = (c == 1 ? TYPE_IDENTITY + : c == 0 || c == -1 ? TYPE_QUADRANT_ROTATION + : TYPE_GENERAL_ROTATION); + } + + /** + * Set this transform to a rotation about a point. A positive angle (in + * radians) rotates the positive x-axis to the positive y-axis. This is the + * same as calling: + *
+   * tx.setToTranslation(x, y);
+   * tx.rotate(theta);
+   * tx.translate(-x, -y);
+   * 
+ * + *

The resulting matrix is: + *

+   * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
+   * [ sin(theta)  cos(theta) y-x*sin-y*cos ]
+   * [     0           0            1       ]
+   * 
+ * + * @param theta the rotation angle + * @param x the x coordinate of the pivot point + * @param y the y coordinate of the pivot point + */ + public void setToRotation(double theta, double x, double y) + { + double c = Math.cos(theta); + double s = Math.sin(theta); + m00 = c; + m01 = -s; + m02 = x - x * c + y * s; + m10 = s; + m11 = c; + m12 = y - x * s - y * c; + updateType(); + } + + /** + * Set this transform to a scale: + *
+   * [ sx 0  0 ]
+   * [ 0  sy 0 ]
+   * [ 0  0  1 ]
+   * 
+ * + * @param sx the x scaling factor + * @param sy the y scaling factor + */ + public void setToScale(double sx, double sy) + { + m00 = sx; + m01 = m02 = m10 = m12 = 0; + m11 = sy; + type = (sx != sy ? TYPE_GENERAL_SCALE + : sx == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE); + } + + /** + * Set this transform to a shear (points are shifted in the x direction based + * on a factor of their y coordinate, and in the y direction as a factor of + * their x coordinate): + *
+   * [  1  shx 0 ]
+   * [ shy  1  0 ]
+   * [  0   0  1 ]
+   * 
+ * + * @param shx the x shearing factor + * @param shy the y shearing factor + */ + public void setToShear(double shx, double shy) + { + m00 = m11 = 1; + m01 = shx; + m10 = shy; + m02 = m12 = 0; + updateType(); + } + + /** + * Set this transform to a copy of the given one. + * + * @param tx the transform to copy + * @throws NullPointerException if tx is null + */ + public void setTransform(AffineTransform tx) + { + m00 = tx.m00; + m01 = tx.m01; + m02 = tx.m02; + m10 = tx.m10; + m11 = tx.m11; + m12 = tx.m12; + type = tx.type; + } + + /** + * Set this transform to the given values: + *
+   * [ m00 m01 m02 ]
+   * [ m10 m11 m12 ]
+   * [  0   0   1  ]
+   * 
+ * + * @param m00 the x scaling component + * @param m10 the y shearing component + * @param m01 the x shearing component + * @param m11 the y scaling component + * @param m02 the x translation component + * @param m12 the y translation component + */ + public void setTransform(double m00, double m10, double m01, + double m11, double m02, double m12) + { + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m11 = m11; + this.m02 = m02; + this.m12 = m12; + updateType(); + } + + /** + * Set this transform to the result of performing the original version of + * this followed by tx. This is commonly used when chaining transformations + * from one space to another. In matrix form: + *
+   * [ this ] = [ this ] x [ tx ]
+   * 
+ * + * @param tx the transform to concatenate + * @throws NullPointerException if tx is null + * @see #preConcatenate(AffineTransform) + */ + public void concatenate(AffineTransform tx) + { + double n00 = m00 * tx.m00 + m01 * tx.m10; + double n01 = m00 * tx.m01 + m01 * tx.m11; + double n02 = m00 * tx.m02 + m01 * tx.m12 + m02; + double n10 = m10 * tx.m00 + m11 * tx.m10; + double n11 = m10 * tx.m01 + m11 * tx.m11; + double n12 = m10 * tx.m02 + m11 * tx.m12 + m12; + m00 = n00; + m01 = n01; + m02 = n02; + m10 = n10; + m11 = n11; + m12 = n12; + updateType(); + } + + /** + * Set this transform to the result of performing tx followed by the + * original version of this. This is less common than normal concatenation, + * but can still be used to chain transformations from one space to another. + * In matrix form: + *
+   * [ this ] = [ tx ] x [ this ]
+   * 
+ * + * @param tx the transform to concatenate + * @throws NullPointerException if tx is null + * @see #concatenate(AffineTransform) + */ + public void preConcatenate(AffineTransform tx) + { + double n00 = tx.m00 * m00 + tx.m01 * m10; + double n01 = tx.m00 * m01 + tx.m01 * m11; + double n02 = tx.m00 * m02 + tx.m01 * m12 + tx.m02; + double n10 = tx.m10 * m00 + tx.m11 * m10; + double n11 = tx.m10 * m01 + tx.m11 * m11; + double n12 = tx.m10 * m02 + tx.m11 * m12 + tx.m12; + m00 = n00; + m01 = n01; + m02 = n02; + m10 = n10; + m11 = n11; + m12 = n12; + updateType(); + } + + /** + * Returns a transform, which if concatenated to this one, will result in + * the identity transform. This is useful for undoing transformations, but + * is only possible if the original transform has an inverse (ie. does not + * map multiple points to the same line or point). A transform exists only + * if getDeterminant() has a non-zero value. + * + * The inverse is calculated as: + * + *
+   *
+   * Let A be the matrix for which we want to find the inverse:
+   *
+   * A = [ m00 m01 m02 ]
+   *     [ m10 m11 m12 ]
+   *     [ 0   0   1   ] 
+   *
+   *
+   *                 1    
+   * inverse (A) =  ---   x  adjoint(A) 
+   *                det 
+   *
+   *
+   *
+   *             =   1       [  m11  -m01   m01*m12-m02*m11  ]
+   *                ---   x  [ -m10   m00  -m00*m12+m10*m02  ]
+   *                det      [  0     0     m00*m11-m10*m01  ]
+   *
+   *
+   *
+   *             = [  m11/det  -m01/det   m01*m12-m02*m11/det ]
+   *               [ -m10/det   m00/det  -m00*m12+m10*m02/det ]
+   *               [   0           0          1               ]
+   *
+   *
+   * 
+ * + * + * + * @return a new inverse transform + * @throws NoninvertibleTransformException if inversion is not possible + * @see #getDeterminant() + */ + public AffineTransform createInverse() + throws NoninvertibleTransformException + { + double det = getDeterminant(); + if (det == 0) + throw new NoninvertibleTransformException("can't invert transform"); + + double im00 = m11 / det; + double im10 = -m10 / det; + double im01 = -m01 / det; + double im11 = m00 / det; + double im02 = (m01 * m12 - m02 * m11) / det; + double im12 = (-m00 * m12 + m10 * m02) / det; + + return new AffineTransform (im00, im10, im01, im11, im02, im12); + } + + /** + * Perform this transformation on the given source point, and store the + * result in the destination (creating it if necessary). It is safe for + * src and dst to be the same. + * + * @param src the source point + * @param dst the destination, or null + * @return the transformation of src, in dst if it was non-null + * @throws NullPointerException if src is null + */ + public Point2D transform(Point2D src, Point2D dst) + { + if (dst == null) + dst = new Point2D.Double(); + double x = src.getX(); + double y = src.getY(); + double nx = m00 * x + m01 * y + m02; + double ny = m10 * x + m11 * y + m12; + dst.setLocation(nx, ny); + return dst; + } + + /** + * Perform this transformation on an array of points, storing the results + * in another (possibly same) array. This will not create a destination + * array, but will create points for the null entries of the destination. + * The transformation is done sequentially. While having a single source + * and destination point be the same is safe, you should be aware that + * duplicate references to the same point in the source, and having the + * source overlap the destination, may result in your source points changing + * from a previous transform before it is their turn to be evaluated. + * + * @param src the array of source points + * @param srcOff the starting offset into src + * @param dst the array of destination points (may have null entries) + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null, or src has null + * entries + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + * @throws ArrayStoreException if new points are incompatible with dst + */ + public void transform(Point2D[] src, int srcOff, + Point2D[] dst, int dstOff, int num) + { + while (--num >= 0) + dst[dstOff] = transform(src[srcOff++], dst[dstOff++]); + } + + /** + * Perform this transformation on an array of points, in (x,y) pairs, + * storing the results in another (possibly same) array. This will not + * create a destination array. All sources are copied before the + * transformation, so that no result will overwrite a point that has not yet + * been evaluated. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void transform(float[] srcPts, int srcOff, + float[] dstPts, int dstOff, int num) + { + if (srcPts == dstPts && dstOff > srcOff + && num > 1 && srcOff + 2 * num > dstOff) + { + float[] f = new float[2 * num]; + System.arraycopy(srcPts, srcOff, f, 0, 2 * num); + srcPts = f; + } + while (--num >= 0) + { + float x = srcPts[srcOff++]; + float y = srcPts[srcOff++]; + dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02); + dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12); + } + } + + /** + * Perform this transformation on an array of points, in (x,y) pairs, + * storing the results in another (possibly same) array. This will not + * create a destination array. All sources are copied before the + * transformation, so that no result will overwrite a point that has not yet + * been evaluated. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void transform(double[] srcPts, int srcOff, + double[] dstPts, int dstOff, int num) + { + if (srcPts == dstPts && dstOff > srcOff + && num > 1 && srcOff + 2 * num > dstOff) + { + double[] d = new double[2 * num]; + System.arraycopy(srcPts, srcOff, d, 0, 2 * num); + srcPts = d; + } + while (--num >= 0) + { + double x = srcPts[srcOff++]; + double y = srcPts[srcOff++]; + dstPts[dstOff++] = m00 * x + m01 * y + m02; + dstPts[dstOff++] = m10 * x + m11 * y + m12; + } + } + + /** + * Perform this transformation on an array of points, in (x,y) pairs, + * storing the results in another array. This will not create a destination + * array. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void transform(float[] srcPts, int srcOff, + double[] dstPts, int dstOff, int num) + { + while (--num >= 0) + { + float x = srcPts[srcOff++]; + float y = srcPts[srcOff++]; + dstPts[dstOff++] = m00 * x + m01 * y + m02; + dstPts[dstOff++] = m10 * x + m11 * y + m12; + } + } + + /** + * Perform this transformation on an array of points, in (x,y) pairs, + * storing the results in another array. This will not create a destination + * array. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void transform(double[] srcPts, int srcOff, + float[] dstPts, int dstOff, int num) + { + while (--num >= 0) + { + double x = srcPts[srcOff++]; + double y = srcPts[srcOff++]; + dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02); + dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12); + } + } + + /** + * Perform the inverse of this transformation on the given source point, + * and store the result in the destination (creating it if necessary). It + * is safe for src and dst to be the same. + * + * @param src the source point + * @param dst the destination, or null + * @return the inverse transformation of src, in dst if it was non-null + * @throws NullPointerException if src is null + * @throws NoninvertibleTransformException if the inverse does not exist + * @see #getDeterminant() + */ + public Point2D inverseTransform(Point2D src, Point2D dst) + throws NoninvertibleTransformException + { + return createInverse().transform(src, dst); + } + + /** + * Perform the inverse of this transformation on an array of points, in + * (x,y) pairs, storing the results in another (possibly same) array. This + * will not create a destination array. All sources are copied before the + * transformation, so that no result will overwrite a point that has not yet + * been evaluated. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + * @throws NoninvertibleTransformException if the inverse does not exist + * @see #getDeterminant() + */ + public void inverseTransform(double[] srcPts, int srcOff, + double[] dstPts, int dstOff, int num) + throws NoninvertibleTransformException + { + createInverse().transform(srcPts, srcOff, dstPts, dstOff, num); + } + + /** + * Perform this transformation, less any translation, on the given source + * point, and store the result in the destination (creating it if + * necessary). It is safe for src and dst to be the same. The reduced + * transform is equivalent to: + *
+   * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
+   * [ y' ]   [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
+   * 
+ * + * @param src the source point + * @param dst the destination, or null + * @return the delta transformation of src, in dst if it was non-null + * @throws NullPointerException if src is null + */ + public Point2D deltaTransform(Point2D src, Point2D dst) + { + if (dst == null) + dst = new Point2D.Double(); + double x = src.getX(); + double y = src.getY(); + double nx = m00 * x + m01 * y; + double ny = m10 * x + m11 * y; + dst.setLocation(nx, ny); + return dst; + } + + /** + * Perform this transformation, less any translation, on an array of points, + * in (x,y) pairs, storing the results in another (possibly same) array. + * This will not create a destination array. All sources are copied before + * the transformation, so that no result will overwrite a point that has + * not yet been evaluated. The reduced transform is equivalent to: + *
+   * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
+   * [ y' ]   [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
+   * 
+ * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void deltaTransform(double[] srcPts, int srcOff, + double[] dstPts, int dstOff, + int num) + { + if (srcPts == dstPts && dstOff > srcOff + && num > 1 && srcOff + 2 * num > dstOff) + { + double[] d = new double[2 * num]; + System.arraycopy(srcPts, srcOff, d, 0, 2 * num); + srcPts = d; + } + while (--num >= 0) + { + double x = srcPts[srcOff++]; + double y = srcPts[srcOff++]; + dstPts[dstOff++] = m00 * x + m01 * y; + dstPts[dstOff++] = m10 * x + m11 * y; + } + } + + /** + * Return a new Shape, based on the given one, where the path of the shape + * has been transformed by this transform. Notice that this uses GeneralPath, + * which only stores points in float precision. + * + * @param src the shape source to transform + * @return the shape, transformed by this, null if src is + * null. + * @see GeneralPath#transform(AffineTransform) + */ + public Shape createTransformedShape(Shape src) + { + if(src == null) + return null; + GeneralPath p = new GeneralPath(src); + p.transform(this); + return p; + } + + /** + * Returns a string representation of the transform, in the format: + * "AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], [" + * + m10 + ", " + m11 + ", " + m12 + "]]". + * + * @return the string representation + */ + public String toString() + { + return "AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], [" + + m10 + ", " + m11 + ", " + m12 + "]]"; + } + + /** + * Tests if this transformation is the identity: + *
+   * [ 1 0 0 ]
+   * [ 0 1 0 ]
+   * [ 0 0 1 ]
+   * 
+ * + * @return true if this is the identity transform + */ + public boolean isIdentity() + { + // Rather than rely on type, check explicitly. + return (m00 == 1 && m01 == 0 && m02 == 0 + && m10 == 0 && m11 == 1 && m12 == 0); + } + + /** + * Create a new transform of the same run-time type, with the same + * transforming properties as this one. + * + * @return the clone + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Return the hashcode for this transformation. The formula is not + * documented, but appears to be the same as: + *
+   * long l = Double.doubleToLongBits(getScaleX());
+   * l = l * 31 + Double.doubleToLongBits(getShearY());
+   * l = l * 31 + Double.doubleToLongBits(getShearX());
+   * l = l * 31 + Double.doubleToLongBits(getScaleY());
+   * l = l * 31 + Double.doubleToLongBits(getTranslateX());
+   * l = l * 31 + Double.doubleToLongBits(getTranslateY());
+   * return (int) ((l >> 32) ^ l);
+   * 
+ * + * @return the hashcode + */ + public int hashCode() + { + long l = Double.doubleToLongBits(m00); + l = l * 31 + Double.doubleToLongBits(m10); + l = l * 31 + Double.doubleToLongBits(m01); + l = l * 31 + Double.doubleToLongBits(m11); + l = l * 31 + Double.doubleToLongBits(m02); + l = l * 31 + Double.doubleToLongBits(m12); + return (int) ((l >> 32) ^ l); + } + + /** + * Compares two transforms for equality. This returns true if they have the + * same matrix values. + * + * @param obj the transform to compare + * @return true if it is equal + */ + public boolean equals(Object obj) + { + if (! (obj instanceof AffineTransform)) + return false; + AffineTransform t = (AffineTransform) obj; + return (m00 == t.m00 && m01 == t.m01 && m02 == t.m02 + && m10 == t.m10 && m11 == t.m11 && m12 == t.m12); + } + + /** + * Helper to decode the type from the matrix. This is not guaranteed + * to find the optimal type, but at least it will be valid. + */ + private void updateType() + { + double det = getDeterminant(); + if (det == 0) + { + type = TYPE_GENERAL_TRANSFORM; + return; + } + // Scale (includes rotation by PI) or translation. + if (m01 == 0 && m10 == 0) + { + if (m00 == m11) + type = m00 == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE; + else + type = TYPE_GENERAL_SCALE; + if (m02 != 0 || m12 != 0) + type |= TYPE_TRANSLATION; + } + // Rotation. + else if (m00 == m11 && m01 == -m10) + { + type = m00 == 0 ? TYPE_QUADRANT_ROTATION : TYPE_GENERAL_ROTATION; + if (det != 1) + type |= TYPE_UNIFORM_SCALE; + if (m02 != 0 || m12 != 0) + type |= TYPE_TRANSLATION; + } + else + type = TYPE_GENERAL_TRANSFORM; + } + + /** + * Reads a transform from an object stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if there is a problem deserializing + * @throws IOException if there is a problem deserializing + */ + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject(); + updateType(); + } +} // class AffineTransform diff --git a/libjava/classpath/java/awt/geom/Arc2D.java b/libjava/classpath/java/awt/geom/Arc2D.java new file mode 100644 index 0000000..eff34a0 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Arc2D.java @@ -0,0 +1,1399 @@ +/* Arc2D.java -- represents an arc in 2-D space + Copyright (C) 2002, 2003, 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 java.awt.geom; + +import java.util.NoSuchElementException; + + +/** + * This class represents all arcs (segments of an ellipse in 2-D space). The + * arcs are defined by starting angle and extent (arc length) in degrees, as + * opposed to radians (like the rest of Java), and can be open, chorded, or + * wedge shaped. The angles are skewed according to the ellipse, so that 45 + * degrees always points to the upper right corner (positive x, negative y) + * of the bounding rectangle. A positive extent draws a counterclockwise arc, + * and while the angle can be any value, the path iterator only traverses the + * first 360 degrees. Storage is up to the subclasses. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sven de Marothy (sven@physto.se) + * @since 1.2 + */ +public abstract class Arc2D extends RectangularShape +{ + /** + * An open arc, with no segment connecting the endpoints. This type of + * arc still contains the same points as a chorded version. + */ + public static final int OPEN = 0; + + /** + * A closed arc with a single segment connecting the endpoints (a chord). + */ + public static final int CHORD = 1; + + /** + * A closed arc with two segments, one from each endpoint, meeting at the + * center of the ellipse. + */ + public static final int PIE = 2; + + /** The closure type of this arc. This is package-private to avoid an + * accessor method. */ + int type; + + /** + * Create a new arc, with the specified closure type. + * + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE}. + * @throws IllegalArgumentException if type is invalid + */ + protected Arc2D(int type) + { + if (type < OPEN || type > PIE) + throw new IllegalArgumentException(); + this.type = type; + } + + /** + * Get the starting angle of the arc in degrees. + * + * @return the starting angle + * @see #setAngleStart(double) + */ + public abstract double getAngleStart(); + + /** + * Get the extent angle of the arc in degrees. + * + * @return the extent angle + * @see #setAngleExtent(double) + */ + public abstract double getAngleExtent(); + + /** + * Return the closure type of the arc. + * + * @return the closure type + * @see #OPEN + * @see #CHORD + * @see #PIE + * @see #setArcType(int) + */ + public int getArcType() + { + return type; + } + + /** + * Returns the starting point of the arc. + * + * @return the start point + */ + public Point2D getStartPoint() + { + double angle = Math.toRadians(getAngleStart()); + double rx = getWidth() / 2; + double ry = getHeight() / 2; + double x = getX() + rx + rx * Math.cos(angle); + double y = getY() + ry - ry * Math.sin(angle); + return new Point2D.Double(x, y); + } + + /** + * Returns the ending point of the arc. + * + * @return the end point + */ + public Point2D getEndPoint() + { + double angle = Math.toRadians(getAngleStart() + getAngleExtent()); + double rx = getWidth() / 2; + double ry = getHeight() / 2; + double x = getX() + rx + rx * Math.cos(angle); + double y = getY() + ry - ry * Math.sin(angle); + return new Point2D.Double(x, y); + } + + /** + * Set the parameters of the arc. The angles are in degrees, and a positive + * extent sweeps counterclockwise (from the positive x-axis to the negative + * y-axis). + * + * @param x the new x coordinate of the upper left of the bounding box + * @param y the new y coordinate of the upper left of the bounding box + * @param w the new width of the bounding box + * @param h the new height of the bounding box + * @param start the start angle, in degrees + * @param extent the arc extent, in degrees + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public abstract void setArc(double x, double y, double w, double h, + double start, double extent, int type); + + /** + * Set the parameters of the arc. The angles are in degrees, and a positive + * extent sweeps counterclockwise (from the positive x-axis to the negative + * y-axis). + * + * @param p the upper left point of the bounding box + * @param d the dimensions of the bounding box + * @param start the start angle, in degrees + * @param extent the arc extent, in degrees + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @throws NullPointerException if p or d is null + */ + public void setArc(Point2D p, Dimension2D d, double start, double extent, + int type) + { + setArc(p.getX(), p.getY(), d.getWidth(), d.getHeight(), start, extent, type); + } + + /** + * Set the parameters of the arc. The angles are in degrees, and a positive + * extent sweeps counterclockwise (from the positive x-axis to the negative + * y-axis). + * + * @param r the new bounding box + * @param start the start angle, in degrees + * @param extent the arc extent, in degrees + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @throws NullPointerException if r is null + */ + public void setArc(Rectangle2D r, double start, double extent, int type) + { + setArc(r.getX(), r.getY(), r.getWidth(), r.getHeight(), start, extent, type); + } + + /** + * Set the parameters of the arc from the given one. + * + * @param a the arc to copy + * @throws NullPointerException if a is null + */ + public void setArc(Arc2D a) + { + setArc(a.getX(), a.getY(), a.getWidth(), a.getHeight(), a.getAngleStart(), + a.getAngleExtent(), a.getArcType()); + } + + /** + * Set the parameters of the arc. The angles are in degrees, and a positive + * extent sweeps counterclockwise (from the positive x-axis to the negative + * y-axis). This controls the center point and radius, so the arc will be + * circular. + * + * @param x the x coordinate of the center of the circle + * @param y the y coordinate of the center of the circle + * @param r the radius of the circle + * @param start the start angle, in degrees + * @param extent the arc extent, in degrees + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public void setArcByCenter(double x, double y, double r, double start, + double extent, int type) + { + setArc(x - r, y - r, r + r, r + r, start, extent, type); + } + + /** + * Sets the parameters of the arc by finding the tangents of two lines, and + * using the specified radius. The arc will be circular, will begin on the + * tangent point of the line extending from p1 to p2, and will end on the + * tangent point of the line extending from p2 to p3. + * + * XXX What happens if the points are colinear, or the radius negative? + * + * @param p1 the first point + * @param p2 the tangent line intersection point + * @param p3 the third point + * @param r the radius of the arc + * @throws NullPointerException if any point is null + */ + public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double r) + { + if ((p2.getX() - p1.getX()) * (p3.getY() - p1.getY()) + - (p3.getX() - p1.getX()) * (p2.getY() - p1.getY()) > 0) + { + Point2D p = p3; + p3 = p1; + p1 = p; + } + + // normalized tangent vectors + double dx1 = (p1.getX() - p2.getX()) / p1.distance(p2); + double dy1 = (p1.getY() - p2.getY()) / p1.distance(p2); + double dx2 = (p2.getX() - p3.getX()) / p3.distance(p2); + double dy2 = (p2.getY() - p3.getY()) / p3.distance(p2); + double theta1 = Math.atan2(dx1, dy1); + double theta2 = Math.atan2(dx2, dy2); + + double dx = r * Math.cos(theta2) - r * Math.cos(theta1); + double dy = -r * Math.sin(theta2) + r * Math.sin(theta1); + + if (theta1 < 0) + theta1 += 2 * Math.PI; + if (theta2 < 0) + theta2 += 2 * Math.PI; + if (theta2 < theta1) + theta2 += 2 * Math.PI; + + // Vectors of the lines, not normalized, note we change + // the direction of line 2. + dx1 = p1.getX() - p2.getX(); + dy1 = p1.getY() - p2.getY(); + dx2 = p3.getX() - p2.getX(); + dy2 = p3.getY() - p2.getY(); + + // Calculate the tangent point to the second line + double t2 = -(dx1 * dy - dy1 * dx) / (dx2 * dy1 - dx1 * dy2); + double x2 = t2 * (p3.getX() - p2.getX()) + p2.getX(); + double y2 = t2 * (p3.getY() - p2.getY()) + p2.getY(); + + // calculate the center point + double x = x2 - r * Math.cos(theta2); + double y = y2 + r * Math.sin(theta2); + + setArc(x - r, y - r, 2 * r, 2 * r, Math.toDegrees(theta1), + Math.toDegrees(theta2 - theta1), getArcType()); + } + + /** + * Set the start, in degrees. + * + * @param start the new start angle + * @see #getAngleStart() + */ + public abstract void setAngleStart(double start); + + /** + * Set the extent, in degrees. + * + * @param extent the new extent angle + * @see #getAngleExtent() + */ + public abstract void setAngleExtent(double extent); + + /** + * Sets the starting angle to the angle of the given point relative to + * the center of the arc. The extent remains constant; in other words, + * this rotates the arc. + * + * @param p the new start point + * @throws NullPointerException if p is null + * @see #getStartPoint() + * @see #getAngleStart() + */ + public void setAngleStart(Point2D p) + { + // Normalize. + double x = p.getX() - (getX() + getWidth() / 2); + double y = p.getY() - (getY() + getHeight() / 2); + setAngleStart(Math.toDegrees(Math.atan2(-y, x))); + } + + /** + * Sets the starting and extent angles to those of the given points + * relative to the center of the arc. The arc will be non-empty, and will + * extend counterclockwise. + * + * @param x1 the first x coordinate + * @param y1 the first y coordinate + * @param x2 the second x coordinate + * @param y2 the second y coordinate + * @see #setAngleStart(Point2D) + */ + public void setAngles(double x1, double y1, double x2, double y2) + { + // Normalize the points. + double mx = getX(); + double my = getY(); + double mw = getWidth(); + double mh = getHeight(); + x1 = x1 - (mx + mw / 2); + y1 = y1 - (my + mh / 2); + x2 = x2 - (mx + mw / 2); + y2 = y2 - (my + mh / 2); + double start = Math.toDegrees(Math.atan2(-y1, x1)); + double extent = Math.toDegrees(Math.atan2(-y2, x2)) - start; + if (extent < 0) + extent += 360; + setAngleStart(start); + setAngleExtent(extent); + } + + /** + * Sets the starting and extent angles to those of the given points + * relative to the center of the arc. The arc will be non-empty, and will + * extend counterclockwise. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + * @see #setAngleStart(Point2D) + */ + public void setAngles(Point2D p1, Point2D p2) + { + setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + } + + /** + * Set the closure type of this arc. + * + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @see #getArcType() + */ + public void setArcType(int type) + { + if (type < OPEN || type > PIE) + throw new IllegalArgumentException(); + this.type = type; + } + + /** + * Sets the location and bounds of the ellipse of which this arc is a part. + * + * @param x the new x coordinate + * @param y the new y coordinate + * @param w the new width + * @param h the new height + * @see #getFrame() + */ + public void setFrame(double x, double y, double w, double h) + { + setArc(x, y, w, h, getAngleStart(), getAngleExtent(), type); + } + + /** + * Gets the bounds of the arc. This is much tighter than + * getBounds, as it takes into consideration the start and + * end angles, and the center point of a pie wedge, rather than just the + * overall ellipse. + * + * @return the bounds of the arc + * @see #getBounds() + */ + public Rectangle2D getBounds2D() + { + double extent = getAngleExtent(); + if (Math.abs(extent) >= 360) + return makeBounds(getX(), getY(), getWidth(), getHeight()); + + // Find the minimal bounding box. This determined by its extrema, + // which are the center, the endpoints of the arc, and any local + // maximum contained by the arc. + double rX = getWidth() / 2; + double rY = getHeight() / 2; + double centerX = getX() + rX; + double centerY = getY() + rY; + + Point2D p1 = getStartPoint(); + Rectangle2D result = makeBounds(p1.getX(), p1.getY(), 0, 0); + result.add(getEndPoint()); + + if (type == PIE) + result.add(centerX, centerY); + if (containsAngle(0)) + result.add(centerX + rX, centerY); + if (containsAngle(90)) + result.add(centerX, centerY - rY); + if (containsAngle(180)) + result.add(centerX - rX, centerY); + if (containsAngle(270)) + result.add(centerX, centerY + rY); + + return result; + } + + /** + * Construct a bounding box in a precision appropriate for the subclass. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @return the rectangle for use in getBounds2D + */ + protected abstract Rectangle2D makeBounds(double x, double y, double w, + double h); + + /** + * Tests if the given angle, in degrees, is included in the arc. + * All angles are normalized to be between 0 and 360 degrees. + * + * @param a the angle to test + * @return true if it is contained + */ + public boolean containsAngle(double a) + { + double start = getAngleStart(); + double extent = getAngleExtent(); + double end = start + extent; + + if (extent == 0) + return false; + + if (extent >= 360 || extent <= -360) + return true; + + if (extent < 0) + { + end = start; + start += extent; + } + + start %= 360; + while (start < 0) + start += 360; + + end %= 360; + while (end < start) + end += 360; + + a %= 360; + while (a < start) + a += 360; + + return a >= start && a < end; // starting angle included, ending angle not + } + + /** + * Determines if the arc contains the given point. If the bounding box + * is empty, then this will return false. + * + * The area considered 'inside' an arc of type OPEN is the same as the + * area inside an equivalent filled CHORD-type arc. The area considered + * 'inside' a CHORD-type arc is the same as the filled area. + * + * @param x the x coordinate to test + * @param y the y coordinate to test + * @return true if the point is inside the arc + */ + public boolean contains(double x, double y) + { + double w = getWidth(); + double h = getHeight(); + double extent = getAngleExtent(); + if (w <= 0 || h <= 0 || extent == 0) + return false; + + double mx = getX() + w / 2; + double my = getY() + h / 2; + double dx = (x - mx) * 2 / w; + double dy = (y - my) * 2 / h; + if ((dx * dx + dy * dy) >= 1.0) + return false; + + double angle = Math.toDegrees(Math.atan2(-dy, dx)); + if (getArcType() == PIE) + return containsAngle(angle); + + double a1 = Math.toRadians(getAngleStart()); + double a2 = Math.toRadians(getAngleStart() + extent); + double x1 = mx + getWidth() * Math.cos(a1) / 2; + double y1 = my - getHeight() * Math.sin(a1) / 2; + double x2 = mx + getWidth() * Math.cos(a2) / 2; + double y2 = my - getHeight() * Math.sin(a2) / 2; + double sgn = ((x2 - x1) * (my - y1) - (mx - x1) * (y2 - y1)) * ((x2 - x1) * (y + - y1) - (x - x1) * (y2 - y1)); + + if (Math.abs(extent) > 180) + { + if (containsAngle(angle)) + return true; + return sgn > 0; + } + else + { + if (! containsAngle(angle)) + return false; + return sgn < 0; + } + } + + /** + * Tests if a given rectangle intersects the area of the arc. + * + * For a definition of the 'inside' area, see the contains() method. + * @see #contains(double, double) + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @return true if the two shapes share common points + */ + public boolean intersects(double x, double y, double w, double h) + { + double extent = getAngleExtent(); + if (extent == 0) + return false; + + if (contains(x, y) || contains(x, y + h) || contains(x + w, y) + || contains(x + w, y + h)) + return true; + + Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); + + double a = getWidth() / 2.0; + double b = getHeight() / 2.0; + + double mx = getX() + a; + double my = getY() + b; + double x1 = mx + a * Math.cos(Math.toRadians(getAngleStart())); + double y1 = my - b * Math.sin(Math.toRadians(getAngleStart())); + double x2 = mx + a * Math.cos(Math.toRadians(getAngleStart() + extent)); + double y2 = my - b * Math.sin(Math.toRadians(getAngleStart() + extent)); + + if (getArcType() != CHORD) + { + // check intersections against the pie radii + if (rect.intersectsLine(mx, my, x1, y1)) + return true; + if (rect.intersectsLine(mx, my, x2, y2)) + return true; + } + else// check the chord + if (rect.intersectsLine(x1, y1, x2, y2)) + return true; + + // Check the Arc segment against the four edges + double dx; + + // Check the Arc segment against the four edges + double dy; + dy = y - my; + dx = a * Math.sqrt(1 - ((dy * dy) / (b * b))); + if (! java.lang.Double.isNaN(dx)) + { + if (mx + dx >= x && mx + dx <= x + w + && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) + return true; + if (mx - dx >= x && mx - dx <= x + w + && containsAngle(Math.toDegrees(Math.atan2(-dy, -dx)))) + return true; + } + dy = (y + h) - my; + dx = a * Math.sqrt(1 - ((dy * dy) / (b * b))); + if (! java.lang.Double.isNaN(dx)) + { + if (mx + dx >= x && mx + dx <= x + w + && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) + return true; + if (mx - dx >= x && mx - dx <= x + w + && containsAngle(Math.toDegrees(Math.atan2(-dy, -dx)))) + return true; + } + dx = x - mx; + dy = b * Math.sqrt(1 - ((dx * dx) / (a * a))); + if (! java.lang.Double.isNaN(dy)) + { + if (my + dy >= y && my + dy <= y + h + && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) + return true; + if (my - dy >= y && my - dy <= y + h + && containsAngle(Math.toDegrees(Math.atan2(dy, dx)))) + return true; + } + + dx = (x + w) - mx; + dy = b * Math.sqrt(1 - ((dx * dx) / (a * a))); + if (! java.lang.Double.isNaN(dy)) + { + if (my + dy >= y && my + dy <= y + h + && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) + return true; + if (my - dy >= y && my - dy <= y + h + && containsAngle(Math.toDegrees(Math.atan2(dy, dx)))) + return true; + } + + // Check whether the arc is contained within the box + if (rect.contains(mx, my)) + return true; + + return false; + } + + /** + * Tests if a given rectangle is contained in the area of the arc. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @return true if the arc contains the rectangle + */ + public boolean contains(double x, double y, double w, double h) + { + double extent = getAngleExtent(); + if (extent == 0) + return false; + + if (! (contains(x, y) && contains(x, y + h) && contains(x + w, y) + && contains(x + w, y + h))) + return false; + + Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); + + double a = getWidth() / 2.0; + double b = getHeight() / 2.0; + + double mx = getX() + a; + double my = getY() + b; + double x1 = mx + a * Math.cos(Math.toRadians(getAngleStart())); + double y1 = my - b * Math.sin(Math.toRadians(getAngleStart())); + double x2 = mx + a * Math.cos(Math.toRadians(getAngleStart() + extent)); + double y2 = my - b * Math.sin(Math.toRadians(getAngleStart() + extent)); + if (getArcType() != CHORD) + { + // check intersections against the pie radii + if (rect.intersectsLine(mx, my, x1, y1)) + return false; + + if (rect.intersectsLine(mx, my, x2, y2)) + return false; + } + else if (rect.intersectsLine(x1, y1, x2, y2)) + return false; + return true; + } + + /** + * Tests if a given rectangle is contained in the area of the arc. + * + * @param r the rectangle + * @return true if the arc contains the rectangle + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Returns an iterator over this arc, with an optional transformation. + * This iterator is threadsafe, so future modifications to the arc do not + * affect the iteration. + * + * @param at the transformation, or null + * @return a path iterator + */ + public PathIterator getPathIterator(AffineTransform at) + { + return new ArcIterator(this, at); + } + + /** + * This class is used to iterate over an arc. Since ellipses are a subclass + * of arcs, this is used by Ellipse2D as well. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + static final class ArcIterator implements PathIterator + { + /** The current iteration. */ + private int current; + + /** The last iteration. */ + private final int limit; + + /** The optional transformation. */ + private final AffineTransform xform; + + /** The x coordinate of the bounding box. */ + private final double x; + + /** The y coordinate of the bounding box. */ + private final double y; + + /** The width of the bounding box. */ + private final double w; + + /** The height of the bounding box. */ + private final double h; + + /** The start angle, in radians (not degrees). */ + private final double start; + + /** The extent angle, in radians (not degrees). */ + private final double extent; + + /** The arc closure type. */ + private final int type; + + /** + * Construct a new iterator over an arc. + * + * @param a the arc + * @param xform the transform + */ + public ArcIterator(Arc2D a, AffineTransform xform) + { + this.xform = xform; + x = a.getX(); + y = a.getY(); + w = a.getWidth(); + h = a.getHeight(); + double start = a.getAngleStart() * (Math.PI / 180); + double extent = a.getAngleExtent() * (Math.PI / 180); + + if (extent < 0) + { + extent = -extent; + start = 2 * Math.PI - extent + start; + } + this.start = start; + this.extent = extent; + + type = a.type; + if (w < 0 || h < 0) + limit = -1; + else if (extent == 0) + limit = type; + else if (extent <= Math.PI / 2.0) + limit = type + 1; + else if (extent <= Math.PI) + limit = type + 2; + else if (extent <= 3.0 * (Math.PI / 2.0)) + limit = type + 3; + else + limit = type + 4; + } + + /** + * Construct a new iterator over an ellipse. + * + * @param e the ellipse + * @param xform the transform + */ + public ArcIterator(Ellipse2D e, AffineTransform xform) + { + this.xform = xform; + x = e.getX(); + y = e.getY(); + w = e.getWidth(); + h = e.getHeight(); + start = 0; + extent = 2 * Math.PI; + type = CHORD; + limit = (w < 0 || h < 0) ? -1 : 5; + } + + /** + * Return the winding rule. + * + * @return {@link PathIterator#WIND_NON_ZERO} + */ + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + /** + * Test if the iteration is complete. + * + * @return true if more segments exist + */ + public boolean isDone() + { + return current > limit; + } + + /** + * Advance the iterator. + */ + public void next() + { + current++; + } + + /** + * Put the current segment into the array, and return the segment type. + * + * @param coords an array of 6 elements + * @return the segment type + * @throws NullPointerException if coords is null + * @throws ArrayIndexOutOfBoundsException if coords is too small + */ + public int currentSegment(float[] coords) + { + double[] double_coords = new double[6]; + int code = currentSegment(double_coords); + for (int i = 0; i < 6; ++i) + coords[i] = (float) double_coords[i]; + return code; + } + + /** + * Put the current segment into the array, and return the segment type. + * + * @param coords an array of 6 elements + * @return the segment type + * @throws NullPointerException if coords is null + * @throws ArrayIndexOutOfBoundsException if coords is too small + */ + public int currentSegment(double[] coords) + { + double rx = w / 2; + double ry = h / 2; + double xmid = x + rx; + double ymid = y + ry; + + if (current > limit) + throw new NoSuchElementException("arc iterator out of bounds"); + + if (current == 0) + { + coords[0] = xmid + rx * Math.cos(start); + coords[1] = ymid - ry * Math.sin(start); + if (xform != null) + xform.transform(coords, 0, coords, 0, 1); + return SEG_MOVETO; + } + + if (type != OPEN && current == limit) + return SEG_CLOSE; + + if ((current == limit - 1) && (type == PIE)) + { + coords[0] = xmid; + coords[1] = ymid; + if (xform != null) + xform.transform(coords, 0, coords, 0, 1); + return SEG_LINETO; + } + + // note that this produces a cubic approximation of the arc segment, + // not a true ellipsoid. there's no ellipsoid path segment code, + // unfortunately. the cubic approximation looks about right, though. + double kappa = (Math.sqrt(2.0) - 1.0) * (4.0 / 3.0); + double quad = (Math.PI / 2.0); + + double curr_begin = start + (current - 1) * quad; + double curr_extent = Math.min((start + extent) - curr_begin, quad); + double portion_of_a_quadrant = curr_extent / quad; + + double x0 = xmid + rx * Math.cos(curr_begin); + double y0 = ymid - ry * Math.sin(curr_begin); + + double x1 = xmid + rx * Math.cos(curr_begin + curr_extent); + double y1 = ymid - ry * Math.sin(curr_begin + curr_extent); + + AffineTransform trans = new AffineTransform(); + double[] cvec = new double[2]; + double len = kappa * portion_of_a_quadrant; + double angle = curr_begin; + + // in a hypothetical "first quadrant" setting, our first control + // vector would be sticking up, from [1,0] to [1,kappa]. + // + // let us recall however that in java2d, y coords are upside down + // from what one would consider "normal" first quadrant rules, so we + // will *subtract* the y value of this control vector from our first + // point. + cvec[0] = 0; + cvec[1] = len; + trans.scale(rx, ry); + trans.rotate(angle); + trans.transform(cvec, 0, cvec, 0, 1); + coords[0] = x0 + cvec[0]; + coords[1] = y0 - cvec[1]; + + // control vector #2 would, ideally, be sticking out and to the + // right, in a first quadrant arc segment. again, subtraction of y. + cvec[0] = 0; + cvec[1] = -len; + trans.rotate(curr_extent); + trans.transform(cvec, 0, cvec, 0, 1); + coords[2] = x1 + cvec[0]; + coords[3] = y1 - cvec[1]; + + // end point + coords[4] = x1; + coords[5] = y1; + + if (xform != null) + xform.transform(coords, 0, coords, 0, 3); + + return SEG_CUBICTO; + } + } // class ArcIterator + + /** + * This class implements an arc in double precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + */ + public static class Double extends Arc2D + { + /** The x coordinate of the box bounding the ellipse of this arc. */ + public double x; + + /** The y coordinate of the box bounding the ellipse of this arc. */ + public double y; + + /** The width of the box bounding the ellipse of this arc. */ + public double width; + + /** The height of the box bounding the ellipse of this arc. */ + public double height; + + /** The start angle of this arc, in degrees. */ + public double start; + + /** The extent angle of this arc, in degrees. */ + public double extent; + + /** + * Create a new, open arc at (0,0) with 0 extent. + */ + public Double() + { + super(OPEN); + } + + /** + * Create a new arc of the given type at (0,0) with 0 extent. + * + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public Double(int type) + { + super(type); + } + + /** + * Create a new arc with the given dimensions. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public Double(double x, double y, double w, double h, double start, + double extent, int type) + { + super(type); + this.x = x; + this.y = y; + width = w; + height = h; + this.start = start; + this.extent = extent; + } + + /** + * Create a new arc with the given dimensions. + * + * @param r the bounding box + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @throws NullPointerException if r is null + */ + public Double(Rectangle2D r, double start, double extent, int type) + { + super(type); + x = r.getX(); + y = r.getY(); + width = r.getWidth(); + height = r.getHeight(); + this.start = start; + this.extent = extent; + } + + /** + * Return the x coordinate of the bounding box. + * + * @return the value of x + */ + public double getX() + { + return x; + } + + /** + * Return the y coordinate of the bounding box. + * + * @return the value of y + */ + public double getY() + { + return y; + } + + /** + * Return the width of the bounding box. + * + * @return the value of width + */ + public double getWidth() + { + return width; + } + + /** + * Return the height of the bounding box. + * + * @return the value of height + */ + public double getHeight() + { + return height; + } + + /** + * Return the start angle of the arc, in degrees. + * + * @return the value of start + */ + public double getAngleStart() + { + return start; + } + + /** + * Return the extent of the arc, in degrees. + * + * @return the value of extent + */ + public double getAngleExtent() + { + return extent; + } + + /** + * Tests if the arc contains points. + * + * @return true if the arc has no interior + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Sets the arc to the given dimensions. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public void setArc(double x, double y, double w, double h, double start, + double extent, int type) + { + this.x = x; + this.y = y; + width = w; + height = h; + this.start = start; + this.extent = extent; + setArcType(type); + } + + /** + * Sets the start angle of the arc. + * + * @param start the new start angle + */ + public void setAngleStart(double start) + { + this.start = start; + } + + /** + * Sets the extent angle of the arc. + * + * @param extent the new extent angle + */ + public void setAngleExtent(double extent) + { + this.extent = extent; + } + + /** + * Creates a tight bounding box given dimensions that more precise than + * the bounding box of the ellipse. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + protected Rectangle2D makeBounds(double x, double y, double w, double h) + { + return new Rectangle2D.Double(x, y, w, h); + } + } // class Double + + /** + * This class implements an arc in float precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + */ + public static class Float extends Arc2D + { + /** The x coordinate of the box bounding the ellipse of this arc. */ + public float x; + + /** The y coordinate of the box bounding the ellipse of this arc. */ + public float y; + + /** The width of the box bounding the ellipse of this arc. */ + public float width; + + /** The height of the box bounding the ellipse of this arc. */ + public float height; + + /** The start angle of this arc, in degrees. */ + public float start; + + /** The extent angle of this arc, in degrees. */ + public float extent; + + /** + * Create a new, open arc at (0,0) with 0 extent. + */ + public Float() + { + super(OPEN); + } + + /** + * Create a new arc of the given type at (0,0) with 0 extent. + * + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public Float(int type) + { + super(type); + } + + /** + * Create a new arc with the given dimensions. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public Float(float x, float y, float w, float h, float start, + float extent, int type) + { + super(type); + this.x = x; + this.y = y; + width = w; + height = h; + this.start = start; + this.extent = extent; + } + + /** + * Create a new arc with the given dimensions. + * + * @param r the bounding box + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @throws NullPointerException if r is null + */ + public Float(Rectangle2D r, float start, float extent, int type) + { + super(type); + x = (float) r.getX(); + y = (float) r.getY(); + width = (float) r.getWidth(); + height = (float) r.getHeight(); + this.start = start; + this.extent = (float) extent; + } + + /** + * Return the x coordinate of the bounding box. + * + * @return the value of x + */ + public double getX() + { + return x; + } + + /** + * Return the y coordinate of the bounding box. + * + * @return the value of y + */ + public double getY() + { + return y; + } + + /** + * Return the width of the bounding box. + * + * @return the value of width + */ + public double getWidth() + { + return width; + } + + /** + * Return the height of the bounding box. + * + * @return the value of height + */ + public double getHeight() + { + return height; + } + + /** + * Return the start angle of the arc, in degrees. + * + * @return the value of start + */ + public double getAngleStart() + { + return start; + } + + /** + * Return the extent of the arc, in degrees. + * + * @return the value of extent + */ + public double getAngleExtent() + { + return extent; + } + + /** + * Tests if the arc contains points. + * + * @return true if the arc has no interior + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Sets the arc to the given dimensions. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public void setArc(double x, double y, double w, double h, double start, + double extent, int type) + { + this.x = (float) x; + this.y = (float) y; + width = (float) w; + height = (float) h; + this.start = (float) start; + this.extent = (float) extent; + setArcType(type); + } + + /** + * Sets the start angle of the arc. + * + * @param start the new start angle + */ + public void setAngleStart(double start) + { + this.start = (float) start; + } + + /** + * Sets the extent angle of the arc. + * + * @param extent the new extent angle + */ + public void setAngleExtent(double extent) + { + this.extent = (float) extent; + } + + /** + * Creates a tight bounding box given dimensions that more precise than + * the bounding box of the ellipse. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + protected Rectangle2D makeBounds(double x, double y, double w, double h) + { + return new Rectangle2D.Float((float) x, (float) y, (float) w, (float) h); + } + } // class Float +} // class Arc2D diff --git a/libjava/classpath/java/awt/geom/Area.java b/libjava/classpath/java/awt/geom/Area.java new file mode 100644 index 0000000..7a0fac4 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Area.java @@ -0,0 +1,3312 @@ +/* Area.java -- represents a shape built by constructive area geometry + Copyright (C) 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 java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.Vector; + + +/** + * The Area class represents any area for the purpose of + * Constructive Area Geometry (CAG) manipulations. CAG manipulations + * work as an area-wise form of boolean logic, where the basic operations are: + *

  • Add (in boolean algebra: A or B)
    + *
  • Subtract (in boolean algebra: A and (not B) )
    + *
  • Intersect (in boolean algebra: A and B)
    + *
  • Exclusive Or
    + * Illustration of CAG operations
    + * Above is an illustration of the CAG operations on two ring shapes.

    + * + * The contains and intersects() methods are also more accurate than the + * specification of #Shape requires.

    + * + * Please note that constructing an Area can be slow + * (Self-intersection resolving is proportional to the square of + * the number of segments).

    + * @see #add(Area) + * @see #subtract(Area) + * @see #intersect(Area) + * @see #exclusiveOr(Area) + * + * @author Sven de Marothy (sven@physto.se) + * + * @since 1.2 + * @status Works, but could be faster and more reliable. + */ +public class Area implements Shape, Cloneable +{ + /** + * General numerical precision + */ + private static final double EPSILON = 1E-11; + + /** + * recursive subdivision epsilon - (see getRecursionDepth) + */ + private static final double RS_EPSILON = 1E-13; + + /** + * Snap distance - points within this distance are considered equal + */ + private static final double PE_EPSILON = 1E-11; + + /** + * Segment vectors containing solid areas and holes + * This is package-private to avoid an accessor method. + */ + Vector solids; + + /** + * Segment vectors containing solid areas and holes + * This is package-private to avoid an accessor method. + */ + Vector holes; + + /** + * Vector (temporary) storing curve-curve intersections + */ + private Vector cc_intersections; + + /** + * Winding rule WIND_NON_ZERO used, after construction, + * this is irrelevant. + */ + private int windingRule; + + /** + * Constructs an empty Area + */ + public Area() + { + solids = new Vector(); + holes = new Vector(); + } + + /** + * Constructs an Area from any given Shape.

    + * + * If the Shape is self-intersecting, the created Area will consist + * of non-self-intersecting subpaths, and any inner paths which + * are found redundant in accordance with the Shape's winding rule + * will not be included. + * + * @param s the shape (null not permitted). + * + * @throws NullPointerException if s is null. + */ + public Area(Shape s) + { + this(); + + Vector p = makeSegment(s); + + // empty path + if (p == null) + return; + + // delete empty paths + for (int i = 0; i < p.size(); i++) + if (((Segment) p.elementAt(i)).getSignedArea() == 0.0) + p.remove(i--); + + /* + * Resolve self intersecting paths into non-intersecting + * solids and holes. + * Algorithm is as follows: + * 1: Create nodes at all self intersections + * 2: Put all segments into a list + * 3: Grab a segment, follow it, change direction at each node, + * removing segments from the list in the process + * 4: Repeat (3) until no segments remain in the list + * 5: Remove redundant paths and sort into solids and holes + */ + Vector paths = new Vector(); + Segment v; + + for (int i = 0; i < p.size(); i++) + { + Segment path = (Segment) p.elementAt(i); + createNodesSelf(path); + } + + if (p.size() > 1) + { + for (int i = 0; i < p.size() - 1; i++) + for (int j = i + 1; j < p.size(); j++) + { + Segment path1 = (Segment) p.elementAt(i); + Segment path2 = (Segment) p.elementAt(j); + createNodes(path1, path2); + } + } + + // we have intersecting points. + Vector segments = new Vector(); + + for (int i = 0; i < p.size(); i++) + { + Segment path = v = (Segment) p.elementAt(i); + do + { + segments.add(v); + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Performs an add (union) operation on this area with another Area.
    + * @param area - the area to be unioned with this one + */ + public void add(Area area) + { + if (equals(area)) + return; + if (area.isEmpty()) + return; + + Area B = (Area) area.clone(); + + Vector pathA = new Vector(); + Vector pathB = new Vector(); + pathA.addAll(solids); + pathA.addAll(holes); + pathB.addAll(B.solids); + pathB.addAll(B.holes); + + int nNodes = 0; + + for (int i = 0; i < pathA.size(); i++) + { + Segment a = (Segment) pathA.elementAt(i); + for (int j = 0; j < pathB.size(); j++) + { + Segment b = (Segment) pathB.elementAt(j); + nNodes += createNodes(a, b); + } + } + + Vector paths = new Vector(); + Segment v; + + // we have intersecting points. + Vector segments = new Vector(); + + // In a union operation, we keep all + // segments of A oustide B and all B outside A + for (int i = 0; i < pathA.size(); i++) + { + v = (Segment) pathA.elementAt(i); + Segment path = v; + do + { + if (v.isSegmentOutside(area)) + segments.add(v); + v = v.next; + } + while (v != path); + } + + for (int i = 0; i < pathB.size(); i++) + { + v = (Segment) pathB.elementAt(i); + Segment path = v; + do + { + if (v.isSegmentOutside(this)) + segments.add(v); + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Performs a subtraction operation on this Area.
    + * @param area the area to be subtracted from this area. + * @throws NullPointerException if area is null. + */ + public void subtract(Area area) + { + if (isEmpty() || area.isEmpty()) + return; + + if (equals(area)) + { + reset(); + return; + } + + Vector pathA = new Vector(); + Area B = (Area) area.clone(); + pathA.addAll(solids); + pathA.addAll(holes); + + // reverse the directions of B paths. + setDirection(B.holes, true); + setDirection(B.solids, false); + + Vector pathB = new Vector(); + pathB.addAll(B.solids); + pathB.addAll(B.holes); + + int nNodes = 0; + + // create nodes + for (int i = 0; i < pathA.size(); i++) + { + Segment a = (Segment) pathA.elementAt(i); + for (int j = 0; j < pathB.size(); j++) + { + Segment b = (Segment) pathB.elementAt(j); + nNodes += createNodes(a, b); + } + } + + Vector paths = new Vector(); + + // we have intersecting points. + Vector segments = new Vector(); + + // In a subtraction operation, we keep all + // segments of A oustide B and all B within A + // We outsideness-test only one segment in each path + // and the segments before and after any node + for (int i = 0; i < pathA.size(); i++) + { + Segment v = (Segment) pathA.elementAt(i); + Segment path = v; + if (v.isSegmentOutside(area) && v.node == null) + segments.add(v); + boolean node = false; + do + { + if ((v.node != null || node)) + { + node = (v.node != null); + if (v.isSegmentOutside(area)) + segments.add(v); + } + v = v.next; + } + while (v != path); + } + + for (int i = 0; i < pathB.size(); i++) + { + Segment v = (Segment) pathB.elementAt(i); + Segment path = v; + if (! v.isSegmentOutside(this) && v.node == null) + segments.add(v); + v = v.next; + boolean node = false; + do + { + if ((v.node != null || node)) + { + node = (v.node != null); + if (! v.isSegmentOutside(this)) + segments.add(v); + } + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Performs an intersection operation on this Area.
    + * @param area - the area to be intersected with this area. + * @throws NullPointerException if area is null. + */ + public void intersect(Area area) + { + if (isEmpty() || area.isEmpty()) + { + reset(); + return; + } + if (equals(area)) + return; + + Vector pathA = new Vector(); + Area B = (Area) area.clone(); + pathA.addAll(solids); + pathA.addAll(holes); + + Vector pathB = new Vector(); + pathB.addAll(B.solids); + pathB.addAll(B.holes); + + int nNodes = 0; + + // create nodes + for (int i = 0; i < pathA.size(); i++) + { + Segment a = (Segment) pathA.elementAt(i); + for (int j = 0; j < pathB.size(); j++) + { + Segment b = (Segment) pathB.elementAt(j); + nNodes += createNodes(a, b); + } + } + + Vector paths = new Vector(); + + // we have intersecting points. + Vector segments = new Vector(); + + // In an intersection operation, we keep all + // segments of A within B and all B within A + // (The rest must be redundant) + // We outsideness-test only one segment in each path + // and the segments before and after any node + for (int i = 0; i < pathA.size(); i++) + { + Segment v = (Segment) pathA.elementAt(i); + Segment path = v; + if (! v.isSegmentOutside(area) && v.node == null) + segments.add(v); + boolean node = false; + do + { + if ((v.node != null || node)) + { + node = (v.node != null); + if (! v.isSegmentOutside(area)) + segments.add(v); + } + v = v.next; + } + while (v != path); + } + + for (int i = 0; i < pathB.size(); i++) + { + Segment v = (Segment) pathB.elementAt(i); + Segment path = v; + if (! v.isSegmentOutside(this) && v.node == null) + segments.add(v); + v = v.next; + boolean node = false; + do + { + if ((v.node != null || node)) + { + node = (v.node != null); + if (! v.isSegmentOutside(this)) + segments.add(v); + } + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Performs an exclusive-or operation on this Area.
    + * @param area - the area to be XORed with this area. + * @throws NullPointerException if area is null. + */ + public void exclusiveOr(Area area) + { + if (area.isEmpty()) + return; + + if (isEmpty()) + { + Area B = (Area) area.clone(); + solids = B.solids; + holes = B.holes; + return; + } + if (equals(area)) + { + reset(); + return; + } + + Vector pathA = new Vector(); + + Area B = (Area) area.clone(); + Vector pathB = new Vector(); + pathA.addAll(solids); + pathA.addAll(holes); + + // reverse the directions of B paths. + setDirection(B.holes, true); + setDirection(B.solids, false); + pathB.addAll(B.solids); + pathB.addAll(B.holes); + + int nNodes = 0; + + for (int i = 0; i < pathA.size(); i++) + { + Segment a = (Segment) pathA.elementAt(i); + for (int j = 0; j < pathB.size(); j++) + { + Segment b = (Segment) pathB.elementAt(j); + nNodes += createNodes(a, b); + } + } + + Vector paths = new Vector(); + Segment v; + + // we have intersecting points. + Vector segments = new Vector(); + + // In an XOR operation, we operate on all segments + for (int i = 0; i < pathA.size(); i++) + { + v = (Segment) pathA.elementAt(i); + Segment path = v; + do + { + segments.add(v); + v = v.next; + } + while (v != path); + } + + for (int i = 0; i < pathB.size(); i++) + { + v = (Segment) pathB.elementAt(i); + Segment path = v; + do + { + segments.add(v); + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Clears the Area object, creating an empty area. + */ + public void reset() + { + solids = new Vector(); + holes = new Vector(); + } + + /** + * Returns whether this area encloses any area. + * @return true if the object encloses any area. + */ + public boolean isEmpty() + { + if (solids.size() == 0) + return true; + + double totalArea = 0; + for (int i = 0; i < solids.size(); i++) + totalArea += Math.abs(((Segment) solids.elementAt(i)).getSignedArea()); + for (int i = 0; i < holes.size(); i++) + totalArea -= Math.abs(((Segment) holes.elementAt(i)).getSignedArea()); + if (totalArea <= EPSILON) + return true; + + return false; + } + + /** + * Determines whether the Area consists entirely of line segments + * @return true if the Area lines-only, false otherwise + */ + public boolean isPolygonal() + { + for (int i = 0; i < holes.size(); i++) + if (! ((Segment) holes.elementAt(i)).isPolygonal()) + return false; + for (int i = 0; i < solids.size(); i++) + if (! ((Segment) solids.elementAt(i)).isPolygonal()) + return false; + return true; + } + + /** + * Determines if the Area is rectangular.

    + * + * This is strictly qualified. An area is considered rectangular if:
    + *

  • It consists of a single polygonal path.
    + *
  • It is oriented parallel/perpendicular to the xy axis
    + *
  • It must be exactly rectangular, i.e. small errors induced by + * transformations may cause a false result, although the area is + * visibly rectangular.

    + * @return true if the above criteria are met, false otherwise + */ + public boolean isRectangular() + { + if (isEmpty()) + return true; + + if (holes.size() != 0 || solids.size() != 1) + return false; + + Segment path = (Segment) solids.elementAt(0); + if (! path.isPolygonal()) + return false; + + int nCorners = 0; + Segment s = path; + do + { + Segment s2 = s.next; + double d1 = (s.P2.getX() - s.P1.getX())*(s2.P2.getX() - s2.P1.getX())/ + ((s.P1.distance(s.P2)) * (s2.P1.distance(s2.P2))); + double d2 = (s.P2.getY() - s.P1.getY())*(s2.P2.getY() - s2.P1.getY())/ + ((s.P1.distance(s.P2)) * (s2.P1.distance(s2.P2))); + double dotproduct = d1 + d2; + + // For some reason, only rectangles on the XY axis count. + if (d1 != 0 && d2 != 0) + return false; + + if (Math.abs(dotproduct) == 0) // 90 degree angle + nCorners++; + else if ((Math.abs(1.0 - dotproduct) > 0)) // 0 degree angle? + return false; // if not, return false + + s = s.next; + } + while (s != path); + + return nCorners == 4; + } + + /** + * Returns whether the Area consists of more than one simple + * (non self-intersecting) subpath. + * + * @return true if the Area consists of none or one simple subpath, + * false otherwise. + */ + public boolean isSingular() + { + return (holes.size() == 0 && solids.size() <= 1); + } + + /** + * Returns the bounding box of the Area.

    Unlike the CubicCurve2D and + * QuadraticCurve2D classes, this method will return the tightest possible + * bounding box, evaluating the extreme points of each curved segment.

    + * @return the bounding box + */ + public Rectangle2D getBounds2D() + { + if (solids.size() == 0) + return new Rectangle2D.Double(0.0, 0.0, 0.0, 0.0); + + double xmin; + double xmax; + double ymin; + double ymax; + xmin = xmax = ((Segment) solids.elementAt(0)).P1.getX(); + ymin = ymax = ((Segment) solids.elementAt(0)).P1.getY(); + + for (int path = 0; path < solids.size(); path++) + { + Rectangle2D r = ((Segment) solids.elementAt(path)).getPathBounds(); + xmin = Math.min(r.getMinX(), xmin); + ymin = Math.min(r.getMinY(), ymin); + xmax = Math.max(r.getMaxX(), xmax); + ymax = Math.max(r.getMaxY(), ymax); + } + + return (new Rectangle2D.Double(xmin, ymin, (xmax - xmin), (ymax - ymin))); + } + + /** + * Returns the bounds of this object in Rectangle format. + * Please note that this may lead to loss of precision. + * + * @return The bounds. + * @see #getBounds2D() + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + /** + * Create a new area of the same run-time type with the same contents as + * this one. + * + * @return the clone + */ + public Object clone() + { + try + { + Area clone = new Area(); + for (int i = 0; i < solids.size(); i++) + clone.solids.add(((Segment) solids.elementAt(i)).cloneSegmentList()); + for (int i = 0; i < holes.size(); i++) + clone.holes.add(((Segment) holes.elementAt(i)).cloneSegmentList()); + return clone; + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Compares two Areas. + * + * @param area the area to compare against this area (null + * permitted). + * @return true if the areas are equal, and false + * otherwise. + */ + public boolean equals(Area area) + { + if (area == null) + return false; + + if (! getBounds2D().equals(area.getBounds2D())) + return false; + + if (solids.size() != area.solids.size() + || holes.size() != area.holes.size()) + return false; + + Vector pathA = new Vector(); + pathA.addAll(solids); + pathA.addAll(holes); + Vector pathB = new Vector(); + pathB.addAll(area.solids); + pathB.addAll(area.holes); + + int nPaths = pathA.size(); + boolean[][] match = new boolean[2][nPaths]; + + for (int i = 0; i < nPaths; i++) + { + for (int j = 0; j < nPaths; j++) + { + Segment p1 = (Segment) pathA.elementAt(i); + Segment p2 = (Segment) pathB.elementAt(j); + if (! match[0][i] && ! match[1][j]) + if (p1.pathEquals(p2)) + match[0][i] = match[1][j] = true; + } + } + + boolean result = true; + for (int i = 0; i < nPaths; i++) + result = result && match[0][i] && match[1][i]; + return result; + } + + /** + * Transforms this area by the AffineTransform at. + * + * @param at the transform. + */ + public void transform(AffineTransform at) + { + for (int i = 0; i < solids.size(); i++) + ((Segment) solids.elementAt(i)).transformSegmentList(at); + for (int i = 0; i < holes.size(); i++) + ((Segment) holes.elementAt(i)).transformSegmentList(at); + + // Note that the orientation is not invariant under inversion + if ((at.getType() & AffineTransform.TYPE_FLIP) != 0) + { + setDirection(holes, false); + setDirection(solids, true); + } + } + + /** + * Returns a new Area equal to this one, transformed + * by the AffineTransform at. + * @param at the transform. + * @return the transformed area + * @throws NullPointerException if at is null. + */ + public Area createTransformedArea(AffineTransform at) + { + Area a = (Area) clone(); + a.transform(at); + return a; + } + + /** + * Determines if the point (x,y) is contained within this Area. + * + * @param x the x-coordinate of the point. + * @param y the y-coordinate of the point. + * @return true if the point is contained, false otherwise. + */ + public boolean contains(double x, double y) + { + int n = 0; + for (int i = 0; i < solids.size(); i++) + if (((Segment) solids.elementAt(i)).contains(x, y)) + n++; + + for (int i = 0; i < holes.size(); i++) + if (((Segment) holes.elementAt(i)).contains(x, y)) + n--; + + return (n != 0); + } + + /** + * Determines if the Point2D p is contained within this Area. + * + * @param p the point. + * @return true if the point is contained, false + * otherwise. + * @throws NullPointerException if p is null. + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Determines if the rectangle specified by (x,y) as the upper-left + * and with width w and height h is completely contained within this Area, + * returns false otherwise.

    + * + * This method should always produce the correct results, unlike for other + * classes in geom. + * + * @param x the x-coordinate of the rectangle. + * @param y the y-coordinate of the rectangle. + * @param w the width of the the rectangle. + * @param h the height of the rectangle. + * @return true if the rectangle is considered contained + */ + public boolean contains(double x, double y, double w, double h) + { + LineSegment[] l = new LineSegment[4]; + l[0] = new LineSegment(x, y, x + w, y); + l[1] = new LineSegment(x, y + h, x + w, y + h); + l[2] = new LineSegment(x, y, x, y + h); + l[3] = new LineSegment(x + w, y, x + w, y + h); + + // Since every segment in the area must a contour + // between inside/outside segments, ANY intersection + // will mean the rectangle is not entirely contained. + for (int i = 0; i < 4; i++) + { + for (int path = 0; path < solids.size(); path++) + { + Segment v; + Segment start; + start = v = (Segment) solids.elementAt(path); + do + { + if (l[i].hasIntersections(v)) + return false; + v = v.next; + } + while (v != start); + } + for (int path = 0; path < holes.size(); path++) + { + Segment v; + Segment start; + start = v = (Segment) holes.elementAt(path); + do + { + if (l[i].hasIntersections(v)) + return false; + v = v.next; + } + while (v != start); + } + } + + // Is any point inside? + if (! contains(x, y)) + return false; + + // Final hoop: Is the rectangle non-intersecting and inside, + // but encloses a hole? + Rectangle2D r = new Rectangle2D.Double(x, y, w, h); + for (int path = 0; path < holes.size(); path++) + if (! ((Segment) holes.elementAt(path)).isSegmentOutside(r)) + return false; + + return true; + } + + /** + * Determines if the Rectangle2D specified by r is completely contained + * within this Area, returns false otherwise.

    + * + * This method should always produce the correct results, unlike for other + * classes in geom. + * + * @param r the rectangle. + * @return true if the rectangle is considered contained + * + * @throws NullPointerException if r is null. + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determines if the rectangle specified by (x,y) as the upper-left + * and with width w and height h intersects any part of this Area. + * + * @param x the x-coordinate for the rectangle. + * @param y the y-coordinate for the rectangle. + * @param w the width of the rectangle. + * @param h the height of the rectangle. + * @return true if the rectangle intersects the area, + * false otherwise. + */ + public boolean intersects(double x, double y, double w, double h) + { + if (solids.size() == 0) + return false; + + LineSegment[] l = new LineSegment[4]; + l[0] = new LineSegment(x, y, x + w, y); + l[1] = new LineSegment(x, y + h, x + w, y + h); + l[2] = new LineSegment(x, y, x, y + h); + l[3] = new LineSegment(x + w, y, x + w, y + h); + + // Return true on any intersection + for (int i = 0; i < 4; i++) + { + for (int path = 0; path < solids.size(); path++) + { + Segment v; + Segment start; + start = v = (Segment) solids.elementAt(path); + do + { + if (l[i].hasIntersections(v)) + return true; + v = v.next; + } + while (v != start); + } + for (int path = 0; path < holes.size(); path++) + { + Segment v; + Segment start; + start = v = (Segment) holes.elementAt(path); + do + { + if (l[i].hasIntersections(v)) + return true; + v = v.next; + } + while (v != start); + } + } + + // Non-intersecting, Is any point inside? + if (contains(x + w * 0.5, y + h * 0.5)) + return true; + + // What if the rectangle encloses the whole shape? + Point2D p = ((Segment) solids.elementAt(0)).getMidPoint(); + if ((new Rectangle2D.Double(x, y, w, h)).contains(p)) + return true; + return false; + } + + /** + * Determines if the Rectangle2D specified by r intersects any + * part of this Area. + * @param r the rectangle to test intersection with (null + * not permitted). + * @return true if the rectangle intersects the area, + * false otherwise. + * @throws NullPointerException if r is null. + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Returns a PathIterator object defining the contour of this Area, + * transformed by at. + * + * @param at the transform. + * @return A path iterator. + */ + public PathIterator getPathIterator(AffineTransform at) + { + return (new AreaIterator(at)); + } + + /** + * Returns a flattened PathIterator object defining the contour of this + * Area, transformed by at and with a defined flatness. + * + * @param at the transform. + * @param flatness the flatness. + * @return A path iterator. + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + //--------------------------------------------------------------------- + // Non-public methods and classes + + /** + * Private pathiterator object. + */ + private class AreaIterator implements PathIterator + { + private Vector segments; + private int index; + private AffineTransform at; + + // Simple compound type for segments + class IteratorSegment + { + int type; + double[] coords; + + IteratorSegment() + { + coords = new double[6]; + } + } + + /** + * The contructor here does most of the work, + * creates a vector of IteratorSegments, which can + * readily be returned + */ + public AreaIterator(AffineTransform at) + { + this.at = at; + index = 0; + segments = new Vector(); + Vector allpaths = new Vector(); + allpaths.addAll(solids); + allpaths.addAll(holes); + + for (int i = 0; i < allpaths.size(); i++) + { + Segment v = (Segment) allpaths.elementAt(i); + Segment start = v; + + IteratorSegment is = new IteratorSegment(); + is.type = SEG_MOVETO; + is.coords[0] = start.P1.getX(); + is.coords[1] = start.P1.getY(); + segments.add(is); + + do + { + is = new IteratorSegment(); + is.type = v.pathIteratorFormat(is.coords); + segments.add(is); + v = v.next; + } + while (v != start); + + is = new IteratorSegment(); + is.type = SEG_CLOSE; + segments.add(is); + } + } + + public int currentSegment(double[] coords) + { + IteratorSegment s = (IteratorSegment) segments.elementAt(index); + if (at != null) + at.transform(s.coords, 0, coords, 0, 3); + else + for (int i = 0; i < 6; i++) + coords[i] = s.coords[i]; + return (s.type); + } + + public int currentSegment(float[] coords) + { + IteratorSegment s = (IteratorSegment) segments.elementAt(index); + double[] d = new double[6]; + if (at != null) + { + at.transform(s.coords, 0, d, 0, 3); + for (int i = 0; i < 6; i++) + coords[i] = (float) d[i]; + } + else + for (int i = 0; i < 6; i++) + coords[i] = (float) s.coords[i]; + return (s.type); + } + + // Note that the winding rule should not matter here, + // EVEN_ODD is chosen because it renders faster. + public int getWindingRule() + { + return (PathIterator.WIND_EVEN_ODD); + } + + public boolean isDone() + { + return (index >= segments.size()); + } + + public void next() + { + index++; + } + } + + /** + * Performs the fundamental task of the Weiler-Atherton algorithm, + * traverse a list of segments, for each segment: + * Follow it, removing segments from the list and switching paths + * at each node. Do so until the starting segment is reached. + * + * Returns a Vector of the resulting paths. + */ + private Vector weilerAtherton(Vector segments) + { + Vector paths = new Vector(); + while (segments.size() > 0) + { + // Iterate over the path + Segment start = (Segment) segments.elementAt(0); + Segment s = start; + do + { + segments.remove(s); + if (s.node != null) + { // switch over + s.next = s.node; + s.node = null; + } + s = s.next; // continue + } + while (s != start); + + paths.add(start); + } + return paths; + } + + /** + * A small wrapper class to store intersection points + */ + private class Intersection + { + Point2D p; // the 2D point of intersection + double ta; // the parametric value on a + double tb; // the parametric value on b + Segment seg; // segment placeholder for node setting + + public Intersection(Point2D p, double ta, double tb) + { + this.p = p; + this.ta = ta; + this.tb = tb; + } + } + + /** + * Returns the recursion depth necessary to approximate the + * curve by line segments within the error RS_EPSILON. + * + * This is done with Wang's formula: + * L0 = max{0<=i<=N-2}(|xi - 2xi+1 + xi+2|,|yi - 2yi+1 + yi+2|) + * r0 = log4(sqrt(2)*N*(N-1)*L0/8e) + * Where e is the maximum distance error (RS_EPSILON) + */ + private int getRecursionDepth(CubicSegment curve) + { + double x0 = curve.P1.getX(); + double y0 = curve.P1.getY(); + + double x1 = curve.cp1.getX(); + double y1 = curve.cp1.getY(); + + double x2 = curve.cp2.getX(); + double y2 = curve.cp2.getY(); + + double x3 = curve.P2.getX(); + double y3 = curve.P2.getY(); + + double L0 = Math.max(Math.max(Math.abs(x0 - 2 * x1 + x2), + Math.abs(x1 - 2 * x2 + x3)), + Math.max(Math.abs(y0 - 2 * y1 + y2), + Math.abs(y1 - 2 * y2 + y3))); + + double f = Math.sqrt(2) * 6.0 * L0 / (8.0 * RS_EPSILON); + + int r0 = (int) Math.ceil(Math.log(f) / Math.log(4.0)); + return (r0); + } + + /** + * Performs recursive subdivision: + * @param c1 - curve 1 + * @param c2 - curve 2 + * @param depth1 - recursion depth of curve 1 + * @param depth2 - recursion depth of curve 2 + * @param t1 - global parametric value of the first curve's starting point + * @param t2 - global parametric value of the second curve's starting point + * @param w1 - global parametric length of curve 1 + * @param c1 - global parametric length of curve 2 + * + * The final four parameters are for keeping track of the parametric + * value of the curve. For a full curve t = 0, w = 1, w is halved with + * each subdivision. + */ + private void recursiveSubdivide(CubicCurve2D c1, CubicCurve2D c2, + int depth1, int depth2, double t1, + double t2, double w1, double w2) + { + boolean flat1 = depth1 <= 0; + boolean flat2 = depth2 <= 0; + + if (flat1 && flat2) + { + double xlk = c1.getP2().getX() - c1.getP1().getX(); + double ylk = c1.getP2().getY() - c1.getP1().getY(); + + double xnm = c2.getP2().getX() - c2.getP1().getX(); + double ynm = c2.getP2().getY() - c2.getP1().getY(); + + double xmk = c2.getP1().getX() - c1.getP1().getX(); + double ymk = c2.getP1().getY() - c1.getP1().getY(); + double det = xnm * ylk - ynm * xlk; + + if (det + 1.0 == 1.0) + return; + + double detinv = 1.0 / det; + double s = (xnm * ymk - ynm * xmk) * detinv; + double t = (xlk * ymk - ylk * xmk) * detinv; + if ((s < 0.0) || (s > 1.0) || (t < 0.0) || (t > 1.0)) + return; + + double[] temp = new double[2]; + temp[0] = t1 + s * w1; + temp[1] = t2 + t * w1; + cc_intersections.add(temp); + return; + } + + CubicCurve2D.Double c11 = new CubicCurve2D.Double(); + CubicCurve2D.Double c12 = new CubicCurve2D.Double(); + CubicCurve2D.Double c21 = new CubicCurve2D.Double(); + CubicCurve2D.Double c22 = new CubicCurve2D.Double(); + + if (! flat1 && ! flat2) + { + depth1--; + depth2--; + w1 = w1 * 0.5; + w2 = w2 * 0.5; + c1.subdivide(c11, c12); + c2.subdivide(c21, c22); + if (c11.getBounds2D().intersects(c21.getBounds2D())) + recursiveSubdivide(c11, c21, depth1, depth2, t1, t2, w1, w2); + if (c11.getBounds2D().intersects(c22.getBounds2D())) + recursiveSubdivide(c11, c22, depth1, depth2, t1, t2 + w2, w1, w2); + if (c12.getBounds2D().intersects(c21.getBounds2D())) + recursiveSubdivide(c12, c21, depth1, depth2, t1 + w1, t2, w1, w2); + if (c12.getBounds2D().intersects(c22.getBounds2D())) + recursiveSubdivide(c12, c22, depth1, depth2, t1 + w1, t2 + w2, w1, w2); + return; + } + + if (! flat1) + { + depth1--; + c1.subdivide(c11, c12); + w1 = w1 * 0.5; + if (c11.getBounds2D().intersects(c2.getBounds2D())) + recursiveSubdivide(c11, c2, depth1, depth2, t1, t2, w1, w2); + if (c12.getBounds2D().intersects(c2.getBounds2D())) + recursiveSubdivide(c12, c2, depth1, depth2, t1 + w1, t2, w1, w2); + return; + } + + depth2--; + c2.subdivide(c21, c22); + w2 = w2 * 0.5; + if (c1.getBounds2D().intersects(c21.getBounds2D())) + recursiveSubdivide(c1, c21, depth1, depth2, t1, t2, w1, w2); + if (c1.getBounds2D().intersects(c22.getBounds2D())) + recursiveSubdivide(c1, c22, depth1, depth2, t1, t2 + w2, w1, w2); + } + + /** + * Returns a set of interesections between two Cubic segments + * Or null if no intersections were found. + * + * The method used to find the intersection is recursive midpoint + * subdivision. Outline description: + * + * 1) Check if the bounding boxes of the curves intersect, + * 2) If so, divide the curves in the middle and test the bounding + * boxes again, + * 3) Repeat until a maximum recursion depth has been reached, where + * the intersecting curves can be approximated by line segments. + * + * This is a reasonably accurate method, although the recursion depth + * is typically around 20, the bounding-box tests allow for significant + * pruning of the subdivision tree. + * + * This is package-private to avoid an accessor method. + */ + Intersection[] cubicCubicIntersect(CubicSegment curve1, CubicSegment curve2) + { + Rectangle2D r1 = curve1.getBounds(); + Rectangle2D r2 = curve2.getBounds(); + + if (! r1.intersects(r2)) + return null; + + cc_intersections = new Vector(); + recursiveSubdivide(curve1.getCubicCurve2D(), curve2.getCubicCurve2D(), + getRecursionDepth(curve1), getRecursionDepth(curve2), + 0.0, 0.0, 1.0, 1.0); + + if (cc_intersections.size() == 0) + return null; + + Intersection[] results = new Intersection[cc_intersections.size()]; + for (int i = 0; i < cc_intersections.size(); i++) + { + double[] temp = (double[]) cc_intersections.elementAt(i); + results[i] = new Intersection(curve1.evaluatePoint(temp[0]), temp[0], + temp[1]); + } + cc_intersections = null; + return (results); + } + + /** + * Returns the intersections between a line and a quadratic bezier + * Or null if no intersections are found1 + * This is done through combining the line's equation with the + * parametric form of the Bezier and solving the resulting quadratic. + * This is package-private to avoid an accessor method. + */ + Intersection[] lineQuadIntersect(LineSegment l, QuadSegment c) + { + double[] y = new double[3]; + double[] x = new double[3]; + double[] r = new double[3]; + int nRoots; + double x0 = c.P1.getX(); + double y0 = c.P1.getY(); + double x1 = c.cp.getX(); + double y1 = c.cp.getY(); + double x2 = c.P2.getX(); + double y2 = c.P2.getY(); + + double lx0 = l.P1.getX(); + double ly0 = l.P1.getY(); + double lx1 = l.P2.getX(); + double ly1 = l.P2.getY(); + double dx = lx1 - lx0; + double dy = ly1 - ly0; + + // form r(t) = y(t) - x(t) for the bezier + y[0] = y0; + y[1] = 2 * (y1 - y0); + y[2] = (y2 - 2 * y1 + y0); + + x[0] = x0; + x[1] = 2 * (x1 - x0); + x[2] = (x2 - 2 * x1 + x0); + + // a point, not a line + if (dy == 0 && dx == 0) + return null; + + // line on y axis + if (dx == 0 || (dy / dx) > 1.0) + { + double k = dx / dy; + x[0] -= lx0; + y[0] -= ly0; + y[0] *= k; + y[1] *= k; + y[2] *= k; + } + else + { + double k = dy / dx; + x[0] -= lx0; + y[0] -= ly0; + x[0] *= k; + x[1] *= k; + x[2] *= k; + } + + for (int i = 0; i < 3; i++) + r[i] = y[i] - x[i]; + + if ((nRoots = QuadCurve2D.solveQuadratic(r)) > 0) + { + Intersection[] temp = new Intersection[nRoots]; + int intersections = 0; + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + Point2D p = c.evaluatePoint(t); + + // if the line is on an axis, snap the point to that axis. + if (dx == 0) + p.setLocation(lx0, p.getY()); + if (dy == 0) + p.setLocation(p.getX(), ly0); + + if (p.getX() <= Math.max(lx0, lx1) + && p.getX() >= Math.min(lx0, lx1) + && p.getY() <= Math.max(ly0, ly1) + && p.getY() >= Math.min(ly0, ly1)) + { + double lineparameter = p.distance(l.P1) / l.P2.distance(l.P1); + temp[i] = new Intersection(p, lineparameter, t); + intersections++; + } + } + else + temp[i] = null; + } + if (intersections == 0) + return null; + + Intersection[] rValues = new Intersection[intersections]; + + for (int i = 0; i < nRoots; i++) + if (temp[i] != null) + rValues[--intersections] = temp[i]; + return (rValues); + } + return null; + } + + /** + * Returns the intersections between a line and a cubic segment + * This is done through combining the line's equation with the + * parametric form of the Bezier and solving the resulting quadratic. + * This is package-private to avoid an accessor method. + */ + Intersection[] lineCubicIntersect(LineSegment l, CubicSegment c) + { + double[] y = new double[4]; + double[] x = new double[4]; + double[] r = new double[4]; + int nRoots; + double x0 = c.P1.getX(); + double y0 = c.P1.getY(); + double x1 = c.cp1.getX(); + double y1 = c.cp1.getY(); + double x2 = c.cp2.getX(); + double y2 = c.cp2.getY(); + double x3 = c.P2.getX(); + double y3 = c.P2.getY(); + + double lx0 = l.P1.getX(); + double ly0 = l.P1.getY(); + double lx1 = l.P2.getX(); + double ly1 = l.P2.getY(); + double dx = lx1 - lx0; + double dy = ly1 - ly0; + + // form r(t) = y(t) - x(t) for the bezier + y[0] = y0; + y[1] = 3 * (y1 - y0); + y[2] = 3 * (y2 + y0 - 2 * y1); + y[3] = y3 - 3 * y2 + 3 * y1 - y0; + + x[0] = x0; + x[1] = 3 * (x1 - x0); + x[2] = 3 * (x2 + x0 - 2 * x1); + x[3] = x3 - 3 * x2 + 3 * x1 - x0; + + // a point, not a line + if (dy == 0 && dx == 0) + return null; + + // line on y axis + if (dx == 0 || (dy / dx) > 1.0) + { + double k = dx / dy; + x[0] -= lx0; + y[0] -= ly0; + y[0] *= k; + y[1] *= k; + y[2] *= k; + y[3] *= k; + } + else + { + double k = dy / dx; + x[0] -= lx0; + y[0] -= ly0; + x[0] *= k; + x[1] *= k; + x[2] *= k; + x[3] *= k; + } + for (int i = 0; i < 4; i++) + r[i] = y[i] - x[i]; + + if ((nRoots = CubicCurve2D.solveCubic(r)) > 0) + { + Intersection[] temp = new Intersection[nRoots]; + int intersections = 0; + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + // if the line is on an axis, snap the point to that axis. + Point2D p = c.evaluatePoint(t); + if (dx == 0) + p.setLocation(lx0, p.getY()); + if (dy == 0) + p.setLocation(p.getX(), ly0); + + if (p.getX() <= Math.max(lx0, lx1) + && p.getX() >= Math.min(lx0, lx1) + && p.getY() <= Math.max(ly0, ly1) + && p.getY() >= Math.min(ly0, ly1)) + { + double lineparameter = p.distance(l.P1) / l.P2.distance(l.P1); + temp[i] = new Intersection(p, lineparameter, t); + intersections++; + } + } + else + temp[i] = null; + } + + if (intersections == 0) + return null; + + Intersection[] rValues = new Intersection[intersections]; + for (int i = 0; i < nRoots; i++) + if (temp[i] != null) + rValues[--intersections] = temp[i]; + return (rValues); + } + return null; + } + + /** + * Returns the intersection between two lines, or null if there is no + * intersection. + * This is package-private to avoid an accessor method. + */ + Intersection linesIntersect(LineSegment a, LineSegment b) + { + Point2D P1 = a.P1; + Point2D P2 = a.P2; + Point2D P3 = b.P1; + Point2D P4 = b.P2; + + if (! Line2D.linesIntersect(P1.getX(), P1.getY(), P2.getX(), P2.getY(), + P3.getX(), P3.getY(), P4.getX(), P4.getY())) + return null; + + double x1 = P1.getX(); + double y1 = P1.getY(); + double rx = P2.getX() - x1; + double ry = P2.getY() - y1; + + double x2 = P3.getX(); + double y2 = P3.getY(); + double sx = P4.getX() - x2; + double sy = P4.getY() - y2; + + double determinant = sx * ry - sy * rx; + double nom = (sx * (y2 - y1) + sy * (x1 - x2)); + + // Parallel lines don't intersect. At least we pretend they don't. + if (Math.abs(determinant) < EPSILON) + return null; + + nom = nom / determinant; + + if (nom == 0.0) + return null; + if (nom == 1.0) + return null; + + Point2D p = new Point2D.Double(x1 + nom * rx, y1 + nom * ry); + + return new Intersection(p, p.distance(P1) / P1.distance(P2), + p.distance(P3) / P3.distance(P4)); + } + + /** + * Determines if two points are equal, within an error margin + * 'snap distance' + * This is package-private to avoid an accessor method. + */ + boolean pointEquals(Point2D a, Point2D b) + { + return (a.equals(b) || a.distance(b) < PE_EPSILON); + } + + /** + * Helper method + * Turns a shape into a Vector of Segments + */ + private Vector makeSegment(Shape s) + { + Vector paths = new Vector(); + PathIterator pi = s.getPathIterator(null); + double[] coords = new double[6]; + Segment subpath = null; + Segment current = null; + double cx; + double cy; + double subpathx; + double subpathy; + cx = cy = subpathx = subpathy = 0.0; + + this.windingRule = pi.getWindingRule(); + + while (! pi.isDone()) + { + Segment v; + switch (pi.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + if (subpath != null) + { // close existing open path + current.next = new LineSegment(cx, cy, subpathx, subpathy); + current = current.next; + current.next = subpath; + } + subpath = null; + subpathx = cx = coords[0]; + subpathy = cy = coords[1]; + break; + + // replace 'close' with a line-to. + case PathIterator.SEG_CLOSE: + if (subpath != null && (subpathx != cx || subpathy != cy)) + { + current.next = new LineSegment(cx, cy, subpathx, subpathy); + current = current.next; + current.next = subpath; + cx = subpathx; + cy = subpathy; + subpath = null; + } + else if (subpath != null) + { + current.next = subpath; + subpath = null; + } + break; + case PathIterator.SEG_LINETO: + if (cx != coords[0] || cy != coords[1]) + { + v = new LineSegment(cx, cy, coords[0], coords[1]); + if (subpath == null) + { + subpath = current = v; + paths.add(subpath); + } + else + { + current.next = v; + current = current.next; + } + cx = coords[0]; + cy = coords[1]; + } + break; + case PathIterator.SEG_QUADTO: + v = new QuadSegment(cx, cy, coords[0], coords[1], coords[2], + coords[3]); + if (subpath == null) + { + subpath = current = v; + paths.add(subpath); + } + else + { + current.next = v; + current = current.next; + } + cx = coords[2]; + cy = coords[3]; + break; + case PathIterator.SEG_CUBICTO: + v = new CubicSegment(cx, cy, coords[0], coords[1], coords[2], + coords[3], coords[4], coords[5]); + if (subpath == null) + { + subpath = current = v; + paths.add(subpath); + } + else + { + current.next = v; + current = current.next; + } + + // check if the cubic is self-intersecting + double[] lpts = ((CubicSegment) v).getLoop(); + if (lpts != null) + { + // if it is, break off the loop into its own path. + v.subdivideInsert(lpts[0]); + v.next.subdivideInsert((lpts[1] - lpts[0]) / (1.0 - lpts[0])); + + CubicSegment loop = (CubicSegment) v.next; + v.next = loop.next; + loop.next = loop; + + v.P2 = v.next.P1 = loop.P2 = loop.P1; // snap points + paths.add(loop); + current = v.next; + } + + cx = coords[4]; + cy = coords[5]; + break; + } + pi.next(); + } + + if (subpath != null) + { // close any open path + if (subpathx != cx || subpathy != cy) + { + current.next = new LineSegment(cx, cy, subpathx, subpathy); + current = current.next; + current.next = subpath; + } + else + current.next = subpath; + } + + if (paths.size() == 0) + return (null); + + return (paths); + } + + /** + * Find the intersections of two separate closed paths, + * A and B, split the segments at the intersection points, + * and create nodes pointing from one to the other + */ + private int createNodes(Segment A, Segment B) + { + int nNodes = 0; + + Segment a = A; + Segment b = B; + + do + { + do + { + nNodes += a.splitIntersections(b); + b = b.next; + } + while (b != B); + + a = a.next; // move to the next segment + } + while (a != A); // until one wrap. + + return (nNodes); + } + + /** + * Find the intersections of a path with itself. + * Splits the segments at the intersection points, + * and create nodes pointing from one to the other. + */ + private int createNodesSelf(Segment A) + { + int nNodes = 0; + Segment a = A; + + if (A.next == A) + return 0; + + do + { + Segment b = a.next; + do + { + if (b != a) // necessary + nNodes += a.splitIntersections(b); + b = b.next; + } + while (b != A); + a = a.next; // move to the next segment + } + while (a != A); // until one wrap. + + return (nNodes); + } + + /** + * Deletes paths which are redundant from a list, (i.e. solid areas within + * solid areas) Clears any nodes. Sorts the remaining paths into solids + * and holes, sets their orientation and sets the solids and holes lists. + */ + private void deleteRedundantPaths(Vector paths) + { + int npaths = paths.size(); + + int[][] contains = new int[npaths][npaths]; + int[][] windingNumbers = new int[npaths][2]; + int neg; + Rectangle2D[] bb = new Rectangle2D[npaths]; // path bounding boxes + + neg = ((windingRule == PathIterator.WIND_NON_ZERO) ? -1 : 1); + + for (int i = 0; i < npaths; i++) + bb[i] = ((Segment) paths.elementAt(i)).getPathBounds(); + + // Find which path contains which, assign winding numbers + for (int i = 0; i < npaths; i++) + { + Segment pathA = (Segment) paths.elementAt(i); + pathA.nullNodes(); // remove any now-redundant nodes, in case. + int windingA = pathA.hasClockwiseOrientation() ? 1 : neg; + + for (int j = 0; j < npaths; j++) + if (i != j) + { + Segment pathB = (Segment) paths.elementAt(j); + + // A contains B + if (bb[i].intersects(bb[j])) + { + Segment s = pathB.next; + while (s.P1.getY() == s.P2.getY() && s != pathB) + s = s.next; + Point2D p = s.getMidPoint(); + if (pathA.contains(p.getX(), p.getY())) + contains[i][j] = windingA; + } + else + // A does not contain B + contains[i][j] = 0; + } + else + contains[i][j] = windingA; // i == j + } + + for (int i = 0; i < npaths; i++) + { + windingNumbers[i][0] = 0; + for (int j = 0; j < npaths; j++) + windingNumbers[i][0] += contains[j][i]; + windingNumbers[i][1] = contains[i][i]; + } + + Vector solids = new Vector(); + Vector holes = new Vector(); + + if (windingRule == PathIterator.WIND_NON_ZERO) + { + for (int i = 0; i < npaths; i++) + { + if (windingNumbers[i][0] == 0) + holes.add(paths.elementAt(i)); + else if (windingNumbers[i][0] - windingNumbers[i][1] == 0 + && Math.abs(windingNumbers[i][0]) == 1) + solids.add(paths.elementAt(i)); + } + } + else + { + windingRule = PathIterator.WIND_NON_ZERO; + for (int i = 0; i < npaths; i++) + { + if ((windingNumbers[i][0] & 1) == 0) + holes.add(paths.elementAt(i)); + else if ((windingNumbers[i][0] & 1) == 1) + solids.add(paths.elementAt(i)); + } + } + + setDirection(holes, false); + setDirection(solids, true); + this.holes = holes; + this.solids = solids; + } + + /** + * Sets the winding direction of a Vector of paths + * @param clockwise gives the direction, + * true = clockwise, false = counter-clockwise + */ + private void setDirection(Vector paths, boolean clockwise) + { + Segment v; + for (int i = 0; i < paths.size(); i++) + { + v = (Segment) paths.elementAt(i); + if (clockwise != v.hasClockwiseOrientation()) + v.reverseAll(); + } + } + + /** + * Class representing a linked-list of vertices forming a closed polygon, + * convex or concave, without holes. + */ + private abstract class Segment implements Cloneable + { + // segment type, PathIterator segment types are used. + Point2D P1; + Point2D P2; + Segment next; + Segment node; + + Segment() + { + P1 = P2 = null; + node = next = null; + } + + /** + * Reverses the direction of a single segment + */ + abstract void reverseCoords(); + + /** + * Returns the segment's midpoint + */ + abstract Point2D getMidPoint(); + + /** + * Returns the bounding box of this segment + */ + abstract Rectangle2D getBounds(); + + /** + * Transforms a single segment + */ + abstract void transform(AffineTransform at); + + /** + * Returns the PathIterator type of a segment + */ + abstract int getType(); + + /** + */ + abstract int splitIntersections(Segment b); + + /** + * Returns the PathIterator coords of a segment + */ + abstract int pathIteratorFormat(double[] coords); + + /** + * Returns the number of intersections on the positive X axis, + * with the origin at (x,y), used for contains()-testing + * + * (Although that could be done by the line-intersect methods, + * a dedicated method is better to guarantee consitent handling + * of endpoint-special-cases) + */ + abstract int rayCrossing(double x, double y); + + /** + * Subdivides the segment at parametric value t, inserting + * the new segment into the linked list after this, + * such that this becomes [0,t] and this.next becomes [t,1] + */ + abstract void subdivideInsert(double t); + + /** + * Returns twice the area of a curve, relative the P1-P2 line + * Used for area calculations. + */ + abstract double curveArea(); + + /** + * Compare two segments. + */ + abstract boolean equals(Segment b); + + /** + * Determines if this path of segments contains the point (x,y) + */ + boolean contains(double x, double y) + { + Segment v = this; + int crossings = 0; + do + { + int n = v.rayCrossing(x, y); + crossings += n; + v = v.next; + } + while (v != this); + return ((crossings & 1) == 1); + } + + /** + * Nulls all nodes of the path. Clean up any 'hairs'. + */ + void nullNodes() + { + Segment v = this; + do + { + v.node = null; + v = v.next; + } + while (v != this); + } + + /** + * Transforms each segment in the closed path + */ + void transformSegmentList(AffineTransform at) + { + Segment v = this; + do + { + v.transform(at); + v = v.next; + } + while (v != this); + } + + /** + * Determines the winding direction of the path + * By the sign of the area. + */ + boolean hasClockwiseOrientation() + { + return (getSignedArea() > 0.0); + } + + /** + * Returns the bounds of this path + */ + public Rectangle2D getPathBounds() + { + double xmin; + double xmax; + double ymin; + double ymax; + xmin = xmax = P1.getX(); + ymin = ymax = P1.getY(); + + Segment v = this; + do + { + Rectangle2D r = v.getBounds(); + xmin = Math.min(r.getMinX(), xmin); + ymin = Math.min(r.getMinY(), ymin); + xmax = Math.max(r.getMaxX(), xmax); + ymax = Math.max(r.getMaxY(), ymax); + v = v.next; + } + while (v != this); + + return (new Rectangle2D.Double(xmin, ymin, (xmax - xmin), (ymax - ymin))); + } + + /** + * Calculates twice the signed area of the path; + */ + double getSignedArea() + { + Segment s; + double area = 0.0; + + s = this; + do + { + area += s.curveArea(); + + area += s.P1.getX() * s.next.P1.getY() + - s.P1.getY() * s.next.P1.getX(); + s = s.next; + } + while (s != this); + + return area; + } + + /** + * Reverses the orientation of the whole polygon + */ + void reverseAll() + { + reverseCoords(); + Segment v = next; + Segment former = this; + while (v != this) + { + v.reverseCoords(); + Segment vnext = v.next; + v.next = former; + former = v; + v = vnext; + } + next = former; + } + + /** + * Inserts a Segment after this one + */ + void insert(Segment v) + { + Segment n = next; + next = v; + v.next = n; + } + + /** + * Returns if this segment path is polygonal + */ + boolean isPolygonal() + { + Segment v = this; + do + { + if (! (v instanceof LineSegment)) + return false; + v = v.next; + } + while (v != this); + return true; + } + + /** + * Clones this path + */ + Segment cloneSegmentList() throws CloneNotSupportedException + { + Vector list = new Vector(); + Segment v = next; + + while (v != this) + { + list.add(v); + v = v.next; + } + + Segment clone = (Segment) this.clone(); + v = clone; + for (int i = 0; i < list.size(); i++) + { + clone.next = (Segment) ((Segment) list.elementAt(i)).clone(); + clone = clone.next; + } + clone.next = v; + return v; + } + + /** + * Creates a node between this segment and segment b + * at the given intersection + * @return the number of nodes created (0 or 1) + */ + int createNode(Segment b, Intersection i) + { + Point2D p = i.p; + if ((pointEquals(P1, p) || pointEquals(P2, p)) + && (pointEquals(b.P1, p) || pointEquals(b.P2, p))) + return 0; + + subdivideInsert(i.ta); + b.subdivideInsert(i.tb); + + // snap points + b.P2 = b.next.P1 = P2 = next.P1 = i.p; + + node = b.next; + b.node = next; + return 1; + } + + /** + * Creates multiple nodes from a list of intersections, + * This must be done in the order of ascending parameters, + * and the parameters must be recalculated in accordance + * with each split. + * @return the number of nodes created + */ + protected int createNodes(Segment b, Intersection[] x) + { + Vector v = new Vector(); + for (int i = 0; i < x.length; i++) + { + Point2D p = x[i].p; + if (! ((pointEquals(P1, p) || pointEquals(P2, p)) + && (pointEquals(b.P1, p) || pointEquals(b.P2, p)))) + v.add(x[i]); + } + + int nNodes = v.size(); + Intersection[] A = new Intersection[nNodes]; + Intersection[] B = new Intersection[nNodes]; + for (int i = 0; i < nNodes; i++) + A[i] = B[i] = (Intersection) v.elementAt(i); + + // Create two lists sorted by the parameter + // Bubble sort, OK I suppose, since the number of intersections + // cannot be larger than 9 (cubic-cubic worst case) anyway + for (int i = 0; i < nNodes - 1; i++) + { + for (int j = i + 1; j < nNodes; j++) + { + if (A[i].ta > A[j].ta) + { + Intersection swap = A[i]; + A[i] = A[j]; + A[j] = swap; + } + if (B[i].tb > B[j].tb) + { + Intersection swap = B[i]; + B[i] = B[j]; + B[j] = swap; + } + } + } + // subdivide a + Segment s = this; + for (int i = 0; i < nNodes; i++) + { + s.subdivideInsert(A[i].ta); + + // renormalize the parameters + for (int j = i + 1; j < nNodes; j++) + A[j].ta = (A[j].ta - A[i].ta) / (1.0 - A[i].ta); + + A[i].seg = s; + s = s.next; + } + + // subdivide b, set nodes + s = b; + for (int i = 0; i < nNodes; i++) + { + s.subdivideInsert(B[i].tb); + + for (int j = i + 1; j < nNodes; j++) + B[j].tb = (B[j].tb - B[i].tb) / (1.0 - B[i].tb); + + // set nodes + B[i].seg.node = s.next; // node a -> b + s.node = B[i].seg.next; // node b -> a + + // snap points + B[i].seg.P2 = B[i].seg.next.P1 = s.P2 = s.next.P1 = B[i].p; + s = s.next; + } + return nNodes; + } + + /** + * Determines if two paths are equal. + * Colinear line segments are ignored in the comparison. + */ + boolean pathEquals(Segment B) + { + if (! getPathBounds().equals(B.getPathBounds())) + return false; + + Segment startA = getTopLeft(); + Segment startB = B.getTopLeft(); + Segment a = startA; + Segment b = startB; + do + { + if (! a.equals(b)) + return false; + + if (a instanceof LineSegment) + a = ((LineSegment) a).lastCoLinear(); + if (b instanceof LineSegment) + b = ((LineSegment) b).lastCoLinear(); + + a = a.next; + b = b.next; + } + while (a != startA && b != startB); + return true; + } + + /** + * Return the segment with the top-leftmost first point + */ + Segment getTopLeft() + { + Segment v = this; + Segment tl = this; + do + { + if (v.P1.getY() < tl.P1.getY()) + tl = v; + else if (v.P1.getY() == tl.P1.getY()) + { + if (v.P1.getX() < tl.P1.getX()) + tl = v; + } + v = v.next; + } + while (v != this); + return tl; + } + + /** + * Returns if the path has a segment outside a shape + */ + boolean isSegmentOutside(Shape shape) + { + return ! shape.contains(getMidPoint()); + } + } // class Segment + + private 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() + { + return new LineSegment(P1, P2); + } + + /** + * Transforms the segment + */ + void transform(AffineTransform at) + { + P1 = at.transform(P1, null); + P2 = at.transform(P2, null); + } + + /** + * Swap start and end points + */ + void reverseCoords() + { + Point2D p = P1; + P1 = P2; + P2 = p; + } + + /** + * Returns the segment's midpoint + */ + Point2D getMidPoint() + { + return (new Point2D.Double(0.5 * (P1.getX() + P2.getX()), + 0.5 * (P1.getY() + P2.getY()))); + } + + /** + * Returns twice the area of a curve, relative the P1-P2 line + * Obviously, a line does not enclose any area besides the line + */ + double curveArea() + { + return 0; + } + + /** + * Returns the PathIterator type of a segment + */ + int getType() + { + return (PathIterator.SEG_LINETO); + } + + /** + * Subdivides the segment at parametric value t, inserting + * the new segment into the linked list after this, + * such that this becomes [0,t] and this.next becomes [t,1] + */ + void subdivideInsert(double t) + { + Point2D p = new Point2D.Double((P2.getX() - P1.getX()) * t + P1.getX(), + (P2.getY() - P1.getY()) * t + P1.getY()); + insert(new LineSegment(p, P2)); + P2 = p; + next.node = node; + node = null; + } + + /** + * Determines if two line segments are strictly colinear + */ + boolean isCoLinear(LineSegment b) + { + double x1 = P1.getX(); + double y1 = P1.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + double x3 = b.P1.getX(); + double y3 = b.P1.getY(); + double x4 = b.P2.getX(); + double y4 = b.P2.getY(); + + if ((y1 - y3) * (x4 - x3) - (x1 - x3) * (y4 - y3) != 0.0) + return false; + + return ((x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3) == 0.0); + } + + /** + * Return the last segment colinear with this one. + * Used in comparing paths. + */ + Segment lastCoLinear() + { + Segment prev = this; + Segment v = next; + + while (v instanceof LineSegment) + { + if (isCoLinear((LineSegment) v)) + { + prev = v; + v = v.next; + } + else + return prev; + } + return prev; + } + + /** + * Compare two segments. + * We must take into account that the lines may be broken into colinear + * subsegments and ignore them. + */ + boolean equals(Segment b) + { + if (! (b instanceof LineSegment)) + return false; + Point2D p1 = P1; + Point2D p3 = b.P1; + + if (! p1.equals(p3)) + return false; + + Point2D p2 = lastCoLinear().P2; + Point2D p4 = ((LineSegment) b).lastCoLinear().P2; + return (p2.equals(p4)); + } + + /** + * Returns a line segment + */ + int pathIteratorFormat(double[] coords) + { + coords[0] = P2.getX(); + coords[1] = P2.getY(); + return (PathIterator.SEG_LINETO); + } + + /** + * Returns if the line has intersections. + */ + boolean hasIntersections(Segment b) + { + if (b instanceof LineSegment) + return (linesIntersect(this, (LineSegment) b) != null); + + if (b instanceof QuadSegment) + return (lineQuadIntersect(this, (QuadSegment) b) != null); + + if (b instanceof CubicSegment) + return (lineCubicIntersect(this, (CubicSegment) b) != null); + + return false; + } + + /** + * Splits intersections into nodes, + * This one handles line-line, line-quadratic, line-cubic + */ + int splitIntersections(Segment b) + { + if (b instanceof LineSegment) + { + Intersection i = linesIntersect(this, (LineSegment) b); + + if (i == null) + return 0; + + return createNode(b, i); + } + + Intersection[] x = null; + + if (b instanceof QuadSegment) + x = lineQuadIntersect(this, (QuadSegment) b); + + if (b instanceof CubicSegment) + x = lineCubicIntersect(this, (CubicSegment) b); + + if (x == null) + return 0; + + if (x.length == 1) + return createNode(b, (Intersection) x[0]); + + return createNodes(b, x); + } + + /** + * Returns the bounding box of this segment + */ + Rectangle2D getBounds() + { + return (new Rectangle2D.Double(Math.min(P1.getX(), P2.getX()), + Math.min(P1.getY(), P2.getY()), + Math.abs(P1.getX() - P2.getX()), + Math.abs(P1.getY() - P2.getY()))); + } + + /** + * Returns the number of intersections on the positive X axis, + * with the origin at (x,y), used for contains()-testing + */ + int rayCrossing(double x, double y) + { + double x0 = P1.getX() - x; + double y0 = P1.getY() - y; + double x1 = P2.getX() - x; + double y1 = P2.getY() - y; + + if (y0 * y1 > 0) + return 0; + + if (x0 < 0 && x1 < 0) + return 0; + + if (y0 == 0.0) + y0 -= EPSILON; + + if (y1 == 0.0) + y1 -= EPSILON; + + if (Line2D.linesIntersect(x0, y0, x1, y1, + EPSILON, 0.0, Double.MAX_VALUE, 0.0)) + return 1; + return 0; + } + } // class LineSegment + + /** + * 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. + */ + private class QuadSegment extends Segment + { + Point2D cp; // control point + + /** + * Constructor, takes the coordinates of the start, control, + * and end point, respectively. + */ + 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); + } + + /** + * Clones this segment + */ + public Object clone() + { + return new QuadSegment(P1.getX(), P1.getY(), cp.getX(), cp.getY(), + P2.getX(), P2.getY()); + } + + /** + * Returns twice the area of a curve, relative the P1-P2 line + * + * The area formula can be derived by using Green's formula in the + * plane on the parametric form of the bezier. + */ + double curveArea() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp.getX(); + double y1 = cp.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + + double P = (y2 - 2 * y1 + y0); + double Q = 2 * (y1 - y0); + + double A = (x2 - 2 * x1 + x0); + double B = 2 * (x1 - x0); + + double area = (B * P - A * Q) / 3.0; + return (area); + } + + /** + * Compare two segments. + */ + boolean equals(Segment b) + { + if (! (b instanceof QuadSegment)) + return false; + + return (P1.equals(b.P1) && cp.equals(((QuadSegment) b).cp) + && P2.equals(b.P2)); + } + + /** + * Returns a Point2D corresponding to the parametric value t + * of the curve + */ + Point2D evaluatePoint(double t) + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp.getX(); + double y1 = cp.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + + return new Point2D.Double(t * t * (x2 - 2 * x1 + x0) + 2 * t * (x1 - x0) + + x0, + t * t * (y2 - 2 * y1 + y0) + 2 * t * (y1 - y0) + + y0); + } + + /** + * Returns the bounding box of this segment + */ + Rectangle2D getBounds() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp.getX(); + double y1 = cp.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + double r0; + double r1; + + double xmax = Math.max(x0, x2); + double ymax = Math.max(y0, y2); + double xmin = Math.min(x0, x2); + double ymin = Math.min(y0, y2); + + r0 = 2 * (y1 - y0); + r1 = 2 * (y2 - 2 * y1 + y0); + if (r1 != 0.0) + { + double t = -r0 / r1; + if (t > 0.0 && t < 1.0) + { + double y = evaluatePoint(t).getY(); + ymax = Math.max(y, ymax); + ymin = Math.min(y, ymin); + } + } + r0 = 2 * (x1 - x0); + r1 = 2 * (x2 - 2 * x1 + x0); + if (r1 != 0.0) + { + double t = -r0 / r1; + if (t > 0.0 && t < 1.0) + { + double x = evaluatePoint(t).getY(); + xmax = Math.max(x, xmax); + xmin = Math.min(x, xmin); + } + } + + return (new Rectangle2D.Double(xmin, ymin, xmax - xmin, ymax - ymin)); + } + + /** + * Returns a cubic segment corresponding to this curve + */ + CubicSegment getCubicSegment() + { + double x1 = P1.getX() + 2.0 * (cp.getX() - P1.getX()) / 3.0; + double y1 = P1.getY() + 2.0 * (cp.getY() - P1.getY()) / 3.0; + double x2 = cp.getX() + (P2.getX() - cp.getX()) / 3.0; + double y2 = cp.getY() + (P2.getY() - cp.getY()) / 3.0; + + return new CubicSegment(P1.getX(), P1.getY(), x1, y1, x2, y2, P2.getX(), + P2.getY()); + } + + /** + * Returns the segment's midpoint + */ + Point2D getMidPoint() + { + return evaluatePoint(0.5); + } + + /** + * Returns the PathIterator type of a segment + */ + int getType() + { + return (PathIterator.SEG_QUADTO); + } + + /** + * Returns the PathIterator coords of a segment + */ + int pathIteratorFormat(double[] coords) + { + coords[0] = cp.getX(); + coords[1] = cp.getY(); + coords[2] = P2.getX(); + coords[3] = P2.getY(); + return (PathIterator.SEG_QUADTO); + } + + /** + * Returns the number of intersections on the positive X axis, + * with the origin at (x,y), used for contains()-testing + */ + int rayCrossing(double x, double y) + { + double x0 = P1.getX() - x; + double y0 = P1.getY() - y; + double x1 = cp.getX() - x; + double y1 = cp.getY() - y; + double x2 = P2.getX() - x; + double y2 = P2.getY() - y; + double[] r = new double[3]; + int nRoots; + int nCrossings = 0; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0) && (y0 * y1 <= 0 || y1 * y2 <= 0)) + { + if (y0 == 0.0) + y0 -= EPSILON; + if (y2 == 0.0) + y2 -= EPSILON; + + r[0] = y0; + r[1] = 2 * (y1 - y0); + r[2] = (y2 - 2 * y1 + y0); + + nRoots = QuadCurve2D.solveQuadratic(r); + for (int i = 0; i < nRoots; i++) + if (r[i] > 0.0f && r[i] < 1.0f) + { + double t = r[i]; + if (t * t * (x2 - 2 * x1 + x0) + 2 * t * (x1 - x0) + x0 > 0.0) + nCrossings++; + } + } + return nCrossings; + } + + /** + * Swap start and end points + */ + void reverseCoords() + { + Point2D temp = P1; + P1 = P2; + P2 = temp; + } + + /** + * Splits intersections into nodes, + * This one handles quadratic-quadratic only, + * Quadratic-line is passed on to the LineSegment class, + * Quadratic-cubic is passed on to the CubicSegment class + */ + int splitIntersections(Segment b) + { + if (b instanceof LineSegment) + return (b.splitIntersections(this)); + + if (b instanceof CubicSegment) + return (b.splitIntersections(this)); + + if (b instanceof QuadSegment) + { + // Use the cubic-cubic intersection routine for quads as well, + // Since a quadratic can be exactly described as a cubic, this + // should not be a problem; + // The recursion depth will be the same in any case. + Intersection[] x = cubicCubicIntersect(getCubicSegment(), + ((QuadSegment) b) + .getCubicSegment()); + if (x == null) + return 0; + + if (x.length == 1) + return createNode(b, (Intersection) x[0]); + + return createNodes(b, x); + } + return 0; + } + + /** + * Subdivides the segment at parametric value t, inserting + * the new segment into the linked list after this, + * such that this becomes [0,t] and this.next becomes [t,1] + */ + void subdivideInsert(double t) + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp.getX(); + double y1 = cp.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + + double p10x = x0 + t * (x1 - x0); + double p10y = y0 + t * (y1 - y0); + double p11x = x1 + t * (x2 - x1); + double p11y = y1 + t * (y2 - y1); + double p20x = p10x + t * (p11x - p10x); + double p20y = p10y + t * (p11y - p10y); + + insert(new QuadSegment(p20x, p20y, p11x, p11y, x2, y2)); + P2 = next.P1; + cp.setLocation(p10x, p10y); + + next.node = node; + node = null; + } + + /** + * Transforms the segment + */ + void transform(AffineTransform at) + { + P1 = at.transform(P1, null); + P2 = at.transform(P2, null); + cp = at.transform(cp, null); + } + } // class QuadSegment + + /** + * Cubic Bezier curve segment + */ + private class CubicSegment extends Segment + { + Point2D cp1; // control points + 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); + } + + /** + * Clones this segment + */ + public Object clone() + { + return new CubicSegment(P1.getX(), P1.getY(), cp1.getX(), cp1.getY(), + cp2.getX(), cp2.getY(), P2.getX(), P2.getY()); + } + + /** + * Returns twice the area of a curve, relative the P1-P2 line + * + * The area formula can be derived by using Green's formula in the + * plane on the parametric form of the bezier. + */ + double curveArea() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp1.getX(); + double y1 = cp1.getY(); + double x2 = cp2.getX(); + double y2 = cp2.getY(); + double x3 = P2.getX(); + double y3 = P2.getY(); + + double P = y3 - 3 * y2 + 3 * y1 - y0; + double Q = 3 * (y2 + y0 - 2 * y1); + double R = 3 * (y1 - y0); + + double A = x3 - 3 * x2 + 3 * x1 - x0; + double B = 3 * (x2 + x0 - 2 * x1); + double C = 3 * (x1 - x0); + + double area = (B * P - A * Q) / 5.0 + (C * P - A * R) / 2.0 + + (C * Q - B * R) / 3.0; + + return (area); + } + + /** + * Compare two segments. + */ + boolean equals(Segment b) + { + if (! (b instanceof CubicSegment)) + return false; + + return (P1.equals(b.P1) && cp1.equals(((CubicSegment) b).cp1) + && cp2.equals(((CubicSegment) b).cp2) && P2.equals(b.P2)); + } + + /** + * Returns a Point2D corresponding to the parametric value t + * of the curve + */ + Point2D evaluatePoint(double t) + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp1.getX(); + double y1 = cp1.getY(); + double x2 = cp2.getX(); + double y2 = cp2.getY(); + double x3 = P2.getX(); + double y3 = P2.getY(); + + return new Point2D.Double(-(t * t * t) * (x0 - 3 * x1 + 3 * x2 - x3) + + 3 * t * t * (x0 - 2 * x1 + x2) + + 3 * t * (x1 - x0) + x0, + -(t * t * t) * (y0 - 3 * y1 + 3 * y2 - y3) + + 3 * t * t * (y0 - 2 * y1 + y2) + + 3 * t * (y1 - y0) + y0); + } + + /** + * Returns the bounding box of this segment + */ + Rectangle2D getBounds() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp1.getX(); + double y1 = cp1.getY(); + double x2 = cp2.getX(); + double y2 = cp2.getY(); + double x3 = P2.getX(); + double y3 = P2.getY(); + double[] r = new double[3]; + + double xmax = Math.max(x0, x3); + double ymax = Math.max(y0, y3); + double xmin = Math.min(x0, x3); + double ymin = Math.min(y0, y3); + + r[0] = 3 * (y1 - y0); + r[1] = 6.0 * (y2 + y0 - 2 * y1); + r[2] = 3.0 * (y3 - 3 * y2 + 3 * y1 - y0); + + int n = QuadCurve2D.solveQuadratic(r); + for (int i = 0; i < n; i++) + { + double t = r[i]; + if (t > 0 && t < 1.0) + { + double y = evaluatePoint(t).getY(); + ymax = Math.max(y, ymax); + ymin = Math.min(y, ymin); + } + } + + r[0] = 3 * (x1 - x0); + r[1] = 6.0 * (x2 + x0 - 2 * x1); + r[2] = 3.0 * (x3 - 3 * x2 + 3 * x1 - x0); + n = QuadCurve2D.solveQuadratic(r); + for (int i = 0; i < n; i++) + { + double t = r[i]; + if (t > 0 && t < 1.0) + { + double x = evaluatePoint(t).getX(); + xmax = Math.max(x, xmax); + xmin = Math.min(x, xmin); + } + } + return (new Rectangle2D.Double(xmin, ymin, (xmax - xmin), (ymax - ymin))); + } + + /** + * Returns a CubicCurve2D object corresponding to this segment. + */ + CubicCurve2D getCubicCurve2D() + { + return new CubicCurve2D.Double(P1.getX(), P1.getY(), cp1.getX(), + cp1.getY(), cp2.getX(), cp2.getY(), + P2.getX(), P2.getY()); + } + + /** + * Returns the parametric points of self-intersection if the cubic + * is self-intersecting, null otherwise. + */ + double[] getLoop() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp1.getX(); + double y1 = cp1.getY(); + double x2 = cp2.getX(); + double y2 = cp2.getY(); + double x3 = P2.getX(); + double y3 = P2.getY(); + double[] r = new double[4]; + double k; + double R; + double T; + double A; + double B; + double[] results = new double[2]; + + R = x3 - 3 * x2 + 3 * x1 - x0; + T = y3 - 3 * y2 + 3 * y1 - y0; + + // A qudratic + if (R == 0.0 && T == 0.0) + return null; + + // true cubic + if (R != 0.0 && T != 0.0) + { + A = 3 * (x2 + x0 - 2 * x1) / R; + B = 3 * (x1 - x0) / R; + + double P = 3 * (y2 + y0 - 2 * y1) / T; + double Q = 3 * (y1 - y0) / T; + + if (A == P || Q == B) + return null; + + k = (Q - B) / (A - P); + } + else + { + if (R == 0.0) + { + // quadratic in x + k = -(3 * (x1 - x0)) / (3 * (x2 + x0 - 2 * x1)); + A = 3 * (y2 + y0 - 2 * y1) / T; + B = 3 * (y1 - y0) / T; + } + else + { + // quadratic in y + k = -(3 * (y1 - y0)) / (3 * (y2 + y0 - 2 * y1)); + A = 3 * (x2 + x0 - 2 * x1) / R; + B = 3 * (x1 - x0) / R; + } + } + + r[0] = -k * k * k - A * k * k - B * k; + r[1] = 3 * k * k + 2 * k * A + 2 * B; + r[2] = -3 * k; + r[3] = 2; + + int n = CubicCurve2D.solveCubic(r); + if (n != 3) + return null; + + // sort r + double t; + for (int i = 0; i < 2; i++) + for (int j = i + 1; j < 3; j++) + if (r[j] < r[i]) + { + t = r[i]; + r[i] = r[j]; + r[j] = t; + } + + if (Math.abs(r[0] + r[2] - k) < 1E-13) + if (r[0] >= 0.0 && r[0] <= 1.0 && r[2] >= 0.0 && r[2] <= 1.0) + if (evaluatePoint(r[0]).distance(evaluatePoint(r[2])) < PE_EPSILON * 10) + { // we snap the points anyway + results[0] = r[0]; + results[1] = r[2]; + return (results); + } + return null; + } + + /** + * Returns the segment's midpoint + */ + Point2D getMidPoint() + { + return evaluatePoint(0.5); + } + + /** + * Returns the PathIterator type of a segment + */ + int getType() + { + return (PathIterator.SEG_CUBICTO); + } + + /** + * Returns the PathIterator coords of a segment + */ + int pathIteratorFormat(double[] coords) + { + coords[0] = cp1.getX(); + coords[1] = cp1.getY(); + coords[2] = cp2.getX(); + coords[3] = cp2.getY(); + coords[4] = P2.getX(); + coords[5] = P2.getY(); + return (PathIterator.SEG_CUBICTO); + } + + /** + * Returns the number of intersections on the positive X axis, + * with the origin at (x,y), used for contains()-testing + */ + int rayCrossing(double x, double y) + { + double x0 = P1.getX() - x; + double y0 = P1.getY() - y; + double x1 = cp1.getX() - x; + double y1 = cp1.getY() - y; + double x2 = cp2.getX() - x; + double y2 = cp2.getY() - y; + double x3 = P2.getX() - x; + double y3 = P2.getY() - y; + double[] r = new double[4]; + int nRoots; + int nCrossings = 0; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0 || x3 > 0.0) + && (y0 * y1 <= 0 || y1 * y2 <= 0 || y2 * y3 <= 0)) + { + if (y0 == 0.0) + y0 -= EPSILON; + if (y3 == 0.0) + y3 -= EPSILON; + + r[0] = y0; + r[1] = 3 * (y1 - y0); + r[2] = 3 * (y2 + y0 - 2 * y1); + r[3] = y3 - 3 * y2 + 3 * y1 - y0; + + if ((nRoots = CubicCurve2D.solveCubic(r)) > 0) + for (int i = 0; i < nRoots; i++) + { + if (r[i] > 0.0 && r[i] < 1.0) + { + double t = r[i]; + if (-(t * t * t) * (x0 - 3 * x1 + 3 * x2 - x3) + + 3 * t * t * (x0 - 2 * x1 + x2) + 3 * t * (x1 - x0) + + x0 > 0.0) + nCrossings++; + } + } + } + return nCrossings; + } + + /** + * Swap start and end points + */ + void reverseCoords() + { + Point2D p = P1; + P1 = P2; + P2 = p; + p = cp1; // swap control points + cp1 = cp2; + cp2 = p; + } + + /** + * Splits intersections into nodes, + * This one handles cubic-cubic and cubic-quadratic intersections + */ + int splitIntersections(Segment b) + { + if (b instanceof LineSegment) + return (b.splitIntersections(this)); + + Intersection[] x = null; + + if (b instanceof QuadSegment) + x = cubicCubicIntersect(this, ((QuadSegment) b).getCubicSegment()); + + if (b instanceof CubicSegment) + x = cubicCubicIntersect(this, (CubicSegment) b); + + if (x == null) + return 0; + + if (x.length == 1) + return createNode(b, x[0]); + + return createNodes(b, x); + } + + /** + * Subdivides the segment at parametric value t, inserting + * the new segment into the linked list after this, + * such that this becomes [0,t] and this.next becomes [t,1] + */ + void subdivideInsert(double t) + { + CubicSegment s = (CubicSegment) clone(); + double p1x = (s.cp1.getX() - s.P1.getX()) * t + s.P1.getX(); + double p1y = (s.cp1.getY() - s.P1.getY()) * t + s.P1.getY(); + + double px = (s.cp2.getX() - s.cp1.getX()) * t + s.cp1.getX(); + double py = (s.cp2.getY() - s.cp1.getY()) * t + s.cp1.getY(); + + s.cp2.setLocation((s.P2.getX() - s.cp2.getX()) * t + s.cp2.getX(), + (s.P2.getY() - s.cp2.getY()) * t + s.cp2.getY()); + + s.cp1.setLocation((s.cp2.getX() - px) * t + px, + (s.cp2.getY() - py) * t + py); + + double p2x = (px - p1x) * t + p1x; + double p2y = (py - p1y) * t + p1y; + + double p3x = (s.cp1.getX() - p2x) * t + p2x; + double p3y = (s.cp1.getY() - p2y) * t + p2y; + s.P1.setLocation(p3x, p3y); + + // insert new curve + insert(s); + + // set this curve + cp1.setLocation(p1x, p1y); + cp2.setLocation(p2x, p2y); + P2 = s.P1; + next.node = node; + node = null; + } + + /** + * Transforms the segment + */ + void transform(AffineTransform at) + { + P1 = at.transform(P1, null); + P2 = at.transform(P2, null); + cp1 = at.transform(cp1, null); + cp2 = at.transform(cp2, null); + } + } // class CubicSegment +} // class Area diff --git a/libjava/classpath/java/awt/geom/CubicCurve2D.java b/libjava/classpath/java/awt/geom/CubicCurve2D.java new file mode 100644 index 0000000..50c3811 --- /dev/null +++ b/libjava/classpath/java/awt/geom/CubicCurve2D.java @@ -0,0 +1,1724 @@ +/* CubicCurve2D.java -- represents a parameterized cubic curve in 2-D space + Copyright (C) 2002, 2003, 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 java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + + +/** + * A two-dimensional curve that is parameterized with a cubic + * function. + * + *

    A drawing of a CubicCurve2D + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Graydon Hoare (graydon@redhat.com) + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Sven de Marothy (sven@physto.se) + * + * @since 1.2 + */ +public abstract class CubicCurve2D implements Shape, Cloneable +{ + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; + private static final double EPSILON = 1E-10; + + /** + * Constructs a new CubicCurve2D. Typical users will want to + * construct instances of a subclass, such as {@link + * CubicCurve2D.Float} or {@link CubicCurve2D.Double}. + */ + protected CubicCurve2D() + { + } + + /** + * Returns the x coordinate of the curve’s start + * point. + */ + public abstract double getX1(); + + /** + * Returns the y coordinate of the curve’s start + * point. + */ + public abstract double getY1(); + + /** + * Returns the curve’s start point. + */ + public abstract Point2D getP1(); + + /** + * Returns the x coordinate of the curve’s first + * control point. + */ + public abstract double getCtrlX1(); + + /** + * Returns the y coordinate of the curve’s first + * control point. + */ + public abstract double getCtrlY1(); + + /** + * Returns the curve’s first control point. + */ + public abstract Point2D getCtrlP1(); + + /** + * Returns the x coordinate of the curve’s second + * control point. + */ + public abstract double getCtrlX2(); + + /** + * Returns the y coordinate of the curve’s second + * control point. + */ + public abstract double getCtrlY2(); + + /** + * Returns the curve’s second control point. + */ + public abstract Point2D getCtrlP2(); + + /** + * Returns the x coordinate of the curve’s end + * point. + */ + public abstract double getX2(); + + /** + * Returns the y coordinate of the curve’s end + * point. + */ + public abstract double getY2(); + + /** + * Returns the curve’s end point. + */ + public abstract Point2D getP2(); + + /** + * Changes the curve geometry, separately specifying each coordinate + * value. + * + *

    A drawing of a CubicCurve2D + * + * @param x1 the x coordinate of the curve’s new start + * point. + * + * @param y1 the y coordinate of the curve’s new start + * point. + * + * @param cx1 the x coordinate of the curve’s new + * first control point. + * + * @param cy1 the y coordinate of the curve’s new + * first control point. + * + * @param cx2 the x coordinate of the curve’s new + * second control point. + * + * @param cy2 the y coordinate of the curve’s new + * second control point. + * + * @param x2 the x coordinate of the curve’s new end + * point. + * + * @param y2 the y coordinate of the curve’s new end + * point. + */ + public abstract void setCurve(double x1, double y1, double cx1, double cy1, + double cx2, double cy2, double x2, double y2); + + /** + * Changes the curve geometry, specifying coordinate values in an + * array. + * + * @param coords an array containing the new coordinate values. The + * x coordinate of the new start point is located at + * coords[offset], its y coordinate at + * coords[offset + 1]. The x coordinate of the + * new first control point is located at coords[offset + + * 2], its y coordinate at coords[offset + + * 3]. The x coordinate of the new second control + * point is located at coords[offset + 4], its y + * coordinate at coords[offset + 5]. The x + * coordinate of the new end point is located at coords[offset + * + 6], its y coordinate at coords[offset + + * 7]. + * + * @param offset the offset of the first coordinate value in + * coords. + */ + public void setCurve(double[] coords, int offset) + { + setCurve(coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++]); + } + + /** + * Changes the curve geometry, specifying coordinate values in + * separate Point objects. + * + *

    A drawing of a CubicCurve2D + * + *

    The curve does not keep any reference to the passed point + * objects. Therefore, a later change to p1, + * c1, c2 or p2 will not + * affect the curve geometry. + * + * @param p1 the new start point. + * @param c1 the new first control point. + * @param c2 the new second control point. + * @param p2 the new end point. + */ + public void setCurve(Point2D p1, Point2D c1, Point2D c2, Point2D p2) + { + setCurve(p1.getX(), p1.getY(), c1.getX(), c1.getY(), c2.getX(), c2.getY(), + p2.getX(), p2.getY()); + } + + /** + * Changes the curve geometry, specifying coordinate values in an + * array of Point objects. + * + *

    A drawing of a CubicCurve2D + * + *

    The curve does not keep references to the passed point + * objects. Therefore, a later change to the pts array + * or any of its elements will not affect the curve geometry. + * + * @param pts an array containing the points. The new start point + * is located at pts[offset], the new first control + * point at pts[offset + 1], the new second control + * point at pts[offset + 2], and the new end point + * at pts[offset + 3]. + * + * @param offset the offset of the start point in pts. + */ + public void setCurve(Point2D[] pts, int offset) + { + setCurve(pts[offset].getX(), pts[offset++].getY(), pts[offset].getX(), + pts[offset++].getY(), pts[offset].getX(), pts[offset++].getY(), + pts[offset].getX(), pts[offset++].getY()); + } + + /** + * Changes the curve geometry to that of another curve. + * + * @param c the curve whose coordinates will be copied. + */ + public void setCurve(CubicCurve2D c) + { + setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(), + c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2()); + } + + /** + * Calculates the squared flatness of a cubic curve, directly + * specifying each coordinate value. The flatness is the maximal + * distance of a control point to the line between start and end + * point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the square of the distance between C2 and the + * gray line, i.e. the squared length of the red line. + * + * @param x1 the x coordinate of the start point P1. + * @param y1 the y coordinate of the start point P1. + * @param cx1 the x coordinate of the first control point C1. + * @param cy1 the y coordinate of the first control point C1. + * @param cx2 the x coordinate of the second control point C2. + * @param cy2 the y coordinate of the second control point C2. + * @param x2 the x coordinate of the end point P2. + * @param y2 the y coordinate of the end point P2. + */ + public static double getFlatnessSq(double x1, double y1, double cx1, + double cy1, double cx2, double cy2, + double x2, double y2) + { + return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, cx1, cy1), + Line2D.ptSegDistSq(x1, y1, x2, y2, cx2, cy2)); + } + + /** + * Calculates the flatness of a cubic curve, directly specifying + * each coordinate value. The flatness is the maximal distance of a + * control point to the line between start and end point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the distance between C2 and the gray line, + * i.e. the length of the red line. + * + * @param x1 the x coordinate of the start point P1. + * @param y1 the y coordinate of the start point P1. + * @param cx1 the x coordinate of the first control point C1. + * @param cy1 the y coordinate of the first control point C1. + * @param cx2 the x coordinate of the second control point C2. + * @param cy2 the y coordinate of the second control point C2. + * @param x2 the x coordinate of the end point P2. + * @param y2 the y coordinate of the end point P2. + */ + public static double getFlatness(double x1, double y1, double cx1, + double cy1, double cx2, double cy2, + double x2, double y2) + { + return Math.sqrt(getFlatnessSq(x1, y1, cx1, cy1, cx2, cy2, x2, y2)); + } + + /** + * Calculates the squared flatness of a cubic curve, specifying the + * coordinate values in an array. The flatness is the maximal + * distance of a control point to the line between start and end + * point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the square of the distance between C2 and the + * gray line, i.e. the squared length of the red line. + * + * @param coords an array containing the coordinate values. The + * x coordinate of the start point P1 is located at + * coords[offset], its y coordinate at + * coords[offset + 1]. The x coordinate of the + * first control point C1 is located at coords[offset + + * 2], its y coordinate at coords[offset + + * 3]. The x coordinate of the second control point C2 + * is located at coords[offset + 4], its y + * coordinate at coords[offset + 5]. The x + * coordinate of the end point P2 is located at coords[offset + * + 6], its y coordinate at coords[offset + + * 7]. + * + * @param offset the offset of the first coordinate value in + * coords. + */ + public static double getFlatnessSq(double[] coords, int offset) + { + return getFlatnessSq(coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++]); + } + + /** + * Calculates the flatness of a cubic curve, specifying the + * coordinate values in an array. The flatness is the maximal + * distance of a control point to the line between start and end + * point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the distance between C2 and the gray line, + * i.e. the length of the red line. + * + * @param coords an array containing the coordinate values. The + * x coordinate of the start point P1 is located at + * coords[offset], its y coordinate at + * coords[offset + 1]. The x coordinate of the + * first control point C1 is located at coords[offset + + * 2], its y coordinate at coords[offset + + * 3]. The x coordinate of the second control point C2 + * is located at coords[offset + 4], its y + * coordinate at coords[offset + 5]. The x + * coordinate of the end point P2 is located at coords[offset + * + 6], its y coordinate at coords[offset + + * 7]. + * + * @param offset the offset of the first coordinate value in + * coords. + */ + public static double getFlatness(double[] coords, int offset) + { + return Math.sqrt(getFlatnessSq(coords[offset++], coords[offset++], + coords[offset++], coords[offset++], + coords[offset++], coords[offset++], + coords[offset++], coords[offset++])); + } + + /** + * Calculates the squared flatness of this curve. The flatness is + * the maximal distance of a control point to the line between start + * and end point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the square of the distance between C2 and the + * gray line, i.e. the squared length of the red line. + */ + public double getFlatnessSq() + { + return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), + getCtrlX2(), getCtrlY2(), getX2(), getY2()); + } + + /** + * Calculates the flatness of this curve. The flatness is the + * maximal distance of a control point to the line between start and + * end point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the distance between C2 and the gray line, + * i.e. the length of the red line. + */ + public double getFlatness() + { + return Math.sqrt(getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), + getCtrlX2(), getCtrlY2(), getX2(), getY2())); + } + + /** + * Subdivides this curve into two halves. + * + *

    A drawing that illustrates the effects of
+   * subdividing a CubicCurve2D + * + * @param left a curve whose geometry will be set to the left half + * of this curve, or null if the caller is not + * interested in the left half. + * + * @param right a curve whose geometry will be set to the right half + * of this curve, or null if the caller is not + * interested in the right half. + */ + public void subdivide(CubicCurve2D left, CubicCurve2D right) + { + // Use empty slots at end to share single array. + double[] d = new double[] + { + getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(), + getCtrlY2(), getX2(), getY2(), 0, 0, 0, 0, 0, 0 + }; + subdivide(d, 0, d, 0, d, 6); + if (left != null) + left.setCurve(d, 0); + if (right != null) + right.setCurve(d, 6); + } + + /** + * Subdivides a cubic curve into two halves. + * + *

    A drawing that illustrates the effects of
+   * subdividing a CubicCurve2D + * + * @param src the curve to be subdivided. + * + * @param left a curve whose geometry will be set to the left half + * of src, or null if the caller is not + * interested in the left half. + * + * @param right a curve whose geometry will be set to the right half + * of src, or null if the caller is not + * interested in the right half. + */ + public static void subdivide(CubicCurve2D src, CubicCurve2D left, + CubicCurve2D right) + { + src.subdivide(left, right); + } + + /** + * Subdivides a cubic curve into two halves, passing all coordinates + * in an array. + * + *

    A drawing that illustrates the effects of
+   * subdividing a CubicCurve2D + * + *

    The left end point and the right start point will always be + * identical. Memory-concious programmers thus may want to pass the + * same array for both left and right, and + * set rightOff to leftOff + 6. + * + * @param src an array containing the coordinates of the curve to be + * subdivided. The x coordinate of the start point P1 is + * located at src[srcOff], its y at + * src[srcOff + 1]. The x coordinate of the + * first control point C1 is located at src[srcOff + + * 2], its y at src[srcOff + 3]. The + * x coordinate of the second control point C2 is located at + * src[srcOff + 4], its y at src[srcOff + + * 5]. The x coordinate of the end point is located at + * src[srcOff + 6], its y at src[srcOff + + * 7]. + * + * @param srcOff an offset into src, specifying + * the index of the start point’s x coordinate. + * + * @param left an array that will receive the coordinates of the + * left half of src. It is acceptable to pass + * src. A caller who is not interested in the left half + * can pass null. + * + * @param leftOff an offset into left, specifying the + * index where the start point’s x coordinate will be + * stored. + * + * @param right an array that will receive the coordinates of the + * right half of src. It is acceptable to pass + * src or left. A caller who is not + * interested in the right half can pass null. + * + * @param rightOff an offset into right, specifying the + * index where the start point’s x coordinate will be + * stored. + */ + public static void subdivide(double[] src, int srcOff, double[] left, + int leftOff, double[] right, int rightOff) + { + // To understand this code, please have a look at the image + // "CubicCurve2D-3.png" in the sub-directory "doc-files". + double src_C1_x; + double src_C1_y; + double src_C2_x; + double src_C2_y; + double left_P1_x; + double left_P1_y; + double left_C1_x; + double left_C1_y; + double left_C2_x; + double left_C2_y; + double right_C1_x; + double right_C1_y; + double right_C2_x; + double right_C2_y; + double right_P2_x; + double right_P2_y; + double Mid_x; // Mid = left.P2 = right.P1 + double Mid_y; // Mid = left.P2 = right.P1 + + left_P1_x = src[srcOff]; + left_P1_y = src[srcOff + 1]; + src_C1_x = src[srcOff + 2]; + src_C1_y = src[srcOff + 3]; + src_C2_x = src[srcOff + 4]; + src_C2_y = src[srcOff + 5]; + right_P2_x = src[srcOff + 6]; + right_P2_y = src[srcOff + 7]; + + left_C1_x = (left_P1_x + src_C1_x) / 2; + left_C1_y = (left_P1_y + src_C1_y) / 2; + right_C2_x = (right_P2_x + src_C2_x) / 2; + right_C2_y = (right_P2_y + src_C2_y) / 2; + Mid_x = (src_C1_x + src_C2_x) / 2; + Mid_y = (src_C1_y + src_C2_y) / 2; + left_C2_x = (left_C1_x + Mid_x) / 2; + left_C2_y = (left_C1_y + Mid_y) / 2; + right_C1_x = (Mid_x + right_C2_x) / 2; + right_C1_y = (Mid_y + right_C2_y) / 2; + Mid_x = (left_C2_x + right_C1_x) / 2; + Mid_y = (left_C2_y + right_C1_y) / 2; + + if (left != null) + { + left[leftOff] = left_P1_x; + left[leftOff + 1] = left_P1_y; + left[leftOff + 2] = left_C1_x; + left[leftOff + 3] = left_C1_y; + left[leftOff + 4] = left_C2_x; + left[leftOff + 5] = left_C2_y; + left[leftOff + 6] = Mid_x; + left[leftOff + 7] = Mid_y; + } + + if (right != null) + { + right[rightOff] = Mid_x; + right[rightOff + 1] = Mid_y; + right[rightOff + 2] = right_C1_x; + right[rightOff + 3] = right_C1_y; + right[rightOff + 4] = right_C2_x; + right[rightOff + 5] = right_C2_y; + right[rightOff + 6] = right_P2_x; + right[rightOff + 7] = right_P2_y; + } + } + + /** + * Finds the non-complex roots of a cubic equation, placing the + * results into the same array as the equation coefficients. The + * following equation is being solved: + * + *

    eqn[3] · x3 + * + eqn[2] · x2 + * + eqn[1] · x + * + eqn[0] + * = 0 + *
    + * + *

    For some background about solving cubic equations, see the + * article “Cubic Formula” in PlanetMath. For an extensive + * library of numerical algorithms written in the C programming + * language, see the GNU + * Scientific Library, from which this implementation was + * adapted. + * + * @param eqn an array with the coefficients of the equation. When + * this procedure has returned, eqn will contain the + * non-complex solutions of the equation, in no particular order. + * + * @return the number of non-complex solutions. A result of 0 + * indicates that the equation has no non-complex solutions. A + * result of -1 indicates that the equation is constant (i.e., + * always or never zero). + * + * @see #solveCubic(double[], double[]) + * @see QuadCurve2D#solveQuadratic(double[],double[]) + * + * @author Brian Gough (bjg@network-theory.com) + * (original C implementation in the GNU Scientific Library) + * + * @author Sascha Brawer (brawer@dandelis.ch) + * (adaptation to Java) + */ + public static int solveCubic(double[] eqn) + { + return solveCubic(eqn, eqn); + } + + /** + * Finds the non-complex roots of a cubic equation. The following + * equation is being solved: + * + *

    eqn[3] · x3 + * + eqn[2] · x2 + * + eqn[1] · x + * + eqn[0] + * = 0 + *
    + * + *

    For some background about solving cubic equations, see the + * article “Cubic Formula” in PlanetMath. For an extensive + * library of numerical algorithms written in the C programming + * language, see the GNU + * Scientific Library, from which this implementation was + * adapted. + * + * @see QuadCurve2D#solveQuadratic(double[],double[]) + * + * @param eqn an array with the coefficients of the equation. + * + * @param res an array into which the non-complex roots will be + * stored. The results may be in an arbitrary order. It is safe to + * pass the same array object reference for both eqn + * and res. + * + * @return the number of non-complex solutions. A result of 0 + * indicates that the equation has no non-complex solutions. A + * result of -1 indicates that the equation is constant (i.e., + * always or never zero). + * + * @author Brian Gough (bjg@network-theory.com) + * (original C implementation in the GNU Scientific Library) + * + * @author Sascha Brawer (brawer@dandelis.ch) + * (adaptation to Java) + */ + public static int solveCubic(double[] eqn, double[] res) + { + // Adapted from poly/solve_cubic.c in the GNU Scientific Library + // (GSL), revision 1.7 of 2003-07-26. For the original source, see + // http://www.gnu.org/software/gsl/ + // + // Brian Gough, the author of that code, has granted the + // permission to use it in GNU Classpath under the GNU Classpath + // license, and has assigned the copyright to the Free Software + // Foundation. + // + // The Java implementation is very similar to the GSL code, but + // not a strict one-to-one copy. For example, GSL would sort the + // result. + + double a; + double b; + double c; + double q; + double r; + double Q; + double R; + double c3; + double Q3; + double R2; + double CR2; + double CQ3; + + // If the cubic coefficient is zero, we have a quadratic equation. + c3 = eqn[3]; + if (c3 == 0) + return QuadCurve2D.solveQuadratic(eqn, res); + + // Divide the equation by the cubic coefficient. + c = eqn[0] / c3; + b = eqn[1] / c3; + a = eqn[2] / c3; + + // We now need to solve x^3 + ax^2 + bx + c = 0. + q = a * a - 3 * b; + r = 2 * a * a * a - 9 * a * b + 27 * c; + + Q = q / 9; + R = r / 54; + + Q3 = Q * Q * Q; + R2 = R * R; + + CR2 = 729 * r * r; + CQ3 = 2916 * q * q * q; + + if (R == 0 && Q == 0) + { + // The GNU Scientific Library would return three identical + // solutions in this case. + res[0] = -a / 3; + return 1; + } + + if (CR2 == CQ3) + { + /* this test is actually R2 == Q3, written in a form suitable + for exact computation with integers */ + /* Due to finite precision some double roots may be missed, and + considered to be a pair of complex roots z = x +/- epsilon i + close to the real axis. */ + double sqrtQ = Math.sqrt(Q); + + if (R > 0) + { + res[0] = -2 * sqrtQ - a / 3; + res[1] = sqrtQ - a / 3; + } + else + { + res[0] = -sqrtQ - a / 3; + res[1] = 2 * sqrtQ - a / 3; + } + return 2; + } + + if (CR2 < CQ3) /* equivalent to R2 < Q3 */ + { + double sqrtQ = Math.sqrt(Q); + double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ; + double theta = Math.acos(R / sqrtQ3); + double norm = -2 * sqrtQ; + res[0] = norm * Math.cos(theta / 3) - a / 3; + res[1] = norm * Math.cos((theta + 2.0 * Math.PI) / 3) - a / 3; + res[2] = norm * Math.cos((theta - 2.0 * Math.PI) / 3) - a / 3; + + // The GNU Scientific Library sorts the results. We don't. + return 3; + } + + double sgnR = (R >= 0 ? 1 : -1); + double A = -sgnR * Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0 / 3.0); + double B = Q / A; + res[0] = A + B - a / 3; + return 1; + } + + /** + * Determines whether a position lies inside the area bounded + * by the curve and the straight line connecting its end points. + * + *

    A drawing of the area spanned by the curve + * + *

    The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + */ + public boolean contains(double x, double y) + { + if (! getBounds2D().contains(x, y)) + return false; + + return ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0); + } + + /** + * Determines whether a point lies inside the area bounded + * by the curve and the straight line connecting its end points. + * + *

    A drawing of the area spanned by the curve + * + *

    The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Determines whether any part of a rectangle is inside the area bounded + * by the curve and the straight line connecting its end points. + * + *

    A drawing of the area spanned by the curve + * + *

    The above drawing illustrates in which area points are + * considered “inside” in a CubicCurve2D. + * @see #contains(double, double) + */ + public boolean intersects(double x, double y, double w, double h) + { + if (! getBounds2D().contains(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Determines whether any part of a Rectangle2D is inside the area bounded + * by the curve and the straight line connecting its end points. + * @see #intersects(double, double, double, double) + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determine whether a rectangle is entirely inside the area that is bounded + * by the curve and the straight line connecting its end points. + * + *

    A drawing of the area spanned by the curve + * + *

    The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + * @see #contains(double, double) + */ + public boolean contains(double x, double y, double w, double h) + { + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return false; + + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Determine whether a Rectangle2D is entirely inside the area that is + * bounded by the curve and the straight line connecting its end points. + * + *

    A drawing of the area spanned by the curve + * + *

    The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + * @see #contains(double, double) + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control points. + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + public PathIterator getPathIterator(final AffineTransform at) + { + return new PathIterator() + { + /** Current coordinate. */ + private int current = 0; + + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current >= 2; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = (float) getX1(); + coords[1] = (float) getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = (float) getCtrlX1(); + coords[1] = (float) getCtrlY1(); + coords[2] = (float) getCtrlX2(); + coords[3] = (float) getCtrlY2(); + coords[4] = (float) getX2(); + coords[5] = (float) getY2(); + result = SEG_CUBICTO; + break; + default: + throw new NoSuchElementException("cubic iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 3); + return result; + } + + public int currentSegment(double[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = getX1(); + coords[1] = getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = getCtrlX1(); + coords[1] = getCtrlY1(); + coords[2] = getCtrlX2(); + coords[3] = getCtrlY2(); + coords[4] = getX2(); + coords[5] = getY2(); + result = SEG_CUBICTO; + break; + default: + throw new NoSuchElementException("cubic iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 3); + return result; + } + }; + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + /** + * Create a new curve with the same contents as this one. + * + * @return the clone. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Helper method used by contains() and intersects() methods, that + * returns the number of curve/line intersections on a given axis + * extending from a certain point. + * + * @param x x coordinate of the origin point + * @param y y coordinate of the origin point + * @param useYaxis axis used, if true the positive Y axis is used, + * false uses the positive X axis. + * + * This is an implementation of the line-crossings algorithm, + * Detailed in an article on Eric Haines' page: + * http://www.acm.org/tog/editors/erich/ptinpoly/ + * + * A special-case not adressed in this code is self-intersections + * of the curve, e.g. if the axis intersects the self-itersection, + * the degenerate roots of the polynomial will erroneously count as + * a single intersection of the curve, and not two. + */ + private int getAxisIntersections(double x, double y, boolean useYaxis, + double distance) + { + int nCrossings = 0; + double a0; + double a1; + double a2; + double a3; + double b0; + double b1; + double b2; + double b3; + double[] r = new double[4]; + int nRoots; + + a0 = a3 = 0.0; + + if (useYaxis) + { + a0 = getY1() - y; + a1 = getCtrlY1() - y; + a2 = getCtrlY2() - y; + a3 = getY2() - y; + b0 = getX1() - x; + b1 = getCtrlX1() - x; + b2 = getCtrlX2() - x; + b3 = getX2() - x; + } + else + { + a0 = getX1() - x; + a1 = getCtrlX1() - x; + a2 = getCtrlX2() - x; + a3 = getX2() - x; + b0 = getY1() - y; + b1 = getCtrlY1() - y; + b2 = getCtrlY2() - y; + b3 = getY2() - y; + } + + /* If the axis intersects a start/endpoint, shift it up by some small + amount to guarantee the line is 'inside' + If this is not done, bad behaviour may result for points on that axis.*/ + if (a0 == 0.0 || a3 == 0.0) + { + double small = getFlatness() * EPSILON; + if (a0 == 0.0) + a0 -= small; + if (a3 == 0.0) + a3 -= small; + } + + if (useYaxis) + { + if (Line2D.linesIntersect(b0, a0, b3, a3, EPSILON, 0.0, distance, 0.0)) + nCrossings++; + } + else + { + if (Line2D.linesIntersect(a0, b0, a3, b3, 0.0, EPSILON, 0.0, distance)) + nCrossings++; + } + + r[0] = a0; + r[1] = 3 * (a1 - a0); + r[2] = 3 * (a2 + a0 - 2 * a1); + r[3] = a3 - 3 * a2 + 3 * a1 - a0; + + if ((nRoots = solveCubic(r)) != 0) + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + double crossing = -(t * t * t) * (b0 - 3 * b1 + 3 * b2 - b3) + + 3 * t * t * (b0 - 2 * b1 + b2) + + 3 * t * (b1 - b0) + b0; + if (crossing > 0.0 && crossing <= distance) + nCrossings++; + } + } + + return (nCrossings); + } + + /** + * A two-dimensional curve that is parameterized with a cubic + * function and stores coordinate values in double-precision + * floating-point format. + * + * @see CubicCurve2D.Float + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class Double extends CubicCurve2D + { + /** + * The x coordinate of the curve’s start point. + */ + public double x1; + + /** + * The y coordinate of the curve’s start point. + */ + public double y1; + + /** + * The x coordinate of the curve’s first control point. + */ + public double ctrlx1; + + /** + * The y coordinate of the curve’s first control point. + */ + public double ctrly1; + + /** + * The x coordinate of the curve’s second control point. + */ + public double ctrlx2; + + /** + * The y coordinate of the curve’s second control point. + */ + public double ctrly2; + + /** + * The x coordinate of the curve’s end point. + */ + public double x2; + + /** + * The y coordinate of the curve’s end point. + */ + public double y2; + + /** + * Constructs a new CubicCurve2D that stores its coordinate values + * in double-precision floating-point format. All points are + * initially at position (0, 0). + */ + public Double() + { + } + + /** + * Constructs a new CubicCurve2D that stores its coordinate values + * in double-precision floating-point format, specifying the + * initial position of each point. + * + *

    A drawing of a CubicCurve2D + * + * @param x1 the x coordinate of the curve’s start + * point. + * + * @param y1 the y coordinate of the curve’s start + * point. + * + * @param cx1 the x coordinate of the curve’s first + * control point. + * + * @param cy1 the y coordinate of the curve’s first + * control point. + * + * @param cx2 the x coordinate of the curve’s second + * control point. + * + * @param cy2 the y coordinate of the curve’s second + * control point. + * + * @param x2 the x coordinate of the curve’s end + * point. + * + * @param y2 the y coordinate of the curve’s end + * point. + */ + public Double(double x1, double y1, double cx1, double cy1, double cx2, + double cy2, double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx1 = cx1; + ctrly1 = cy1; + ctrlx2 = cx2; + ctrly2 = cy2; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Returns the x coordinate of the curve’s start + * point. + */ + public double getX1() + { + return x1; + } + + /** + * Returns the y coordinate of the curve’s start + * point. + */ + public double getY1() + { + return y1; + } + + /** + * Returns the curve’s start point. + */ + public Point2D getP1() + { + return new Point2D.Double(x1, y1); + } + + /** + * Returns the x coordinate of the curve’s first + * control point. + */ + public double getCtrlX1() + { + return ctrlx1; + } + + /** + * Returns the y coordinate of the curve’s first + * control point. + */ + public double getCtrlY1() + { + return ctrly1; + } + + /** + * Returns the curve’s first control point. + */ + public Point2D getCtrlP1() + { + return new Point2D.Double(ctrlx1, ctrly1); + } + + /** + * Returns the x coordinate of the curve’s second + * control point. + */ + public double getCtrlX2() + { + return ctrlx2; + } + + /** + * Returns the y coordinate of the curve’s second + * control point. + */ + public double getCtrlY2() + { + return ctrly2; + } + + /** + * Returns the curve’s second control point. + */ + public Point2D getCtrlP2() + { + return new Point2D.Double(ctrlx2, ctrly2); + } + + /** + * Returns the x coordinate of the curve’s end + * point. + */ + public double getX2() + { + return x2; + } + + /** + * Returns the y coordinate of the curve’s end + * point. + */ + public double getY2() + { + return y2; + } + + /** + * Returns the curve’s end point. + */ + public Point2D getP2() + { + return new Point2D.Double(x2, y2); + } + + /** + * Changes the curve geometry, separately specifying each coordinate + * value. + * + *

    A drawing of a CubicCurve2D + * + * @param x1 the x coordinate of the curve’s new start + * point. + * + * @param y1 the y coordinate of the curve’s new start + * point. + * + * @param cx1 the x coordinate of the curve’s new + * first control point. + * + * @param cy1 the y coordinate of the curve’s new + * first control point. + * + * @param cx2 the x coordinate of the curve’s new + * second control point. + * + * @param cy2 the y coordinate of the curve’s new + * second control point. + * + * @param x2 the x coordinate of the curve’s new end + * point. + * + * @param y2 the y coordinate of the curve’s new end + * point. + */ + public void setCurve(double x1, double y1, double cx1, double cy1, + double cx2, double cy2, double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx1 = cx1; + ctrly1 = cy1; + ctrlx2 = cx2; + ctrly2 = cy2; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control points. As the + * illustration below shows, the invisible control points may cause + * the bounds to be much larger than the area that is actually + * covered by the curve. + * + *

    An illustration of the bounds of a CubicCurve2D + */ + public Rectangle2D getBounds2D() + { + double nx1 = Math.min(Math.min(x1, ctrlx1), Math.min(ctrlx2, x2)); + double ny1 = Math.min(Math.min(y1, ctrly1), Math.min(ctrly2, y2)); + double nx2 = Math.max(Math.max(x1, ctrlx1), Math.max(ctrlx2, x2)); + double ny2 = Math.max(Math.max(y1, ctrly1), Math.max(ctrly2, y2)); + return new Rectangle2D.Double(nx1, ny1, nx2 - nx1, ny2 - ny1); + } + } + + /** + * A two-dimensional curve that is parameterized with a cubic + * function and stores coordinate values in single-precision + * floating-point format. + * + * @see CubicCurve2D.Float + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class Float extends CubicCurve2D + { + /** + * The x coordinate of the curve’s start point. + */ + public float x1; + + /** + * The y coordinate of the curve’s start point. + */ + public float y1; + + /** + * The x coordinate of the curve’s first control point. + */ + public float ctrlx1; + + /** + * The y coordinate of the curve’s first control point. + */ + public float ctrly1; + + /** + * The x coordinate of the curve’s second control point. + */ + public float ctrlx2; + + /** + * The y coordinate of the curve’s second control point. + */ + public float ctrly2; + + /** + * The x coordinate of the curve’s end point. + */ + public float x2; + + /** + * The y coordinate of the curve’s end point. + */ + public float y2; + + /** + * Constructs a new CubicCurve2D that stores its coordinate values + * in single-precision floating-point format. All points are + * initially at position (0, 0). + */ + public Float() + { + } + + /** + * Constructs a new CubicCurve2D that stores its coordinate values + * in single-precision floating-point format, specifying the + * initial position of each point. + * + *

    A drawing of a CubicCurve2D + * + * @param x1 the x coordinate of the curve’s start + * point. + * + * @param y1 the y coordinate of the curve’s start + * point. + * + * @param cx1 the x coordinate of the curve’s first + * control point. + * + * @param cy1 the y coordinate of the curve’s first + * control point. + * + * @param cx2 the x coordinate of the curve’s second + * control point. + * + * @param cy2 the y coordinate of the curve’s second + * control point. + * + * @param x2 the x coordinate of the curve’s end + * point. + * + * @param y2 the y coordinate of the curve’s end + * point. + */ + public Float(float x1, float y1, float cx1, float cy1, float cx2, + float cy2, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx1 = cx1; + ctrly1 = cy1; + ctrlx2 = cx2; + ctrly2 = cy2; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Returns the x coordinate of the curve’s start + * point. + */ + public double getX1() + { + return x1; + } + + /** + * Returns the y coordinate of the curve’s start + * point. + */ + public double getY1() + { + return y1; + } + + /** + * Returns the curve’s start point. + */ + public Point2D getP1() + { + return new Point2D.Float(x1, y1); + } + + /** + * Returns the x coordinate of the curve’s first + * control point. + */ + public double getCtrlX1() + { + return ctrlx1; + } + + /** + * Returns the y coordinate of the curve’s first + * control point. + */ + public double getCtrlY1() + { + return ctrly1; + } + + /** + * Returns the curve’s first control point. + */ + public Point2D getCtrlP1() + { + return new Point2D.Float(ctrlx1, ctrly1); + } + + /** + * Returns the s coordinate of the curve’s second + * control point. + */ + public double getCtrlX2() + { + return ctrlx2; + } + + /** + * Returns the y coordinate of the curve’s second + * control point. + */ + public double getCtrlY2() + { + return ctrly2; + } + + /** + * Returns the curve’s second control point. + */ + public Point2D getCtrlP2() + { + return new Point2D.Float(ctrlx2, ctrly2); + } + + /** + * Returns the x coordinate of the curve’s end + * point. + */ + public double getX2() + { + return x2; + } + + /** + * Returns the y coordinate of the curve’s end + * point. + */ + public double getY2() + { + return y2; + } + + /** + * Returns the curve’s end point. + */ + public Point2D getP2() + { + return new Point2D.Float(x2, y2); + } + + /** + * Changes the curve geometry, separately specifying each coordinate + * value as a double-precision floating-point number. + * + *

    A drawing of a CubicCurve2D + * + * @param x1 the x coordinate of the curve’s new start + * point. + * + * @param y1 the y coordinate of the curve’s new start + * point. + * + * @param cx1 the x coordinate of the curve’s new + * first control point. + * + * @param cy1 the y coordinate of the curve’s new + * first control point. + * + * @param cx2 the x coordinate of the curve’s new + * second control point. + * + * @param cy2 the y coordinate of the curve’s new + * second control point. + * + * @param x2 the x coordinate of the curve’s new end + * point. + * + * @param y2 the y coordinate of the curve’s new end + * point. + */ + public void setCurve(double x1, double y1, double cx1, double cy1, + double cx2, double cy2, double x2, double y2) + { + this.x1 = (float) x1; + this.y1 = (float) y1; + ctrlx1 = (float) cx1; + ctrly1 = (float) cy1; + ctrlx2 = (float) cx2; + ctrly2 = (float) cy2; + this.x2 = (float) x2; + this.y2 = (float) y2; + } + + /** + * Changes the curve geometry, separately specifying each coordinate + * value as a single-precision floating-point number. + * + *

    A drawing of a CubicCurve2D + * + * @param x1 the x coordinate of the curve’s new start + * point. + * + * @param y1 the y coordinate of the curve’s new start + * point. + * + * @param cx1 the x coordinate of the curve’s new + * first control point. + * + * @param cy1 the y coordinate of the curve’s new + * first control point. + * + * @param cx2 the x coordinate of the curve’s new + * second control point. + * + * @param cy2 the y coordinate of the curve’s new + * second control point. + * + * @param x2 the x coordinate of the curve’s new end + * point. + * + * @param y2 the y coordinate of the curve’s new end + * point. + */ + public void setCurve(float x1, float y1, float cx1, float cy1, float cx2, + float cy2, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx1 = cx1; + ctrly1 = cy1; + ctrlx2 = cx2; + ctrly2 = cy2; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control points. As the + * illustration below shows, the invisible control points may cause + * the bounds to be much larger than the area that is actually + * covered by the curve. + * + *

    An illustration of the bounds of a CubicCurve2D + */ + public Rectangle2D getBounds2D() + { + float nx1 = (float) Math.min(Math.min(x1, ctrlx1), Math.min(ctrlx2, x2)); + float ny1 = (float) Math.min(Math.min(y1, ctrly1), Math.min(ctrly2, y2)); + float nx2 = (float) Math.max(Math.max(x1, ctrlx1), Math.max(ctrlx2, x2)); + float ny2 = (float) Math.max(Math.max(y1, ctrly1), Math.max(ctrly2, y2)); + return new Rectangle2D.Float(nx1, ny1, nx2 - nx1, ny2 - ny1); + } + } +} diff --git a/libjava/classpath/java/awt/geom/Dimension2D.java b/libjava/classpath/java/awt/geom/Dimension2D.java new file mode 100644 index 0000000..6b5ce88 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Dimension2D.java @@ -0,0 +1,118 @@ +/* Dimension2D.java -- abstraction of a dimension + Copyright (C) 1999, 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 java.awt.geom; + +/** + * This stores a dimension in 2-dimensional space - a width (along the x-axis) + * and height (along the y-axis). The storage is left to subclasses. + * + * @author Per Bothner (bothner@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class Dimension2D implements Cloneable +{ + /** + * The default constructor. + */ + protected Dimension2D() + { + } + + /** + * Get the width of this dimension. A negative result, while legal, is + * undefined in meaning. + * + * @return the width + */ + public abstract double getWidth(); + + /** + * Get the height of this dimension. A negative result, while legal, is + * undefined in meaning. + * + * @return the height + */ + public abstract double getHeight(); + + /** + * Set the size of this dimension to the requested values. Loss of precision + * may occur. + * + * @param w the new width + * @param h the new height + */ + public abstract void setSize(double w, double h); + + /** + * Set the size of this dimension to the requested value. Loss of precision + * may occur. + * + * @param d the dimension containing the new values + * + * @throws NullPointerException if d is null + */ + public void setSize(Dimension2D d) + { + setSize(d.getWidth(), d.getHeight()); + } + + /** + * Create a new dimension of the same run-time type with the same contents + * as this one. + * + * @return the clone + * + * @exception OutOfMemoryError If there is not enough memory available. + * + * @since 1.2 + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } +} // class Dimension2D diff --git a/libjava/classpath/java/awt/geom/Ellipse2D.java b/libjava/classpath/java/awt/geom/Ellipse2D.java new file mode 100644 index 0000000..e883077 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Ellipse2D.java @@ -0,0 +1,413 @@ +/* Ellipse2D.java -- represents an ellipse in 2-D space + 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 java.awt.geom; + + +/** + * Ellipse2D is the shape of an ellipse. + *
    + * A drawing of an ellipse
    + * The ellipse is defined by it's bounding box (shown in red), + * and is defined by the implicit curve:
    + *

    (x/a)2 + + * (y/b)2 = 1

    + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * + * @since 1.2 + */ +public abstract class Ellipse2D extends RectangularShape +{ + /** + * Ellipse2D is defined as abstract. + * Implementing classes are Ellipse2D.Float and Ellipse2D.Double. + */ + protected Ellipse2D() + { + } + + /** + * Determines if a point is contained within the ellipse.

    + * @param x - x coordinate of the point. + * @param y - y coordinate of the point. + * @return true if the point is within the ellipse, false otherwise. + */ + public boolean contains(double x, double y) + { + double rx = getWidth() / 2; + double ry = getHeight() / 2; + double tx = (x - (getX() + rx)) / rx; + double ty = (y - (getY() + ry)) / ry; + return tx * tx + ty * ty < 1.0; + } + + /** + * Determines if a rectangle is completely contained within the + * ellipse.

    + * @param x - x coordinate of the upper-left corner of the rectangle + * @param y - y coordinate of the upper-left corner of the rectangle + * @param w - width of the rectangle + * @param h - height of the rectangle + * @return true if the rectangle is completely contained, false otherwise. + */ + public boolean contains(double x, double y, double w, double h) + { + double x2 = x + w; + double y2 = y + h; + return (contains(x, y) && contains(x, y2) && contains(x2, y) + && contains(x2, y2)); + } + + /** + * Returns a PathIterator object corresponding to the ellipse.

    + * + * Note: An ellipse cannot be represented exactly in PathIterator + * segments, the outline is thefore approximated with cubic + * Bezier segments. + * + * @param at an optional transform. + * @return A path iterator. + */ + public PathIterator getPathIterator(AffineTransform at) + { + // An ellipse is just a complete arc. + return new Arc2D.ArcIterator(this, at); + } + + /** + * Determines if a rectangle intersects any part of the ellipse.

    + * @param x - x coordinate of the upper-left corner of the rectangle + * @param y - y coordinate of the upper-left corner of the rectangle + * @param w - width of the rectangle + * @param h - height of the rectangle + * @return true if the rectangle intersects the ellipse, false otherwise. + */ + public boolean intersects(double x, double y, double w, double h) + { + Rectangle2D r = new Rectangle2D.Double(x, y, w, h); + if (! r.intersects(getX(), getY(), getWidth(), getHeight())) + return false; + + if (contains(x, y) || contains(x, y + h) || contains(x + w, y) + || contains(x + w, y + h)) + return true; + + Line2D l1 = new Line2D.Double(getX(), getY() + (getHeight() / 2), + getX() + getWidth(), + getY() + (getHeight() / 2)); + Line2D l2 = new Line2D.Double(getX() + (getWidth() / 2), getY(), + getX() + (getWidth() / 2), + getY() + getHeight()); + + if (l1.intersects(r) || l2.intersects(r)) + return true; + + return false; + } + + /** + * An {@link Ellipse2D} that stores its coordinates using double + * primitives. + */ + public static class Double extends Ellipse2D + { + /** + * The height of the ellipse. + */ + public double height; + + /** + * The width of the ellipse. + */ + public double width; + + /** + * The upper-left x coordinate of the bounding-box + */ + public double x; + + /** + * The upper-left y coordinate of the bounding-box + */ + public double y; + + /** + * Creates a new Ellipse2D with an upper-left coordinate of (0,0) + * and a zero size. + */ + public Double() + { + } + + /** + * Creates a new Ellipse2D within a given rectangle + * using double-precision coordinates.

    + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + */ + public Double(double x, double y, double w, double h) + { + this.x = x; + this.y = y; + height = h; + width = w; + } + + /** + * Returns the bounding-box of the ellipse. + * @return The bounding box. + */ + public Rectangle2D getBounds2D() + { + return new Rectangle2D.Double(x, y, width, height); + } + + /** + * Returns the height of the ellipse. + * @return The height of the ellipse. + */ + public double getHeight() + { + return height; + } + + /** + * Returns the width of the ellipse. + * @return The width of the ellipse. + */ + public double getWidth() + { + return width; + } + + /** + * Returns x coordinate of the upper-left corner of + * the ellipse's bounding-box. + * @return The x coordinate. + */ + public double getX() + { + return x; + } + + /** + * Returns y coordinate of the upper-left corner of + * the ellipse's bounding-box. + * @return The y coordinate. + */ + public double getY() + { + return y; + } + + /** + * Returns true if the ellipse encloses no area, and + * false otherwise. + * + * @return A boolean. + */ + public boolean isEmpty() + { + return height <= 0 || width <= 0; + } + + /** + * Sets the geometry of the ellipse's bounding box.

    + * + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + */ + public void setFrame(double x, double y, double w, double h) + { + this.x = x; + this.y = y; + height = h; + width = w; + } + } // class Double + + /** + * An {@link Ellipse2D} that stores its coordinates using float + * primitives. + */ + public static class Float extends Ellipse2D + { + /** + * The height of the ellipse. + */ + public float height; + + /** + * The width of the ellipse. + */ + public float width; + + /** + * The upper-left x coordinate of the bounding-box + */ + public float x; + + /** + * The upper-left y coordinate of the bounding-box + */ + public float y; + + /** + * Creates a new Ellipse2D with an upper-left coordinate of (0,0) + * and a zero size. + */ + public Float() + { + } + + /** + * Creates a new Ellipse2D within a given rectangle + * using floating-point precision.

    + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + * + */ + public Float(float x, float y, float w, float h) + { + this.x = x; + this.y = y; + this.height = h; + this.width = w; + } + + /** + * Returns the bounding-box of the ellipse. + * @return The bounding box. + */ + public Rectangle2D getBounds2D() + { + return new Rectangle2D.Float(x, y, width, height); + } + + /** + * Returns the height of the ellipse. + * @return The height of the ellipse. + */ + public double getHeight() + { + return height; + } + + /** + * Returns the width of the ellipse. + * @return The width of the ellipse. + */ + public double getWidth() + { + return width; + } + + /** + * Returns x coordinate of the upper-left corner of + * the ellipse's bounding-box. + * @return The x coordinate. + */ + public double getX() + { + return x; + } + + /** + * Returns y coordinate of the upper-left corner of + * the ellipse's bounding-box. + * @return The y coordinate. + */ + public double getY() + { + return y; + } + + /** + * Returns true if the ellipse encloses no area, and + * false otherwise. + * + * @return A boolean. + */ + public boolean isEmpty() + { + return height <= 0 || width <= 0; + } + + /** + * Sets the geometry of the ellipse's bounding box.

    + * + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + */ + public void setFrame(float x, float y, float w, float h) + { + this.x = x; + this.y = y; + height = h; + width = w; + } + + /** + * Sets the geometry of the ellipse's bounding box. + * + * Note: This leads to a loss of precision.

    + * + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + */ + public void setFrame(double x, double y, double w, double h) + { + this.x = (float) x; + this.y = (float) y; + height = (float) h; + width = (float) w; + } + } // class Float +} // class Ellipse2D diff --git a/libjava/classpath/java/awt/geom/FlatteningPathIterator.java b/libjava/classpath/java/awt/geom/FlatteningPathIterator.java new file mode 100644 index 0000000..b06e6cc --- /dev/null +++ b/libjava/classpath/java/awt/geom/FlatteningPathIterator.java @@ -0,0 +1,579 @@ +/* FlatteningPathIterator.java -- Approximates curves by straight lines + Copyright (C) 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.geom; + +import java.util.NoSuchElementException; + + +/** + * A PathIterator for approximating curved path segments by sequences + * of straight lines. Instances of this class will only return + * segments of type {@link PathIterator#SEG_MOVETO}, {@link + * PathIterator#SEG_LINETO}, and {@link PathIterator#SEG_CLOSE}. + * + *

    The accuracy of the approximation is determined by two + * parameters: + * + *

    • The flatness is a threshold value for deciding when + * a curved segment is consided flat enough for being approximated by + * a single straight line. Flatness is defined as the maximal distance + * of a curve control point to the straight line that connects the + * curve start and end. A lower flatness threshold means a closer + * approximation. See {@link QuadCurve2D#getFlatness()} and {@link + * CubicCurve2D#getFlatness()} for drawings which illustrate the + * meaning of flatness.
    • + * + *
    • The recursion limit imposes an upper bound for how often + * a curved segment gets subdivided. A limit of n means that + * for each individual quadratic and cubic Bézier spline + * segment, at most 2n {@link + * PathIterator#SEG_LINETO} segments will be created.
    + * + *

    Memory Efficiency: The memory consumption grows linearly + * with the recursion limit. Neither the flatness parameter nor + * the number of segments in the flattened path will affect the memory + * consumption. + * + *

    Thread Safety: Multiple threads can safely work on + * separate instances of this class. However, multiple threads should + * not concurrently access the same instance, as no synchronization is + * performed. + * + * @see Implementation Note + * + * @author Sascha Brawer (brawer@dandelis.ch) + * + * @since 1.2 + */ +public class FlatteningPathIterator + implements PathIterator +{ + /** + * The PathIterator whose curved segments are being approximated. + */ + private final PathIterator srcIter; + + + /** + * The square of the flatness threshold value, which determines when + * a curve segment is considered flat enough that no further + * subdivision is needed. + * + *

    Calculating flatness actually produces the squared flatness + * value. To avoid the relatively expensive calculation of a square + * root for each curve segment, we perform all flatness comparisons + * on squared values. + * + * @see QuadCurve2D#getFlatnessSq() + * @see CubicCurve2D#getFlatnessSq() + */ + private final double flatnessSq; + + + /** + * The maximal number of subdivions that are performed to + * approximate a quadratic or cubic curve segment. + */ + private final int recursionLimit; + + + /** + * A stack for holding the coordinates of subdivided segments. + * + * @see Implementation Note + */ + private double[] stack; + + + /** + * The current stack size. + * + * @see Implementation Note + */ + private int stackSize; + + + /** + * The number of recursions that were performed to arrive at + * a segment on the stack. + * + * @see Implementation Note + */ + private int[] recLevel; + + + + private final double[] scratch = new double[6]; + + + /** + * The segment type of the last segment that was returned by + * the source iterator. + */ + private int srcSegType; + + + /** + * The current x position of the source iterator. + */ + private double srcPosX; + + + /** + * The current y position of the source iterator. + */ + private double srcPosY; + + + /** + * A flag that indicates when this path iterator has finished its + * iteration over path segments. + */ + private boolean done; + + + /** + * Constructs a new PathIterator for approximating an input + * PathIterator with straight lines. The approximation works by + * recursive subdivisons, until the specified flatness threshold is + * not exceeded. + * + *

    There will not be more than 10 nested recursion steps, which + * means that a single SEG_QUADTO or + * SEG_CUBICTO segment is approximated by at most + * 210 = 1024 straight lines. + */ + public FlatteningPathIterator(PathIterator src, double flatness) + { + this(src, flatness, 10); + } + + + /** + * Constructs a new PathIterator for approximating an input + * PathIterator with straight lines. The approximation works by + * recursive subdivisons, until the specified flatness threshold is + * not exceeded. Additionally, the number of recursions is also + * bound by the specified recursion limit. + */ + public FlatteningPathIterator(PathIterator src, double flatness, + int limit) + { + if (flatness < 0 || limit < 0) + throw new IllegalArgumentException(); + + srcIter = src; + flatnessSq = flatness * flatness; + recursionLimit = limit; + fetchSegment(); + } + + + /** + * Returns the maximally acceptable flatness. + * + * @see QuadCurve2D#getFlatness() + * @see CubicCurve2D#getFlatness() + */ + public double getFlatness() + { + return Math.sqrt(flatnessSq); + } + + + /** + * Returns the maximum number of recursive curve subdivisions. + */ + public int getRecursionLimit() + { + return recursionLimit; + } + + + // Documentation will be copied from PathIterator. + public int getWindingRule() + { + return srcIter.getWindingRule(); + } + + + // Documentation will be copied from PathIterator. + public boolean isDone() + { + return done; + } + + + // Documentation will be copied from PathIterator. + public void next() + { + if (stackSize > 0) + { + --stackSize; + if (stackSize > 0) + { + switch (srcSegType) + { + case PathIterator.SEG_QUADTO: + subdivideQuadratic(); + return; + + case PathIterator.SEG_CUBICTO: + subdivideCubic(); + return; + + default: + throw new IllegalStateException(); + } + } + } + + srcIter.next(); + fetchSegment(); + } + + + // Documentation will be copied from PathIterator. + public int currentSegment(double[] coords) + { + if (done) + throw new NoSuchElementException(); + + switch (srcSegType) + { + case PathIterator.SEG_CLOSE: + return srcSegType; + + case PathIterator.SEG_MOVETO: + case PathIterator.SEG_LINETO: + coords[0] = srcPosX; + coords[1] = srcPosY; + return srcSegType; + + case PathIterator.SEG_QUADTO: + if (stackSize == 0) + { + coords[0] = srcPosX; + coords[1] = srcPosY; + } + else + { + int sp = stack.length - 4 * stackSize; + coords[0] = stack[sp + 2]; + coords[1] = stack[sp + 3]; + } + return PathIterator.SEG_LINETO; + + case PathIterator.SEG_CUBICTO: + if (stackSize == 0) + { + coords[0] = srcPosX; + coords[1] = srcPosY; + } + else + { + int sp = stack.length - 6 * stackSize; + coords[0] = stack[sp + 4]; + coords[1] = stack[sp + 5]; + } + return PathIterator.SEG_LINETO; + } + + throw new IllegalStateException(); + } + + + // Documentation will be copied from PathIterator. + public int currentSegment(float[] coords) + { + if (done) + throw new NoSuchElementException(); + + switch (srcSegType) + { + case PathIterator.SEG_CLOSE: + return srcSegType; + + case PathIterator.SEG_MOVETO: + case PathIterator.SEG_LINETO: + coords[0] = (float) srcPosX; + coords[1] = (float) srcPosY; + return srcSegType; + + case PathIterator.SEG_QUADTO: + if (stackSize == 0) + { + coords[0] = (float) srcPosX; + coords[1] = (float) srcPosY; + } + else + { + int sp = stack.length - 4 * stackSize; + coords[0] = (float) stack[sp + 2]; + coords[1] = (float) stack[sp + 3]; + } + return PathIterator.SEG_LINETO; + + case PathIterator.SEG_CUBICTO: + if (stackSize == 0) + { + coords[0] = (float) srcPosX; + coords[1] = (float) srcPosY; + } + else + { + int sp = stack.length - 6 * stackSize; + coords[0] = (float) stack[sp + 4]; + coords[1] = (float) stack[sp + 5]; + } + return PathIterator.SEG_LINETO; + } + + throw new IllegalStateException(); + } + + + /** + * Fetches the next segment from the source iterator. + */ + private void fetchSegment() + { + int sp; + + if (srcIter.isDone()) + { + done = true; + return; + } + + srcSegType = srcIter.currentSegment(scratch); + + switch (srcSegType) + { + case PathIterator.SEG_CLOSE: + return; + + case PathIterator.SEG_MOVETO: + case PathIterator.SEG_LINETO: + srcPosX = scratch[0]; + srcPosY = scratch[1]; + return; + + case PathIterator.SEG_QUADTO: + if (recursionLimit == 0) + { + srcPosX = scratch[2]; + srcPosY = scratch[3]; + stackSize = 0; + return; + } + sp = 4 * recursionLimit; + stackSize = 1; + if (stack == null) + { + stack = new double[sp + /* 4 + 2 */ 6]; + recLevel = new int[recursionLimit + 1]; + } + recLevel[0] = 0; + stack[sp] = srcPosX; // P1.x + stack[sp + 1] = srcPosY; // P1.y + stack[sp + 2] = scratch[0]; // C.x + stack[sp + 3] = scratch[1]; // C.y + srcPosX = stack[sp + 4] = scratch[2]; // P2.x + srcPosY = stack[sp + 5] = scratch[3]; // P2.y + subdivideQuadratic(); + break; + + case PathIterator.SEG_CUBICTO: + if (recursionLimit == 0) + { + srcPosX = scratch[4]; + srcPosY = scratch[5]; + stackSize = 0; + return; + } + sp = 6 * recursionLimit; + stackSize = 1; + if ((stack == null) || (stack.length < sp + 8)) + { + stack = new double[sp + /* 6 + 2 */ 8]; + recLevel = new int[recursionLimit + 1]; + } + recLevel[0] = 0; + stack[sp] = srcPosX; // P1.x + stack[sp + 1] = srcPosY; // P1.y + stack[sp + 2] = scratch[0]; // C1.x + stack[sp + 3] = scratch[1]; // C1.y + stack[sp + 4] = scratch[2]; // C2.x + stack[sp + 5] = scratch[3]; // C2.y + srcPosX = stack[sp + 6] = scratch[4]; // P2.x + srcPosY = stack[sp + 7] = scratch[5]; // P2.y + subdivideCubic(); + return; + } + } + + + /** + * Repeatedly subdivides the quadratic curve segment that is on top + * of the stack. The iteration terminates when the recursion limit + * has been reached, or when the resulting segment is flat enough. + */ + private void subdivideQuadratic() + { + int sp; + int level; + + sp = stack.length - 4 * stackSize - 2; + level = recLevel[stackSize - 1]; + while ((level < recursionLimit) + && (QuadCurve2D.getFlatnessSq(stack, sp) >= flatnessSq)) + { + recLevel[stackSize] = recLevel[stackSize - 1] = ++level; + QuadCurve2D.subdivide(stack, sp, stack, sp - 4, stack, sp); + ++stackSize; + sp -= 4; + } + } + + + /** + * Repeatedly subdivides the cubic curve segment that is on top + * of the stack. The iteration terminates when the recursion limit + * has been reached, or when the resulting segment is flat enough. + */ + private void subdivideCubic() + { + int sp; + int level; + + sp = stack.length - 6 * stackSize - 2; + level = recLevel[stackSize - 1]; + while ((level < recursionLimit) + && (CubicCurve2D.getFlatnessSq(stack, sp) >= flatnessSq)) + { + recLevel[stackSize] = recLevel[stackSize - 1] = ++level; + + CubicCurve2D.subdivide(stack, sp, stack, sp - 6, stack, sp); + ++stackSize; + sp -= 6; + } + } + + + /* These routines were useful for debugging. Since they would + * just bloat the implementation, they are commented out. + * + * + + private static String segToString(int segType, double[] d, int offset) + { + String s; + + switch (segType) + { + case PathIterator.SEG_CLOSE: + return "SEG_CLOSE"; + + case PathIterator.SEG_MOVETO: + return "SEG_MOVETO (" + d[offset] + ", " + d[offset + 1] + ")"; + + case PathIterator.SEG_LINETO: + return "SEG_LINETO (" + d[offset] + ", " + d[offset + 1] + ")"; + + case PathIterator.SEG_QUADTO: + return "SEG_QUADTO (" + d[offset] + ", " + d[offset + 1] + + ") (" + d[offset + 2] + ", " + d[offset + 3] + ")"; + + case PathIterator.SEG_CUBICTO: + return "SEG_CUBICTO (" + d[offset] + ", " + d[offset + 1] + + ") (" + d[offset + 2] + ", " + d[offset + 3] + + ") (" + d[offset + 4] + ", " + d[offset + 5] + ")"; + } + + throw new IllegalStateException(); + } + + + private void dumpQuadraticStack(String msg) + { + int sp = stack.length - 4 * stackSize - 2; + int i = 0; + System.err.print(" " + msg + ":"); + while (sp < stack.length) + { + System.err.print(" (" + stack[sp] + ", " + stack[sp+1] + ")"); + if (i < recLevel.length) + System.out.print("/" + recLevel[i++]); + if (sp + 3 < stack.length) + System.err.print(" [" + stack[sp+2] + ", " + stack[sp+3] + "]"); + sp += 4; + } + System.err.println(); + } + + + private void dumpCubicStack(String msg) + { + int sp = stack.length - 6 * stackSize - 2; + int i = 0; + System.err.print(" " + msg + ":"); + while (sp < stack.length) + { + System.err.print(" (" + stack[sp] + ", " + stack[sp+1] + ")"); + if (i < recLevel.length) + System.out.print("/" + recLevel[i++]); + if (sp + 3 < stack.length) + { + System.err.print(" [" + stack[sp+2] + ", " + stack[sp+3] + "]"); + System.err.print(" [" + stack[sp+4] + ", " + stack[sp+5] + "]"); + } + sp += 6; + } + System.err.println(); + } + + * + * + */ +} diff --git a/libjava/classpath/java/awt/geom/GeneralPath.java b/libjava/classpath/java/awt/geom/GeneralPath.java new file mode 100644 index 0000000..f548558 --- /dev/null +++ b/libjava/classpath/java/awt/geom/GeneralPath.java @@ -0,0 +1,958 @@ +/* GeneralPath.java -- represents a shape built from subpaths + Copyright (C) 2002, 2003, 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 java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; + + +/** + * A general geometric path, consisting of any number of subpaths + * constructed out of straight lines and cubic or quadratic Bezier + * curves. + * + *

    The inside of the curve is defined for drawing purposes by a winding + * rule. Either the WIND_EVEN_ODD or WIND_NON_ZERO winding rule can be chosen. + * + *

    A drawing of a GeneralPath + *

    The EVEN_ODD winding rule defines a point as inside a path if: + * A ray from the point towards infinity in an arbitrary direction + * intersects the path an odd number of times. Points A and + * C in the image are considered to be outside the path. + * (both intersect twice) + * Point B intersects once, and is inside. + * + *

    The NON_ZERO winding rule defines a point as inside a path if: + * The path intersects the ray in an equal number of opposite directions. + * Point A in the image is outside (one intersection in the + * ’up’ + * direction, one in the ’down’ direction) Point B in + * the image is inside (one intersection ’down’) + * Point C in the image is outside (two intersections + * ’down’) + * + * @see Line2D + * @see CubicCurve2D + * @see QuadCurve2D + * + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Sven de Marothy (sven@physto.se) + * + * @since 1.2 + */ +public final class GeneralPath implements Shape, Cloneable +{ + public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD; + public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO; + + /** Initial size if not specified. */ + private static final int INIT_SIZE = 10; + + /** A big number, but not so big it can't survive a few float operations */ + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; + + /** The winding rule. + * This is package-private to avoid an accessor method. + */ + int rule; + + /** + * The path type in points. Note that xpoints[index] and ypoints[index] maps + * to types[index]; the control points of quad and cubic paths map as + * well but are ignored. + * This is package-private to avoid an accessor method. + */ + byte[] types; + + /** + * The list of all points seen. Since you can only append floats, it makes + * sense for these to be float[]. I have no idea why Sun didn't choose to + * allow a general path of double precision points. + * Note: Storing x and y coords seperately makes for a slower transforms, + * But it speeds up and simplifies box-intersection checking a lot. + * These are package-private to avoid accessor methods. + */ + float[] xpoints; + float[] ypoints; + + /** The index of the most recent moveto point, or null. */ + private int subpath = -1; + + /** The next available index into points. + * This is package-private to avoid an accessor method. + */ + int index; + + /** + * Constructs a GeneralPath with the default (NON_ZERO) + * winding rule and initial capacity (20). + */ + public GeneralPath() + { + this(WIND_NON_ZERO, INIT_SIZE); + } + + /** + * Constructs a GeneralPath with a specific winding rule + * and the default initial capacity (20). + * @param rule the winding rule (WIND_NON_ZERO or WIND_EVEN_ODD) + */ + public GeneralPath(int rule) + { + this(rule, INIT_SIZE); + } + + /** + * Constructs a GeneralPath with a specific winding rule + * and the initial capacity. The initial capacity should be + * the approximate number of path segments to be used. + * @param rule the winding rule (WIND_NON_ZERO or WIND_EVEN_ODD) + * @param capacity the inital capacity, in path segments + */ + public GeneralPath(int rule, int capacity) + { + if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) + throw new IllegalArgumentException(); + this.rule = rule; + if (capacity < INIT_SIZE) + capacity = INIT_SIZE; + types = new byte[capacity]; + xpoints = new float[capacity]; + ypoints = new float[capacity]; + } + + /** + * Constructs a GeneralPath from an arbitrary shape object. + * The Shapes PathIterator path and winding rule will be used. + * @param s the shape + */ + public GeneralPath(Shape s) + { + types = new byte[INIT_SIZE]; + xpoints = new float[INIT_SIZE]; + ypoints = new float[INIT_SIZE]; + PathIterator pi = s.getPathIterator(null); + setWindingRule(pi.getWindingRule()); + append(pi, false); + } + + /** + * Adds a new point to a path. + */ + public void moveTo(float x, float y) + { + subpath = index; + ensureSize(index + 1); + types[index] = PathIterator.SEG_MOVETO; + xpoints[index] = x; + ypoints[index++] = y; + } + + /** + * Appends a straight line to the current path. + * @param x x coordinate of the line endpoint. + * @param y y coordinate of the line endpoint. + */ + public void lineTo(float x, float y) + { + ensureSize(index + 1); + types[index] = PathIterator.SEG_LINETO; + xpoints[index] = x; + ypoints[index++] = y; + } + + /** + * Appends a quadratic Bezier curve to the current path. + * @param x1 x coordinate of the control point + * @param y1 y coordinate of the control point + * @param x2 x coordinate of the curve endpoint. + * @param y2 y coordinate of the curve endpoint. + */ + public void quadTo(float x1, float y1, float x2, float y2) + { + ensureSize(index + 2); + types[index] = PathIterator.SEG_QUADTO; + xpoints[index] = x1; + ypoints[index++] = y1; + xpoints[index] = x2; + ypoints[index++] = y2; + } + + /** + * Appends a cubic Bezier curve to the current path. + * @param x1 x coordinate of the first control point + * @param y1 y coordinate of the first control point + * @param x2 x coordinate of the second control point + * @param y2 y coordinate of the second control point + * @param x3 x coordinate of the curve endpoint. + * @param y3 y coordinate of the curve endpoint. + */ + public void curveTo(float x1, float y1, float x2, float y2, float x3, + float y3) + { + ensureSize(index + 3); + types[index] = PathIterator.SEG_CUBICTO; + xpoints[index] = x1; + ypoints[index++] = y1; + xpoints[index] = x2; + ypoints[index++] = y2; + xpoints[index] = x3; + ypoints[index++] = y3; + } + + /** + * Closes the current subpath by drawing a line + * back to the point of the last moveTo. + */ + public void closePath() + { + ensureSize(index + 1); + types[index] = PathIterator.SEG_CLOSE; + xpoints[index] = xpoints[subpath]; + ypoints[index++] = ypoints[subpath]; + } + + /** + * Appends the segments of a Shape to the path. If connect is + * true, the new path segments are connected to the existing one with a line. + * The winding rule of the Shape is ignored. + */ + public void append(Shape s, boolean connect) + { + append(s.getPathIterator(null), connect); + } + + /** + * Appends the segments of a PathIterator to this GeneralPath. + * Optionally, the initial {@link PathIterator#SEG_MOVETO} segment + * of the appended path is changed into a {@link + * PathIterator#SEG_LINETO} segment. + * + * @param iter the PathIterator specifying which segments shall be + * appended. + * + * @param connect true for substituting the initial + * {@link PathIterator#SEG_MOVETO} segment by a {@link + * PathIterator#SEG_LINETO}, or false for not + * performing any substitution. If this GeneralPath is currently + * empty, connect is assumed to be false, + * thus leaving the initial {@link PathIterator#SEG_MOVETO} + * unchanged. + */ + public void append(PathIterator iter, boolean connect) + { + // A bad implementation of this method had caused Classpath bug #6076. + float[] f = new float[6]; + while (! iter.isDone()) + { + switch (iter.currentSegment(f)) + { + case PathIterator.SEG_MOVETO: + if (! connect || (index == 0)) + { + moveTo(f[0], f[1]); + break; + } + if ((index >= 1) && (types[index - 1] == PathIterator.SEG_CLOSE) + && (f[0] == xpoints[index - 1]) + && (f[1] == ypoints[index - 1])) + break; + + // Fall through. + case PathIterator.SEG_LINETO: + lineTo(f[0], f[1]); + break; + case PathIterator.SEG_QUADTO: + quadTo(f[0], f[1], f[2], f[3]); + break; + case PathIterator.SEG_CUBICTO: + curveTo(f[0], f[1], f[2], f[3], f[4], f[5]); + break; + case PathIterator.SEG_CLOSE: + closePath(); + break; + } + + connect = false; + iter.next(); + } + } + + /** + * Returns the path’s current winding rule. + */ + public int getWindingRule() + { + return rule; + } + + /** + * Sets the path’s winding rule, which controls which areas are + * considered ’inside’ or ’outside’ the path + * on drawing. Valid rules are WIND_EVEN_ODD for an even-odd winding rule, + * or WIND_NON_ZERO for a non-zero winding rule. + */ + public void setWindingRule(int rule) + { + if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) + throw new IllegalArgumentException(); + this.rule = rule; + } + + /** + * Returns the current appending point of the path. + */ + public Point2D getCurrentPoint() + { + if (subpath < 0) + return null; + return new Point2D.Float(xpoints[index - 1], ypoints[index - 1]); + } + + /** + * Resets the path. All points and segments are destroyed. + */ + public void reset() + { + subpath = -1; + index = 0; + } + + /** + * Applies a transform to the path. + */ + public void transform(AffineTransform xform) + { + double nx; + double ny; + double[] m = new double[6]; + xform.getMatrix(m); + for (int i = 0; i < index; i++) + { + nx = m[0] * xpoints[i] + m[2] * ypoints[i] + m[4]; + ny = m[1] * xpoints[i] + m[3] * ypoints[i] + m[5]; + xpoints[i] = (float) nx; + ypoints[i] = (float) ny; + } + } + + /** + * Creates a transformed version of the path. + * @param xform the transform to apply + * @return a new transformed GeneralPath + */ + public Shape createTransformedShape(AffineTransform xform) + { + GeneralPath p = new GeneralPath(this); + p.transform(xform); + return p; + } + + /** + * Returns the path’s bounding box. + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + /** + * Returns the path’s bounding box, in float precision + */ + public Rectangle2D getBounds2D() + { + float x1; + float y1; + float x2; + float y2; + + if (index > 0) + { + x1 = x2 = xpoints[0]; + y1 = y2 = ypoints[0]; + } + else + x1 = x2 = y1 = y2 = 0.0f; + + for (int i = 0; i < index; i++) + { + x1 = Math.min(xpoints[i], x1); + y1 = Math.min(ypoints[i], y1); + x2 = Math.max(xpoints[i], x2); + y2 = Math.max(ypoints[i], y2); + } + return (new Rectangle2D.Float(x1, y1, x2 - x1, y2 - y1)); + } + + /** + * Evaluates if a point is within the GeneralPath, + * The NON_ZERO winding rule is used, regardless of the + * set winding rule. + * @param x x coordinate of the point to evaluate + * @param y y coordinate of the point to evaluate + * @return true if the point is within the path, false otherwise + */ + public boolean contains(double x, double y) + { + return (getWindingNumber(x, y) != 0); + } + + /** + * Evaluates if a Point2D is within the GeneralPath, + * The NON_ZERO winding rule is used, regardless of the + * set winding rule. + * @param p The Point2D to evaluate + * @return true if the point is within the path, false otherwise + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Evaluates if a rectangle is completely contained within the path. + * This method will return false in the cases when the box + * intersects an inner segment of the path. + * (i.e.: The method is accurate for the EVEN_ODD winding rule) + */ + public boolean contains(double x, double y, double w, double h) + { + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, false, w) != 0 /* top */ + || getAxisIntersections(x, y + h, false, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, true, h) != 0 /* right */ + || getAxisIntersections(x, y, true, h) != 0) /* left */ + return false; + + /* No intersections, is any point inside? */ + if (getWindingNumber(x, y) != 0) + return true; + + return false; + } + + /** + * Evaluates if a rectangle is completely contained within the path. + * This method will return false in the cases when the box + * intersects an inner segment of the path. + * (i.e.: The method is accurate for the EVEN_ODD winding rule) + * @param r the rectangle + * @return true if the rectangle is completely contained + * within the path, false otherwise + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Evaluates if a rectangle intersects the path. + * @param x x coordinate of the rectangle + * @param y y coordinate of the rectangle + * @param w width of the rectangle + * @param h height of the rectangle + * @return true if the rectangle intersects the path, + * false otherwise + */ + public boolean intersects(double x, double y, double w, double h) + { + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, false, w) != 0 /* top */ + || getAxisIntersections(x, y + h, false, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, true, h) != 0 /* right */ + || getAxisIntersections(x, y, true, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if (getWindingNumber(x, y) != 0) + return true; + + return false; + } + + /** + * Evaluates if a Rectangle2D intersects the path. + * @param r The rectangle + * @return true if the rectangle intersects the path, + * false otherwise + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * A PathIterator that iterates over the segments of a GeneralPath. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private static class GeneralPathIterator implements PathIterator + { + /** + * The number of coordinate values for each segment type. + */ + private static final int[] NUM_COORDS = { + /* 0: SEG_MOVETO */ 1, + /* 1: SEG_LINETO */ 1, + /* 2: SEG_QUADTO */ 2, + /* 3: SEG_CUBICTO */ 3, + /* 4: SEG_CLOSE */ 0}; + + /** + * The GeneralPath whose segments are being iterated. + * This is package-private to avoid an accessor method. + */ + final GeneralPath path; + + /** + * The affine transformation used to transform coordinates. + */ + private final AffineTransform transform; + + /** + * The current position of the iterator. + */ + private int pos; + + /** + * Constructs a new iterator for enumerating the segments of a + * GeneralPath. + * + * @param at an affine transformation for projecting the returned + * points, or null to return the original points + * without any mapping. + */ + GeneralPathIterator(GeneralPath path, AffineTransform transform) + { + this.path = path; + this.transform = transform; + } + + /** + * Returns the current winding rule of the GeneralPath. + */ + public int getWindingRule() + { + return path.rule; + } + + /** + * Determines whether the iterator has reached the last segment in + * the path. + */ + public boolean isDone() + { + return pos >= path.index; + } + + /** + * Advances the iterator position by one segment. + */ + public void next() + { + int seg; + + /* + * Increment pos by the number of coordinate pairs. + */ + seg = path.types[pos]; + if (seg == SEG_CLOSE) + pos++; + else + pos += NUM_COORDS[seg]; + } + + /** + * Returns the current segment in float coordinates. + */ + public int currentSegment(float[] coords) + { + int seg; + int numCoords; + + seg = path.types[pos]; + numCoords = NUM_COORDS[seg]; + if (numCoords > 0) + { + for (int i = 0; i < numCoords; i++) + { + coords[i << 1] = path.xpoints[pos + i]; + coords[(i << 1) + 1] = path.ypoints[pos + i]; + } + + if (transform != null) + transform.transform( /* src */ + coords, /* srcOffset */ + 0, /* dest */ coords, /* destOffset */ + 0, /* numPoints */ numCoords); + } + return seg; + } + + /** + * Returns the current segment in double coordinates. + */ + public int currentSegment(double[] coords) + { + int seg; + int numCoords; + + seg = path.types[pos]; + numCoords = NUM_COORDS[seg]; + if (numCoords > 0) + { + for (int i = 0; i < numCoords; i++) + { + coords[i << 1] = (double) path.xpoints[pos + i]; + coords[(i << 1) + 1] = (double) path.ypoints[pos + i]; + } + if (transform != null) + transform.transform( /* src */ + coords, /* srcOffset */ + 0, /* dest */ coords, /* destOffset */ + 0, /* numPoints */ numCoords); + } + return seg; + } + } + + /** + * Creates a PathIterator for iterating along the segments of the path. + * + * @param at an affine transformation for projecting the returned + * points, or null to let the created iterator return + * the original points without any mapping. + */ + public PathIterator getPathIterator(AffineTransform at) + { + return new GeneralPathIterator(this, at); + } + + /** + * Creates a new FlatteningPathIterator for the path + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + /** + * Creates a new shape of the same run-time type with the same contents + * as this one. + * + * @return the clone + * + * @exception OutOfMemoryError If there is not enough memory available. + * + * @since 1.2 + */ + public Object clone() + { + // This class is final; no need to use super.clone(). + return new GeneralPath(this); + } + + /** + * Helper method - ensure the size of the data arrays, + * otherwise, reallocate new ones twice the size + */ + private void ensureSize(int size) + { + if (subpath < 0) + throw new IllegalPathStateException("need initial moveto"); + if (size <= xpoints.length) + return; + byte[] b = new byte[types.length << 1]; + System.arraycopy(types, 0, b, 0, index); + types = b; + float[] f = new float[xpoints.length << 1]; + System.arraycopy(xpoints, 0, f, 0, index); + xpoints = f; + f = new float[ypoints.length << 1]; + System.arraycopy(ypoints, 0, f, 0, index); + ypoints = f; + } + + /** + * Helper method - Get the total number of intersections from (x,y) along + * a given axis, within a given distance. + */ + private int getAxisIntersections(double x, double y, boolean useYaxis, + double distance) + { + return (evaluateCrossings(x, y, false, useYaxis, distance)); + } + + /** + * Helper method - returns the winding number of a point. + */ + private int getWindingNumber(double x, double y) + { + /* Evaluate the crossings from x,y to infinity on the y axis (arbitrary + choice). Note that we don't actually use Double.INFINITY, since that's + slower, and may cause problems. */ + return (evaluateCrossings(x, y, true, true, BIG_VALUE)); + } + + /** + * Helper method - evaluates the number of intersections on an axis from + * the point (x,y) to the point (x,y+distance) or (x+distance,y). + * @param x x coordinate. + * @param y y coordinate. + * @param neg True if opposite-directed intersections should cancel, + * false to sum all intersections. + * @param useYaxis Use the Y axis, false uses the X axis. + * @param distance Interval from (x,y) on the selected axis to find + * intersections. + */ + private int evaluateCrossings(double x, double y, boolean neg, + boolean useYaxis, double distance) + { + float cx = 0.0f; + float cy = 0.0f; + float firstx = 0.0f; + float firsty = 0.0f; + + int negative = (neg) ? -1 : 1; + double x0; + double x1; + double x2; + double x3; + double y0; + double y1; + double y2; + double y3; + double[] r = new double[4]; + int nRoots; + double epsilon = 0.0; + int pos = 0; + int windingNumber = 0; + boolean pathStarted = false; + + if (index == 0) + return (0); + if (useYaxis) + { + float[] swap1; + swap1 = ypoints; + ypoints = xpoints; + xpoints = swap1; + double swap2; + swap2 = y; + y = x; + x = swap2; + } + + /* Get a value which is hopefully small but not insignificant relative + the path. */ + epsilon = ypoints[0] * 1E-7; + + if(epsilon == 0) + epsilon = 1E-7; + + pos = 0; + while (pos < index) + { + switch (types[pos]) + { + case PathIterator.SEG_MOVETO: + if (pathStarted) // close old path + { + x0 = cx; + y0 = cy; + x1 = firstx; + y1 = firsty; + + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (Line2D.linesIntersect(x0, y0, x1, y1, + epsilon, 0.0, distance, 0.0)) + windingNumber += (y1 < y0) ? 1 : negative; + + cx = firstx; + cy = firsty; + } + cx = firstx = xpoints[pos] - (float) x; + cy = firsty = ypoints[pos++] - (float) y; + pathStarted = true; + break; + case PathIterator.SEG_CLOSE: + x0 = cx; + y0 = cy; + x1 = firstx; + y1 = firsty; + + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (Line2D.linesIntersect(x0, y0, x1, y1, + epsilon, 0.0, distance, 0.0)) + windingNumber += (y1 < y0) ? 1 : negative; + + cx = firstx; + cy = firsty; + pos++; + pathStarted = false; + break; + case PathIterator.SEG_LINETO: + x0 = cx; + y0 = cy; + x1 = xpoints[pos] - (float) x; + y1 = ypoints[pos++] - (float) y; + + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (Line2D.linesIntersect(x0, y0, x1, y1, + epsilon, 0.0, distance, 0.0)) + windingNumber += (y1 < y0) ? 1 : negative; + + cx = xpoints[pos - 1] - (float) x; + cy = ypoints[pos - 1] - (float) y; + break; + case PathIterator.SEG_QUADTO: + x0 = cx; + y0 = cy; + x1 = xpoints[pos] - x; + y1 = ypoints[pos++] - y; + x2 = xpoints[pos] - x; + y2 = ypoints[pos++] - y; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0) + && (y0 * y1 <= 0 || y1 * y2 <= 0)) + { + if (y0 == 0.0) + y0 -= epsilon; + if (y2 == 0.0) + y2 -= epsilon; + + r[0] = y0; + r[1] = 2 * (y1 - y0); + r[2] = (y2 - 2 * y1 + y0); + + /* degenerate roots (=tangent points) do not + contribute to the winding number. */ + if ((nRoots = QuadCurve2D.solveQuadratic(r)) == 2) + for (int i = 0; i < nRoots; i++) + { + float t = (float) r[i]; + if (t > 0.0f && t < 1.0f) + { + double crossing = t * t * (x2 - 2 * x1 + x0) + + 2 * t * (x1 - x0) + x0; + if (crossing >= 0.0 && crossing <= distance) + windingNumber += (2 * t * (y2 - 2 * y1 + y0) + + 2 * (y1 - y0) < 0) ? 1 : negative; + } + } + } + + cx = xpoints[pos - 1] - (float) x; + cy = ypoints[pos - 1] - (float) y; + break; + case PathIterator.SEG_CUBICTO: + x0 = cx; + y0 = cy; + x1 = xpoints[pos] - x; + y1 = ypoints[pos++] - y; + x2 = xpoints[pos] - x; + y2 = ypoints[pos++] - y; + x3 = xpoints[pos] - x; + y3 = ypoints[pos++] - y; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0 || x3 > 0.0) + && (y0 * y1 <= 0 || y1 * y2 <= 0 || y2 * y3 <= 0)) + { + if (y0 == 0.0) + y0 -= epsilon; + if (y3 == 0.0) + y3 -= epsilon; + + r[0] = y0; + r[1] = 3 * (y1 - y0); + r[2] = 3 * (y2 + y0 - 2 * y1); + r[3] = y3 - 3 * y2 + 3 * y1 - y0; + + if ((nRoots = CubicCurve2D.solveCubic(r)) != 0) + for (int i = 0; i < nRoots; i++) + { + float t = (float) r[i]; + if (t > 0.0 && t < 1.0) + { + double crossing = -(t * t * t) * (x0 - 3 * x1 + + 3 * x2 - x3) + + 3 * t * t * (x0 - 2 * x1 + x2) + + 3 * t * (x1 - x0) + x0; + if (crossing >= 0 && crossing <= distance) + windingNumber += (3 * t * t * (y3 + 3 * y1 + - 3 * y2 - y0) + + 6 * t * (y0 - 2 * y1 + y2) + + 3 * (y1 - y0) < 0) ? 1 : negative; + } + } + } + + cx = xpoints[pos - 1] - (float) x; + cy = ypoints[pos - 1] - (float) y; + break; + } + } + + // swap coordinates back + if (useYaxis) + { + float[] swap; + swap = ypoints; + ypoints = xpoints; + xpoints = swap; + } + return (windingNumber); + } +} // class GeneralPath + diff --git a/libjava/classpath/java/awt/geom/IllegalPathStateException.java b/libjava/classpath/java/awt/geom/IllegalPathStateException.java new file mode 100644 index 0000000..4d190c7 --- /dev/null +++ b/libjava/classpath/java/awt/geom/IllegalPathStateException.java @@ -0,0 +1,71 @@ +/* IllegalPathStateException.java -- an operation was in an illegal path state + 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 java.awt.geom; + +/** + * Thrown when an operation on a path is in an illegal state, such as appending + * a segment to a GeneralPath without an initial moveto. + * + * @author Tom Tromey (tromey@cygnus.com) + * @see GeneralPath + * @status updated to 1.4 + */ +public class IllegalPathStateException extends RuntimeException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -5158084205220481094L; + + /** + * Create an exception with no message. + */ + public IllegalPathStateException() + { + } + + /** + * Create an exception with a message. + * + * @param msg the message + */ + public IllegalPathStateException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/awt/geom/Line2D.java b/libjava/classpath/java/awt/geom/Line2D.java new file mode 100644 index 0000000..e15e7cf --- /dev/null +++ b/libjava/classpath/java/awt/geom/Line2D.java @@ -0,0 +1,1182 @@ +/* Line2D.java -- represents a line in 2-D space, plus operations on a line + Copyright (C) 2000, 2001, 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 java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + +/** + * Represents a directed line bewteen two points in (x,y) Cartesian space. + * Remember, on-screen graphics have increasing x from left-to-right, and + * increasing y from top-to-bottom. The storage is left to subclasses. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @author David Gilbert + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class Line2D implements Shape, Cloneable +{ + /** + * The default constructor. + */ + protected Line2D() + { + } + + /** + * Return the x coordinate of the first point. + * + * @return the starting x coordinate + */ + public abstract double getX1(); + + /** + * Return the y coordinate of the first point. + * + * @return the starting y coordinate + */ + public abstract double getY1(); + + /** + * Return the first point. + * + * @return the starting point + */ + public abstract Point2D getP1(); + + /** + * Return the x coordinate of the second point. + * + * @return the ending x coordinate + */ + public abstract double getX2(); + + /** + * Return the y coordinate of the second point. + * + * @return the ending y coordinate + */ + public abstract double getY2(); + + /** + * Return the second point. + * + * @return the ending point + */ + public abstract Point2D getP2(); + + /** + * Set the coordinates of the line to the given coordinates. Loss of + * precision may occur due to rounding issues. + * + * @param x1 the first x coordinate + * @param y1 the first y coordinate + * @param x2 the second x coordinate + * @param y2 the second y coordinate + */ + public abstract void setLine(double x1, double y1, double x2, double y2); + + /** + * Set the coordinates to the given points. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + */ + public void setLine(Point2D p1, Point2D p2) + { + setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + } + + /** + * Set the coordinates to those of the given line. + * + * @param l the line to copy + * @throws NullPointerException if l is null + */ + public void setLine(Line2D l) + { + setLine(l.getX1(), l.getY1(), l.getX2(), l.getY2()); + } + + /** + * Computes the relative rotation direction needed to pivot the line about + * the first point in order to have the second point colinear with point p. + * Because of floating point rounding, don't expect this to be a perfect + * measure of colinearity. The answer is 1 if the line has a shorter rotation + * in the direction of the positive X axis to the negative Y axis + * (counter-clockwise in the default Java coordinate system), or -1 if the + * shortest rotation is in the opposite direction (clockwise). If p + * is already colinear, the return value is -1 if it lies beyond the first + * point, 0 if it lies in the segment, or 1 if it lies beyond the second + * point. If the first and second point are coincident, this returns 0. + * + * @param x1 the first x coordinate + * @param y1 the first y coordinate + * @param x2 the second x coordinate + * @param y2 the second y coordinate + * @param px the reference x coordinate + * @param py the reference y coordinate + * @return the relative rotation direction + */ + public static int relativeCCW(double x1, double y1, double x2, double y2, + double px, double py) + { + if ((x1 == x2 && y1 == y2) + || (x1 == px && y1 == py)) + return 0; // Coincident points. + // Translate to the origin. + x2 -= x1; + y2 -= y1; + px -= x1; + py -= y1; + double slope2 = y2 / x2; + double slopep = py / px; + if (slope2 == slopep || (x2 == 0 && px == 0)) + return y2 > 0 // Colinear. + ? (py < 0 ? -1 : py > y2 ? 1 : 0) + : (py > 0 ? -1 : py < y2 ? 1 : 0); + if (x2 >= 0 && slope2 >= 0) + return px >= 0 // Quadrant 1. + ? (slope2 > slopep ? 1 : -1) + : (slope2 < slopep ? 1 : -1); + if (y2 > 0) + return px < 0 // Quadrant 2. + ? (slope2 > slopep ? 1 : -1) + : (slope2 < slopep ? 1 : -1); + if (slope2 >= 0.0) + return px >= 0 // Quadrant 3. + ? (slope2 < slopep ? 1 : -1) + : (slope2 > slopep ? 1 : -1); + return px < 0 // Quadrant 4. + ? (slope2 < slopep ? 1 : -1) + : (slope2 > slopep ? 1 : -1); + } + + /** + * Computes the relative rotation direction needed to pivot this line about + * the first point in order to have the second point colinear with point p. + * Because of floating point rounding, don't expect this to be a perfect + * measure of colinearity. The answer is 1 if the line has a shorter rotation + * in the direction of the positive X axis to the negative Y axis + * (counter-clockwise in the default Java coordinate system), or -1 if the + * shortest rotation is in the opposite direction (clockwise). If p + * is already colinear, the return value is -1 if it lies beyond the first + * point, 0 if it lies in the segment, or 1 if it lies beyond the second + * point. If the first and second point are coincident, this returns 0. + * + * @param px the reference x coordinate + * @param py the reference y coordinate + * @return the relative rotation direction + * @see #relativeCCW(double, double, double, double, double, double) + */ + public int relativeCCW(double px, double py) + { + return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Computes the relative rotation direction needed to pivot this line about + * the first point in order to have the second point colinear with point p. + * Because of floating point rounding, don't expect this to be a perfect + * measure of colinearity. The answer is 1 if the line has a shorter rotation + * in the direction of the positive X axis to the negative Y axis + * (counter-clockwise in the default Java coordinate system), or -1 if the + * shortest rotation is in the opposite direction (clockwise). If p + * is already colinear, the return value is -1 if it lies beyond the first + * point, 0 if it lies in the segment, or 1 if it lies beyond the second + * point. If the first and second point are coincident, this returns 0. + * + * @param p the reference point + * @return the relative rotation direction + * @throws NullPointerException if p is null + * @see #relativeCCW(double, double, double, double, double, double) + */ + public int relativeCCW(Point2D p) + { + return relativeCCW(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Computes twice the (signed) area of the triangle defined by the three + * points. This method is used for intersection testing. + * + * @param x1 the x-coordinate of the first point. + * @param y1 the y-coordinate of the first point. + * @param x2 the x-coordinate of the second point. + * @param y2 the y-coordinate of the second point. + * @param x3 the x-coordinate of the third point. + * @param y3 the y-coordinate of the third point. + * + * @return Twice the area. + */ + private static double area2(double x1, double y1, + double x2, double y2, + double x3, double y3) + { + return (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); + } + + /** + * Returns true if (x3, y3) lies between (x1, y1) and (x2, y2), + * and false otherwise, This test assumes that the three points are + * collinear, and is used for intersection testing. + * + * @param x1 the x-coordinate of the first point. + * @param y1 the y-coordinate of the first point. + * @param x2 the x-coordinate of the second point. + * @param y2 the y-coordinate of the second point. + * @param x3 the x-coordinate of the third point. + * @param y3 the y-coordinate of the third point. + * + * @return A boolean. + */ + private static boolean between(double x1, double y1, + double x2, double y2, + double x3, double y3) + { + if (x1 != x2) { + return (x1 <= x3 && x3 <= x2) || (x1 >= x3 && x3 >= x2); + } + else { + return (y1 <= y3 && y3 <= y2) || (y1 >= y3 && y3 >= y2); + } + } + + /** + * Test if the line segment (x1,y1)->(x2,y2) intersects the line segment + * (x3,y3)->(x4,y4). + * + * @param x1 the first x coordinate of the first segment + * @param y1 the first y coordinate of the first segment + * @param x2 the second x coordinate of the first segment + * @param y2 the second y coordinate of the first segment + * @param x3 the first x coordinate of the second segment + * @param y3 the first y coordinate of the second segment + * @param x4 the second x coordinate of the second segment + * @param y4 the second y coordinate of the second segment + * @return true if the segments intersect + */ + public static boolean linesIntersect(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + double a1, a2, a3, a4; + + // deal with special cases + if ((a1 = area2(x1, y1, x2, y2, x3, y3)) == 0.0) + { + // check if p3 is between p1 and p2 OR + // p4 is collinear also AND either between p1 and p2 OR at opposite ends + if (between(x1, y1, x2, y2, x3, y3)) + { + return true; + } + else + { + if (area2(x1, y1, x2, y2, x4, y4) == 0.0) + { + return between(x3, y3, x4, y4, x1, y1) + || between (x3, y3, x4, y4, x2, y2); + } + else { + return false; + } + } + } + else if ((a2 = area2(x1, y1, x2, y2, x4, y4)) == 0.0) + { + // check if p4 is between p1 and p2 (we already know p3 is not + // collinear) + return between(x1, y1, x2, y2, x4, y4); + } + + if ((a3 = area2(x3, y3, x4, y4, x1, y1)) == 0.0) { + // check if p1 is between p3 and p4 OR + // p2 is collinear also AND either between p1 and p2 OR at opposite ends + if (between(x3, y3, x4, y4, x1, y1)) { + return true; + } + else { + if (area2(x3, y3, x4, y4, x2, y2) == 0.0) { + return between(x1, y1, x2, y2, x3, y3) + || between (x1, y1, x2, y2, x4, y4); + } + else { + return false; + } + } + } + else if ((a4 = area2(x3, y3, x4, y4, x2, y2)) == 0.0) { + // check if p2 is between p3 and p4 (we already know p1 is not + // collinear) + return between(x3, y3, x4, y4, x2, y2); + } + else { // test for regular intersection + return ((a1 > 0.0) ^ (a2 > 0.0)) && ((a3 > 0.0) ^ (a4 > 0.0)); + } + } + + /** + * Test if this line intersects the line given by (x1,y1)->(x2,y2). + * + * @param x1 the first x coordinate of the other segment + * @param y1 the first y coordinate of the other segment + * @param x2 the second x coordinate of the other segment + * @param y2 the second y coordinate of the other segment + * @return true if the segments intersect + * @see #linesIntersect(double, double, double, double, + * double, double, double, double) + */ + public boolean intersectsLine(double x1, double y1, double x2, double y2) + { + return linesIntersect(getX1(), getY1(), getX2(), getY2(), + x1, y1, x2, y2); + } + + /** + * Test if this line intersects the given line. + * + * @param l the other segment + * @return true if the segments intersect + * @throws NullPointerException if l is null + * @see #linesIntersect(double, double, double, double, + * double, double, double, double) + */ + public boolean intersectsLine(Line2D l) + { + return linesIntersect(getX1(), getY1(), getX2(), getY2(), + l.getX1(), l.getY1(), l.getX2(), l.getY2()); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on the line segment. If the point is on the segment, the + * result will be 0. + * + * @param x1 the first x coordinate of the segment + * @param y1 the first y coordinate of the segment + * @param x2 the second x coordinate of the segment + * @param y2 the second y coordinate of the segment + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the square of the distance from the point to the segment + * @see #ptSegDist(double, double, double, double, double, double) + * @see #ptLineDistSq(double, double, double, double, double, double) + */ + public static double ptSegDistSq(double x1, double y1, double x2, double y2, + double px, double py) + { + double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); + + double x, y; + if (pd2 == 0) + { + // Points are coincident. + x = x1; + y = y2; + } + else + { + double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2; + + if (u < 0) + { + // "Off the end" + x = x1; + y = y1; + } + else if (u > 1.0) + { + x = x2; + y = y2; + } + else + { + x = x1 + u * (x2 - x1); + y = y1 + u * (y2 - y1); + } + } + + return (x - px) * (x - px) + (y - py) * (y - py); + } + + /** + * Measures the shortest distance from the reference point to a point on + * the line segment. If the point is on the segment, the result will be 0. + * + * @param x1 the first x coordinate of the segment + * @param y1 the first y coordinate of the segment + * @param x2 the second x coordinate of the segment + * @param y2 the second y coordinate of the segment + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the distance from the point to the segment + * @see #ptSegDistSq(double, double, double, double, double, double) + * @see #ptLineDist(double, double, double, double, double, double) + */ + public static double ptSegDist(double x1, double y1, double x2, double y2, + double px, double py) + { + return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py)); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on this line segment. If the point is on the segment, the + * result will be 0. + * + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the square of the distance from the point to the segment + * @see #ptSegDistSq(double, double, double, double, double, double) + */ + public double ptSegDistSq(double px, double py) + { + return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on this line segment. If the point is on the segment, the + * result will be 0. + * + * @param p the point + * @return the square of the distance from the point to the segment + * @throws NullPointerException if p is null + * @see #ptSegDistSq(double, double, double, double, double, double) + */ + public double ptSegDistSq(Point2D p) + { + return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Measures the shortest distance from the reference point to a point on + * this line segment. If the point is on the segment, the result will be 0. + * + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the distance from the point to the segment + * @see #ptSegDist(double, double, double, double, double, double) + */ + public double ptSegDist(double px, double py) + { + return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Measures the shortest distance from the reference point to a point on + * this line segment. If the point is on the segment, the result will be 0. + * + * @param p the point + * @return the distance from the point to the segment + * @throws NullPointerException if p is null + * @see #ptSegDist(double, double, double, double, double, double) + */ + public double ptSegDist(Point2D p) + { + return ptSegDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on the infinite line extended from the segment. If the point + * is on the segment, the result will be 0. If the segment is length 0, + * the distance is to the common endpoint. + * + * @param x1 the first x coordinate of the segment + * @param y1 the first y coordinate of the segment + * @param x2 the second x coordinate of the segment + * @param y2 the second y coordinate of the segment + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the square of the distance from the point to the extended line + * @see #ptLineDist(double, double, double, double, double, double) + * @see #ptSegDistSq(double, double, double, double, double, double) + */ + public static double ptLineDistSq(double x1, double y1, double x2, double y2, + double px, double py) + { + double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); + + double x, y; + if (pd2 == 0) + { + // Points are coincident. + x = x1; + y = y2; + } + else + { + double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2; + x = x1 + u * (x2 - x1); + y = y1 + u * (y2 - y1); + } + + return (x - px) * (x - px) + (y - py) * (y - py); + } + + /** + * Measures the shortest distance from the reference point to a point on + * the infinite line extended from the segment. If the point is on the + * segment, the result will be 0. If the segment is length 0, the distance + * is to the common endpoint. + * + * @param x1 the first x coordinate of the segment + * @param y1 the first y coordinate of the segment + * @param x2 the second x coordinate of the segment + * @param y2 the second y coordinate of the segment + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the distance from the point to the extended line + * @see #ptLineDistSq(double, double, double, double, double, double) + * @see #ptSegDist(double, double, double, double, double, double) + */ + public static double ptLineDist(double x1, double y1, + double x2, double y2, + double px, double py) + { + return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py)); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on the infinite line extended from this segment. If the point + * is on the segment, the result will be 0. If the segment is length 0, + * the distance is to the common endpoint. + * + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the square of the distance from the point to the extended line + * @see #ptLineDistSq(double, double, double, double, double, double) + */ + public double ptLineDistSq(double px, double py) + { + return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on the infinite line extended from this segment. If the point + * is on the segment, the result will be 0. If the segment is length 0, + * the distance is to the common endpoint. + * + * @param p the point + * @return the square of the distance from the point to the extended line + * @throws NullPointerException if p is null + * @see #ptLineDistSq(double, double, double, double, double, double) + */ + public double ptLineDistSq(Point2D p) + { + return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), + p.getX(), p.getY()); + } + + /** + * Measures the shortest distance from the reference point to a point on + * the infinite line extended from this segment. If the point is on the + * segment, the result will be 0. If the segment is length 0, the distance + * is to the common endpoint. + * + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the distance from the point to the extended line + * @see #ptLineDist(double, double, double, double, double, double) + */ + public double ptLineDist(double px, double py) + { + return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Measures the shortest distance from the reference point to a point on + * the infinite line extended from this segment. If the point is on the + * segment, the result will be 0. If the segment is length 0, the distance + * is to the common endpoint. + * + * @param p the point + * @return the distance from the point to the extended line + * @throws NullPointerException if p is null + * @see #ptLineDist(double, double, double, double, double, double) + */ + public double ptLineDist(Point2D p) + { + return ptLineDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Test if a point is contained inside the line. Since a line has no area, + * this returns false. + * + * @param x the x coordinate + * @param y the y coordinate + * @return false; the line does not contain points + */ + public boolean contains(double x, double y) + { + return false; + } + + /** + * Test if a point is contained inside the line. Since a line has no area, + * this returns false. + * + * @param p the point + * @return false; the line does not contain points + */ + public boolean contains(Point2D p) + { + return false; + } + + /** + * Tests if this line intersects the interior of the specified rectangle. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @return true if the line intersects the rectangle + */ + public boolean intersects(double x, double y, double w, double h) + { + if (w <= 0 || h <= 0) + return false; + double x1 = getX1(); + double y1 = getY1(); + double x2 = getX2(); + double y2 = getY2(); + + if (x1 >= x && x1 <= x + w && y1 >= y && y1 <= y + h) + return true; + if (x2 >= x && x2 <= x + w && y2 >= y && y2 <= y + h) + return true; + + double x3 = x + w; + double y3 = y + h; + + return (linesIntersect(x1, y1, x2, y2, x, y, x, y3) + || linesIntersect(x1, y1, x2, y2, x, y3, x3, y3) + || linesIntersect(x1, y1, x2, y2, x3, y3, x3, y) + || linesIntersect(x1, y1, x2, y2, x3, y, x, y)); + } + + /** + * Tests if this line intersects the interior of the specified rectangle. + * + * @param r the rectangle + * @return true if the line intersects the rectangle + * @throws NullPointerException if r is null + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Tests if the line contains a rectangle. Since lines have no area, this + * always returns false. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @return false; the line does not contain points + */ + public boolean contains(double x, double y, double w, double h) + { + return false; + } + + /** + * Tests if the line contains a rectangle. Since lines have no area, this + * always returns false. + * + * @param r the rectangle + * @return false; the line does not contain points + */ + public boolean contains(Rectangle2D r) + { + return false; + } + + /** + * Gets a bounding box (not necessarily minimal) for this line. + * + * @return the integer bounding box + * @see #getBounds2D() + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + /** + * Return a path iterator, possibly applying a transform on the result. This + * iterator is not threadsafe. + * + * @param at the transform, or null + * @return a new path iterator + */ + public PathIterator getPathIterator(final AffineTransform at) + { + return new PathIterator() + { + /** Current coordinate. */ + private int current = 0; + + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current >= 2; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = (float) getX1(); + coords[1] = (float) getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = (float) getX2(); + coords[1] = (float) getY2(); + result = SEG_LINETO; + break; + default: + throw new NoSuchElementException("line iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return result; + } + + public int currentSegment(double[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = getX1(); + coords[1] = getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = getX2(); + coords[1] = getY2(); + result = SEG_LINETO; + break; + default: + throw new NoSuchElementException("line iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return result; + } + }; + } + + /** + * Return a flat path iterator, possibly applying a transform on the result. + * This iterator is not threadsafe. + * + * @param at the transform, or null + * @param flatness ignored, since lines are already flat + * @return a new path iterator + * @see #getPathIterator(AffineTransform) + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return getPathIterator(at); + } + + /** + * Create a new line of the same run-time type with the same contents as + * this one. + * + * @return the clone + * + * @exception OutOfMemoryError If there is not enough memory available. + * + * @since 1.2 + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * This class defines a point in double precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Double extends Line2D + { + /** The x coordinate of the first point. */ + public double x1; + + /** The y coordinate of the first point. */ + public double y1; + + /** The x coordinate of the second point. */ + public double x2; + + /** The y coordinate of the second point. */ + public double y2; + + /** + * Construct the line segment (0,0)->(0,0). + */ + public Double() + { + } + + /** + * Construct the line segment with the specified points. + * + * @param x1 the x coordinate of the first point + * @param y1 the y coordinate of the first point + * @param x2 the x coordinate of the second point + * @param y2 the y coordinate of the second point + */ + public Double(double x1, double y1, double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Construct the line segment with the specified points. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + */ + public Double(Point2D p1, Point2D p2) + { + x1 = p1.getX(); + y1 = p1.getY(); + x2 = p2.getX(); + y2 = p2.getY(); + } + + /** + * Return the x coordinate of the first point. + * + * @return the value of x1 + */ + public double getX1() + { + return x1; + } + + /** + * Return the y coordinate of the first point. + * + * @return the value of y1 + */ + public double getY1() + { + return y1; + } + + /** + * Return the first point. + * + * @return the point (x1,y1) + */ + public Point2D getP1() + { + return new Point2D.Double(x1, y1); + } + + /** + * Return the x coordinate of the second point. + * + * @return the value of x2 + */ + public double getX2() + { + return x2; + } + + /** + * Return the y coordinate of the second point. + * + * @return the value of y2 + */ + public double getY2() + { + return y2; + } + + /** + * Return the second point. + * + * @return the point (x2,y2) + */ + public Point2D getP2() + { + return new Point2D.Double(x2, y2); + } + + /** + * Set this line to the given points. + * + * @param x1 the new x coordinate of the first point + * @param y1 the new y coordinate of the first point + * @param x2 the new x coordinate of the second point + * @param y2 the new y coordinate of the second point + */ + public void setLine(double x1, double y1, double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Return the exact bounds of this line segment. + * + * @return the bounding box + */ + public Rectangle2D getBounds2D() + { + double x = Math.min(x1, x2); + double y = Math.min(y1, y2); + double w = Math.abs(x1 - x2); + double h = Math.abs(y1 - y2); + return new Rectangle2D.Double(x, y, w, h); + } + } // class Double + + /** + * This class defines a point in float precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Float extends Line2D + { + /** The x coordinate of the first point. */ + public float x1; + + /** The y coordinate of the first point. */ + public float y1; + + /** The x coordinate of the second point. */ + public float x2; + + /** The y coordinate of the second point. */ + public float y2; + + /** + * Construct the line segment (0,0)->(0,0). + */ + public Float() + { + } + + /** + * Construct the line segment with the specified points. + * + * @param x1 the x coordinate of the first point + * @param y1 the y coordinate of the first point + * @param x2 the x coordinate of the second point + * @param y2 the y coordinate of the second point + */ + public Float(float x1, float y1, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Construct the line segment with the specified points. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + */ + public Float(Point2D p1, Point2D p2) + { + x1 = (float) p1.getX(); + y1 = (float) p1.getY(); + x2 = (float) p2.getX(); + y2 = (float) p2.getY(); + } + + /** + * Return the x coordinate of the first point. + * + * @return the value of x1 + */ + public double getX1() + { + return x1; + } + + /** + * Return the y coordinate of the first point. + * + * @return the value of y1 + */ + public double getY1() + { + return y1; + } + + /** + * Return the first point. + * + * @return the point (x1,y1) + */ + public Point2D getP1() + { + return new Point2D.Float(x1, y1); + } + + /** + * Return the x coordinate of the second point. + * + * @return the value of x2 + */ + public double getX2() + { + return x2; + } + + /** + * Return the y coordinate of the second point. + * + * @return the value of y2 + */ + public double getY2() + { + return y2; + } + + /** + * Return the second point. + * + * @return the point (x2,y2) + */ + public Point2D getP2() + { + return new Point2D.Float(x2, y2); + } + + /** + * Set this line to the given points. + * + * @param x1 the new x coordinate of the first point + * @param y1 the new y coordinate of the first point + * @param x2 the new x coordinate of the second point + * @param y2 the new y coordinate of the second point + */ + public void setLine(double x1, double y1, double x2, double y2) + { + this.x1 = (float) x1; + this.y1 = (float) y1; + this.x2 = (float) x2; + this.y2 = (float) y2; + } + + /** + * Set this line to the given points. + * + * @param x1 the new x coordinate of the first point + * @param y1 the new y coordinate of the first point + * @param x2 the new x coordinate of the second point + * @param y2 the new y coordinate of the second point + */ + public void setLine(float x1, float y1, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Return the exact bounds of this line segment. + * + * @return the bounding box + */ + public Rectangle2D getBounds2D() + { + float x = Math.min(x1, x2); + float y = Math.min(y1, y2); + float w = Math.abs(x1 - x2); + float h = Math.abs(y1 - y2); + return new Rectangle2D.Float(x, y, w, h); + } + } // class Float +} // class Line2D diff --git a/libjava/classpath/java/awt/geom/NoninvertibleTransformException.java b/libjava/classpath/java/awt/geom/NoninvertibleTransformException.java new file mode 100644 index 0000000..7995a52 --- /dev/null +++ b/libjava/classpath/java/awt/geom/NoninvertibleTransformException.java @@ -0,0 +1,65 @@ +/* NoninvertibleTransformException.java -- a transform can't be inverted + 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 java.awt.geom; + +/** + * Thrown if an operation requires an inverse of an + * AffineTransform, but the transform is in a non-invertible + * state. + * + * @author Tom Tromey (tromey@cygnus.com) + * @see AffineTransform + * @status updated to 1.4 + */ +public class NoninvertibleTransformException extends Exception +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 6137225240503990466L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public NoninvertibleTransformException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/awt/geom/PathIterator.java b/libjava/classpath/java/awt/geom/PathIterator.java new file mode 100644 index 0000000..2cd08b9 --- /dev/null +++ b/libjava/classpath/java/awt/geom/PathIterator.java @@ -0,0 +1,189 @@ +/* PathIterator.java -- describes a shape by iterating over its vertices + Copyright (C) 2000, 2002, 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + +/** + * This interface provides a directed path over the boundary of a shape. The + * path can contain 1st through 3rd order Bezier curves (lines, and quadratic + * and cubic splines). A shape can have multiple disjoint paths via the + * MOVETO directive, and can close a circular path back to the previos + * MOVETO via the CLOSE directive. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see java.awt.Shape + * @see java.awt.Stroke + * @see FlatteningPathIterator + * @since 1.2 + * @status updated to 1.4 + */ +public interface PathIterator +{ + /** + * The even-odd winding mode: a point is internal to the shape if a ray + * from the point to infinity (in any direction) crosses an odd number of + * segments. + */ + int WIND_EVEN_ODD = 0; + + /** + * The non-zero winding mode: a point is internal to the shape if a ray + * from the point to infinity (in any direction) crosses a different number + * of segments headed clockwise than those headed counterclockwise. + */ + int WIND_NON_ZERO = 1; + + /** + * Starts a new subpath. There is no segment from the previous vertex. + */ + int SEG_MOVETO = 0; + + /** + * The current segment is a line. + */ + int SEG_LINETO = 1; + + /** + * The current segment is a quadratic parametric curve. It is interpolated + * as t varies from 0 to 1 over the current point (CP), first control point + * (P1), and final interpolated control point (P2): + *

    +   *  P(t) = B(2,0)*CP + B(2,1)*P1 + B(2,2)*P2
    +   *    0 <= t <= 1
    +   *  B(n,m) = mth coefficient of nth degree Bernstein polynomial
    +   *         = C(n,m) * t^(m) * (1 - t)^(n-m)
    +   *  C(n,m) = Combinations of n things, taken m at a time
    +   *         = n! / (m! * (n-m)!)
    +   * 
    + */ + int SEG_QUADTO = 2; + + /** + * The current segment is a cubic parametric curve (more commonly known as + * a Bezier curve). It is interpolated as t varies from 0 to 1 over the + * current point (CP), first control point (P1), the second control point + * (P2), and final interpolated control point (P3): + *
    +   *  P(t) = B(3,0)*CP + B(3,1)*P1 + B(3,2)*P2 + B(3,3)*P3
    +   *    0 <= t <= 1
    +   *  B(n,m) = mth coefficient of nth degree Bernstein polynomial
    +   *         = C(n,m) * t^(m) * (1 - t)^(n-m)
    +   *  C(n,m) = Combinations of n things, taken m at a time
    +   *         = n! / (m! * (n-m)!)
    +   * 
    + */ + int SEG_CUBICTO = 3; + + /** + * The current segment closes a loop by an implicit line to the previous + * SEG_MOVETO coordinate. + */ + int SEG_CLOSE = 4; + + /** + * Returns the winding rule to determine which points are inside this path. + * + * @return the winding rule + * @see #WIND_EVEN_ODD + * @see #WIND_NON_ZERO + */ + int getWindingRule(); + + /** + * Tests if the iterator is exhausted. If this returns true, currentSegment + * and next may throw a NoSuchElementException (although this is not + * required). + * + * @return true if the iteration is complete + */ + boolean isDone(); + + /** + * Advance to the next segment in the iteration. It is not specified what + * this does if called when isDone() returns true. + * + * @throws java.util.NoSuchElementException optional when isDone() is true + */ + void next(); + + /** + * Returns the coordinates of the next point(s), as well as the type of + * line segment. The input array must be at least a float[6], to accomodate + * up to three (x,y) point pairs (although if you know the iterator is + * flat, you can probably get by with a float[2]). If the returned type is + * SEG_MOVETO or SEG_LINETO, the first point in the array is modified; if + * the returned type is SEG_QUADTO, the first two points are modified; if + * the returned type is SEG_CUBICTO, all three points are modified; and if + * the returned type is SEG_CLOSE, the array is untouched. + * + * @param coords the array to place the point coordinates in + * @return the segment type + * @throws NullPointerException if coords is null + * @throws ArrayIndexOutOfBoundsException if coords is too small + * @throws java.util.NoSuchElementException optional when isDone() is true + * @see #SEG_MOVETO + * @see #SEG_LINETO + * @see #SEG_QUADTO + * @see #SEG_CUBICTO + * @see #SEG_CLOSE + */ + int currentSegment(float[] coords); + + /** + * Returns the coordinates of the next point(s), as well as the type of + * line segment. The input array must be at least a double[6], to accomodate + * up to three (x,y) point pairs (although if you know the iterator is + * flat, you can probably get by with a double[2]). If the returned type is + * SEG_MOVETO or SEG_LINETO, the first point in the array is modified; if + * the returned type is SEG_QUADTO, the first two points are modified; if + * the returned type is SEG_CUBICTO, all three points are modified; and if + * the returned type is SEG_CLOSE, the array is untouched. + * + * @param coords the array to place the point coordinates in + * @return the segment type + * @throws NullPointerException if coords is null + * @throws ArrayIndexOutOfBoundsException if coords is too small + * @throws java.util.NoSuchElementException optional when isDone() is true + * @see #SEG_MOVETO + * @see #SEG_LINETO + * @see #SEG_QUADTO + * @see #SEG_CUBICTO + * @see #SEG_CLOSE + */ + int currentSegment(double[] coords); +} // interface PathIterator diff --git a/libjava/classpath/java/awt/geom/Point2D.java b/libjava/classpath/java/awt/geom/Point2D.java new file mode 100644 index 0000000..9f22a5a --- /dev/null +++ b/libjava/classpath/java/awt/geom/Point2D.java @@ -0,0 +1,396 @@ +/* Point2D.java -- generic point in 2-D space + Copyright (C) 1999, 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 java.awt.geom; + +/** + * This class implements a generic point in 2D Cartesian space. The storage + * representation is left up to the subclass. Point includes two useful + * nested classes, for float and double storage respectively. + * + * @author Per Bothner (bothner@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class Point2D implements Cloneable +{ + /** + * The default constructor. + * + * @see java.awt.Point + * @see Point2D.Float + * @see Point2D.Double + */ + protected Point2D() + { + } + + /** + * Get the X coordinate, in double precision. + * + * @return the x coordinate + */ + public abstract double getX(); + + /** + * Get the Y coordinate, in double precision. + * + * @return the y coordinate + */ + public abstract double getY(); + + /** + * Set the location of this point to the new coordinates. There may be a + * loss of precision. + * + * @param x the new x coordinate + * @param y the new y coordinate + */ + public abstract void setLocation(double x, double y); + + /** + * Set the location of this point to the new coordinates. There may be a + * loss of precision. + * + * @param p the point to copy + * @throws NullPointerException if p is null + */ + public void setLocation(Point2D p) + { + setLocation(p.getX(), p.getY()); + } + + /** + * Return the square of the distance between two points. + * + * @param x1 the x coordinate of point 1 + * @param y1 the y coordinate of point 1 + * @param x2 the x coordinate of point 2 + * @param y2 the y coordinate of point 2 + * @return (x2 - x1)^2 + (y2 - y1)^2 + */ + public static double distanceSq(double x1, double y1, double x2, double y2) + { + x2 -= x1; + y2 -= y1; + return x2 * x2 + y2 * y2; + } + + /** + * Return the distance between two points. + * + * @param x1 the x coordinate of point 1 + * @param y1 the y coordinate of point 1 + * @param x2 the x coordinate of point 2 + * @param y2 the y coordinate of point 2 + * @return the distance from (x1,y1) to (x2,y2) + */ + public static double distance(double x1, double y1, double x2, double y2) + { + return Math.sqrt(distanceSq(x1, y1, x2, y2)); + } + + /** + * Return the square of the distance from this point to the given one. + * + * @param x the x coordinate of the other point + * @param y the y coordinate of the other point + * @return the square of the distance + */ + public double distanceSq(double x, double y) + { + return distanceSq(getX(), x, getY(), y); + } + + /** + * Return the square of the distance from this point to the given one. + * + * @param p the other point + * @return the square of the distance + * @throws NullPointerException if p is null + */ + public double distanceSq(Point2D p) + { + return distanceSq(getX(), p.getX(), getY(), p.getY()); + } + + /** + * Return the distance from this point to the given one. + * + * @param x the x coordinate of the other point + * @param y the y coordinate of the other point + * @return the distance + */ + public double distance(double x, double y) + { + return distance(getX(), x, getY(), y); + } + + /** + * Return the distance from this point to the given one. + * + * @param p the other point + * @return the distance + * @throws NullPointerException if p is null + */ + public double distance(Point2D p) + { + return distance(getX(), p.getX(), getY(), p.getY()); + } + + /** + * Create a new point of the same run-time type with the same contents as + * this one. + * + * @return the clone + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Return the hashcode for this point. The formula is not documented, but + * appears to be the same as: + *
    +   * long l = Double.doubleToLongBits(getY());
    +   * l = l * 31 ^ Double.doubleToLongBits(getX());
    +   * return (int) ((l >> 32) ^ l);
    +   * 
    + * + * @return the hashcode + */ + public int hashCode() + { + // Talk about a fun time reverse engineering this one! + long l = java.lang.Double.doubleToLongBits(getY()); + l = l * 31 ^ java.lang.Double.doubleToLongBits(getX()); + return (int) ((l >> 32) ^ l); + } + + /** + * Compares two points for equality. This returns true if they have the + * same coordinates. + * + * @param o the point to compare + * @return true if it is equal + */ + public boolean equals(Object o) + { + if (! (o instanceof Point2D)) + return false; + Point2D p = (Point2D) o; + return getX() == p.getX() && getY() == p.getY(); + } + + /** + * This class defines a point in double precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Double extends Point2D + { + /** The X coordinate. */ + public double x; + + /** The Y coordinate. */ + public double y; + + /** + * Create a new point at (0,0). + */ + public Double() + { + } + + /** + * Create a new point at (x,y). + * + * @param x the x coordinate + * @param y the y coordinate + */ + public Double(double x, double y) + { + this.x = x; + this.y = y; + } + + /** + * Return the x coordinate. + * + * @return the x coordinate + */ + public double getX() + { + return x; + } + + /** + * Return the y coordinate. + * + * @return the y coordinate + */ + public double getY() + { + return y; + } + + /** + * Sets the location of this point. + * + * @param x the new x coordinate + * @param y the new y coordinate + */ + public void setLocation(double x, double y) + { + this.x = x; + this.y = y; + } + + /** + * Returns a string representation of this object. The format is: + * "Point2D.Double[" + x + ", " + y + ']'. + * + * @return a string representation of this object + */ + public String toString() + { + return "Point2D.Double[" + x + ", " + y + ']'; + } + } // class Double + + /** + * This class defines a point in float precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Float extends Point2D + { + /** The X coordinate. */ + public float x; + + /** The Y coordinate. */ + public float y; + + /** + * Create a new point at (0,0). + */ + public Float() + { + } + + /** + * Create a new point at (x,y). + * + * @param x the x coordinate + * @param y the y coordinate + */ + public Float(float x, float y) + { + this.x = x; + this.y = y; + } + + /** + * Return the x coordinate. + * + * @return the x coordinate + */ + public double getX() + { + return x; + } + + /** + * Return the y coordinate. + * + * @return the y coordinate + */ + public double getY() + { + return y; + } + + /** + * Sets the location of this point. + * + * @param x the new x coordinate + * @param y the new y coordinate + */ + public void setLocation(double x, double y) + { + this.x = (float) x; + this.y = (float) y; + } + + /** + * Sets the location of this point. + * + * @param x the new x coordinate + * @param y the new y coordinate + */ + public void setLocation(float x, float y) + { + this.x = x; + this.y = y; + } + + /** + * Returns a string representation of this object. The format is: + * "Point2D.Float[" + x + ", " + y + ']'. + * + * @return a string representation of this object + */ + public String toString() + { + return "Point2D.Float[" + x + ", " + y + ']'; + } + } // class Float +} // class Point2D diff --git a/libjava/classpath/java/awt/geom/QuadCurve2D.java b/libjava/classpath/java/awt/geom/QuadCurve2D.java new file mode 100644 index 0000000..41021db --- /dev/null +++ b/libjava/classpath/java/awt/geom/QuadCurve2D.java @@ -0,0 +1,1467 @@ +/* QuadCurve2D.java -- represents a parameterized quadratic curve in 2-D space + Copyright (C) 2002, 2003, 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 java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + +/** + * A two-dimensional curve that is parameterized with a quadratic + * function. + * + *

    A drawing of a QuadCurve2D + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Graydon Hoare (graydon@redhat.com) + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Sven de Marothy (sven@physto.se) + * + * @since 1.2 + */ +public abstract class QuadCurve2D implements Shape, Cloneable +{ + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; + private static final double EPSILON = 1E-10; + + /** + * Constructs a new QuadCurve2D. Typical users will want to + * construct instances of a subclass, such as {@link + * QuadCurve2D.Float} or {@link QuadCurve2D.Double}. + */ + protected QuadCurve2D() + { + } + + /** + * Returns the x coordinate of the curve’s start + * point. + */ + public abstract double getX1(); + + /** + * Returns the y coordinate of the curve’s start + * point. + */ + public abstract double getY1(); + + /** + * Returns the curve’s start point. + */ + public abstract Point2D getP1(); + + /** + * Returns the x coordinate of the curve’s control + * point. + */ + public abstract double getCtrlX(); + + /** + * Returns the y coordinate of the curve’s control + * point. + */ + public abstract double getCtrlY(); + + /** + * Returns the curve’s control point. + */ + public abstract Point2D getCtrlPt(); + + /** + * Returns the x coordinate of the curve’s end + * point. + */ + public abstract double getX2(); + + /** + * Returns the y coordinate of the curve’s end + * point. + */ + public abstract double getY2(); + + /** + * Returns the curve’s end point. + */ + public abstract Point2D getP2(); + + /** + * Changes the curve geometry, separately specifying each coordinate + * value. + * + * @param x1 the x coordinate of the curve’s new start + * point. + * + * @param y1 the y coordinate of the curve’s new start + * point. + * + * @param cx the x coordinate of the curve’s new + * control point. + * + * @param cy the y coordinate of the curve’s new + * control point. + * + * @param x2 the x coordinate of the curve’s new end + * point. + * + * @param y2 the y coordinate of the curve’s new end + * point. + */ + public abstract void setCurve(double x1, double y1, double cx, double cy, + double x2, double y2); + + /** + * Changes the curve geometry, passing coordinate values in an + * array. + * + * @param coords an array containing the new coordinate values. The + * x coordinate of the new start point is located at + * coords[offset], its y coordinate at + * coords[offset + 1]. The x coordinate of the + * new control point is located at coords[offset + 2], + * its y coordinate at coords[offset + 3]. The + * x coordinate of the new end point is located at + * coords[offset + 4], its y coordinate at + * coords[offset + 5]. + * + * @param offset the offset of the first coordinate value in + * coords. + */ + public void setCurve(double[] coords, int offset) + { + setCurve(coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++], coords[offset++]); + } + + /** + * Changes the curve geometry, specifying coordinate values in + * separate Point objects. + * + *

    A drawing of a QuadCurve2D + * + *

    The curve does not keep any reference to the passed point + * objects. Therefore, a later change to p1, + * c p2 will not affect the curve + * geometry. + * + * @param p1 the new start point. + * @param c the new control point. + * @param p2 the new end point. + */ + public void setCurve(Point2D p1, Point2D c, Point2D p2) + { + setCurve(p1.getX(), p1.getY(), c.getX(), c.getY(), p2.getX(), p2.getY()); + } + + /** + * Changes the curve geometry, specifying coordinate values in an + * array of Point objects. + * + *

    A drawing of a QuadCurve2D + * + *

    The curve does not keep references to the passed point + * objects. Therefore, a later change to the pts array + * or any of its elements will not affect the curve geometry. + * + * @param pts an array containing the points. The new start point + * is located at pts[offset], the new control + * point at pts[offset + 1], and the new end point + * at pts[offset + 2]. + * + * @param offset the offset of the start point in pts. + */ + public void setCurve(Point2D[] pts, int offset) + { + setCurve(pts[offset].getX(), pts[offset].getY(), pts[offset + 1].getX(), + pts[offset + 1].getY(), pts[offset + 2].getX(), + pts[offset + 2].getY()); + } + + /** + * Changes the geometry of the curve to that of another curve. + * + * @param c the curve whose coordinates will be copied. + */ + public void setCurve(QuadCurve2D c) + { + setCurve(c.getX1(), c.getY1(), c.getCtrlX(), c.getCtrlY(), c.getX2(), + c.getY2()); + } + + /** + * Calculates the squared flatness of a quadratic curve, directly + * specifying each coordinate value. The flatness is the distance of + * the control point to the line between start and end point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the square of the distance between C and the gray line, i.e. + * the squared length of the red line. + * + * @param x1 the x coordinate of the start point P1. + * @param y1 the y coordinate of the start point P1. + * @param cx the x coordinate of the control point C. + * @param cy the y coordinate of the control point C. + * @param x2 the x coordinate of the end point P2. + * @param y2 the y coordinate of the end point P2. + */ + public static double getFlatnessSq(double x1, double y1, double cx, + double cy, double x2, double y2) + { + return Line2D.ptSegDistSq(x1, y1, x2, y2, cx, cy); + } + + /** + * Calculates the flatness of a quadratic curve, directly specifying + * each coordinate value. The flatness is the distance of the + * control point to the line between start and end point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the distance between C and the gray line, i.e. the length of + * the red line. + * + * @param x1 the x coordinate of the start point P1. + * @param y1 the y coordinate of the start point P1. + * @param cx the x coordinate of the control point C. + * @param cy the y coordinate of the control point C. + * @param x2 the x coordinate of the end point P2. + * @param y2 the y coordinate of the end point P2. + */ + public static double getFlatness(double x1, double y1, double cx, double cy, + double x2, double y2) + { + return Line2D.ptSegDist(x1, y1, x2, y2, cx, cy); + } + + /** + * Calculates the squared flatness of a quadratic curve, specifying + * the coordinate values in an array. The flatness is the distance + * of the control point to the line between start and end point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the square of the distance between C and the gray line, i.e. + * the squared length of the red line. + * + * @param coords an array containing the coordinate values. The + * x coordinate of the start point P1 is located at + * coords[offset], its y coordinate at + * coords[offset + 1]. The x coordinate of the + * control point C is located at coords[offset + 2], + * its y coordinate at coords[offset + 3]. The + * x coordinate of the end point P2 is located at + * coords[offset + 4], its y coordinate at + * coords[offset + 5]. + * + * @param offset the offset of the first coordinate value in + * coords. + */ + public static double getFlatnessSq(double[] coords, int offset) + { + return Line2D.ptSegDistSq(coords[offset], coords[offset + 1], + coords[offset + 4], coords[offset + 5], + coords[offset + 2], coords[offset + 3]); + } + + /** + * Calculates the flatness of a quadratic curve, specifying the + * coordinate values in an array. The flatness is the distance of + * the control point to the line between start and end point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the the distance between C and the gray line, i.e. the length of + * the red line. + * + * @param coords an array containing the coordinate values. The + * x coordinate of the start point P1 is located at + * coords[offset], its y coordinate at + * coords[offset + 1]. The x coordinate of the + * control point C is located at coords[offset + 2], + * its y coordinate at coords[offset + 3]. The + * x coordinate of the end point P2 is located at + * coords[offset + 4], its y coordinate at + * coords[offset + 5]. + * + * @param offset the offset of the first coordinate value in + * coords. + */ + public static double getFlatness(double[] coords, int offset) + { + return Line2D.ptSegDist(coords[offset], coords[offset + 1], + coords[offset + 4], coords[offset + 5], + coords[offset + 2], coords[offset + 3]); + } + + /** + * Calculates the squared flatness of this curve. The flatness is + * the distance of the control point to the line between start and + * end point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the square of the distance between C and the gray line, i.e. the + * squared length of the red line. + */ + public double getFlatnessSq() + { + return Line2D.ptSegDistSq(getX1(), getY1(), getX2(), getY2(), getCtrlX(), + getCtrlY()); + } + + /** + * Calculates the flatness of this curve. The flatness is the + * distance of the control point to the line between start and end + * point. + * + *

    A drawing that illustrates the flatness + * + *

    In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the distance between C and the gray line, i.e. the length of the + * red line. + */ + public double getFlatness() + { + return Line2D.ptSegDist(getX1(), getY1(), getX2(), getY2(), getCtrlX(), + getCtrlY()); + } + + /** + * Subdivides this curve into two halves. + * + *

    A drawing that illustrates the effects of
+   * subdividing a QuadCurve2D + * + * @param left a curve whose geometry will be set to the left half + * of this curve, or null if the caller is not + * interested in the left half. + * + * @param right a curve whose geometry will be set to the right half + * of this curve, or null if the caller is not + * interested in the right half. + */ + public void subdivide(QuadCurve2D left, QuadCurve2D right) + { + // Use empty slots at end to share single array. + double[] d = new double[] + { + getX1(), getY1(), getCtrlX(), getCtrlY(), getX2(), getY2(), + 0, 0, 0, 0 + }; + subdivide(d, 0, d, 0, d, 4); + if (left != null) + left.setCurve(d, 0); + if (right != null) + right.setCurve(d, 4); + } + + /** + * Subdivides a quadratic curve into two halves. + * + *

    A drawing that illustrates the effects of
+   * subdividing a QuadCurve2D + * + * @param src the curve to be subdivided. + * + * @param left a curve whose geometry will be set to the left half + * of src, or null if the caller is not + * interested in the left half. + * + * @param right a curve whose geometry will be set to the right half + * of src, or null if the caller is not + * interested in the right half. + */ + public static void subdivide(QuadCurve2D src, QuadCurve2D left, + QuadCurve2D right) + { + src.subdivide(left, right); + } + + /** + * Subdivides a quadratic curve into two halves, passing all + * coordinates in an array. + * + *

    A drawing that illustrates the effects of
+   * subdividing a QuadCurve2D + * + *

    The left end point and the right start point will always be + * identical. Memory-concious programmers thus may want to pass the + * same array for both left and right, and + * set rightOff to leftOff + 4. + * + * @param src an array containing the coordinates of the curve to be + * subdivided. The x coordinate of the start point is + * located at src[srcOff], its y at + * src[srcOff + 1]. The x coordinate of the + * control point is located at src[srcOff + 2], its + * y at src[srcOff + 3]. The x + * coordinate of the end point is located at src[srcOff + + * 4], its y at src[srcOff + 5]. + * + * @param srcOff an offset into src, specifying + * the index of the start point’s x coordinate. + * + * @param left an array that will receive the coordinates of the + * left half of src. It is acceptable to pass + * src. A caller who is not interested in the left half + * can pass null. + * + * @param leftOff an offset into left, specifying the + * index where the start point’s x coordinate will be + * stored. + * + * @param right an array that will receive the coordinates of the + * right half of src. It is acceptable to pass + * src or left. A caller who is not + * interested in the right half can pass null. + * + * @param rightOff an offset into right, specifying the + * index where the start point’s x coordinate will be + * stored. + */ + public static void subdivide(double[] src, int srcOff, double[] left, + int leftOff, double[] right, int rightOff) + { + double x1; + double y1; + double xc; + double yc; + double x2; + double y2; + + x1 = src[srcOff]; + y1 = src[srcOff + 1]; + xc = src[srcOff + 2]; + yc = src[srcOff + 3]; + x2 = src[srcOff + 4]; + y2 = src[srcOff + 5]; + + if (left != null) + { + left[leftOff] = x1; + left[leftOff + 1] = y1; + } + + if (right != null) + { + right[rightOff + 4] = x2; + right[rightOff + 5] = y2; + } + + x1 = (x1 + xc) / 2; + x2 = (xc + x2) / 2; + xc = (x1 + x2) / 2; + y1 = (y1 + yc) / 2; + y2 = (y2 + yc) / 2; + yc = (y1 + y2) / 2; + + if (left != null) + { + left[leftOff + 2] = x1; + left[leftOff + 3] = y1; + left[leftOff + 4] = xc; + left[leftOff + 5] = yc; + } + + if (right != null) + { + right[rightOff] = xc; + right[rightOff + 1] = yc; + right[rightOff + 2] = x2; + right[rightOff + 3] = y2; + } + } + + /** + * Finds the non-complex roots of a quadratic equation, placing the + * results into the same array as the equation coefficients. The + * following equation is being solved: + * + *

    eqn[2] · x2 + * + eqn[1] · x + * + eqn[0] + * = 0 + *
    + * + *

    For some background about solving quadratic equations, see the + * article “Quadratic Formula” in PlanetMath. For an extensive library + * of numerical algorithms written in the C programming language, + * see the GNU Scientific + * Library. + * + * @see #solveQuadratic(double[], double[]) + * @see CubicCurve2D#solveCubic(double[], double[]) + * + * @param eqn an array with the coefficients of the equation. When + * this procedure has returned, eqn will contain the + * non-complex solutions of the equation, in no particular order. + * + * @return the number of non-complex solutions. A result of 0 + * indicates that the equation has no non-complex solutions. A + * result of -1 indicates that the equation is constant (i.e., + * always or never zero). + * + * @author Brian Gough (bjg@network-theory.com) + * (original C implementation in the GNU Scientific Library) + * + * @author Sascha Brawer (brawer@dandelis.ch) + * (adaptation to Java) + */ + public static int solveQuadratic(double[] eqn) + { + return solveQuadratic(eqn, eqn); + } + + /** + * Finds the non-complex roots of a quadratic equation. The + * following equation is being solved: + * + *

    eqn[2] · x2 + * + eqn[1] · x + * + eqn[0] + * = 0 + *
    + * + *

    For some background about solving quadratic equations, see the + * article “Quadratic Formula” in PlanetMath. For an extensive library + * of numerical algorithms written in the C programming language, + * see the GNU Scientific + * Library. + * + * @see CubicCurve2D#solveCubic(double[],double[]) + * + * @param eqn an array with the coefficients of the equation. + * + * @param res an array into which the non-complex roots will be + * stored. The results may be in an arbitrary order. It is safe to + * pass the same array object reference for both eqn + * and res. + * + * @return the number of non-complex solutions. A result of 0 + * indicates that the equation has no non-complex solutions. A + * result of -1 indicates that the equation is constant (i.e., + * always or never zero). + * + * @author Brian Gough (bjg@network-theory.com) + * (original C implementation in the GNU Scientific Library) + * + * @author Sascha Brawer (brawer@dandelis.ch) + * (adaptation to Java) + */ + public static int solveQuadratic(double[] eqn, double[] res) + { + // Taken from poly/solve_quadratic.c in the GNU Scientific Library + // (GSL), cvs revision 1.7 of 2003-07-26. For the original source, + // see http://www.gnu.org/software/gsl/ + // + // Brian Gough, the author of that code, has granted the + // permission to use it in GNU Classpath under the GNU Classpath + // license, and has assigned the copyright to the Free Software + // Foundation. + // + // The Java implementation is very similar to the GSL code, but + // not a strict one-to-one copy. For example, GSL would sort the + // result. + double a; + double b; + double c; + double disc; + + c = eqn[0]; + b = eqn[1]; + a = eqn[2]; + + // Check for linear or constant functions. This is not done by the + // GNU Scientific Library. Without this special check, we + // wouldn't return -1 for constant functions, and 2 instead of 1 + // for linear functions. + if (a == 0) + { + if (b == 0) + return -1; + + res[0] = -c / b; + return 1; + } + + disc = b * b - 4 * a * c; + + if (disc < 0) + return 0; + + if (disc == 0) + { + // The GNU Scientific Library returns two identical results here. + // We just return one. + res[0] = -0.5 * b / a; + return 1; + } + + // disc > 0 + if (b == 0) + { + double r; + + r = Math.abs(0.5 * Math.sqrt(disc) / a); + res[0] = -r; + res[1] = r; + } + else + { + double sgnb; + double temp; + + sgnb = (b > 0 ? 1 : -1); + temp = -0.5 * (b + sgnb * Math.sqrt(disc)); + + // The GNU Scientific Library sorts the result here. We don't. + res[0] = temp / a; + res[1] = c / temp; + } + return 2; + } + + /** + * Determines whether a point is inside the area bounded + * by the curve and the straight line connecting its end points. + * + *

    A drawing of the area spanned by the curve + * + *

    The above drawing illustrates in which area points are + * considered “inside” a QuadCurve2D. + */ + public boolean contains(double x, double y) + { + if (! getBounds2D().contains(x, y)) + return false; + + return ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0); + } + + /** + * Determines whether a point is inside the area bounded + * by the curve and the straight line connecting its end points. + * + *

    A drawing of the area spanned by the curve + * + *

    The above drawing illustrates in which area points are + * considered “inside” a QuadCurve2D. + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Determines whether any part of a rectangle is inside the area bounded + * by the curve and the straight line connecting its end points. + * + *

    A drawing of the area spanned by the curve + * + *

    The above drawing illustrates in which area points are + * considered “inside” in a CubicCurve2D. + */ + public boolean intersects(double x, double y, double w, double h) + { + if (! getBounds2D().contains(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Determines whether any part of a Rectangle2D is inside the area bounded + * by the curve and the straight line connecting its end points. + * @see #intersects(double, double, double, double) + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determines whether a rectangle is entirely inside the area bounded + * by the curve and the straight line connecting its end points. + * + *

    A drawing of the area spanned by the curve + * + *

    The above drawing illustrates in which area points are + * considered “inside” a QuadCurve2D. + * @see #contains(double, double) + */ + public boolean contains(double x, double y, double w, double h) + { + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return false; + + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Determines whether a Rectangle2D is entirely inside the area that is + * bounded by the curve and the straight line connecting its end points. + * @see #contains(double, double, double, double) + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control point. As the illustration + * below shows, the invisible control point may cause the bounds to + * be much larger than the area that is actually covered by the + * curve. + * + *

    An illustration of the bounds of a QuadCurve2D + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + public PathIterator getPathIterator(final AffineTransform at) + { + return new PathIterator() + { + /** Current coordinate. */ + private int current = 0; + + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current >= 2; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = (float) getX1(); + coords[1] = (float) getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = (float) getCtrlX(); + coords[1] = (float) getCtrlY(); + coords[2] = (float) getX2(); + coords[3] = (float) getY2(); + result = SEG_QUADTO; + break; + default: + throw new NoSuchElementException("quad iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 2); + return result; + } + + public int currentSegment(double[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = getX1(); + coords[1] = getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = getCtrlX(); + coords[1] = getCtrlY(); + coords[2] = getX2(); + coords[3] = getY2(); + result = SEG_QUADTO; + break; + default: + throw new NoSuchElementException("quad iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 2); + return result; + } + }; + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + /** + * Creates a new curve with the same contents as this one. + * + * @return the clone. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Helper method used by contains() and intersects() methods + * Return the number of curve/line intersections on a given axis + * extending from a certain point. useYaxis is true for using the Y axis, + * @param x x coordinate of the origin point + * @param y y coordinate of the origin point + * @param useYaxis axis to follow, if true the positive Y axis is used, + * false uses the positive X axis. + * + * This is an implementation of the line-crossings algorithm, + * Detailed in an article on Eric Haines' page: + * http://www.acm.org/tog/editors/erich/ptinpoly/ + */ + private int getAxisIntersections(double x, double y, boolean useYaxis, + double distance) + { + int nCrossings = 0; + double a0; + double a1; + double a2; + double b0; + double b1; + double b2; + double[] r = new double[3]; + int nRoots; + + a0 = a2 = 0.0; + + if (useYaxis) + { + a0 = getY1() - y; + a1 = getCtrlY() - y; + a2 = getY2() - y; + b0 = getX1() - x; + b1 = getCtrlX() - x; + b2 = getX2() - x; + } + else + { + a0 = getX1() - x; + a1 = getCtrlX() - x; + a2 = getX2() - x; + b0 = getY1() - y; + b1 = getCtrlY() - y; + b2 = getY2() - y; + } + + /* If the axis intersects a start/endpoint, shift it up by some small + amount to guarantee the line is 'inside' + If this is not done,bad behaviour may result for points on that axis. */ + if (a0 == 0.0 || a2 == 0.0) + { + double small = getFlatness() * EPSILON; + if (a0 == 0.0) + a0 -= small; + + if (a2 == 0.0) + a2 -= small; + } + + r[0] = a0; + r[1] = 2 * (a1 - a0); + r[2] = (a2 - 2 * a1 + a0); + + nRoots = solveQuadratic(r); + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + double crossing = t * t * (b2 - 2 * b1 + b0) + 2 * t * (b1 - b0) + + b0; + /* single root is always doubly degenerate in quads */ + if (crossing > 0 && crossing < distance) + nCrossings += (nRoots == 1) ? 2 : 1; + } + } + + if (useYaxis) + { + if (Line2D.linesIntersect(b0, a0, b2, a2, EPSILON, 0.0, distance, 0.0)) + nCrossings++; + } + else + { + if (Line2D.linesIntersect(a0, b0, a2, b2, 0.0, EPSILON, 0.0, distance)) + nCrossings++; + } + + return (nCrossings); + } + + /** + * A two-dimensional curve that is parameterized with a quadratic + * function and stores coordinate values in double-precision + * floating-point format. + * + * @see QuadCurve2D.Float + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class Double extends QuadCurve2D + { + /** + * The x coordinate of the curve’s start point. + */ + public double x1; + + /** + * The y coordinate of the curve’s start point. + */ + public double y1; + + /** + * The x coordinate of the curve’s control point. + */ + public double ctrlx; + + /** + * The y coordinate of the curve’s control point. + */ + public double ctrly; + + /** + * The x coordinate of the curve’s end point. + */ + public double x2; + + /** + * The y coordinate of the curve’s end point. + */ + public double y2; + + /** + * Constructs a new QuadCurve2D that stores its coordinate values + * in double-precision floating-point format. All points are + * initially at position (0, 0). + */ + public Double() + { + } + + /** + * Constructs a new QuadCurve2D that stores its coordinate values + * in double-precision floating-point format, specifying the + * initial position of each point. + * + * @param x1 the x coordinate of the curve’s start + * point. + * + * @param y1 the y coordinate of the curve’s start + * point. + * + * @param cx the x coordinate of the curve’s control + * point. + * + * @param cy the y coordinate of the curve’s control + * point. + * + * @param x2 the x coordinate of the curve’s end + * point. + * + * @param y2 the y coordinate of the curve’s end + * point. + */ + public Double(double x1, double y1, double cx, double cy, double x2, + double y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx = cx; + ctrly = cy; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Returns the x coordinate of the curve’s start + * point. + */ + public double getX1() + { + return x1; + } + + /** + * Returns the y coordinate of the curve’s start + * point. + */ + public double getY1() + { + return y1; + } + + /** + * Returns the curve’s start point. + */ + public Point2D getP1() + { + return new Point2D.Double(x1, y1); + } + + /** + * Returns the x coordinate of the curve’s control + * point. + */ + public double getCtrlX() + { + return ctrlx; + } + + /** + * Returns the y coordinate of the curve’s control + * point. + */ + public double getCtrlY() + { + return ctrly; + } + + /** + * Returns the curve’s control point. + */ + public Point2D getCtrlPt() + { + return new Point2D.Double(ctrlx, ctrly); + } + + /** + * Returns the x coordinate of the curve’s end + * point. + */ + public double getX2() + { + return x2; + } + + /** + * Returns the y coordinate of the curve’s end + * point. + */ + public double getY2() + { + return y2; + } + + /** + * Returns the curve’s end point. + */ + public Point2D getP2() + { + return new Point2D.Double(x2, y2); + } + + /** + * Changes the geometry of the curve. + * + * @param x1 the x coordinate of the curve’s new + * start point. + * + * @param y1 the y coordinate of the curve’s new + * start point. + * + * @param cx the x coordinate of the curve’s new + * control point. + * + * @param cy the y coordinate of the curve’s new + * control point. + * + * @param x2 the x coordinate of the curve’s new + * end point. + * + * @param y2 the y coordinate of the curve’s new + * end point. + */ + public void setCurve(double x1, double y1, double cx, double cy, + double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx = cx; + ctrly = cy; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control point. As the + * illustration below shows, the invisible control point may cause + * the bounds to be much larger than the area that is actually + * covered by the curve. + * + *

    An illustration of the bounds of a QuadCurve2D + */ + public Rectangle2D getBounds2D() + { + double nx1 = Math.min(Math.min(x1, ctrlx), x2); + double ny1 = Math.min(Math.min(y1, ctrly), y2); + double nx2 = Math.max(Math.max(x1, ctrlx), x2); + double ny2 = Math.max(Math.max(y1, ctrly), y2); + return new Rectangle2D.Double(nx1, ny1, nx2 - nx1, ny2 - ny1); + } + } + + /** + * A two-dimensional curve that is parameterized with a quadratic + * function and stores coordinate values in single-precision + * floating-point format. + * + * @see QuadCurve2D.Double + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class Float extends QuadCurve2D + { + /** + * The x coordinate of the curve’s start point. + */ + public float x1; + + /** + * The y coordinate of the curve’s start point. + */ + public float y1; + + /** + * The x coordinate of the curve’s control point. + */ + public float ctrlx; + + /** + * The y coordinate of the curve’s control point. + */ + public float ctrly; + + /** + * The x coordinate of the curve’s end point. + */ + public float x2; + + /** + * The y coordinate of the curve’s end point. + */ + public float y2; + + /** + * Constructs a new QuadCurve2D that stores its coordinate values + * in single-precision floating-point format. All points are + * initially at position (0, 0). + */ + public Float() + { + } + + /** + * Constructs a new QuadCurve2D that stores its coordinate values + * in single-precision floating-point format, specifying the + * initial position of each point. + * + * @param x1 the x coordinate of the curve’s start + * point. + * + * @param y1 the y coordinate of the curve’s start + * point. + * + * @param cx the x coordinate of the curve’s control + * point. + * + * @param cy the y coordinate of the curve’s control + * point. + * + * @param x2 the x coordinate of the curve’s end + * point. + * + * @param y2 the y coordinate of the curve’s end + * point. + */ + public Float(float x1, float y1, float cx, float cy, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx = cx; + ctrly = cy; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Returns the x coordinate of the curve’s start + * point. + */ + public double getX1() + { + return x1; + } + + /** + * Returns the y coordinate of the curve’s start + * point. + */ + public double getY1() + { + return y1; + } + + /** + * Returns the curve’s start point. + */ + public Point2D getP1() + { + return new Point2D.Float(x1, y1); + } + + /** + * Returns the x coordinate of the curve’s control + * point. + */ + public double getCtrlX() + { + return ctrlx; + } + + /** + * Returns the y coordinate of the curve’s control + * point. + */ + public double getCtrlY() + { + return ctrly; + } + + /** + * Returns the curve’s control point. + */ + public Point2D getCtrlPt() + { + return new Point2D.Float(ctrlx, ctrly); + } + + /** + * Returns the x coordinate of the curve’s end + * point. + */ + public double getX2() + { + return x2; + } + + /** + * Returns the y coordinate of the curve’s end + * point. + */ + public double getY2() + { + return y2; + } + + /** + * Returns the curve’s end point. + */ + public Point2D getP2() + { + return new Point2D.Float(x2, y2); + } + + /** + * Changes the geometry of the curve, specifying coordinate values + * as double-precision floating-point numbers. + * + * @param x1 the x coordinate of the curve’s new + * start point. + * + * @param y1 the y coordinate of the curve’s new + * start point. + * + * @param cx the x coordinate of the curve’s new + * control point. + * + * @param cy the y coordinate of the curve’s new + * control point. + * + * @param x2 the x coordinate of the curve’s new + * end point. + * + * @param y2 the y coordinate of the curve’s new + * end point. + */ + public void setCurve(double x1, double y1, double cx, double cy, + double x2, double y2) + { + this.x1 = (float) x1; + this.y1 = (float) y1; + ctrlx = (float) cx; + ctrly = (float) cy; + this.x2 = (float) x2; + this.y2 = (float) y2; + } + + /** + * Changes the geometry of the curve, specifying coordinate values + * as single-precision floating-point numbers. + * + * @param x1 the x coordinate of the curve’s new + * start point. + * + * @param y1 the y coordinate of the curve’s new + * start point. + * + * @param cx the x coordinate of the curve’s new + * control point. + * + * @param cy the y coordinate of the curve’s new + * control point. + * + * @param x2 the x coordinate of the curve’s new + * end point. + * + * @param y2 the y coordinate of the curve’s new + * end point. + */ + public void setCurve(float x1, float y1, float cx, float cy, float x2, + float y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx = cx; + ctrly = cy; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control point. As the + * illustration below shows, the invisible control point may cause + * the bounds to be much larger than the area that is actually + * covered by the curve. + * + *

    An illustration of the bounds of a QuadCurve2D + */ + public Rectangle2D getBounds2D() + { + float nx1 = (float) Math.min(Math.min(x1, ctrlx), x2); + float ny1 = (float) Math.min(Math.min(y1, ctrly), y2); + float nx2 = (float) Math.max(Math.max(x1, ctrlx), x2); + float ny2 = (float) Math.max(Math.max(y1, ctrly), y2); + return new Rectangle2D.Float(nx1, ny1, nx2 - nx1, ny2 - ny1); + } + } +} diff --git a/libjava/classpath/java/awt/geom/Rectangle2D.java b/libjava/classpath/java/awt/geom/Rectangle2D.java new file mode 100644 index 0000000..6a255f9 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Rectangle2D.java @@ -0,0 +1,992 @@ +/* Rectangle2D.java -- generic rectangles in 2-D space + Copyright (C) 2000, 2001, 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 java.awt.geom; + +import java.util.NoSuchElementException; + +/** + * This class describes a rectangle by a point (x,y) and dimension (w x h). + * The actual storage is left up to subclasses. + * + *

    It is valid for a rectangle to have negative width or height; but it + * is considered to have no area or internal points. Therefore, the behavior + * in methods like contains or intersects is + * undefined unless the rectangle has positive width and height. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class Rectangle2D extends RectangularShape +{ + /** + * The point lies left of the rectangle (p.x < r.x). + * + * @see #outcode(double, double) + */ + public static final int OUT_LEFT = 1; + + /** + * The point lies above the rectangle (p.y < r.y). + * + * @see #outcode(double, double) + */ + public static final int OUT_TOP = 2; + + /** + * The point lies right of the rectangle (p.x > r.maxX). + * + * @see #outcode(double, double) + */ + public static final int OUT_RIGHT = 4; + + /** + * The point lies below of the rectangle (p.y > r.maxY). + * + * @see #outcode(double, double) + */ + public static final int OUT_BOTTOM = 8; + + /** + * Default constructor. + */ + protected Rectangle2D() + { + } + + /** + * Set the bounding box of this rectangle. + * + * @param x the new X coordinate + * @param y the new Y coordinate + * @param w the new width + * @param h the new height + */ + public abstract void setRect(double x, double y, double w, double h); + + /** + * Set the bounding box of this rectangle from the given one. + * + * @param r rectangle to copy + * @throws NullPointerException if r is null + */ + public void setRect(Rectangle2D r) + { + setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Tests if the specified line intersects the interior of this rectangle. + * + * @param x1 the first x coordinate of line segment + * @param y1 the first y coordinate of line segment + * @param x2 the second x coordinate of line segment + * @param y2 the second y coordinate of line segment + * @return true if the line intersects the rectangle + */ + public boolean intersectsLine(double x1, double y1, double x2, double y2) + { + double x = getX(); + double y = getY(); + double w = getWidth(); + double h = getHeight(); + if (w <= 0 || h <= 0) + return false; + + if (x1 >= x && x1 <= x + w && y1 >= y && y1 <= y + h) + return true; + if (x2 >= x && x2 <= x + w && y2 >= y && y2 <= y + h) + return true; + + double x3 = x + w; + double y3 = y + h; + + return (Line2D.linesIntersect(x1, y1, x2, y2, x, y, x, y3) + || Line2D.linesIntersect(x1, y1, x2, y2, x, y3, x3, y3) + || Line2D.linesIntersect(x1, y1, x2, y2, x3, y3, x3, y) + || Line2D.linesIntersect(x1, y1, x2, y2, x3, y, x, y)); + } + + /** + * Tests if the specified line intersects the interior of this rectangle. + * + * @param l the line segment + * @return true if the line intersects the rectangle + * @throws NullPointerException if l is null + */ + public boolean intersectsLine(Line2D l) + { + return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2()); + } + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param x the x coordinate to check + * @param y the y coordinate to check + * @return the binary OR of the result + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + */ + public abstract int outcode(double x, double y); + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param p the point to check + * @return the binary OR of the result + * @throws NullPointerException if p is null + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + */ + public int outcode(Point2D p) + { + return outcode(p.getX(), p.getY()); + } + + /** + * Set the bounding box of this rectangle. + * + * @param x the new X coordinate + * @param y the new Y coordinate + * @param w the new width + * @param h the new height + */ + public void setFrame(double x, double y, double w, double h) + { + setRect(x, y, w, h); + } + + /** + * Returns the bounds of this rectangle. A pretty useless method, as this + * is already a rectangle. + * + * @return a copy of this rectangle + */ + public Rectangle2D getBounds2D() + { + return (Rectangle2D) clone(); + } + + /** + * Test if the given point is contained in the rectangle. + * + * @param x the x coordinate of the point + * @param y the y coordinate of the point + * @return true if (x,y) is in the rectangle + */ + public boolean contains(double x, double y) + { + double mx = getX(); + double my = getY(); + double w = getWidth(); + double h = getHeight(); + return w > 0 && h > 0 && x >= mx && x < mx + w && y >= my && y < my + h; + } + + /** + * Tests if the given rectangle intersects this one. In other words, test if + * the two rectangles share at least one internal point. + * + * @param x the x coordinate of the other rectangle + * @param y the y coordinate of the other rectangle + * @param w the width of the other rectangle + * @param h the height of the other rectangle + * @return true if the rectangles intersect + */ + public boolean intersects(double x, double y, double w, double h) + { + double mx = getX(); + double my = getY(); + double mw = getWidth(); + double mh = getHeight(); + return w > 0 && h > 0 && mw > 0 && mh > 0 + && x < mx + mw && x + w > mx && y < my + mh && y + h > my; + } + + /** + * Tests if this rectangle contains the given one. In other words, test if + * this rectangle contains all points in the given one. + * + * @param x the x coordinate of the other rectangle + * @param y the y coordinate of the other rectangle + * @param w the width of the other rectangle + * @param h the height of the other rectangle + * @return true if this rectangle contains the other + */ + public boolean contains(double x, double y, double w, double h) + { + double mx = getX(); + double my = getY(); + double mw = getWidth(); + double mh = getHeight(); + return w > 0 && h > 0 && mw > 0 && mh > 0 + && x >= mx && x + w <= mx + mw && y >= my && y + h <= my + mh; + } + + /** + * Return a new rectangle which is the intersection of this and the given + * one. The result will be empty if there is no intersection. + * + * @param r the rectangle to be intersected + * @return the intersection + * @throws NullPointerException if r is null + */ + public abstract Rectangle2D createIntersection(Rectangle2D r); + + /** + * Intersects a pair of rectangles, and places the result in the + * destination; this can be used to avoid object creation. This method + * even works when the destination is also a source, although you stand + * to lose the original data. + * + * @param src1 the first source + * @param src2 the second source + * @param dest the destination for the intersection + * @throws NullPointerException if any rectangle is null + */ + public static void intersect(Rectangle2D src1, Rectangle2D src2, + Rectangle2D dest) + { + double x = Math.max(src1.getX(), src2.getX()); + double y = Math.max(src1.getY(), src2.getY()); + double maxx = Math.min(src1.getMaxX(), src2.getMaxX()); + double maxy = Math.min(src1.getMaxY(), src2.getMaxY()); + dest.setRect(x, y, maxx - x, maxy - y); + } + + /** + * Return a new rectangle which is the union of this and the given one. + * + * @param r the rectangle to be merged + * @return the union + * @throws NullPointerException if r is null + */ + public abstract Rectangle2D createUnion(Rectangle2D r); + + /** + * Joins a pair of rectangles, and places the result in the destination; + * this can be used to avoid object creation. This method even works when + * the destination is also a source, although you stand to lose the + * original data. + * + * @param src1 the first source + * @param src2 the second source + * @param dest the destination for the union + * @throws NullPointerException if any rectangle is null + */ + public static void union(Rectangle2D src1, Rectangle2D src2, + Rectangle2D dest) + { + double x = Math.min(src1.getX(), src2.getX()); + double y = Math.min(src1.getY(), src2.getY()); + double maxx = Math.max(src1.getMaxX(), src2.getMaxX()); + double maxy = Math.max(src1.getMaxY(), src2.getMaxY()); + dest.setRect(x, y, maxx - x, maxy - y); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified point. + * However, if the point falls on one of the two borders which are not + * inside the rectangle, a subsequent call to contains may + * return false. + * + * @param newx the X coordinate of the point to add to this rectangle + * @param newy the Y coordinate of the point to add to this rectangle + */ + public void add(double newx, double newy) + { + double minx = Math.min(getX(), newx); + double maxx = Math.max(getMaxX(), newx); + double miny = Math.min(getY(), newy); + double maxy = Math.max(getMaxY(), newy); + setRect(minx, miny, maxx - minx, maxy - miny); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified point. + * However, if the point falls on one of the two borders which are not + * inside the rectangle, a subsequent call to contains may + * return false. + * + * @param p the point to add to this rectangle + * @throws NullPointerException if p is null + */ + public void add(Point2D p) + { + add(p.getX(), p.getY()); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified rectangle. + * + * @param r the rectangle to add to this rectangle + * @throws NullPointerException if r is null + * @see #union(Rectangle2D, Rectangle2D, Rectangle2D) + */ + public void add(Rectangle2D r) + { + union(this, r, this); + } + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. Each call returns + * a new object, independent from others in use. This iterator is thread + * safe; modifications to the rectangle do not affect the results of this + * path instance. + * + * @param at an optional transform to apply to the iterator + * @return a new iterator over the boundary + * @since 1.2 + */ + public PathIterator getPathIterator(final AffineTransform at) + { + final double minx = getX(); + final double miny = getY(); + final double maxx = minx + getWidth(); + final double maxy = miny + getHeight(); + return new PathIterator() + { + /** Current coordinate. */ + private int current = (maxx <= minx && maxy <= miny) ? 6 : 0; + + public int getWindingRule() + { + // A test program showed that Sun J2SE 1.3.1 and 1.4.1_01 + // return WIND_NON_ZERO paths. While this does not really + // make any difference for rectangles (because they are not + // self-intersecting), it seems appropriate to behave + // identically. + + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current > 5; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + switch (current) + { + case 1: + coords[0] = (float) maxx; + coords[1] = (float) miny; + break; + case 2: + coords[0] = (float) maxx; + coords[1] = (float) maxy; + break; + case 3: + coords[0] = (float) minx; + coords[1] = (float) maxy; + break; + case 0: + case 4: + coords[0] = (float) minx; + coords[1] = (float) miny; + break; + case 5: + return SEG_CLOSE; + default: + throw new NoSuchElementException("rect iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return current == 0 ? SEG_MOVETO : SEG_LINETO; + } + + public int currentSegment(double[] coords) + { + switch (current) + { + case 1: + coords[0] = maxx; + coords[1] = miny; + break; + case 2: + coords[0] = maxx; + coords[1] = maxy; + break; + case 3: + coords[0] = minx; + coords[1] = maxy; + break; + case 0: + case 4: + coords[0] = minx; + coords[1] = miny; + break; + case 5: + return SEG_CLOSE; + default: + throw new NoSuchElementException("rect iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return current == 0 ? SEG_MOVETO : SEG_LINETO; + } + }; + } + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. Each call returns + * a new object, independent from others in use. This iterator is thread + * safe; modifications to the rectangle do not affect the results of this + * path instance. As the rectangle is already flat, the flatness parameter + * is ignored. + * + * @param at an optional transform to apply to the iterator + * @param flatness the maximum distance for deviation from the real boundary + * @return a new iterator over the boundary + * @since 1.2 + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return getPathIterator(at); + } + + /** + * Return the hashcode for this rectangle. The formula is not documented, but + * appears to be the same as: + *

    +   * long l = Double.doubleToLongBits(getX())
    +   *   + 37 * Double.doubleToLongBits(getY())
    +   *   + 43 * Double.doubleToLongBits(getWidth())
    +   *   + 47 * Double.doubleToLongBits(getHeight());
    +   * return (int) ((l >> 32) ^ l);
    +   * 
    + * + * @return the hashcode + */ + public int hashCode() + { + // Talk about a fun time reverse engineering this one! + long l = java.lang.Double.doubleToLongBits(getX()) + + 37 * java.lang.Double.doubleToLongBits(getY()) + + 43 * java.lang.Double.doubleToLongBits(getWidth()) + + 47 * java.lang.Double.doubleToLongBits(getHeight()); + return (int) ((l >> 32) ^ l); + } + + /** + * Tests this rectangle for equality against the specified object. This + * will be true if an only if the specified object is an instance of + * Rectangle2D with the same coordinates and dimensions. + * + * @param obj the object to test against for equality + * @return true if the specified object is equal to this one + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Rectangle2D)) + return false; + Rectangle2D r = (Rectangle2D) obj; + return r.getX() == getX() && r.getY() == getY() + && r.getWidth() == getWidth() && r.getHeight() == getHeight(); + } + + /** + * This class defines a rectangle in double precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Double extends Rectangle2D + { + /** The x coordinate of the lower left corner. */ + public double x; + + /** The y coordinate of the lower left corner. */ + public double y; + + /** The width of the rectangle. */ + public double width; + + /** The height of the rectangle. */ + public double height; + + /** + * Create a rectangle at (0,0) with width 0 and height 0. + */ + public Double() + { + } + + /** + * Create a rectangle with the given values. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public Double(double x, double y, double w, double h) + { + this.x = x; + this.y = y; + width = w; + height = h; + } + + /** + * Return the X coordinate. + * + * @return the value of x + */ + public double getX() + { + return x; + } + + /** + * Return the Y coordinate. + * + * @return the value of y + */ + public double getY() + { + return y; + } + + /** + * Return the width. + * + * @return the value of width + */ + public double getWidth() + { + return width; + } + + /** + * Return the height. + * + * @return the value of height + */ + public double getHeight() + { + return height; + } + + /** + * Test if the rectangle is empty. + * + * @return true if width or height is not positive + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public void setRect(double x, double y, double w, double h) + { + this.x = x; + this.y = y; + width = w; + height = h; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param r the rectangle to copy + * @throws NullPointerException if r is null + */ + public void setRect(Rectangle2D r) + { + x = r.getX(); + y = r.getY(); + width = r.getWidth(); + height = r.getHeight(); + } + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param x the x coordinate to check + * @param y the y coordinate to check + * @return the binary OR of the result + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + * @since 1.2 + */ + public int outcode(double x, double y) + { + int result = 0; + if (width <= 0) + result |= OUT_LEFT | OUT_RIGHT; + else if (x < this.x) + result |= OUT_LEFT; + else if (x > this.x + width) + result |= OUT_RIGHT; + if (height <= 0) + result |= OUT_BOTTOM | OUT_TOP; + else if (y < this.y) // Remember that +y heads top-to-bottom. + result |= OUT_TOP; + else if (y > this.y + height) + result |= OUT_BOTTOM; + return result; + } + + /** + * Returns the bounds of this rectangle. A pretty useless method, as this + * is already a rectangle. + * + * @return a copy of this rectangle + */ + public Rectangle2D getBounds2D() + { + return new Double(x, y, width, height); + } + + /** + * Return a new rectangle which is the intersection of this and the given + * one. The result will be empty if there is no intersection. + * + * @param r the rectangle to be intersected + * @return the intersection + * @throws NullPointerException if r is null + */ + public Rectangle2D createIntersection(Rectangle2D r) + { + Double res = new Double(); + intersect(this, r, res); + return res; + } + + /** + * Return a new rectangle which is the union of this and the given one. + * + * @param r the rectangle to be merged + * @return the union + * @throws NullPointerException if r is null + */ + public Rectangle2D createUnion(Rectangle2D r) + { + Double res = new Double(); + union(this, r, res); + return res; + } + + /** + * Returns a string representation of this rectangle. This is in the form + * getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width + * + ",h=" + height + ']'. + * + * @return a string representation of this rectangle + */ + public String toString() + { + return getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width + + ",h=" + height + ']'; + } + } + + /** + * This class defines a rectangle in float precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Float extends Rectangle2D + { + /** The x coordinate of the lower left corner. */ + public float x; + + /** The y coordinate of the lower left corner. */ + public float y; + + /** The width of the rectangle. */ + public float width; + + /** The height of the rectangle. */ + public float height; + + /** + * Create a rectangle at (0,0) with width 0 and height 0. + */ + public Float() + { + } + + /** + * Create a rectangle with the given values. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public Float(float x, float y, float w, float h) + { + this.x = x; + this.y = y; + width = w; + height = h; + } + + /** + * Create a rectangle with the given values. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + Float(double x, double y, double w, double h) + { + this.x = (float) x; + this.y = (float) y; + width = (float) w; + height = (float) h; + } + + /** + * Return the X coordinate. + * + * @return the value of x + */ + public double getX() + { + return x; + } + + /** + * Return the Y coordinate. + * + * @return the value of y + */ + public double getY() + { + return y; + } + + /** + * Return the width. + * + * @return the value of width + */ + public double getWidth() + { + return width; + } + + /** + * Return the height. + * + * @return the value of height + */ + public double getHeight() + { + return height; + } + + /** + * Test if the rectangle is empty. + * + * @return true if width or height is not positive + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public void setRect(float x, float y, float w, float h) + { + this.x = x; + this.y = y; + width = w; + height = h; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public void setRect(double x, double y, double w, double h) + { + this.x = (float) x; + this.y = (float) y; + width = (float) w; + height = (float) h; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param r the rectangle to copy + * @throws NullPointerException if r is null + */ + public void setRect(Rectangle2D r) + { + x = (float) r.getX(); + y = (float) r.getY(); + width = (float) r.getWidth(); + height = (float) r.getHeight(); + } + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param x the x coordinate to check + * @param y the y coordinate to check + * @return the binary OR of the result + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + * @since 1.2 + */ + public int outcode(double x, double y) + { + int result = 0; + if (width <= 0) + result |= OUT_LEFT | OUT_RIGHT; + else if (x < this.x) + result |= OUT_LEFT; + else if (x > this.x + width) + result |= OUT_RIGHT; + if (height <= 0) + result |= OUT_BOTTOM | OUT_TOP; + else if (y < this.y) // Remember that +y heads top-to-bottom. + result |= OUT_TOP; + else if (y > this.y + height) + result |= OUT_BOTTOM; + return result; + } + + /** + * Returns the bounds of this rectangle. A pretty useless method, as this + * is already a rectangle. + * + * @return a copy of this rectangle + */ + public Rectangle2D getBounds2D() + { + return new Float(x, y, width, height); + } + + /** + * Return a new rectangle which is the intersection of this and the given + * one. The result will be empty if there is no intersection. + * + * @param r the rectangle to be intersected + * @return the intersection + * @throws NullPointerException if r is null + */ + public Rectangle2D createIntersection(Rectangle2D r) + { + Float res = new Float(); + intersect(this, r, res); + return res; + } + + /** + * Return a new rectangle which is the union of this and the given one. + * + * @param r the rectangle to be merged + * @return the union + * @throws NullPointerException if r is null + */ + public Rectangle2D createUnion(Rectangle2D r) + { + Float res = new Float(); + union(this, r, res); + return res; + } + + /** + * Returns a string representation of this rectangle. This is in the form + * getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width + * + ",h=" + height + ']'. + * + * @return a string representation of this rectangle + */ + public String toString() + { + return getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width + + ",h=" + height + ']'; + } + } +} diff --git a/libjava/classpath/java/awt/geom/RectangularShape.java b/libjava/classpath/java/awt/geom/RectangularShape.java new file mode 100644 index 0000000..8f66dab --- /dev/null +++ b/libjava/classpath/java/awt/geom/RectangularShape.java @@ -0,0 +1,385 @@ +/* RectangularShape.java -- a rectangular frame for several generic shapes + 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 java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; + +/** + * This class provides a generic framework, and several helper methods, for + * subclasses which represent geometric objects inside a rectangular frame. + * This does not specify any geometry except for the bounding box. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @see Arc2D + * @see Ellipse2D + * @see Rectangle2D + * @see RoundRectangle2D + * @status updated to 1.4 + */ +public abstract class RectangularShape implements Shape, Cloneable +{ + /** + * Default constructor. + */ + protected RectangularShape() + { + } + + /** + * Get the x coordinate of the upper-left corner of the framing rectangle. + * + * @return the x coordinate + */ + public abstract double getX(); + + /** + * Get the y coordinate of the upper-left corner of the framing rectangle. + * + * @return the y coordinate + */ + public abstract double getY(); + + /** + * Get the width of the framing rectangle. + * + * @return the width + */ + public abstract double getWidth(); + + /** + * Get the height of the framing rectangle. + * + * @return the height + */ + public abstract double getHeight(); + + /** + * Get the minimum x coordinate in the frame. This is misnamed, or else + * Sun has a bug, because the implementation returns getX() even when + * getWidth() is negative. + * + * @return the minimum x coordinate + */ + public double getMinX() + { + return getX(); + } + + /** + * Get the minimum y coordinate in the frame. This is misnamed, or else + * Sun has a bug, because the implementation returns getY() even when + * getHeight() is negative. + * + * @return the minimum y coordinate + */ + public double getMinY() + { + return getY(); + } + + /** + * Get the maximum x coordinate in the frame. This is misnamed, or else + * Sun has a bug, because the implementation returns getX()+getWidth() even + * when getWidth() is negative. + * + * @return the maximum x coordinate + */ + public double getMaxX() + { + return getX() + getWidth(); + } + + /** + * Get the maximum y coordinate in the frame. This is misnamed, or else + * Sun has a bug, because the implementation returns getY()+getHeight() even + * when getHeight() is negative. + * + * @return the maximum y coordinate + */ + public double getMaxY() + { + return getY() + getHeight(); + } + + /** + * Return the x coordinate of the center point of the framing rectangle. + * + * @return the central x coordinate + */ + public double getCenterX() + { + return getX() + getWidth() / 2; + } + + /** + * Return the y coordinate of the center point of the framing rectangle. + * + * @return the central y coordinate + */ + public double getCenterY() + { + return getY() + getHeight() / 2; + } + + /** + * Return the frame around this object. Note that this may be a looser + * bounding box than getBounds2D. + * + * @return the frame, in double precision + * @see #setFrame(double, double, double, double) + */ + public Rectangle2D getFrame() + { + return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight()); + } + + /** + * Test if the shape is empty, meaning that no points are inside it. + * + * @return true if the shape is empty + */ + public abstract boolean isEmpty(); + + /** + * Set the framing rectangle of this shape to the given coordinate and size. + * + * @param x the new x coordinate + * @param y the new y coordinate + * @param w the new width + * @param h the new height + * @see #getFrame() + */ + public abstract void setFrame(double x, double y, double w, double h); + + /** + * Set the framing rectangle of this shape to the given coordinate and size. + * + * @param p the new point + * @param d the new dimension + * @throws NullPointerException if p or d is null + * @see #getFrame() + */ + public void setFrame(Point2D p, Dimension2D d) + { + setFrame(p.getX(), p.getY(), d.getWidth(), d.getHeight()); + } + + /** + * Set the framing rectangle of this shape to the given rectangle. + * + * @param r the new framing rectangle + * @throws NullPointerException if r is null + * @see #getFrame() + */ + public void setFrame(Rectangle2D r) + { + setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Set the framing rectangle of this shape using two points on a diagonal. + * The area will be positive. + * + * @param x1 the first x coordinate + * @param y1 the first y coordinate + * @param x2 the second x coordinate + * @param y2 the second y coordinate + */ + public void setFrameFromDiagonal(double x1, double y1, double x2, double y2) + { + if (x1 > x2) + { + double t = x2; + x2 = x1; + x1 = t; + } + if (y1 > y2) + { + double t = y2; + y2 = y1; + y1 = t; + } + setFrame(x1, y1, x2 - x1, y2 - y1); + } + + /** + * Set the framing rectangle of this shape using two points on a diagonal. + * The area will be positive. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + */ + public void setFrameFromDiagonal(Point2D p1, Point2D p2) + { + setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + } + + /** + * Set the framing rectangle of this shape using the center of the frame, + * and one of the four corners. The area will be positive. + * + * @param centerX the x coordinate at the center + * @param centerY the y coordinate at the center + * @param cornerX the x coordinate at a corner + * @param cornerY the y coordinate at a corner + */ + public void setFrameFromCenter(double centerX, double centerY, + double cornerX, double cornerY) + { + double halfw = Math.abs(cornerX - centerX); + double halfh = Math.abs(cornerY - centerY); + setFrame(centerX - halfw, centerY - halfh, halfw + halfw, halfh + halfh); + } + + /** + * Set the framing rectangle of this shape using the center of the frame, + * and one of the four corners. The area will be positive. + * + * @param center the center point + * @param corner a corner point + * @throws NullPointerException if either point is null + */ + public void setFrameFromCenter(Point2D center, Point2D corner) + { + setFrameFromCenter(center.getX(), center.getY(), + corner.getX(), corner.getY()); + } + + /** + * Tests if a point is inside the boundary of the shape. + * + * @param p the point to test + * @return true if the point is inside the shape + * @throws NullPointerException if p is null + * @see #contains(double, double) + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Tests if a rectangle and this shape share common internal points. + * + * @param r the rectangle to test + * @return true if the rectangle intersects this shpae + * @throws NullPointerException if r is null + * @see #intersects(double, double, double, double) + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Tests if the shape completely contains the given rectangle. + * + * @param r the rectangle to test + * @return true if r is contained in this shape + * @throws NullPointerException if r is null + * @see #contains(double, double, double, double) + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Returns a bounding box for this shape, in integer format. Notice that you + * may get a tighter bound with getBounds2D. If the frame is empty, the + * box is the default empty box at the origin. + * + * @return a bounding box + */ + public Rectangle getBounds() + { + if (isEmpty()) + return new Rectangle(); + double x = getX(); + double y = getY(); + double maxx = Math.ceil(x + getWidth()); + double maxy = Math.ceil(y + getHeight()); + x = Math.floor(x); + y = Math.floor(y); + return new Rectangle((int) x, (int) y, (int) (maxx - x), (int) (maxy - y)); + } + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. The path is + * flattened until all segments differ from the curve by at most the value + * of the flatness parameter, within the limits of the default interpolation + * recursion limit of 1024 segments between actual points. Each call + * returns a new object, independent from others in use. The result is + * threadsafe if and only if the iterator returned by + * {@link #getPathIterator(AffineTransform)} is as well. + * + * @param at an optional transform to apply to the iterator + * @param flatness the desired flatness + * @return a new iterator over the boundary + * @throws IllegalArgumentException if flatness is invalid + * @since 1.2 + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + /** + * Create a new shape of the same run-time type with the same contents as + * this one. + * + * @return the clone + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } +} // class RectangularShape diff --git a/libjava/classpath/java/awt/geom/RoundRectangle2D.java b/libjava/classpath/java/awt/geom/RoundRectangle2D.java new file mode 100644 index 0000000..ac0e6f8 --- /dev/null +++ b/libjava/classpath/java/awt/geom/RoundRectangle2D.java @@ -0,0 +1,533 @@ +/* RoundRectangle2D.java -- represents a rectangle with rounded corners + Copyright (C) 2000, 2002, 2003, 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 java.awt.geom; + +import java.util.NoSuchElementException; + + +/** This class implements a rectangle with rounded corners. + * @author Tom Tromey (tromey@cygnus.com) + * @date December 3, 2000 + */ +public abstract class RoundRectangle2D extends RectangularShape +{ + /** Return the arc height of this round rectangle. */ + public abstract double getArcHeight(); + + /** Return the arc width of this round rectangle. */ + public abstract double getArcWidth(); + + /** Set the values of this round rectangle + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + * @param arcWidth The arc width + * @param arcHeight The arc height + */ + public abstract void setRoundRect(double x, double y, double w, double h, + double arcWidth, double arcHeight); + + /** Create a RoundRectangle2D. This is protected because this class + * is abstract and cannot be instantiated. + */ + protected RoundRectangle2D() + { + } + + /** Return true if this object contains the specified point. + * @param x The x coordinate + * @param y The y coordinate + */ + public boolean contains(double x, double y) + { + double mx = getX(); + double mw = getWidth(); + if (x < mx || x >= mx + mw) + return false; + double my = getY(); + double mh = getHeight(); + if (y < my || y >= my + mh) + return false; + + // Now check to see if the point is in range of an arc. + double dy = Math.min(Math.abs(my - y), Math.abs(my + mh - y)); + double dx = Math.min(Math.abs(mx - x), Math.abs(mx + mw - x)); + + // The arc dimensions are that of the corresponding ellipse + // thus a 90 degree segment is half of that. + double aw = getArcWidth() / 2.0; + double ah = getArcHeight() / 2.0; + if (dx > aw || dy > ah) + return true; + + // At this point DX represents the distance from the nearest edge + // of the rectangle. But we want to transform it to represent the + // scaled distance from the center of the ellipse that forms the + // arc. Hence this code: + dy = (ah - dy) / ah; + dx = (aw - dx) / aw; + + return dx * dx + dy * dy <= 1.0; + } + + /** Return true if this object contains the specified rectangle + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + */ + public boolean contains(double x, double y, double w, double h) + { + // We have to check all four points here (for ordinary rectangles + // we can just check opposing corners). + return (contains(x, y) && contains(x, y + h) && contains(x + w, y + h) + && contains(x + w, y)); + } + + /** Return a new path iterator which iterates over this rectangle. + * @param at An affine transform to apply to the object + */ + public PathIterator getPathIterator(final AffineTransform at) + { + final double minx = getX(); + final double miny = getY(); + final double maxx = minx + getWidth(); + final double maxy = miny + getHeight(); + final double arcwidth = getArcWidth(); + final double archeight = getArcHeight(); + return new PathIterator() + { + /** We iterate counterclockwise around the rectangle, starting in the + * upper right. This variable tracks our current point, which + * can be on either side of a given corner. */ + private int current = 0; + + /** Child path iterator, used for corners. */ + private PathIterator corner; + + /** This is used when rendering the corners. We re-use the arc + * for each corner. */ + private Arc2D arc = new Arc2D.Double(); + + /** Temporary array used by getPoint. */ + private double[] temp = new double[2]; + + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current > 9; + } + + private void getPoint(int val) + { + switch (val) + { + case 0: + case 8: + temp[0] = maxx; + temp[1] = miny + archeight; + break; + case 7: + temp[0] = maxx; + temp[1] = maxy - archeight; + break; + case 6: + temp[0] = maxx - arcwidth; + temp[1] = maxy; + break; + case 5: + temp[0] = minx + arcwidth; + temp[1] = maxy; + break; + case 4: + temp[0] = minx; + temp[1] = maxy - archeight; + break; + case 3: + temp[0] = minx; + temp[1] = miny + archeight; + break; + case 2: + temp[0] = minx + arcwidth; + temp[1] = miny; + break; + case 1: + temp[0] = maxx - arcwidth; + temp[1] = miny; + break; + } + } + + public void next() + { + if (current >= 8) + ++current; + else if (corner != null) + { + // We're iterating through the corner. Work on the child + // iterator; if it finishes, reset and move to the next + // point along the rectangle. + corner.next(); + if (corner.isDone()) + { + corner = null; + ++current; + } + } + else + { + // Make an arc between this point on the rectangle and + // the next one, and then iterate over this arc. + getPoint(current); + double x1 = temp[0]; + double y1 = temp[1]; + getPoint(current + 1); + Rectangle2D.Double r = new Rectangle2D.Double(Math.min(x1, + temp[0]), + Math.min(y1, + temp[1]), + Math.abs(x1 + - temp[0]), + Math.abs(y1 + - temp[1])); + arc.setArc(r, (current >> 1) * 90.0, 90.0, Arc2D.OPEN); + corner = arc.getPathIterator(at); + } + } + + public int currentSegment(float[] coords) + { + if (corner != null) + { + int r = corner.currentSegment(coords); + if (r == SEG_MOVETO) + r = SEG_LINETO; + return r; + } + + if (current < 9) + { + getPoint(current); + coords[0] = (float) temp[0]; + coords[1] = (float) temp[1]; + } + else if (current == 9) + return SEG_CLOSE; + else + throw new NoSuchElementException("rect iterator out of bounds"); + + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return current == 0 ? SEG_MOVETO : SEG_LINETO; + } + + public int currentSegment(double[] coords) + { + if (corner != null) + { + int r = corner.currentSegment(coords); + if (r == SEG_MOVETO) + r = SEG_LINETO; + return r; + } + + if (current < 9) + { + getPoint(current); + coords[0] = temp[0]; + coords[1] = temp[1]; + } + else if (current == 9) + return SEG_CLOSE; + else + throw new NoSuchElementException("rect iterator out of bounds"); + + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return current == 0 ? SEG_MOVETO : SEG_LINETO; + } + }; + } + + /** Return true if the given rectangle intersects this shape. + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + */ + public boolean intersects(double x, double y, double w, double h) + { + // Check if any corner is within the rectangle + return (contains(x, y) || contains(x, y + h) || contains(x + w, y + h) + || contains(x + w, y)); + } + + /** Set the boundary of this round rectangle. + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + */ + public void setFrame(double x, double y, double w, double h) + { + // This is a bit lame. + setRoundRect(x, y, w, h, getArcWidth(), getArcHeight()); + } + + /** Set the values of this round rectangle to be the same as those + * of the argument. + * @param rr The round rectangle to copy + */ + public void setRoundRect(RoundRectangle2D rr) + { + setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), + rr.getArcWidth(), rr.getArcHeight()); + } + + /** A subclass of RoundRectangle which keeps its parameters as + * doubles. */ + public static class Double extends RoundRectangle2D + { + /** The height of the corner arc. */ + public double archeight; + + /** The width of the corner arc. */ + public double arcwidth; + + /** The x coordinate of this object. */ + public double x; + + /** The y coordinate of this object. */ + public double y; + + /** The width of this object. */ + public double width; + + /** The height of this object. */ + public double height; + + /** Construct a new instance, with all parameters set to 0. */ + public Double() + { + } + + /** Construct a new instance with the given arguments. + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + * @param arcWidth The arc width + * @param arcHeight The arc height + */ + public Double(double x, double y, double w, double h, double arcWidth, + double arcHeight) + { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.arcwidth = arcWidth; + this.archeight = arcHeight; + } + + public double getArcHeight() + { + return archeight; + } + + public double getArcWidth() + { + return arcwidth; + } + + public Rectangle2D getBounds2D() + { + return new Rectangle2D.Double(x, y, width, height); + } + + public double getX() + { + return x; + } + + public double getY() + { + return y; + } + + public double getWidth() + { + return width; + } + + public double getHeight() + { + return height; + } + + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + public void setRoundRect(double x, double y, double w, double h, + double arcWidth, double arcHeight) + { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.arcwidth = arcWidth; + this.archeight = arcHeight; + } + } // class Double + + /** A subclass of RoundRectangle which keeps its parameters as + * floats. */ + public static class Float extends RoundRectangle2D + { + /** The height of the corner arc. */ + public float archeight; + + /** The width of the corner arc. */ + public float arcwidth; + + /** The x coordinate of this object. */ + public float x; + + /** The y coordinate of this object. */ + public float y; + + /** The width of this object. */ + public float width; + + /** The height of this object. */ + public float height; + + /** Construct a new instance, with all parameters set to 0. */ + public Float() + { + } + + /** Construct a new instance with the given arguments. + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + * @param arcWidth The arc width + * @param arcHeight The arc height + */ + public Float(float x, float y, float w, float h, float arcWidth, + float arcHeight) + { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.arcwidth = arcWidth; + this.archeight = arcHeight; + } + + public double getArcHeight() + { + return archeight; + } + + public double getArcWidth() + { + return arcwidth; + } + + public Rectangle2D getBounds2D() + { + return new Rectangle2D.Float(x, y, width, height); + } + + public double getX() + { + return x; + } + + public double getY() + { + return y; + } + + public double getWidth() + { + return width; + } + + public double getHeight() + { + return height; + } + + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + public void setRoundRect(float x, float y, float w, float h, + float arcWidth, float arcHeight) + { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.arcwidth = arcWidth; + this.archeight = arcHeight; + } + + public void setRoundRect(double x, double y, double w, double h, + double arcWidth, double arcHeight) + { + this.x = (float) x; + this.y = (float) y; + this.width = (float) w; + this.height = (float) h; + this.arcwidth = (float) arcWidth; + this.archeight = (float) arcHeight; + } + } // class Float +} // class RoundRectangle2D diff --git a/libjava/classpath/java/awt/geom/doc-files/Area-1.png b/libjava/classpath/java/awt/geom/doc-files/Area-1.png new file mode 100644 index 0000000..44650f2 Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/Area-1.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-1.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-1.png new file mode 100644 index 0000000..1784509 Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-1.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-2.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-2.png new file mode 100644 index 0000000..1ddae9f Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-2.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-3.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-3.png new file mode 100644 index 0000000..b200dad Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-3.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-4.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-4.png new file mode 100644 index 0000000..e57ffdc Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-4.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-5.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-5.png new file mode 100644 index 0000000..701ab13 Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-5.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/Ellipse-1.png b/libjava/classpath/java/awt/geom/doc-files/Ellipse-1.png new file mode 100644 index 0000000..8317db6 Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/Ellipse-1.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/FlatteningPathIterator-1.html b/libjava/classpath/java/awt/geom/doc-files/FlatteningPathIterator-1.html new file mode 100644 index 0000000..5a52d69 --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/FlatteningPathIterator-1.html @@ -0,0 +1,481 @@ + + + + + The GNU Implementation of java.awt.geom.FlatteningPathIterator + + + + + +

    The GNU Implementation of FlatteningPathIterator

    + +

    Sascha +Brawer, November 2003

    + +

    This document describes the GNU implementation of the class +java.awt.geom.FlatteningPathIterator. It does +not describe how a programmer should use this class; please +refer to the generated API documentation for this purpose. Instead, it +is intended for maintenance programmers who want to understand the +implementation, for example because they want to extend the class or +fix a bug.

    + + +

    Data Structures

    + +

    The algorithm uses a stack. Its allocation is delayed to the time +when the source path iterator actually returns the first curved +segment (either SEG_QUADTO or SEG_CUBICTO). +If the input path does not contain any curved segments, the value of +the stack variable stays null. In this quite +common case, the memory consumption is minimal.

    + +
    stack
    The variable stack is +a double array that holds the start, control and end +points of individual sub-segments.
    + +
    recLevel
    The variable recLevel +holds how many recursive sub-divisions were needed to calculate a +segment. The original curve has recursion level 0. For each +sub-division, the corresponding recursion level is increased by +one.
    + +
    stackSize
    Finally, the variable +stackSize indicates how many sub-segments are stored on +the stack.
    + +

    Algorithm

    + +

    The implementation separately processes each segment that the +base iterator returns.

    + +

    In the case of SEG_CLOSE, +SEG_MOVETO and SEG_LINETO segments, the +implementation simply hands the segment to the consumer, without actually +doing anything.

    + +

    Any SEG_QUADTO and SEG_CUBICTO segments +need to be flattened. Flattening is performed with a fixed-sized +stack, holding the coordinates of subdivided segments. When the base +iterator returns a SEG_QUADTO and +SEG_CUBICTO segments, it is recursively flattened as +follows:

    + +
    1. Intialization: Allocate memory for the stack (unless a +sufficiently large stack has been allocated previously). Push the +original quadratic or cubic curve onto the stack. Mark that segment as +having a recLevel of zero.
    2. + +
    3. If the stack is empty, flattening the segment is complete, +and the next segment is fetched from the base iterator.
    4. + +
    5. If the stack is not empty, pop a curve segment from the +stack. + +
      • If its recLevel exceeds the recursion limit, + hand the current segment to the consumer.
      • + +
      • Calculate the squared flatness of the segment. If it smaller + than flatnessSq, hand the current segment to the + consumer.
      • + +
      • Otherwise, split the segment in two halves. Push the right + half onto the stack. Then, push the left half onto the stack. + Continue with step two.
    6. +
    + +

    The implementation is slightly complicated by the fact that +consumers pull the flattened segments from the +FlatteningPathIterator. This means that we actually +cannot “hand the curent segment over to the consumer.” +But the algorithm is easier to understand if one assumes a +push paradigm.

    + + +

    Example

    + +

    The following example shows how a +FlatteningPathIterator processes a +SEG_QUADTO segment. It is (arbitrarily) assumed that the +recursion limit was set to 2.

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ABCDEFGH
    stack[0]Sll.x
    stack[1]Sll.y
    stack[2]Cll.x
    stack[3]Cll.y
    stack[4]Sl.xEll.x + = Slr.xSlr.xSrl.x
    stack[5]Sl.yEll.x + = Slr.ySlr.ySrl.y
    stack[6]Cl.xClr.xClr.xCrl.x
    stack[7]Cl.yClr.yClr.yCrl.y
    stack[8]S.xEl.x + = Sr.xElr.x + = Sr.xElr.x + = Sr.xSr.xErl.x + = Srr.xSrr.x
    stack[9]S.yEl.y + = Sr.yElr.y + = Sr.yElr.y + = Sr.ySr.yErl.y + = Srr.ySrr.y
    stack[10]C.xCr.xCr.xCr.xCr.xCrr.xCrr.x
    stack[11]C.yCr.yCr.yCr.yCr.yCrr.yCrr.y
    stack[12]E.xEr.xEr.xEr.xEr.xErr.xErr.x
    stack[13]E.yEr.yEr.yEr.yEr.yErr.yErr.x
    stackSize12321210
    recLevel[2]2
    recLevel[1]1222
    recLevel[0]0111122
    +
    + +
      + +
    1. The data structures are initialized as follows. + +
      • The segment’s end point E, control point +C, and start point S are pushed onto the stack.
      • + +
      • Currently, the curve in the stack would be approximated by one + single straight line segment (SE). + Therefore, stackSize is set to 1.
      • + +
      • This single straight line segment is approximating the original + curve, which can be seen as the result of zero recursive + splits. Therefore, recLevel[0] is set to + zero.
      + +Column A shows the state after the initialization step.
    2. + +
    3. The algorithm proceeds by taking the topmost curve segment +(SCE) from the stack. + +
      • The recursion level of this segment (stored in + recLevel[0]) is zero, which is smaller than + the limit 2.
      • + +
      • The method java.awt.geom.QuadCurve2D.getFlatnessSq + is called to calculate the squared flatness.
      • + +
      • For the sake of argument, we assume that the squared flatness is + exceeding the threshold stored in flatnessSq. Thus, the + curve segment SCE gets + subdivided into a left and a right half, namely + SlCl – + El and Sr – + CrEr. Both halves are + pushed onto the stack, so the left half is now on top. + +
         
        The left half starts at the same point + as the original curve, so Sl has the same + coordinates as S. Similarly, the end point of the right + half and of the original curve are identical + (Er = E). More interestingly, the left + half ends where the right half starts. Because + El = Sr, their coordinates need + to be stored only once, which amounts to saving 16 bytes (two + double values) for each iteration.
      + +Column B shows the state after the first iteration.
    4. + +
    5. Again, the topmost curve segment (Sl +– ClEl) is +taken from the stack. + +
      • The recursion level of this segment (stored in + recLevel[1]) is 1, which is smaller than + the limit 2.
      • + +
      • The method java.awt.geom.QuadCurve2D.getFlatnessSq + is called to calculate the squared flatness.
      • + +
      • Assuming that the segment is still not considered + flat enough, it gets subdivided into a left + (SllCll – + Ell) and a right (Slr + – ClrElr) + half.
      + +Column C shows the state after the second iteration.
    6. + +
    7. The topmost curve segment (Sll – +CllEll) is popped from +the stack. + +
      • The recursion level of this segment (stored in + recLevel[2]) is 2, which is not smaller than + the limit 2. Therefore, a SEG_LINETO (from + Sll to Ell) is passed to the + consumer.
      + + The new state is shown in column D.
    8. + + +
    9. The topmost curve segment (Slr – +ClrElr) is popped from +the stack. + +
      • The recursion level of this segment (stored in + recLevel[1]) is 2, which is not smaller than + the limit 2. Therefore, a SEG_LINETO (from + Slr to Elr) is passed to the + consumer.
      + + The new state is shown in column E.
    10. + +
    11. The algorithm proceeds by taking the topmost curve segment +(SrCr – +Er) from the stack. + +
      • The recursion level of this segment (stored in + recLevel[0]) is 1, which is smaller than + the limit 2.
      • + +
      • The method java.awt.geom.QuadCurve2D.getFlatnessSq + is called to calculate the squared flatness.
      • + +
      • For the sake of argument, we again assume that the squared + flatness is exceeding the threshold stored in + flatnessSq. Thus, the curve segment + (SrCr – + Er) is subdivided into a left and a right half, + namely + SrlCrl – + Erl and Srr – + CrrErr. Both halves + are pushed onto the stack.
      + + The new state is shown in column F.
    12. + +
    13. The topmost curve segment (Srl – +CrlErl) is popped from +the stack. + +
      • The recursion level of this segment (stored in + recLevel[2]) is 2, which is not smaller than + the limit 2. Therefore, a SEG_LINETO (from + Srl to Erl) is passed to the + consumer.
      + + The new state is shown in column G.
    14. + +
    15. The topmost curve segment (Srr – +CrrErr) is popped from +the stack. + +
      • The recursion level of this segment (stored in + recLevel[2]) is 2, which is not smaller than + the limit 2. Therefore, a SEG_LINETO (from + Srr to Err) is passed to the + consumer.
      + + The new state is shown in column H.
    16. + +
    17. The stack is now empty. The FlatteningPathIterator will fetch the +next segment from the base iterator, and process it.
    18. + +
    + +

    In order to split the most recently pushed segment, the +subdivideQuadratic() method passes stack +directly to +QuadCurve2D.subdivide(double[],int,double[],int,double[],int). +Because the stack grows towards the beginning of the array, no data +needs to be copied around: subdivide will directly store +the result into the stack, which will have the contents shown to the +right.

    + + + diff --git a/libjava/classpath/java/awt/geom/doc-files/GeneralPath-1.png b/libjava/classpath/java/awt/geom/doc-files/GeneralPath-1.png new file mode 100644 index 0000000..d1d75d5 Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/GeneralPath-1.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-1.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-1.png new file mode 100644 index 0000000..7c2ec0e Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-1.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-2.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-2.png new file mode 100644 index 0000000..496180c Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-2.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-3.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-3.png new file mode 100644 index 0000000..a7557ba Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-3.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-4.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-4.png new file mode 100644 index 0000000..835c064 Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-4.png differ diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-5.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-5.png new file mode 100644 index 0000000..72110cd Binary files /dev/null and b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-5.png differ diff --git a/libjava/classpath/java/awt/geom/package.html b/libjava/classpath/java/awt/geom/package.html new file mode 100644 index 0000000..c8ee827 --- /dev/null +++ b/libjava/classpath/java/awt/geom/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.geom + + +

    Classes to represent 2D objects and different path transformations.

    + + + diff --git a/libjava/classpath/java/awt/im/InputContext.java b/libjava/classpath/java/awt/im/InputContext.java new file mode 100644 index 0000000..e289677 --- /dev/null +++ b/libjava/classpath/java/awt/im/InputContext.java @@ -0,0 +1,434 @@ +/* InputContext.java -- provides the context for text input + 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 java.awt.im; + +import gnu.java.util.EmptyEnumeration; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.Component; +import java.awt.im.spi.InputMethod; +import java.awt.im.spi.InputMethodDescriptor; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Locale; + +/** + * Provides a context for controlling input methods and keyboard layouts. + * This class provides the communication layer between the client component, + * and the various locale-dependent text entry input methods that can be used + * for the client. By default, there is one instance per Window, shared among + * all components, but this limits text entry to one component at a time. + * Thus, text components can create their own instance to allow text entry + * in multiple components at a time. + * + *

    By using the interfaces of {@link java.awt.im.spi}, you can install + * extensions which allow additional input methods. Some of these may use + * platform native input methods, or keyboard layouts provided by the platform. + * Input methods are unavailable if none have been installed and the platform + * has no underlying native input methods. Extensions are installed as jar + * files, usually accessed in the default extension location or specified by + * the -extdir VM flag. The jar must contain a file named + * "META_INF/services/java.awt.im.spi.InputMethodDescriptor" which lists, + * one entry per line in UTF-8 encoding, each class in the jar that implements + * java.awt.im.spi.InputMethodDescriptor. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Component#getInputContext() + * @see Component#enableInputMethods(boolean) + * @since 1.2 + * @status updated to 1.4, but unverified + */ +public class InputContext +{ + /** + * The list of installed input method descriptors. + */ + private static final ArrayList descriptors = new ArrayList(); + static + { + Enumeration e; + try + { + e = ClassLoader.getSystemResources + ("META_INF/services/java.awt.im.spi.InputMethodDescriptor"); + } + catch (IOException ex) + { + // XXX Should we do something else? + e = EmptyEnumeration.getInstance(); + } + while (e.hasMoreElements()) + { + URL url = (URL) e.nextElement(); + BufferedReader in; + String line; + try + { + in = new BufferedReader + (new InputStreamReader(url.openConnection().getInputStream(), + "UTF-8")); + line = in.readLine().trim(); + } + catch (IOException ignored) + { + continue; + } + outer: + while (line != null) + { + try + { + if (line.charAt(0) != '#') + { + Class c = Class.forName(line); + descriptors.add((InputMethodDescriptor) c.newInstance()); + } + line = in.readLine().trim(); + } + catch (IOException ex) + { + continue outer; + } + catch (Exception ignored) + { + } + } + } + } + + /** The current input method; null if no input methods are installed. */ + private InputMethod im; + + /** Map of locales to the most recently selected input method. */ + private final HashMap recent = new HashMap(); + + /** The list of acceptable character subsets. */ + private Character.Subset[] subsets; + + /** + * Construct an InputContext. This is protected, so clients must use + * {@link #getInstance()} instead. + */ + protected InputContext() + { + } + + /** + * Returns a new InputContext. + * + * @return a new instance, initialized to the default locale if available + */ + public static InputContext getInstance() + { + InputContext ic = new InputContext(); + ic.selectInputMethod(Locale.getDefault()); + return ic; + } + + /** + * Attempts to select an input method or keyboard layout which supports the + * given locale. This returns true if a locale is available and was selected. + * The following steps are taken in choosing an input method:

      + *
    • If the currently selected input method or keyboard layout supports + * the requested locale, it remains selected.
    • + *
    • If there is no input method or keyboard layout available that + * supports the requested locale, the current input method or keyboard + * layout remains selected.
    • + *
    • If the user has previously selected an input method or keyboard + * layout for the requested locale from the user interface, then the most + * recently selected such input method or keyboard layout is reselected.
    • + *
    • Otherwise, an input method or keyboard layout that supports the + * requested locale is selected in an implementation dependent way. This + * implementation chooses the first input method which supports the requested + * locale based on the InputMethodDescriptors loaded from the extensions + * installed on the CLASSPATH.
    • + *
    + * + *

    Before switching away from an input method, any currently uncommitted + * text is committed. Not all host operating systems provide API to + * determine the locale of the currently selected native input method or + * keyboard layout, and to select a native input method or keyboard layout + * by locale. For host operating systems that don't provide such API, + * selectInputMethod assumes that native input methods or keyboard layouts + * provided by the host operating system support only the system's default + * locale. + * + *

    An example of where this may be called is in a multi-language document, + * when moving the insertion point between sections of different locale, so + * that the user may use the input method appropriate to that section of the + * document. + * + * @param locale the desired new locale + * @return true if the new locale is active + * @throws NullPointerException if locale is null + */ + public boolean selectInputMethod(Locale locale) + { + if (im != null && im.setLocale(locale)) + { + recent.put(locale, im); + return true; + } + InputMethod next = (InputMethod) recent.get(locale); + outer: + if (next != null) + for (int i = 0, limit = descriptors.size(); i < limit; i++) + { + InputMethodDescriptor d = (InputMethodDescriptor) descriptors.get(i); + Locale[] list; + try + { + list = d.getAvailableLocales(); + } + catch (AWTException ignored) + { + continue; + } + for (int j = list.length; --j >= 0; ) + if (locale.equals(list[j])) + { + try + { + next = d.createInputMethod(); + recent.put(locale, next); + } + catch (Exception ignored) + { + continue; + } + } + } + if (next == null) + return false; + // XXX I'm not sure if this does all the necessary steps in the switch. + if (im != null) + { + try + { + next.setCompositionEnabled(im.isCompositionEnabled()); + } + catch (UnsupportedOperationException ignored) + { + } + im.endComposition(); + im.deactivate(false); + im.hideWindows(); + } + im = next; + im.setLocale(locale); + im.setCharacterSubsets(subsets); + return true; + } + + /** + * Returns the current locale of the current input method or keyboard + * layout. Returns null if the input context does not have a current input + * method or keyboard layout or if the current input method's + * {@link InputMethod#getLocale()} method returns null. Not all host + * operating systems provide API to determine the locale of the currently + * selected native input method or keyboard layout. For host operating + * systems that don't provide such API, getLocale assumes that the current + * locale of all native input methods or keyboard layouts provided by the + * host operating system is the system's default locale. + * + * @return the locale of the current input method, or null + * @since 1.3 + */ + public Locale getLocale() + { + return im == null ? null : im.getLocale(); + } + + /** + * Sets the subsets of Unicode characters allowed to be input by the current + * input method, as well as subsequent input methods. The value of null + * implies all characters are legal. Applications should not rely on this + * behavior, since native host input methods may not allow restrictions. + * If no current input method is available, this has no immediate effect. + * + * @param subsets the set of Unicode subsets to accept, or null + */ + public void setCharacterSubsets(Character.Subset[] subsets) + { + this.subsets = subsets; + if (im != null) + im.setCharacterSubsets(subsets); + } + + /** + * Changes the enabled status of the current input method. An input method + * that is enabled for composition interprets incoming events for both + * composition and control purposes, while a disabled input method only + * interprets control commands (including commands to enable itself). + * + * @param enable whether to enable the input method + * @throws UnsupportedOperationException if there is no current input method, + * or the input method does not support enabling + * @see #isCompositionEnabled() + * @since 1.3 + */ + public void setCompositionEnabled(boolean enable) + { + if (im == null) + throw new UnsupportedOperationException(); + im.setCompositionEnabled(enable); + } + + /** + * Find out if the current input method is enabled. + * + * @return true if the current input method is enabled + * @throws UnsupportedOperationException if there is no current input method, + * or the input method does not support enabling + * @see #setCompositionEnabled(boolean) + * @since 1.3 + */ + public boolean isCompositionEnabled() + { + if (im == null) + throw new UnsupportedOperationException(); + return im.isCompositionEnabled(); + } + + /** + * Starts a reconversion operation in the current input method. The input + * method gets theh text to reconvert from the client component, using + * {@link InputMethodRequests#getSelectedText(Attribute[])}. Then the + * composed and committed text produced by the operation is sent back to + * the client using a sequence of InputMethodRequests. + * + * @throws UnsupportedOperationException if there is no current input method, + * or the input method does not support reconversion + * @since 1.3 + */ + public void reconvert() + { + if (im == null) + throw new UnsupportedOperationException(); + im.reconvert(); + } + + /** + * Dispatches an event to the current input method. This is called + * automatically by AWT. If no input method is available, then the event + * will never be consumed. + * + * @param event the event to dispatch + * @throws NullPointerException if event is null + */ + public void dispatchEvent(AWTEvent event) + { + if (im != null) + im.dispatchEvent(event); + } + + /** + * Notifies the input context that a client component has been removed from + * its containment hierarchy, or that input method support has been disabled + * for the component. This method is usually called from the client + * component's {@link Component#removeNotify()} method. Potentially pending + * input from input methods for this component is discarded. If no input + * methods are available, then this method has no effect. + * + * @param client the client component + * @throws NullPointerException if client is null + */ + public void removeNotify(Component client) + { + // XXX What to do with client information? + if (im != null) + { + im.deactivate(false); + im.removeNotify(); + } + } + + /** + * Ends any input composition that may currently be going on in this + * context. Depending on the platform and possibly user preferences, this + * may commit or delete uncommitted text. Any changes to the text are + * communicated to the active component using an input method event. If no + * input methods are available, then this method has no effect. This may + * be called for a variety of reasons, such as when the user moves the + * insertion point in the client text outside the range of the composed text, + * or when text is saved to file. + */ + public void endComposition() + { + if (im != null) + im.endComposition(); + } + + /** + * Disposes of the input context and release the resources used by it. + * Called automatically by AWT for the default input context of each + * Window. If no input methods are available, then this method has no + * effect. + */ + public void dispose() + { + if (im != null) + { + im.deactivate(false); + im.dispose(); + } + } + + /** + * Returns a control object from the current input method, or null. A + * control object provides implementation-dependent methods that control + * the behavior of the input method or obtain information from the input + * method. Clients have to compare the result against known input method + * control object types. If no input methods are available or the current + * input method does not provide an input method control object, then null + * is returned. + * + * @return the control object, or null + */ + public Object getInputMethodControlObject() + { + return im == null ? null : im.getControlObject(); + } +} // class InputContext diff --git a/libjava/classpath/java/awt/im/InputMethodHighlight.java b/libjava/classpath/java/awt/im/InputMethodHighlight.java new file mode 100644 index 0000000..0d664b1 --- /dev/null +++ b/libjava/classpath/java/awt/im/InputMethodHighlight.java @@ -0,0 +1,185 @@ +/* InputMethodHighlight.java -- highlights the current text selection + 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 java.awt.im; + +import java.util.Map; + +/** + * This describes the highlight attributes of text composed in an input method. + * The description includes an abstract level (whether text has been converted + * yet, and whether it is selected), and a concrete level (which style + * attributes are used in rendering). If no concrete level is defined, the + * renderer should use + * {@link Toolkit#mapInputMethodHighlight(InputMethodHighlight)}. An example + * of conversion state is kana -> kanji. + * + *

    Instances of this class are typically used in + * AttributedCharacterIterators, and may be wrapped in Annotations to separate + * text segments. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see AttributedCharacterIterators + * @see Annotation + * @since 1.2 + * @status updated to 1.4 + */ +public class InputMethodHighlight +{ + /** Raw text state (before conversion). */ + public static final int RAW_TEXT = 0; + + /** Converted text state (after conversion). */ + public static final int CONVERTED_TEXT = 1; + + /** Default do-nothing highlighting for unselected raw text. */ + public static final InputMethodHighlight UNSELECTED_RAW_TEXT_HIGHLIGHT + = new InputMethodHighlight(false, RAW_TEXT); + + /** Default do-nothing highlighting for selected raw text. */ + public static final InputMethodHighlight SELECTED_RAW_TEXT_HIGHLIGHT + = new InputMethodHighlight(true, RAW_TEXT); + + /** Default do-nothing highlighting for unselected converted text. */ + public static final InputMethodHighlight UNSELECTED_CONVERTED_TEXT_HIGHLIGHT + = new InputMethodHighlight(false, CONVERTED_TEXT); + + /** Default do-nothing highlighting for selected converted text. */ + public static final InputMethodHighlight SELECTED_CONVERTED_TEXT_HIGHLIGHT + = new InputMethodHighlight(true, CONVERTED_TEXT); + + /** Whether the highlighting applies to selected text. */ + private final boolean selected; + + /** The state of highlighted text. */ + private final int state; + + /** Any variation on the highlighting style. */ + private final int variation; + + /** The unmodifiable map of rendering styles. */ + private final Map style; + + /** + * Create an input method highlight style, with variation 0 and null style + * mapping. + * + * @param selected whether the text range is selected + * @param state either {@link #RAW_TEXT} or {@link #CONVERTED_TEXT} + * @throws IllegalArgumentException if state is invalid + */ + public InputMethodHighlight(boolean selected, int state) + { + this(selected, state, 0, null); + } + + /** + * Create an input method highlight style, with null style mapping. + * + * @param selected whether the text range is selected + * @param state either {@link #RAW_TEXT} or {@link #CONVERTED_TEXT} + * @param variation the style variation + * @throws IllegalArgumentException if state is invalid + */ + public InputMethodHighlight(boolean selected, int state, int variation) + { + this(selected, state, variation, null); + } + + /** + * Create an input method highlight style. + * + * @param selected whether the text range is selected + * @param state either {@link #RAW_TEXT} or {@link #CONVERTED_TEXT} + * @param variation the style variation + * @param style an unmodifiable map of rendering styles, or null + * @throws IllegalArgumentException if state is invalid + * @since 1.3 + */ + public InputMethodHighlight(boolean selected, int state, int variation, + Map style) + { + if (state != RAW_TEXT && state != CONVERTED_TEXT) + throw new IllegalArgumentException(); + this.selected = selected; + this.state = state; + this.variation = variation; + this.style = style; + } + + /** + * Return whether the highlighting applies to selected text. + * + * @return the selection status + */ + public boolean isSelected() + { + return selected; + } + + /** + * Return the conversion state of the highlighted text. + * + * @return one of {@link #RAW_TEXT} or {@link #CONVERTED_TEXT} + */ + public int getState() + { + return state; + } + + /** + * Return the highlighting style variation. + * + * @return the variation + */ + public int getVariation() + { + return variation; + } + + /** + * Return the rendering style attributes map, or null if it should be the + * default mapping. + * + * @return the style map + * @since 1.3 + */ + public Map getStyle() + { + return style; + } +} // class InputMethodHighlight diff --git a/libjava/classpath/java/awt/im/InputMethodRequests.java b/libjava/classpath/java/awt/im/InputMethodRequests.java new file mode 100644 index 0000000..d50ec33 --- /dev/null +++ b/libjava/classpath/java/awt/im/InputMethodRequests.java @@ -0,0 +1,153 @@ +/* InputMethodRequests.java -- handles text insertion via input methods + 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 java.awt.im; + +import java.awt.Rectangle; +import java.awt.font.TextHitInfo; +import java.text.AttributedCharacterIterator; +import java.text.AttributedCharacterIterator.Attribute; + +/** + * This interface handles requests made by input methods on text editing + * components. A component must specify a handler for input methods that + * implements this interface, and which supports one of two user interfaces: + *

    • on-the-spot: composed text is shown in place
    • + *
    • below-the-spot: composed text is in a separate window, + * usually below the main text window, until it is committed into place at + * the insertion point, overwriting any selected text
    + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Component#getInputMethodRequests() + * @see InputMethodListener + * @since 1.2 + * @status updated to 1.4 + */ +public interface InputMethodRequests +{ + /** + * Gets the location of a given offset of the text. This can be used to + * position a composition window near the location of where the composed + * text will be inserted. + * + *

    If the component has composed text (from the most recent + * InputMethodEvent), then offset 0 indicates the location of the first + * character of this composed text. Otherwise, the offset is ignored, and + * the location should be the beginning of the final line of selected + * text (in horizontal left-to-right text, like English, this would be the + * lower left corner of the selction; in vertical top-to-bottom text, like + * Chinese, this would be the top right corner of the selection). + * + *

    The location returned is a 0-thickness caret (either horizontal or + * vertical, depending on text flow), mapped to absolute screen coordinates. + * + * @param offset offset within composed text, or null + * @return the screen location of the caret at the offset + */ + Rectangle getTextLocation(TextHitInfo offset); + + /** + * Get the text offset for the given screen coordinate. The offset is + * relative to the composed text, and the return is null if it is outside + * the range of composed text. For example, this can be used to find + * where a mouse click should pop up a text composition window. + * + * @param x the x screen coordinate + * @param y the y screen coordinate + * @return a text hit info describing the composed text offset + */ + TextHitInfo getLocationOffset(int x, int y); + + /** + * Gets the offset where the committed text exists in the text editing + * component. This can be used to examine the text surrounding the insert + * position. + * + * @return the offset of the insert position + */ + int getInsertPositionOffset(); + + /** + * Gets an interator which provides access to the text and its attributes, + * except for the uncommitted text. The input method may provide a list of + * attributes it is interested in; and the iterator need not provide + * information on the remaining attributes. If the attribute list is null, + * the iterator must list all attributes. + * + * @param beginIndex the index of the first character in the iteration + * @param endIndex the index of the last character in the iteration + * @param attributes a list of attributes interested in, or null + * @return an iterator over the region of text with its attributes + */ + AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex, + Attribute[] attributes); + + /** + * Gets the length of committed text. + * + * @return the number of committed characters + */ + int getCommittedTextLength(); + + /** + * Gets the latest committed text, and removes it from the component's text + * body. This allows an input method to provide an "Undo" command. In + * general, this should only be supported immediately after a commit, and + * not when other actions intervene; if not supported, simply return null. + * The input method may provide a list of attributes it is interested in; + * and the iterator need not provide information on the remaining attributes. + * If the attribute list is null, the iterator must list all attributes. + * + * @param attributes a list of attributes interested in, or null + * @return the latest committed text, or null + */ + AttributedCharacterIterator cancelLatestCommittedText + (Attribute[] attributes); + + /** + * Gets the currently selected text. One use of this is to implement a + * "Reconvert" feature in an input method, which modifies the selection + * based on the text in the composition window. The input method may + * provide a list of attributes it is interested in; and the iterator need + * not provide information on the remaining attributes. If the attribute + * list is null, the iterator must list all attributes. + * + * @param attributes a list of attributes interested in, or null + * @return the current selection + */ + AttributedCharacterIterator getSelectedText(Attribute[] attributes); +} // interface InputMethodRequests diff --git a/libjava/classpath/java/awt/im/InputSubset.java b/libjava/classpath/java/awt/im/InputSubset.java new file mode 100644 index 0000000..5e7d58e --- /dev/null +++ b/libjava/classpath/java/awt/im/InputSubset.java @@ -0,0 +1,129 @@ +/* InputSubset.java -- subsets of Unicode important in text input + Copyright (C) 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 java.awt.im; + +/** + * Defines additional Unicode character blocks for use by input methods. + * These constants encompass several Unicode blocks, or portions thereof, for + * simplification over {@link Character.UnicodeBlock}. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public final class InputSubset extends Character.Subset +{ + /** + * Constant for all Latin characters, including the characters in the + * BASIC_LATIN, LATIN_1_SUPPLEMENT, LATIN_EXTENDED_A, LATIN_EXTENDED_B + * Unicode character blocks. + */ + public static final InputSubset LATIN = new InputSubset("LATIN"); + + /** + * Constant for the digits included in the BASIC_LATIN Unicode character + * block. + */ + public static final InputSubset LATIN_DIGITS + = new InputSubset("LATIN_DIGITS"); + + /** + * Constant for all Han characters used in writing Traditional Chinese, + * including a subset of the CJK unified ideographs as well as Traditional + * Chinese Han characters that may be defined as surrogate characters. + */ + public static final InputSubset TRADITIONAL_HANZI + = new InputSubset("TRADITIONAL_HANZI"); + + /** + * Constant for all Han characters used in writing Simplified Chinese, + * including a subset of the CJK unified ideographs as well as Simplified + * Chinese Han characters that may be defined as surrogate characters. + */ + public static final InputSubset SIMPLIFIED_HANZI + = new InputSubset("SIMPLIFIED_HANZI"); + + /** + * Constant for all Han characters used in writing Japanese, including a + * subset of the CJK unified ideographs as well as Japanese Han characters + * that may be defined as surrogate characters. + */ + public static final InputSubset KANJI = new InputSubset("KANJI"); + + /** + * Constant for all Han characters used in writing Korean, including a + * subset of the CJK unified ideographs as well as Korean Han characters + * that may be defined as surrogate characters. + */ + public static final InputSubset HANJA = new InputSubset("HANJA"); + + /** + * Constant for the halfwidth katakana subset of the Unicode halfwidth and + * fullwidth forms character block. + */ + public static final InputSubset HALFWIDTH_KATAKANA + = new InputSubset("HALFWIDTH_KATAKANA"); + + /** + * Constant for the fullwidth ASCII variants subset of the Unicode + * halfwidth and fullwidth forms character block. + * + * @since 1.3 + */ + public static final InputSubset FULLWIDTH_LATIN + = new InputSubset("FULLWIDTH_LATIN"); + + /** + * Constant for the fullwidth digits included in the Unicode halfwidth and + * fullwidth forms character block. + * + * @since 1.3 + */ + public static final InputSubset FULLWIDTH_DIGITS + = new InputSubset("FULLWIDTH_DIGITS"); + + /** + * Construct a subset. + * + * @param name the subset name + */ + private InputSubset(String name) + { + super(name); + } +} // class InputSubset diff --git a/libjava/classpath/java/awt/im/package.html b/libjava/classpath/java/awt/im/package.html new file mode 100644 index 0000000..895da66 --- /dev/null +++ b/libjava/classpath/java/awt/im/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.im + + +

    Support for text input methods.

    + + + diff --git a/libjava/classpath/java/awt/im/spi/InputMethod.java b/libjava/classpath/java/awt/im/spi/InputMethod.java new file mode 100644 index 0000000..840d193 --- /dev/null +++ b/libjava/classpath/java/awt/im/spi/InputMethod.java @@ -0,0 +1,240 @@ +/* InputMethod.java -- defines an interface for complex text input + 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 java.awt.im.spi; + +import java.awt.AWTEvent; +import java.awt.Rectangle; +import java.util.Locale; + +/** + * This interface supports complex text input, often for situations where + * the text is more complex than a keyboard will accomodate. For example, + * this can be used for Chinese, Japanese, and Korean, where multiple + * keystrokes are necessary to compose text. This could also support things + * like phonetic English, or reordering Thai. + * + *

    These contexts can be loaded by the input method framework, using + * {@link InputContext#selectInputMethod(Locale)}. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ +public interface InputMethod +{ + /** + * Set the input method context, which ties the input method to a client + * component. This is called once automatically when creating the input + * method. + * + * @param context the context for this input method + * @throws NullPointerException if context is null + */ + void setInputMethodContext(InputMethodContext context); + + /** + * Sets the input locale. If the input method supports that locale, it + * changes its behavior to be consistent with the locale and returns true. + * Otherwise, it returns false. This is called by + * {@link InputContext#selectInputMethod(Locale)} when the user specifies + * a locale, or when the previously selected input method had a locale. + * + * @param locale the locale to use for input + * @return true if the change is successful + * @throws NullPointerException if locale is null + */ + boolean setLocale(Locale locale); + + /** + * Returns the current input locale, or null if none is defined. This is + * called by {@link InputContext#getLocale()}, or before switching input + * methods. + * + * @return the current input locale, or null + */ + Locale getLocale(); + + /** + * Sets the allowed Unicode subsets that this input method can use. Null + * indicates that all characters are allowed. This is called after creation, + * or when switching to this input method, by + * {@link InputContext#setCharacterSubsets(Character.Subset[])}. + * + * @param subsets the accepted subsets for this input method, or null for all + */ + void setCharacterSubsets(Character.Subset[] subsets); + + /** + * Changes the enabled status of this input method. An enabled input method + * accepts incoming events for composition and control purposes, while a + * disabled input method ignores events (except for control purposes). This + * is called by {@link InputContext#setCompositionEnabled(boolean)} or when + * switching from an input method if the previous input method returned + * without exception on {@link #isCompositionEnabled()}. + * + * @param enable whether to enable this input method + * @throws UnsupportedOperationException if enabling/disabling is unsupported + * @see #isCompositionEnabled() + */ + void setCompositionEnabled(boolean enable); + + /** + * Find out if this input method is enabled. This is called by + * {@link InputContext#isCompositionEnabled()}, or when switching input + * methods via {@link InputContext#selectInputMethod(Locale)}. + * + * @return true if this input method is enabled + * @throws UnsupportedOperationException if enabling/disabling is unsupported + * @see #setCompositionEnabled(boolean) + */ + boolean isCompositionEnabled(); + + /** + * Starts a reconversion operation. The input method gets its text from the + * client, using {@link InputMethodRequests#getSelectedText(Attribute[])}. + * Then the composed and committed text produced by the operation is sent + * back to the client using a sequence of InputMethodEvents. This is called + * by {@link InputContext#reconvert()}. + * + * @throws UnsupportedOperationException if reconversion is unsupported + */ + void reconvert(); + + /** + * Dispatch an event to the input method. If input method support is enabled, + * certain events are dispatched to the input method before the client + * component or event listeners. The input method must either consume the + * event or pass it on to the component. Instances of InputEvent, including + * KeyEvent and MouseEvent, are given to this input method. This method is + * called by {@link InputContext#dispatchEvent(AWTEvent)}. + * + * @param event the event to dispatch + * @throws NullPointerException if event is null + */ + void dispatchEvent(AWTEvent event); + + /** + * Notify this input method of changes in the client window. This is called + * when notifications are enabled (see {@link + * InputMethodContext#enableClientWindowNotification(InputMethod, boolean)}, + * if {@link #removeNotify(Component)} has not been called. The following + * situations trigger a notification:

      + *
    • The client window changes in location, size, visibility, + * iconification, or is closed.
    • + *
    • When enabling client notification (or on the first activation after + * enabling if no client existed at the time).
    • + *
    • When activating a new client after removeNotify was + * called on a previous client.
    • + *
    + * + * @param bounds the client window's current bounds, or null + */ + void notifyClientWindowChange(Rectangle bounds); + + /** + * Activate this input method for input processing. If the input method + * provides its own windows, it should make them open and visible at this + * time. This method is called when a client component receives a + * FOCUS_GAINED event, or when switching to this input method from another + * one. It is only called when the input method is inactive, assuming that + * new instances begin in an inactive state. + */ + void activate(); + + /** + * Deactivate this input method, either temporarily or permanently for the + * given client. If the input method provides its own windows, it should + * only close those related to the current composition (such as a lookup + * choice panel), while leaving more persistant windows (like a control + * panel) open to avoid screen flicker. Before control is given to another + * input method, {@link #hideWindows()} will be called on this instance. + * This method is called when a client component receives a + * FOCUS_LOST event, when switching to another input method, or before + * {@link #removeNotify()} when the client is removed. + * + * @param isTemporary true if the focus change is temporary + */ + void deactivate(boolean isTemporary); + + /** + * Close or hide all windows opened by this input method. This is called + * before activating a different input method, and before calling + * {@link #dispose()} on this instance. It is only called when the input + * method is inactive. + */ + void hideWindows(); + + /** + * Notify the input method that a client component has been removed from its + * hierarchy, or that input method support has been disabled. This is + * called by {@link InputContext#removeNotify()}, and only when the input + * method is inactive. + */ + void removeNotify(); + + /** + * End any input composition currently taking place. Depending on the + * platform and user preferences, this may commit or delete uncommitted text, + * using input method events. This may be called for a variety of reasons, + * such as when the user moves the insertion point in the client text outside + * the range of the composed text, or when text is saved to file. This is + * called by {@link InputContext#endComposition()}, when switching to a + * new input method, or by {@link InputContext#selectInputMethod(Locale)}. + */ + void endComposition(); + + /** + * Disposes the input method and release any resources it is using. In + * particular, the input method should dispose windows and close files. This + * is called by {@link InputContext#dispose()}, when the input method is + * inactive; and nothing will be called on this instance afterwards. + */ + void dispose(); + + /** + * Returns a control object from this input method, or null. A control object + * provides method to control the behavior of this input method, as well as + * query information about it. The object is implementation dependent, so + * clients must compare the result against known input method control + * object types. This is called by + * {@link InputContext#getInputMethodControlObject()}. + * + * @return the control object, or null + */ + Object getControlObject(); +} // interface InputMethod diff --git a/libjava/classpath/java/awt/im/spi/InputMethodContext.java b/libjava/classpath/java/awt/im/spi/InputMethodContext.java new file mode 100644 index 0000000..43bee8d --- /dev/null +++ b/libjava/classpath/java/awt/im/spi/InputMethodContext.java @@ -0,0 +1,123 @@ +/* InputMethodContext.java -- communication between an input method and client + 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 java.awt.im.spi; + +import java.awt.Window; +import java.awt.font.TextHitInfo; +import java.awt.im.InputMethodRequests; +import java.text.AttributedCharacterIterator; + +import javax.swing.JFrame; + +/** + * Provides methods for the communication context between an input method + * and the client component. This should be passed to + * {@link InputMethod#setInputMethodContext(InputMethodContext)}. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ +public interface InputMethodContext extends InputMethodRequests +{ + /** + * Create an input method event and dispatch it to the client. + * + * @param id the event type + * @param text an iterator over the text to be committed + * @param count the count of characters to be committed + * @param caret the insertion point of the commit, or null + * @param visiblePosition the best location to make visible, or null + */ + void dispatchInputMethodEvent(int id, AttributedCharacterIterator text, + int count, TextHitInfo caret, + TextHitInfo visiblePosition); + + /** + * Creates a top-level window for use by the input method. This window should + * float above all document windows and dialogs, not receive focus, and have + * lightweight decorations (such as no title, reduced drag regions). But + * this behavior may be modified to meet the platform style. The title may + * or may not be displayed, depending on the platform. + * + *

    If attachToInputContext is true, the new window will share the input + * context of the input method, so that events in the new window are + * dispatched to the input method. Also, this supresses deactivate and + * activate calls to the input method caused by setVisible. + * + * @param title the window title, if one is displayed; null becomes "" + * @param attachToInputContext true for the window to share context with + * the input method + * @return the new window for use by the input method + * @throws HeadlessException if GraphicsEnvironment.isHeadless is true + */ + Window createInputMethodWindow(String title, boolean attachToInputContext); + + /** + * Creates a top-level Swing JFrame for use by the input method. This frame + * should float above all document windows and dialogs, not receive focus, + * and have lightweight decorations (such as no title, reduced drag + * regions). But this behavior may be modified to meet the platform style. + * The title may or may not be displayed, depending on the platform. + * + *

    If attachToInputContext is true, the new window will share the input + * context of the input method, so that events in the new window are + * dispatched to the input method. Also, this supresses deactivate and + * activate calls to the input method caused by setVisible. + * + * @param title the window title, if one is displayed; null becomes "" + * @param attachToInputContext true for the window to share context with + * the input method + * @return the new window for use by the input method + * @throws HeadlessException if GraphicsEnvironment.isHeadless is true + * @since 1.4 + */ + JFrame createInputMethodJFrame(String title, boolean attachToInputContext); + + /** + * Sets whether notification of the client window's location and state should + * be enabled for the input method. When enabled, the input method's + * {@link #notifyClientWindowChange(Rectangle)} method is called. + * Notification is automatically disabled when the input method is disposed. + * + * @param inputMethod the method to change status of + * @param enable true to enable notification + */ + void enableClientWindowNotification(InputMethod inputMethod, boolean enable); +} // interface InputMethodContext diff --git a/libjava/classpath/java/awt/im/spi/InputMethodDescriptor.java b/libjava/classpath/java/awt/im/spi/InputMethodDescriptor.java new file mode 100644 index 0000000..093d731 --- /dev/null +++ b/libjava/classpath/java/awt/im/spi/InputMethodDescriptor.java @@ -0,0 +1,113 @@ +/* InputMethodDescriptor.java -- enables loading and use of an input method + 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 java.awt.im.spi; + +import java.awt.AWTException; +import java.awt.Image; +import java.util.Locale; + +/** + * This interface provides information about an InputMethod before it is + * loaded. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ +public interface InputMethodDescriptor +{ + /** + * Returns the locales supported by the input method this describes. This + * allows the selection of input methods by locale (by language only, or + * also by country and variant), via + * {@link InputContext#selectInputMethod(Locale)}. The returned list should + * ignore pass-through locales, so it is usually a subset of locales for + * which {@link InputMethod#setContext(Locale)} returns true. If + * {@link #hasDynamicLocaleList()} returns true, this is called each time + * information is needed, allowing dynamic addition or removal of supported + * locales. + * + * @return the list of supported locales + * @throws AWTException if the input method is not available + */ + Locale[] getAvailableLocales() throws AWTException; + + /** + * Test whether the input method this describes has a static or dynamic + * locale list. For example, this would return true if the list of supported + * locales depends on adapters currently loaded over a network. + * + * @return true if the locale list is dynamic + */ + boolean hasDynamicLocaleList(); + + /** + * Returns a user visible name of the input locale, displayed in the + * specified locale. The inputLocale parameter must be one obtained from + * the list in {@link #getAvailableLocales()}, or null for a + * locale-independent description of the input method. If a translation to + * the desired display language is not available, another language may be + * used. + * + * @param inputLocale the locale of the input method, or null + * @param displayLanguage the language of the result + * @return the name of the input method when using the given inputLocale + */ + String getInputMethodDisplayName(Locale inputLocale, + Locale displayLanguage); + + /** + * Returns a 16x16 icon for the input locale. The inputLocale parameter + * must be one obtained from the list in {@link #getAvailableLocales()}, or + * null for a locale-independent icon for the input method. + * + * @param inputLocale the locale of the input method, or null + * @return a 16x16 icon for the input method when using the given inputLocale + */ + Image getInputMethodIcon(Locale inputLocale); + + /** + * Creates a new instance of the input method. + * + * @return the newly created input method + * @throws Exception if anything goes wrong + */ + InputMethod createInputMethod() throws Exception; + +} // interface InputMethodDescriptor + diff --git a/libjava/classpath/java/awt/im/spi/package.html b/libjava/classpath/java/awt/im/spi/package.html new file mode 100644 index 0000000..c526ee1 --- /dev/null +++ b/libjava/classpath/java/awt/im/spi/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.im.spi + + +

    Interfaces for implementation of text input methods.

    + + + diff --git a/libjava/classpath/java/awt/image/AffineTransformOp.java b/libjava/classpath/java/awt/image/AffineTransformOp.java new file mode 100644 index 0000000..f11066e --- /dev/null +++ b/libjava/classpath/java/awt/image/AffineTransformOp.java @@ -0,0 +1,375 @@ +/* AffineTransformOp.java -- This class performs affine + transformation between two images or rasters in 2 dimensions. + 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 java.awt.image; + +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +/** + * This class performs affine transformation between two images or + * rasters in 2 dimensions. + * + * @author Olga Rodimina (rodimina@redhat.com) + */ +public class AffineTransformOp implements BufferedImageOp, RasterOp +{ + public static final int TYPE_NEAREST_NEIGHBOR = 1; + + public static final int TYPE_BILINEAR = 2; + + /** + * @since 1.5.0 + */ + public static final int TYPE_BICUBIC = 3; + + private AffineTransform transform; + private RenderingHints hints; + + /** + * Construct AffineTransformOp with the given xform and interpolationType. + * Interpolation type can be TYPE_BILINEAR, TYPE_BICUBIC or + * TYPE_NEAREST_NEIGHBOR. + * + * @param xform AffineTransform that will applied to the source image + * @param interpolationType type of interpolation used + */ + public AffineTransformOp (AffineTransform xform, int interpolationType) + { + this.transform = xform; + if (xform.getDeterminant() == 0) + throw new ImagingOpException(null); + + switch (interpolationType) + { + case TYPE_BILINEAR: + hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + break; + case TYPE_BICUBIC: + hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + break; + default: + hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); + } + } + + /** + * Construct AffineTransformOp with the given xform and rendering hints. + * + * @param xform AffineTransform that will applied to the source image + * @param hints rendering hints that will be used during transformation + */ + public AffineTransformOp (AffineTransform xform, RenderingHints hints) + { + this.transform = xform; + this.hints = hints; + if (xform.getDeterminant() == 0) + throw new ImagingOpException(null); + } + + /** + * Creates empty BufferedImage with the size equal to that of the + * transformed image and correct number of bands. The newly created + * image is created with the specified ColorModel. + * If the ColorModel is equal to null, then image is created + * with the ColorModel of the source image. + * + * @param src source image + * @param destCM color model for the destination image + * @return new compatible destination image + */ + public BufferedImage createCompatibleDestImage (BufferedImage src, + ColorModel destCM) + { + + // if destCm is not specified, use color model of the source image + + if (destCM == null) + destCM = src.getColorModel (); + + return new BufferedImage (destCM, + createCompatibleDestRaster (src.getRaster ()), + src.isAlphaPremultiplied (), + null); + + } + + /** + * Creates empty WritableRaster with the size equal to the transformed + * source raster and correct number of bands + * + * @param src source raster + * @throws RasterFormatException if resulting width or height of raster is 0 + * @return new compatible raster + */ + public WritableRaster createCompatibleDestRaster (Raster src) + { + Rectangle rect = (Rectangle) getBounds2D (src); + + // throw RasterFormatException if resulting width or height of the + // transformed raster is 0 + + if (rect.getWidth () == 0 || rect.getHeight () == 0) + throw new RasterFormatException("width or height is 0"); + + return src.createCompatibleWritableRaster ((int) rect.getWidth (), + (int) rect.getHeight ()); + } + + /** + * Transforms source image using transform specified at the constructor. + * The resulting transformed image is stored in the destination image. + * + * @param src source image + * @param dst destination image + * @return transformed source image + */ + public final BufferedImage filter (BufferedImage src, BufferedImage dst) + { + + if (dst == src) + throw new IllegalArgumentException ("src image cannot be the same as the dst image"); + + // If the destination image is null, then BufferedImage is + // created with ColorModel of the source image + + if (dst == null) + dst = createCompatibleDestImage(src, src.getColorModel ()); + + // FIXME: Must check if color models of src and dst images are the same. + // If it is not, then source image should be converted to color model + // of the destination image + + Graphics2D gr = (Graphics2D) dst.createGraphics (); + gr.setRenderingHints (hints); + gr.drawImage (src, transform, null); + return dst; + + } + + /** + * Transforms source raster using transform specified at the constructor. + * The resulting raster is stored in the destination raster. + * + * @param src source raster + * @param dst destination raster + * @return transformed raster + */ + public final WritableRaster filter (Raster src, WritableRaster dst) + { + if (dst == src) + throw new IllegalArgumentException("src image cannot be the same as" + + " the dst image"); + + if (dst == null) + dst = createCompatibleDestRaster(src); + + if (src.getNumBands() != dst.getNumBands()) + throw new IllegalArgumentException("src and dst must have same number" + + " of bands"); + + double[] dpts = new double[dst.getWidth() * 2]; + double[] pts = new double[dst.getWidth() * 2]; + for (int x = 0; x < dst.getWidth(); x++) + { + dpts[2 * x] = x + dst.getMinX(); + dpts[2 * x + 1] = x; + } + Rectangle srcbounds = src.getBounds(); + if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) + { + for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++) + { + try { + transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2); + } catch (NoninvertibleTransformException e) { + // Can't happen since the constructor traps this + e.printStackTrace(); + } + + for (int x = 0; x < dst.getWidth(); x++) + { + if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1])) + continue; + dst.setDataElements(x + dst.getMinX(), y, + src.getDataElements((int)pts[2 * x], + (int)pts[2 * x + 1], + null)); + } + } + } + else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) + { + double[] tmp = new double[4 * src.getNumBands()]; + for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++) + { + try { + transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2); + } catch (NoninvertibleTransformException e) { + // Can't happen since the constructor traps this + e.printStackTrace(); + } + + for (int x = 0; x < dst.getWidth(); x++) + { + if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1])) + continue; + int xx = (int)pts[2 * x]; + int yy = (int)pts[2 * x + 1]; + double dx = (pts[2 * x] - xx); + double dy = (pts[2 * x + 1] - yy); + + // TODO write this more intelligently + if (xx == src.getMinX() + src.getWidth() - 1 || + yy == src.getMinY() + src.getHeight() - 1) + { + // bottom or right edge + Arrays.fill(tmp, 0); + src.getPixel(xx, yy, tmp); + } + else + { + // Normal case + src.getPixels(xx, yy, 2, 2, tmp); + for (int b = 0; b < src.getNumBands(); b++) + tmp[b] = dx * dy * tmp[b] + + (1 - dx) * dy * tmp[b + src.getNumBands()] + + dx * (1 - dy) * tmp[b + 2 * src.getNumBands()] + + (1 - dx) * (1 - dy) * tmp[b + 3 * src.getNumBands()]; + } + dst.setPixel(x, y, tmp); + } + } + } + else + { + // Bicubic + throw new UnsupportedOperationException("not implemented yet"); + } + + return dst; + } + + /** + * Transforms source image using transform specified at the constructor and + * returns bounds of the transformed image. + * + * @param src image to be transformed + * @return bounds of the transformed image. + */ + public final Rectangle2D getBounds2D (BufferedImage src) + { + return getBounds2D (src.getRaster()); + } + + /** + * Returns bounds of the transformed raster. + * + * @param src raster to be transformed + * @return bounds of the transformed raster. + */ + public final Rectangle2D getBounds2D (Raster src) + { + // determine new size for the transformed raster. + // Need to calculate transformed coordinates of the lower right + // corner of the raster. The upper left corner is always (0,0) + + double x2 = (double) src.getWidth () + src.getMinX (); + double y2 = (double) src.getHeight () + src.getMinY (); + Point2D p2 = getPoint2D (new Point2D.Double (x2,y2), null); + + Rectangle2D rect = new Rectangle (0, 0, (int) p2.getX (), (int) p2.getY ()); + return rect.getBounds (); + } + + /** + * Returns interpolation type used during transformations + * + * @return interpolation type + */ + public final int getInterpolationType () + { + if(hints.containsValue (RenderingHints.VALUE_INTERPOLATION_BILINEAR)) + return TYPE_BILINEAR; + else + return TYPE_NEAREST_NEIGHBOR; + } + + /** + * Returns location of the transformed source point. The resulting point + * is stored in the dstPt if one is specified. + * + * @param srcPt point to be transformed + * @param dstPt destination point + * @return the location of the transformed source point. + */ + public Point2D getPoint2D (Point2D srcPt, Point2D dstPt) + { + return transform.transform (srcPt, dstPt); + } + + /** + * Returns rendering hints that are used during transformation. + * + * @return rendering hints + */ + public final RenderingHints getRenderingHints () + { + return hints; + } + + /** + * Returns transform used in transformation between source and destination + * image. + * + * @return transform + */ + public final AffineTransform getTransform () + { + return transform; + } +} diff --git a/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java b/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java new file mode 100644 index 0000000..b9ca1b7 --- /dev/null +++ b/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java @@ -0,0 +1,127 @@ +/* AreaAveragingScaleFilter.java -- Java class for filtering images + Copyright (C) 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 java.awt.image; + +/** + * This filter should produce images which do not have image artifacts + * like broken lines which were originally unbroken. The cost is of + * course speed. Using bi-linear interpolation here against 4 pixel + * points should give the desired results although Sun does not + * specify what the exact algorithm should be. + *
    + * Currently this filter does nothing and needs to be implemented. + * + * @author C. Brian Jones (cbj@gnu.org) + */ +public class AreaAveragingScaleFilter extends ReplicateScaleFilter +{ + /** + * Construct an instance of AreaAveragingScaleFilter which + * should be used in conjunction with a FilteredImageSource + * object. + * + * @param width the width of the destination image + * @param height the height of the destination image + */ + public AreaAveragingScaleFilter(int width, int height) { + super(width, height); + } + + /** + * The ImageProducer should call this method with a + * bit mask of hints from any of RANDOMPIXELORDER, + * TOPDOWNLEFTRIGHT, COMPLETESCANLINES, + * SINGLEPASS, SINGLEFRAME from the + * ImageConsumer interface. + *
    + * FIXME - more than likely Sun's implementation desires + * TOPDOWNLEFTRIGHT order and this method is overloaded here + * in order to assure that mask is part of the hints added to + * the consumer. + * + * @param flags a bit mask of hints + * @see ImageConsumer + */ + public void setHints(int flags) + { + consumer.setHints(flags); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a byte at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize) + { + consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an int at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize) + { + consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + } + +} + diff --git a/libjava/classpath/java/awt/image/BandCombineOp.java b/libjava/classpath/java/awt/image/BandCombineOp.java new file mode 100644 index 0000000..79efb02 --- /dev/null +++ b/libjava/classpath/java/awt/image/BandCombineOp.java @@ -0,0 +1,168 @@ +/* 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 java.awt.image; + +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * Filter Raster pixels by applying a matrix. + * + * BandCombineOp applies a matrix to each pixel to produce new pixel values. + * The width of the matrix must be the same or one more than the number of + * bands in the source Raster. If one more, the pixels in the source are + * assumed to contain an implicit 1.0 at the end. + * + * The rows of the matrix are multiplied by the pixel to produce the values + * for the destination. Therefore the destination Raster must contain the + * same number of bands as the number of rows in the filter matrix. + * + * @author Jerry Quinn (jlquinn@optonline.net) + */ +public class BandCombineOp implements RasterOp +{ + private RenderingHints hints; + private float[][] matrix; + + /** + * Construct a BandCombineOp. + * + * @param matrix The matrix to filter pixels with. + * @param hints Rendering hints to apply. Ignored. + */ + public BandCombineOp(float[][] matrix, RenderingHints hints) + { + this.matrix = matrix; + this.hints = hints; + } + + /** + * Filter Raster pixels through a matrix. + * + * Applies the Op matrix to source pixes to produce dest pixels. Each row + * of the matrix is multiplied by the src pixel components to produce the + * dest pixel. If matrix is one more than the number of bands in the src, + * the last element is implicitly multiplied by 1, i.e. added to the sum + * for that dest component. + * + * If dest is null, a suitable Raster is created. This implementation uses + * createCompatibleDestRaster. + * + * @param src The source Raster. + * @param dest The destination Raster, or null. + * @returns The destination Raster or an allocated Raster. + * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, + *java.awt.image.WritableRaster) + */ + public WritableRaster filter(Raster src, WritableRaster dest) { + if (dest == null) + dest = createCompatibleDestRaster(src); + + // Filter the pixels + float[] spix = new float[matrix[0].length]; + float[] dpix = new float[matrix.length]; + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + { + // In case matrix rows have implicit translation + spix[spix.length - 1] = 1.0f; + src.getPixel(x, y, spix); + for (int i = 0; i < matrix.length; i++) + { + dpix[i] = 0; + for (int j = 0; j < matrix[0].length; j++) + dpix[i] += spix[j] * matrix[i][j]; + } + dest.setPixel(x, y, dpix); + } + + return dest; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) + */ + public Rectangle2D getBounds2D(Raster src) + { + return src.getBounds(); + } + + /** + * Creates a new WritableRaster that can be used as the destination for this + * Op. This implementation creates a Banded Raster with data type FLOAT. + * @see + *java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) + */ + public WritableRaster createCompatibleDestRaster(Raster src) + { + return Raster.createBandedRaster(DataBuffer.TYPE_FLOAT, src.getWidth(), + src.getHeight(), matrix.length, + new Point(src.getMinX(), src.getMinY())); + } + + /** Return corresponding destination point for source point. + * + * LookupOp will return the value of src unchanged. + * @param src The source point. + * @param dst The destination point. + * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, + *java.awt.geom.Point2D) + */ + public Point2D getPoint2D(Point2D src, Point2D dst) + { + if (dst == null) return (Point2D)src.clone(); + dst.setLocation(src); + return dst; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getRenderingHints() + */ + public RenderingHints getRenderingHints() + { + return hints; + } + + /** Return the matrix for this Op. */ + public float[][] getMatrix() + { + return matrix; + } + +} diff --git a/libjava/classpath/java/awt/image/BandedSampleModel.java b/libjava/classpath/java/awt/image/BandedSampleModel.java new file mode 100644 index 0000000..24d315a --- /dev/null +++ b/libjava/classpath/java/awt/image/BandedSampleModel.java @@ -0,0 +1,548 @@ +/* Copyright (C) 2004, 2005, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/** + * MultiPixelPackedSampleModel provides a single band model that supports + * multiple pixels in a single unit. Pixels have 2^n bits and 2^k pixels fit + * per data element. + * + * @author Jerry Quinn (jlquinn@optonline.net) + */ +public final class BandedSampleModel extends ComponentSampleModel +{ + private int[] bitMasks; + private int[] bitOffsets; + private int[] sampleSize; + private int dataBitOffset; + private int elemBits; + private int numberOfBits; + private int numElems; + + private static int[] createBankArray(int size) + { + int[] result = new int[size]; + for (int i = 0; i < size; i++) + result[i] = i; + return result; + } + + public BandedSampleModel(int dataType, int w, int h, int numBands) + { + this(dataType, w, h, w, createBankArray(numBands), new int[numBands]); + } + + public BandedSampleModel(int dataType, int w, int h, int scanlineStride, + int[] bankIndices, int[] bandOffsets) + { + super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets); + } + + public SampleModel createCompatibleSampleModel(int w, int h) + { + // NOTE: blackdown 1.4.1 sets all offsets to 0. Sun's 1.4.2 docs + // disagree. + + // Compress offsets so minimum is 0, others w*scanlineStride + int[] newoffsets = new int[bandOffsets.length]; + int[] order = new int[bandOffsets.length]; + for (int i=0; i < bandOffsets.length; i++) + order[i] = i; + // FIXME: This is N^2, but not a big issue, unless there's a lot of + // bands... + for (int i=0; i < bandOffsets.length; i++) + for (int j=i+1; j < bandOffsets.length; i++) + if (bankIndices[order[i]] > bankIndices[order[j]] + || (bankIndices[order[i]] == bankIndices[order[j]] + && bandOffsets[order[i]] > bandOffsets[order[j]])) + { + int t = order[i]; order[i] = order[j]; order[j] = t; + } + int bank = 0; + int offset = 0; + for (int i=0; i < bandOffsets.length; i++) + { + if (bankIndices[order[i]] != bank) + { + bank = bankIndices[order[i]]; + offset = 0; + } + newoffsets[order[i]] = offset; + offset += w * scanlineStride; + } + + return new BandedSampleModel(dataType, w, h, scanlineStride, bankIndices, newoffsets); + } + + + public SampleModel createSubsetSampleModel(int[] bands) + { + if (bands.length > bankIndices.length) + throw new + RasterFormatException("BandedSampleModel createSubsetSampleModel too" + +" many bands"); + int[] newoff = new int[bands.length]; + int[] newbanks = new int[bands.length]; + for (int i=0; i < bands.length; i++) + { + int b = bands[i]; + newoff[i] = bandOffsets[b]; + newbanks[i] = bankIndices[b]; + } + + return new BandedSampleModel(dataType, width, height, scanlineStride, + newbanks, newoff); + } + + /** + * Extract all samples of one pixel and return in an array of transfer type. + * + * Extracts the pixel at x, y from data and stores samples into the array + * obj. If obj is null, a new array of getTransferType() is created. + * + * @param x The x-coordinate of the pixel rectangle to store in obj. + * @param y The y-coordinate of the pixel rectangle to store in obj. + * @param obj The primitive array to store the pixels into or null to force creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + * @see java.awt.image.SampleModel#getDataElements(int, int, java.lang.Object, java.awt.image.DataBuffer) + */ + public Object getDataElements(int x, int y, Object obj, + DataBuffer data) + { + int pixel = getSample(x, y, 0, data); + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + { + byte[] b = (byte[])obj; + if (b == null) b = new byte[numBands]; + for (int i=0; i < numBands; i++) + b[i] = (byte)getSample(x, y, i, data); + return b; + } + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + { + short[] b = (short[])obj; + if (b == null) b = new short[numBands]; + for (int i=0; i < numBands; i++) + b[i] = (short)getSample(x, y, i, data); + return b; + } + case DataBuffer.TYPE_INT: + { + int[] b = (int[])obj; + if (b == null) b = new int[numBands]; + for (int i=0; i < numBands; i++) + b[i] = getSample(x, y, i, data); + return b; + } + case DataBuffer.TYPE_FLOAT: + { + float[] b = (float[])obj; + if (b == null) b = new float[numBands]; + for (int i=0; i < numBands; i++) + b[i] = getSampleFloat(x, y, i, data); + return b; + } + case DataBuffer.TYPE_DOUBLE: + { + double[] b = (double[])obj; + if (b == null) b = new double[numBands]; + for (int i=0; i < numBands; i++) + b[i] = getSample(x, y, i, data); + return b; + } + + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } + } + + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + if (iArray == null) iArray = new int[numBands]; + for (int i=0; i < numBands; i++) + iArray[i] = getSample(x, y, i, data); + + return iArray; + } + + /** + * Copy pixels from a region into an array. + * + * Copies the samples of the pixels in the rectangle starting at x, y that + * is w pixels wide and h scanlines high. When there is more than one band, + * the samples stored in order before the next pixel. This ordering isn't + * well specified in Sun's docs as of 1.4.2. + * + * If iArray is null, a new array is allocated, filled, and returned. + * + * @param x The x-coordinate of the pixel rectangle to store in + * iArray. + * @param y The y-coordinate of the pixel rectangle to store in + * iArray. + * @param w The width in pixels of the rectangle. + * @param h The height in pixels of the rectangle. + * @param iArray The int array to store the pixels into or null to force + * creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + */ + public int[] getPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + if (iArray == null) iArray = new int[w*h*numBands]; + int outOffset = 0; + int maxX = x + w; + int maxY = y + h; + for (int yy = x; yy < maxY; yy++) + { + for (int xx = x; xx < maxX; xx++) + { + for (int b = 0; b < numBands; b++) + { + int offset = bandOffsets[b] + yy * scanlineStride + xx; + iArray[outOffset++] = + data.getElem(bankIndices[b], offset); + } + } + } + return iArray; + } + + public int getSample(int x, int y, int b, DataBuffer data) + { + int offset = bandOffsets[b] + y * scanlineStride + x; + return data.getElem(bankIndices[b], offset); + } + + public float getSampleFloat(int x, int y, int b, DataBuffer data) + { + int offset = bandOffsets[b] + y * scanlineStride + x; + return data.getElemFloat(bankIndices[b], offset); + } + + public double getSampleDouble(int x, int y, int b, DataBuffer data) + { + int offset = bandOffsets[b] + y * scanlineStride + x; + return data.getElemDouble(bankIndices[b], offset); + } + + /** + * Copy one band's samples from a region into an array. + * + * Copies from one band the samples of the pixels in the rectangle starting + * at x, y that is w pixels wide and h scanlines high. + * + * If iArray is null, a new array is allocated, filled, and returned. + * + * @param x The x-coordinate of the pixel rectangle to store in + * iArray. + * @param y The y-coordinate of the pixel rectangle to store in + * iArray. + * @param w The width in pixels of the rectangle. + * @param h The height in pixels of the rectangle. + * @param b The band to retrieve. + * @param iArray The int array to store the pixels into or null to force + * creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + */ + public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, + DataBuffer data) + { + if (iArray == null) iArray = new int[w*h]; + int outOffset = 0; + int maxX = x + w; + int maxY = y + h; + for (int yy = y; yy < maxY; yy++) + { + for (int xx = x; xx < maxX; xx++) + { + int offset = bandOffsets[b] + yy * scanlineStride + xx; + iArray[outOffset++] = + data.getElem(bankIndices[b], offset); + } + } + return iArray; + } + + + /** + * Set the pixel at x, y to the value in the first element of the primitive + * array obj. + * + * @param x The x-coordinate of the data elements in obj. + * @param y The y-coordinate of the data elements in obj. + * @param obj The primitive array containing the data elements to set. + * @param data The DataBuffer to store the data elements into. + * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer) + */ + public void setDataElements(int x, int y, Object obj, DataBuffer data) + { + int transferType = getTransferType(); + if (getTransferType() != data.getDataType()) + { + throw new IllegalArgumentException("transfer type ("+ + getTransferType()+"), "+ + "does not match data "+ + "buffer type (" + + data.getDataType() + + ")."); + } + + int offset = y * scanlineStride + x; + + try + { + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + { + DataBufferByte out = (DataBufferByte) data; + byte[] in = (byte[]) obj; + for (int i=0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_SHORT: + { + DataBufferShort out = (DataBufferShort) data; + short[] in = (short[]) obj; + for (int i=0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_USHORT: + { + DataBufferUShort out = (DataBufferUShort) data; + short[] in = (short[]) obj; + for (int i=0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_INT: + { + DataBufferInt out = (DataBufferInt) data; + int[] in = (int[]) obj; + for (int i=0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_FLOAT: + { + DataBufferFloat out = (DataBufferFloat) data; + float[] in = (float[]) obj; + for (int i=0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_DOUBLE: + { + DataBufferDouble out = (DataBufferDouble) data; + double[] in = (double[]) obj; + for (int i=0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + default: + throw new ClassCastException("Unsupported data type"); + } + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + String msg = "While writing data elements" + + ", x="+x+", y="+y+ + ", width="+width+", height="+height+ + ", scanlineStride="+scanlineStride+ + ", offset="+offset+ + ", data.getSize()="+data.getSize()+ + ", data.getOffset()="+data.getOffset()+ + ": " + + aioobe; + throw new ArrayIndexOutOfBoundsException(msg); + } + } + + public void setPixel(int x, int y, int[] iArray, DataBuffer data) + { + for (int b=0; b < numBands; b++) + data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, + iArray[b]); + } + + public void setPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int inOffset = 0; + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = y * scanlineStride + (x + ww); + for (int b=0; b < numBands; b++) + data.setElem(bankIndices[b], bandOffsets[b] + offset, + iArray[inOffset++]); + } + y++; + } + } + + public void setSample(int x, int y, int b, int s, DataBuffer data) + { + data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s); + } + + public void setSample(int x, int y, int b, float s, DataBuffer data) + { + data.setElemFloat(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s); + } + + public void setSample(int x, int y, int b, double s, DataBuffer data) + { + data.setElemDouble(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s); + } + + public void setSamples(int x, int y, int w, int h, int b, int[] iArray, + DataBuffer data) + { + int inOffset = 0; + + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + { + DataBufferByte out = (DataBufferByte) data; + byte[] bank = out.getData(bankIndices[b]); + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + bank[offset] = (byte)iArray[inOffset++]; + } + y++; + } + return; + } + case DataBuffer.TYPE_SHORT: + { + DataBufferShort out = (DataBufferShort) data; + short[] bank = out.getData(bankIndices[b]); + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + bank[offset] = (short)iArray[inOffset++]; + } + y++; + } + return; + } + case DataBuffer.TYPE_USHORT: + { + DataBufferShort out = (DataBufferShort) data; + short[] bank = out.getData(bankIndices[b]); + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + bank[offset] = (short)iArray[inOffset++]; + } + y++; + } + return; + } + case DataBuffer.TYPE_INT: + { + DataBufferInt out = (DataBufferInt) data; + int[] bank = out.getData(bankIndices[b]); + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + bank[offset] = iArray[inOffset++]; + } + y++; + } + return; + } + case DataBuffer.TYPE_FLOAT: + case DataBuffer.TYPE_DOUBLE: + break; + default: + throw new ClassCastException("Unsupported data type"); + } + + // Default implementation probably slower for float and double + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + data.setElem(bankIndices[b], offset, iArray[inOffset++]); + } + y++; + } + } + + /** + * Creates a String with some information about this SampleModel. + * @return A String describing this SampleModel. + * @see java.lang.Object#toString() + */ + public String toString() + { + StringBuffer result = new StringBuffer(); + result.append(getClass().getName()); + result.append("["); + result.append("scanlineStride=").append(scanlineStride); + for(int i=0; i < bitMasks.length; i+=1) + { + result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i])); + } + + result.append("]"); + return result.toString(); + } +} diff --git a/libjava/classpath/java/awt/image/BufferStrategy.java b/libjava/classpath/java/awt/image/BufferStrategy.java new file mode 100644 index 0000000..e86aad6 --- /dev/null +++ b/libjava/classpath/java/awt/image/BufferStrategy.java @@ -0,0 +1,124 @@ +/* BufferStrategy.java -- describes image buffering resources + 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 java.awt.image; + +import java.awt.BufferCapabilities; +import java.awt.Graphics; + +/** + * This class describes a strategy for managing image buffering + * resources on a Canvas or Window. A given buffer strategy may make + * use of hardware acceleration or take advantage of features of the + * native graphics system. Examples of buffering strategies are + * double or triple buffering using either flipping or blitting. For + * the details of these algorithms see BufferCapabilities. + * + * To use a buffer strategy, you retrieve it from either the current + * GraphicsConfiguration or from the Component on which you'd like to + * draw. Then you can query the strategy's capabilities to make sure + * they're suitable. + * + * If the strategy's capabilities are suitable, you can obtain a + * graphics object and use it to draw with this strategy. Drawing + * with a buffer strategy requires extra care, however. You'll need + * to manually cause the next buffer to be shown on the output device. + * And since buffer strategies are usually implemented with a + * VolatileImage, you must frequently check that the contents of the + * buffer are valid and that the buffer still exists. + * + * A buffer strategy is usually implemented using a VolatileImage. + * + * @see VolatileImage + * @since 1.4 + */ +public abstract class BufferStrategy +{ + /** + * Creates a new buffer strategy. + */ + public BufferStrategy() + { + } + + /** + * Retrieves the capabilities of this buffer strategy. + * + * @return this buffer strategy's capabilities + */ + public abstract BufferCapabilities getCapabilities(); + + /** + * Retrieves a graphics object that can be used to draw using this + * buffer strategy. This method may not be synchronized so be + * careful when calling it from multiple threads. You also must + * manually dispose of this graphics object. + * + * @return a graphics object that can be used to draw using this + * buffer strategy + */ + public abstract Graphics getDrawGraphics(); + + /** + * Returns whether or not the buffer's resources have been reclaimed + * by the native graphics system. If the buffer resources have been + * lost then you'll need to obtain new resources before drawing + * again. For details, see the documentation for VolatileImage. + * + * @return true if the contents were lost, false otherwise + */ + public abstract boolean contentsLost(); + + /** + * Returns whether or not the buffer's resources were re-created and + * cleared to the default background color. If the buffer's + * resources have recently been re-created and initialized then the + * buffer's image may need to be re-rendered. For details, see the + * documentation for VolatileImage. + * + * @return true if the contents were restored, false otherwise + */ + public abstract boolean contentsRestored(); + + /** + * Applies this buffer strategy. In other words, this method brings + * the contents of the back or intermediate buffers to the front + * buffer. + */ + public abstract void show(); +} diff --git a/libjava/classpath/java/awt/image/BufferedImage.java b/libjava/classpath/java/awt/image/BufferedImage.java new file mode 100644 index 0000000..124b813 --- /dev/null +++ b/libjava/classpath/java/awt/image/BufferedImage.java @@ -0,0 +1,693 @@ +/* BufferedImage.java -- + Copyright (C) 2000, 2002, 2003, 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 java.awt.image; + +import gnu.java.awt.ComponentDataBlitOp; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Vector; + +/** + * A buffered image always starts at coordinates (0, 0). + * + * The buffered image is not subdivided into multiple tiles. Instead, + * the image consists of one large tile (0,0) with the width and + * height of the image. This tile is always considered to be checked + * out. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class BufferedImage extends Image + implements WritableRenderedImage +{ + public static final int TYPE_CUSTOM = 0, + TYPE_INT_RGB = 1, + TYPE_INT_ARGB = 2, + TYPE_INT_ARGB_PRE = 3, + TYPE_INT_BGR = 4, + TYPE_3BYTE_BGR = 5, + TYPE_4BYTE_ABGR = 6, + TYPE_4BYTE_ABGR_PRE = 7, + TYPE_USHORT_565_RGB = 8, + TYPE_USHORT_555_RGB = 9, + TYPE_BYTE_GRAY = 10, + TYPE_USHORT_GRAY = 11, + TYPE_BYTE_BINARY = 12, + TYPE_BYTE_INDEXED = 13; + + static final int[] bits3 = { 8, 8, 8 }; + static final int[] bits4 = { 8, 8, 8 }; + static final int[] bits1byte = { 8 }; + static final int[] bits1ushort = { 16 }; + + static final int[] masks_int = { 0x00ff0000, + 0x0000ff00, + 0x000000ff, + DataBuffer.TYPE_INT }; + static final int[] masks_565 = { 0xf800, + 0x07e0, + 0x001f, + DataBuffer.TYPE_USHORT}; + static final int[] masks_555 = { 0x7c00, + 0x03e0, + 0x001f, + DataBuffer.TYPE_USHORT}; + + Vector observers; + + public BufferedImage(int w, int h, int type) + { + ColorModel cm = null; + + boolean alpha = false; + boolean premultiplied = false; + switch (type) + { + case TYPE_4BYTE_ABGR_PRE: + case TYPE_INT_ARGB_PRE: + premultiplied = true; + // fall through + case TYPE_INT_ARGB: + case TYPE_4BYTE_ABGR: + alpha = true; + } + + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + switch (type) + { + case TYPE_INT_RGB: + case TYPE_INT_ARGB: + case TYPE_INT_ARGB_PRE: + case TYPE_USHORT_565_RGB: + case TYPE_USHORT_555_RGB: + int[] masks = null; + switch (type) + { + case TYPE_INT_RGB: + case TYPE_INT_ARGB: + case TYPE_INT_ARGB_PRE: + masks = masks_int; + break; + case TYPE_USHORT_565_RGB: + masks = masks_565; + break; + case TYPE_USHORT_555_RGB: + masks = masks_555; + break; + } + + cm = new DirectColorModel(cs, + 32, // 32 bits in an int + masks[0], // r + masks[1], // g + masks[2], // b + alpha ? 0xff000000 : 0, + premultiplied, + masks[3] // data type + ); + break; + + case TYPE_INT_BGR: + String msg = + "FIXME: Programmer is confused. Why (and how) does a " + + "TYPE_INT_BGR image use ComponentColorModel to store " + + "8-bit values? Is data type TYPE_INT or TYPE_BYTE. What " + + "is the difference between TYPE_INT_BGR and TYPE_3BYTE_BGR?"; + throw new UnsupportedOperationException(msg); + + case TYPE_3BYTE_BGR: + case TYPE_4BYTE_ABGR: + case TYPE_4BYTE_ABGR_PRE: + case TYPE_BYTE_GRAY: + case TYPE_USHORT_GRAY: + int[] bits = null; + int dataType = DataBuffer.TYPE_BYTE; + switch (type) { + case TYPE_3BYTE_BGR: + bits = bits3; + break; + case TYPE_4BYTE_ABGR: + case TYPE_4BYTE_ABGR_PRE: + bits = bits4; + break; + case TYPE_BYTE_GRAY: + bits = bits1byte; + break; + case TYPE_USHORT_GRAY: + bits = bits1ushort; + dataType = DataBuffer.TYPE_USHORT; + break; + } + cm = new ComponentColorModel(cs, bits, alpha, premultiplied, + alpha ? + Transparency.TRANSLUCENT: + Transparency.OPAQUE, + dataType); + break; + case TYPE_BYTE_BINARY: + byte[] vals = { 0, (byte) 0xff }; + cm = new IndexColorModel(8, 2, vals, vals, vals); + break; + case TYPE_BYTE_INDEXED: + String msg2 = "type not implemented yet"; + throw new UnsupportedOperationException(msg2); + // FIXME: build color-cube and create color model + } + + init(cm, + cm.createCompatibleWritableRaster(w, h), + premultiplied, + null, // no properties + type + ); + } + + public BufferedImage(int w, int h, int type, + IndexColorModel indexcolormodel) + { + if ((type != TYPE_BYTE_BINARY) && (type != TYPE_BYTE_INDEXED)) + throw new IllegalArgumentException("type must be binary or indexed"); + + init(indexcolormodel, + indexcolormodel.createCompatibleWritableRaster(w, h), + false, // not premultiplied (guess) + null, // no properties + type); + } + + public BufferedImage(ColorModel colormodel, + WritableRaster writableraster, + boolean premultiplied, + Hashtable properties) + { + init(colormodel, writableraster, premultiplied, properties, + TYPE_CUSTOM); + // TODO: perhaps try to identify type? + } + + WritableRaster raster; + ColorModel colorModel; + Hashtable properties; + boolean isPremultiplied; + int type; + + private void init(ColorModel cm, + WritableRaster writableraster, + boolean premultiplied, + Hashtable properties, + int type) + { + raster = writableraster; + colorModel = cm; + this.properties = properties; + isPremultiplied = premultiplied; + this.type = type; + } + + //public void addTileObserver(TileObserver tileobserver) {} + + public void coerceData(boolean premultiplied) + { + colorModel = colorModel.coerceData(raster, premultiplied); + } + + public WritableRaster copyData(WritableRaster dest) + { + if (dest == null) + dest = raster.createCompatibleWritableRaster(getMinX(), getMinY(), + getWidth(),getHeight()); + + int x = dest.getMinX(); + int y = dest.getMinY(); + int w = dest.getWidth(); + int h = dest.getHeight(); + + // create a src child that has the right bounds... + WritableRaster src = + raster.createWritableChild(x, y, w, h, x, y, + null // same bands + ); + if (src.getSampleModel () instanceof ComponentSampleModel + && dest.getSampleModel () instanceof ComponentSampleModel) + // Refer to ComponentDataBlitOp for optimized data blitting: + ComponentDataBlitOp.INSTANCE.filter(src, dest); + else + { + // slower path + int samples[] = src.getPixels (x, y, w, h, (int [])null); + dest.setPixels (x, y, w, h, samples); + } + return dest; + } + + public Graphics2D createGraphics() + { + GraphicsEnvironment env; + env = GraphicsEnvironment.getLocalGraphicsEnvironment (); + return env.createGraphics (this); + } + + public void flush() { + } + + public WritableRaster getAlphaRaster() + { + return colorModel.getAlphaRaster(raster); + } + + public ColorModel getColorModel() + { + return colorModel; + } + + public Raster getData() + { + return copyData(null); + /* TODO: this might be optimized by returning the same + raster (not writable) as long as image data doesn't change. */ + } + + public Raster getData(Rectangle rectangle) + { + WritableRaster dest = + raster.createCompatibleWritableRaster(rectangle); + return copyData(dest); + } + + public Graphics getGraphics() + { + return createGraphics(); + } + + public int getHeight() + { + return raster.getHeight(); + } + + public int getHeight(ImageObserver imageobserver) + { + return getHeight(); + } + + public int getMinTileX() + { + return 0; + } + + public int getMinTileY() + { + return 0; + } + + public int getMinX() + { + return 0; + } + + public int getMinY() + { + return 0; + } + + public int getNumXTiles() + { + return 1; + } + + public int getNumYTiles() + { + return 1; + } + + public Object getProperty(String string) + { + if (properties == null) + return null; + return properties.get(string); + } + + public Object getProperty(String string, ImageObserver imageobserver) + { + return getProperty(string); + } + + + public String[] getPropertyNames() + { + // FIXME: implement + return null; + } + + public int getRGB(int x, int y) + { + Object rgbElem = raster.getDataElements(x, y, + null // create as needed + ); + return colorModel.getRGB(rgbElem); + } + + public int[] getRGB(int startX, int startY, int w, int h, + int[] rgbArray, + int offset, int scanlineStride) + { + if (rgbArray == null) + { + /* + 000000000000000000 + 00000[#######----- [ = start + -----########----- ] = end + -----#######]00000 + 000000000000000000 */ + int size = (h-1)*scanlineStride + w; + rgbArray = new int[size]; + } + + int endX = startX + w; + int endY = startY + h; + + /* *TODO*: + Opportunity for optimization by examining color models... + + Perhaps wrap the rgbArray up in a WritableRaster with packed + sRGB color model and perform optimized rendering into the + array. */ + + Object rgbElem = null; + for (int y=startY; yByteLookupTable instance. + * + * Offset is subtracted from pixel values when looking up in the translation + * tables. If data.length is one, the same table is applied to all pixel + * components. + * + * @param offset Offset to be subtracted. + * @param data Array of lookup tables. + * @exception IllegalArgumentException if offset < 0 or data.length < 1. + */ + public ByteLookupTable(int offset, byte[][] data) + throws IllegalArgumentException + { + super(offset, data.length); + this.data = data; + } + + /** + * Creates a new ByteLookupTable instance. + * + * Offset is subtracted from pixel values when looking up in the translation + * table. The same table is applied to all pixel components. + * + * @param offset Offset to be subtracted. + * @param data Lookup table for all components. + * @exception IllegalArgumentException if offset < 0. + */ + public ByteLookupTable(int offset, byte[] data) + throws IllegalArgumentException + { + super(offset, 1); + this.data = new byte[][] {data}; + } + + /** + * Return the lookup tables. + * + * @return the tables + */ + public final byte[][] getTable() + { + return data; + } + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dst Destination array for values, or null. + * @return Translated values for the pixel. + */ + public int[] lookupPixel(int[] src, int[] dst) + throws ArrayIndexOutOfBoundsException + { + if (dst == null) + dst = new int[src.length]; + + if (data.length == 1) + for (int i=0; i < src.length; i++) + dst[i] = data[0][src[i] - offset]; + else + for (int i=0; i < src.length; i++) + dst[i] = data[i][src[i] - offset]; + + return dst; + } + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dst Destination array for values, or null. + * @return Translated values for the pixel. + */ + public byte[] lookupPixel(byte[] src, byte[] dst) + throws ArrayIndexOutOfBoundsException + { + if (dst == null) + dst = new byte[src.length]; + + if (data.length == 1) + for (int i=0; i < src.length; i++) + dst[i] = data[0][((int)src[i]) - offset]; + else + for (int i=0; i < src.length; i++) + dst[i] = data[i][((int)src[i]) - offset]; + + return dst; + + } +} diff --git a/libjava/classpath/java/awt/image/ColorConvertOp.java b/libjava/classpath/java/awt/image/ColorConvertOp.java new file mode 100644 index 0000000..18609e0 --- /dev/null +++ b/libjava/classpath/java/awt/image/ColorConvertOp.java @@ -0,0 +1,319 @@ +/* ColorModel.java -- + 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 java.awt.image; + +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * ColorConvertOp is a filter for converting an image from one colorspace to + * another colorspace. The filter can convert the image through a sequence + * of colorspaces or just from source to destination. + * + * Color conversion is done on the color components without alpha. Thus + * if a BufferedImage has alpha premultiplied, this is divided out before + * color conversion, and premultiplication applied if the destination + * requires it. + * + * Color rendering and dithering hints may be applied if specified. This is + * likely platform-dependent. + * + * @author jlquinn@optonline.net + */ +public class ColorConvertOp implements BufferedImageOp, RasterOp +{ + private ColorSpace srccs; + private ColorSpace dstcs; + private RenderingHints hints; + private ICC_Profile[] profiles; + private ColorSpace[] spaces; + private boolean rasterValid; + + + /** + * Convert BufferedImage through a ColorSpace. + * + * This filter version is only valid for BufferedImages. The source image + * is converted to cspace. If the destination is not null, it is then + * converted to the destination colorspace. Normally this filter will only + * be used with a null destination. + * + * @param cspace The target color space. + * @param hints Rendering hints to use in conversion, or null. + */ + public ColorConvertOp(ColorSpace cspace, RenderingHints hints) + { + if (cspace == null) + throw new NullPointerException(); + spaces = new ColorSpace[]{cspace}; + this.hints = hints; + rasterValid = false; + } + + public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace, + RenderingHints hints) + { + if (srcCspace == null || dstCspace == null) + throw new NullPointerException(); + spaces = new ColorSpace[]{srcCspace, dstCspace}; + this.hints = hints; + } + + /** + * Convert from a source image destination image color space. + * + * This constructor builds a ColorConvertOp from an array of ICC_Profiles. + * The source image will be converted through the sequence of color spaces + * defined by the profiles. If the sequence of profiles doesn't give a + * well-defined conversion, throws IllegalArgumentException. + * + * NOTE: Sun's docs don't clearly define what a well-defined conversion is + * - or perhaps someone smarter can come along and sort it out. + * + * For BufferedImages, when the first and last profiles match the + * requirements of the source and destination color space respectively, the + * corresponding conversion is unnecessary. TODO: code this up. I don't + * yet understand how you determine this. + * + * For Rasters, the first and last profiles must have the same number of + * bands as the source and destination Rasters, respectively. If this is + * not the case, or there fewer than 2 profiles, an IllegalArgumentException + * will be thrown. + * + * @param profiles + * @param hints + */ + public ColorConvertOp(ICC_Profile[] profiles, RenderingHints hints) + { + if (profiles == null) + throw new NullPointerException(); + this.hints = hints; + this.profiles = profiles; + // TODO: Determine if this is well-defined. + // Create colorspace array with space for src and dest colorspace + spaces = new ColorSpace[profiles.length]; + for (int i = 0; i < profiles.length; i++) + spaces[i] = new ICC_ColorSpace(profiles[i]); + } + + /** Convert from source image color space to destination image color space. + * + * Only valid for BufferedImage objects, this Op converts from the source + * color space to the destination color space. The destination can't be + * null for this operation. + * + * @param hints Rendering hints to use during conversion, or null. + */ + public ColorConvertOp(RenderingHints hints) + { + this.hints = hints; + srccs = null; + dstcs = null; + rasterValid = false; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, + java.awt.image.BufferedImage) + */ + public final BufferedImage filter(BufferedImage src, BufferedImage dst) + { + // TODO: The plan is to create a scanline buffer for intermediate buffers. + // For now we just suck it up and create intermediate buffers. + + if (dst == null && spaces.length == 0) + throw new IllegalArgumentException(); + + // Make sure input isn't premultiplied by alpha + if (src.isAlphaPremultiplied()) + { + BufferedImage tmp = createCompatibleDestImage(src, src.getColorModel()); + copyimage(src, tmp); + tmp.coerceData(false); + src = tmp; + } + + ColorModel scm = src.getColorModel(); + for (int i = 0; i < spaces.length; i++) + { + ColorModel cm = scm.cloneColorModel(spaces[i]); + BufferedImage tmp = createCompatibleDestImage(src, cm); + copyimage(src, tmp); + src = tmp; + } + + // Intermediate conversions leave result in src + if (dst == null) + return src; + + // Apply final conversion + copyimage(src, dst); + return dst; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel) + */ + public BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel dstCM) + { + // FIXME: set properties to those in src + return new BufferedImage(dstCM, + src.getRaster().createCompatibleWritableRaster(), + src.isPremultiplied, + null); + } + + public final ICC_Profile[] getICC_Profiles() + { + return profiles; + } + + /** Return the rendering hints for this op. */ + public final RenderingHints getRenderingHints() + { + return hints; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster) + */ + public final WritableRaster filter(Raster src, WritableRaster dest) + { + if (!rasterValid) + throw new IllegalArgumentException(); + + // Need to iterate through each color space - there must be at least 2 + for (int i = 1; i < spaces.length - 1; i++) + { + // FIXME: this is wrong. tmp needs to have the same number of bands as + // spaces[i] has. + WritableRaster tmp = createCompatibleDestRaster(src); + copyraster(src, spaces[i - 1], tmp, spaces[i]); + src = tmp; + } + + // FIXME: this is wrong. dst needs to have the same number of bands as + // spaces[i] has. + if (dest == null) + dest = createCompatibleDestRaster(src); + copyraster(src, spaces[spaces.length - 2], + dest, spaces[spaces.length - 1]); + + return dest; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) + */ + public WritableRaster createCompatibleDestRaster(Raster src) + { + return src.createCompatibleWritableRaster(); + } + + /** Return corresponding destination point for source point. + * + * LookupOp will return the value of src unchanged. + * @param src The source point. + * @param dst The destination point. + * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D) + */ + public final Point2D getPoint2D(Point2D src, Point2D dst) + { + if (dst == null) return (Point2D)src.clone(); + dst.setLocation(src); + return dst; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) + */ + public final Rectangle2D getBounds2D(BufferedImage src) + { + return src.getRaster().getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) + */ + public final Rectangle2D getBounds2D(Raster src) + { + return src.getBounds(); + } + + // According to Sven de Marothy, we need to copy the src into the dest + // using Graphics2D, in order to use the rendering hints. + private void copyimage(BufferedImage src, BufferedImage dst) + { + Graphics2D gg = dst.createGraphics(); + gg.setRenderingHints(hints); + gg.drawImage(src, 0, 0, null); + gg.dispose(); + } + + private void copyraster(Raster src, ColorSpace scs, WritableRaster dst, + ColorSpace dcs) + { + float[] sbuf = new float[src.getNumBands()]; + + if (hints.get(RenderingHints.KEY_COLOR_RENDERING) == + RenderingHints.VALUE_COLOR_RENDER_QUALITY) + { + // use cie for accuracy + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + dst.setPixel(x, y, + dcs.fromCIEXYZ(scs.toCIEXYZ(src.getPixel(x, y, sbuf)))); + } + else + { + // use rgb - it's probably faster + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + dst.setPixel(x, y, + dcs.fromRGB(scs.toRGB(src.getPixel(x, y, sbuf)))); + } + } + +} diff --git a/libjava/classpath/java/awt/image/ColorModel.java b/libjava/classpath/java/awt/image/ColorModel.java new file mode 100644 index 0000000..1ebcb98 --- /dev/null +++ b/libjava/classpath/java/awt/image/ColorModel.java @@ -0,0 +1,758 @@ +/* ColorModel.java -- + Copyright (C) 1999, 2000, 2002, 2003, 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 java.awt.image; + +import gnu.java.awt.Buffers; + +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.lang.reflect.Constructor; +import java.util.Arrays; + +/** + * A color model operates with colors in several formats: + * + *
      + *
    • normalized: component samples are in range [0.0, 1.0].
    • + * + *
    • color model pixel value: all the color component samples for a + * sigle pixel packed/encoded in a way natural for the color + * model.
    • + * + *
    • color model pixel int value: only makes sense if the natural + * encoding of a single pixel can fit in a single int value.
    • + * + *
    • array of transferType containing a single pixel: the pixel is + * encoded in the natural way of the color model, taking up as many + * array elements as needed.
    • + * + *
    • sRGB pixel int value: a pixel in sRGB color space, encoded in + * default 0xAARRGGBB format, assumed not alpha premultiplied.
    • + * + *
    • single [0, 255] scaled int samples from default sRGB color + * space. These are always assumed to be alpha non-premultiplied.
    • + * + *
    • arrays of unnormalized component samples of single pixel: these + * samples are scaled and multiplied according to the color model, but + * is otherwise not packed or encoded. Each element of the array is one + * separate component sample. The color model only operate on the + * components from one pixel at a time, but using offsets, allows + * manipulation of arrays that contain the components of more than one + * pixel.
    • + * + *
    + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author C. Brian Jones (cbj@gnu.org) + */ +public abstract class ColorModel implements Transparency +{ + protected int pixel_bits; + protected int transferType; + + int[] bits; + ColorSpace cspace; + int transparency; + boolean hasAlpha; + boolean isAlphaPremultiplied; + + static int[] nArray(int value, int times) + { + int[] array = new int[times]; + java.util.Arrays.fill(array, value); + return array; + } + + static byte[] nArray(byte value, int times) + { + byte[] array = new byte[times]; + java.util.Arrays.fill(array, value); + return array; + } + + /** + * Constructs the default color model. The default color model + * can be obtained by calling getRGBdefault of this + * class. + * @param bits the number of bits wide used for bit size of pixel values + */ + public ColorModel(int bits) + { + this(bits * 4, // total bits, sRGB, four channels + nArray(bits, 4), // bits for each channel + ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB + true, // has alpha + false, // not premultiplied + TRANSLUCENT, + Buffers.smallestAppropriateTransferType(bits * 4)); + } + + /** + * Constructs a ColorModel that translates pixel values to + * color/alpha components. + * + * @exception IllegalArgumentException If the length of the bit array is less + * than the number of color or alpha components in this ColorModel, or if the + * transparency is not a valid value, or if the sum of the number of bits in + * bits is less than 1 or if any of the elements in bits is less than 0. + */ + protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace, + boolean hasAlpha, boolean isAlphaPremultiplied, + int transparency, int transferType) + { + int bits_sum = 0; + for (int i = 0; i < bits.length; i++) + { + if (bits [i] < 0) + throw new IllegalArgumentException (); + + bits_sum |= bits [i]; + } + + if ((bits.length < cspace.getNumComponents()) + || (bits_sum < 1)) + throw new IllegalArgumentException (); + + this.pixel_bits = pixel_bits; + this.bits = bits; + this.cspace = cspace; + this.hasAlpha = hasAlpha; + this.isAlphaPremultiplied = isAlphaPremultiplied; + this.transparency = transparency; + this.transferType = transferType; + } + + // This is a hook for ColorConvertOp to create a colormodel with + // a new colorspace + ColorModel cloneColorModel(ColorSpace cspace) + { + Class cls = this.getClass(); + ColorModel cm; + try { + // This constructor will exist. + Constructor ctor = + cls.getConstructor(new Class[]{int.class, int[].class, + ColorSpace.class, boolean.class, + boolean.class, int.class, int.class}); + cm = (ColorModel)ctor. + newInstance(new Object[]{new Integer(pixel_bits), + bits, cspace, Boolean.valueOf(hasAlpha), + Boolean.valueOf(isAlphaPremultiplied), + new Integer(transparency), + new Integer(transferType)}); + } + catch (Exception e) + { + throw new IllegalArgumentException(); + } + return cm; + } + + public void finalize() + { + // Do nothing here. + } + + /** + * Returns the default color model which in Sun's case is an instance + * of DirectColorModel. + */ + public static ColorModel getRGBdefault() + { + return new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000); + } + + public final boolean hasAlpha() + { + return hasAlpha; + } + + public final boolean isAlphaPremultiplied() + { + return isAlphaPremultiplied; + } + + /** + * Get get number of bits wide used for the bit size of pixel values + */ + public int getPixelSize() + { + return pixel_bits; + } + + public int getComponentSize(int componentIdx) + { + return bits[componentIdx]; + } + + public int[] getComponentSize() + { + return bits; + } + + public int getTransparency() + { + return transparency; + } + + public int getNumComponents() + { + return getNumColorComponents() + (hasAlpha ? 1 : 0); + } + + public int getNumColorComponents() + { + return cspace.getNumComponents(); + } + + /** + * Converts pixel value to sRGB and extract red int sample scaled + * to range [0, 255]. + * + * @param pixel pixel value that will be interpreted according to + * the color model, (assumed alpha premultiplied if color model says + * so.) + * + * @return red sample scaled to range [0, 255], from default color + * space sRGB, alpha non-premultiplied. + */ + public abstract int getRed(int pixel); + + /** + * Converts pixel value to sRGB and extract green int sample + * scaled to range [0, 255]. + * + * @see #getRed(int) + */ + public abstract int getGreen(int pixel); + + /** + * Converts pixel value to sRGB and extract blue int sample + * scaled to range [0, 255]. + * + * @see #getRed(int) + */ + public abstract int getBlue(int pixel); + + /** + * Extract alpha int sample from pixel value, scaled to [0, 255]. + * + * @param pixel pixel value that will be interpreted according to + * the color model. + * + * @return alpha sample, scaled to range [0, 255]. + */ + public abstract int getAlpha(int pixel); + + /** + * Converts a pixel int value of the color space of the color + * model to a sRGB pixel int value. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. + * + * @param pixel pixel value that will be interpreted according to + * the color model. + * + * @return a pixel in sRGB color space, encoded in default + * 0xAARRGGBB format. */ + public int getRGB(int pixel) + { + return + ((getAlpha(pixel) & 0xff) << 24) | + (( getRed(pixel) & 0xff) << 16) | + ((getGreen(pixel) & 0xff) << 8) | + (( getBlue(pixel) & 0xff) << 0); + } + + + /** + * In this color model we know that the whole pixel value will + * always be contained within the first element of the pixel + * array. + */ + final int getPixelFromArray(Object inData) { + DataBuffer data = + Buffers.createBufferFromData(transferType, inData, 1); + Object da = Buffers.getData(data); + + return data.getElem(0); + } + + /** + * Converts pixel in the given array to sRGB and extract blue int + * sample scaled to range [0-255]. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. + * + * @param inData array of transferType containing a single pixel. The + * pixel should be encoded in the natural way of the color model. + */ + public int getRed(Object inData) + { + return getRed(getPixelFromArray(inData)); + } + + /** + * @see #getRed(Object) + */ + public int getGreen(Object inData) + { + return getGreen(getPixelFromArray(inData)); + } + + /** + * @see #getRed(Object) + */ + public int getBlue(Object inData) { + return getBlue(getPixelFromArray(inData)); + } + + /** + * @see #getRed(Object) + */ + public int getAlpha(Object inData) { + return getAlpha(getPixelFromArray(inData)); + } + + /** + * Converts a pixel in the given array of the color space of the + * color model to an sRGB pixel int value. + * + *

    This method performs the inverse function of + * getDataElements(int rgb, Object pixel). + * I.e. (rgb == cm.getRGB(cm.getDataElements(rgb, + * null))). + * + * @param inData array of transferType containing a single pixel. The + * pixel should be encoded in the natural way of the color model. + * + * @return a pixel in sRGB color space, encoded in default + * 0xAARRGGBB format. + * + * @see #getDataElements(int, Object) + */ + public int getRGB(Object inData) + { + return + ((getAlpha(inData) & 0xff) << 24) | + (( getRed(inData) & 0xff) << 16) | + ((getGreen(inData) & 0xff) << 8) | + (( getBlue(inData) & 0xff) << 0); + } + + /** + * Converts an sRGB pixel int value to an array containing a + * single pixel of the color space of the color model. + * + *

    This method performs the inverse function of + * getRGB(Object inData). + * + * Outline of conversion process: + * + *

      + * + *
    1. Convert rgb to normalized [0.0, 1.0] sRGB values.
    2. + * + *
    3. Convert to color space components using fromRGB in + * ColorSpace.
    4. + * + *
    5. If color model has alpha and should be premultiplied, + * multiply color space components with alpha value
    6. + * + *
    7. Scale the components to the correct number of bits.
    8. + * + *
    9. Arrange the components in the output array
    10. + * + *
    + * + * @param rgb The color to be converted to dataElements. A pixel + * in sRGB color space, encoded in default 0xAARRGGBB format, + * assumed not alpha premultiplied. + * + * @param pixel to avoid needless creation of arrays, an array to + * use to return the pixel can be given. If null, a suitable array + * will be created. + * + * @return An array of transferType values representing the color, + * in the color model format. The color model defines whether the + * + * @see #getRGB(Object) + */ + public Object getDataElements(int rgb, Object pixel) + { + // subclasses has to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Fills an array with the unnormalized component samples from a + * pixel value. I.e. decompose the pixel, but not perform any + * color conversion. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. + * + * @param pixel pixel value encoded according to the color model. + * + * @return arrays of unnormalized component samples of single + * pixel. The scale and multiplication state of the samples are + * according to the color model. Each component sample is stored + * as a separate element in the array. + */ + public int[] getComponents(int pixel, int[] components, int offset) + { + // subclasses has to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Fills an array with the unnormalized component samples from an + * array of transferType containing a single pixel. I.e. decompose + * the pixel, but not perform any color conversion. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. + * + * @param array of transferType containing a single pixel. The + * pixel should be encoded in the natural way of the color model. + * + * @return arrays of unnormalized component samples of single + * pixel. The scale and multiplication state of the samples are + * according to the color model. Each component sample is stored + * as a separate element in the array. + */ + public int[] getComponents(Object pixel, int[] components, int offset) + { + // subclasses has to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Convert normalized components to unnormalized components. + */ + public int[] getUnnormalizedComponents(float[] normComponents, + int normOffset, + int[] components, + int offset) + { + int numComponents = getNumComponents(); + if (components == null) + { + components = new int[offset + numComponents]; + } + + for (int i=0; igetComponents(int pixel, int[] components, + * int offset). I.e. + * + * (pixel == cm.getDataElement(cm.getComponents(pixel, null, + * 0), 0)). + * + * This method is overriden in subclasses since this abstract class throws + * UnsupportedOperationException(). + * + * @param components Array of unnormalized component samples of single + * pixel. The scale and multiplication state of the samples are according + * to the color model. Each component sample is stored as a separate element + * in the array. + * @param offset Position of the first value of the pixel in components. + * + * @return pixel value encoded according to the color model. + */ + public int getDataElement(int[] components, int offset) + { + // subclasses have to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Converts the normalized component samples from an array to a pixel + * value. I.e. composes the pixel from component samples, but does not + * perform any color conversion or scaling of the samples. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. The method provided by this abstract + * class converts the components to unnormalized form and returns + * getDataElement(int[], int). + * + * @param components Array of normalized component samples of single pixel. + * The scale and multiplication state of the samples are according to the + * color model. Each component sample is stored as a separate element in the + * array. + * @param offset Position of the first value of the pixel in components. + * + * @return pixel value encoded according to the color model. + * @since 1.4 + */ + public int getDataElement (float[] components, int offset) + { + return + getDataElement(getUnnormalizedComponents(components, offset, null, 0), + 0); + } + + public Object getDataElements(int[] components, int offset, Object obj) + { + // subclasses have to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Converts the normalized component samples from an array to an array of + * TransferType values. I.e. composes the pixel from component samples, but + * does not perform any color conversion or scaling of the samples. + * + * If obj is null, a new array of TransferType is allocated and returned. + * Otherwise the results are stored in obj and obj is returned. If obj is + * not long enough, ArrayIndexOutOfBounds is thrown. If obj is not an array + * of primitives, ClassCastException is thrown. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. The method provided by this abstract + * class converts the components to unnormalized form and returns + * getDataElement(int[], int, Object). + * + * @param components Array of normalized component samples of single pixel. + * The scale and multiplication state of the samples are according to the + * color model. Each component sample is stored as a separate element in the + * array. + * @param offset Position of the first value of the pixel in components. + * @param obj Array of TransferType or null. + * + * @return pixel value encoded according to the color model. + * @throws ArrayIndexOutOfBounds + * @throws ClassCastException + * @since 1.4 + */ + public Object getDataElements(float[] components, int offset, Object obj) + { + return + getDataElements(getUnnormalizedComponents(components, offset, null, 0), + 0, obj); + } + + public boolean equals(Object obj) + { + if (!(obj instanceof ColorModel)) return false; + + ColorModel o = (ColorModel) obj; + return + (pixel_bits == o.pixel_bits) && + (transferType == o.transferType) && + (transparency == o.transparency) && + (hasAlpha == o.hasAlpha) && + (isAlphaPremultiplied == o.isAlphaPremultiplied) && + Arrays.equals(bits, o.bits) && + (cspace.equals(o.cspace)); + } + + public final ColorSpace getColorSpace() + { + return cspace; + } + + // Typically overridden + public ColorModel coerceData(WritableRaster raster, + boolean isAlphaPremultiplied) + { + if (this.isAlphaPremultiplied == isAlphaPremultiplied) + return this; + + int w = raster.getWidth(); + int h = raster.getHeight(); + int x = raster.getMinX(); + int y = raster.getMinY(); + int size = w*h; + int numColors = getNumColorComponents(); + int numComponents = getNumComponents(); + int alphaScale = (1<1) throw new IllegalArgumentException(); + return (int) getRGBFloat(pixel)[0]; + } + + public int getGreen(int pixel) + { + if (getNumComponents()>1) throw new IllegalArgumentException(); + return (int) getRGBFloat(pixel)[0]; + } + + public int getBlue(int pixel) + { + if (getNumComponents()>1) throw new IllegalArgumentException(); + return (int) getRGBFloat(pixel)[0]; + } + + public int getAlpha(int pixel) + { + if (getNumComponents()>1) throw new IllegalArgumentException(); + int shift = 8 - getComponentSize(getNumColorComponents()); + if (shift >= 0) return pixel << shift; + return pixel >> (-shift); + } + + public int getRGB(int pixel) + { + float[] rgb = getRGBFloat(pixel); + int ret = getRGB(rgb); + if (hasAlpha()) ret |= getAlpha(pixel) << 24; + return ret; + } + + + /* Note, it's OK to pass a to large array to toRGB(). Extra + elements are ignored. */ + + private float[] getRGBFloat(int pixel) + { + float[] data = { pixel }; + return cspace.toRGB(data); + } + + private float[] getRGBFloat(Object inData) + { + DataBuffer buffer = + Buffers.createBufferFromData(transferType, inData, + getNumComponents()); + int colors = getNumColorComponents(); + float[] data = new float[colors]; + + // FIXME: unpremultiply data that is premultiplied + for (int i=0; i= 0) return alpha << shift; + return alpha >> (-shift); + } + + private int getRGB(float[] rgb) + { + /* NOTE: We could cast to byte instead of int here. This would + avoid bits spilling over from one bit field to + another. But, if we assume that floats are in the [0.0, + 1.0] range, this will never happen anyway. */ + + /* Remember to multiply BEFORE casting to int, otherwise, decimal + point data will be lost. */ + int ret = + (((int) (rgb[0]*255F)) << 16) | + (((int) (rgb[1]*255F)) << 8) | + (((int) (rgb[2]*255F)) << 0); + return ret; + } + + /** + * @param inData pixel data of transferType, as returned by the + * getDataElements method in SampleModel. + */ + public int getRGB(Object inData) + { + float[] rgb = getRGBFloat(inData); + int ret = getRGB(rgb); + if (hasAlpha()) ret |= getAlpha(inData) << 24; + return ret; + } + + public Object getDataElements(int rgb, Object pixel) + { + // Convert rgb to [0.0, 1.0] sRGB values. + float[] rgbFloats = { + ((rgb >> 16)&0xff)/255.0F, + ((rgb >> 8)&0xff)/255.0F, + ((rgb >> 0)&0xff)/255.0F + }; + + // Convert from rgb to color space components. + float[] data = cspace.fromRGB(rgbFloats); + DataBuffer buffer = Buffers.createBuffer(transferType, pixel, + getNumComponents()); + int numColors = getNumColorComponents(); + + if (hasAlpha()) + { + float alpha = ((rgb >> 24)&0xff)/255.0F; + + /* If color model has alpha and should be premultiplied, multiply + color space components with alpha value. */ + if (isAlphaPremultiplied()) { + for (int i=0; i1) throw new IllegalArgumentException(); + if (components == null) + components = new int[getNumComponents() + offset]; + components[offset] = pixel; + return components; + } + + public int[] getComponents(Object pixel, int[] components, int offset) + { + DataBuffer buffer = Buffers.createBuffer(transferType, pixel, + getNumComponents()); + int numComponents = getNumComponents(); + + if (components == null) + components = new int[numComponents + offset]; + + for (int i=0; i1) throw new IllegalArgumentException(); + return components[offset]; + } + + public Object getDataElements(int[] components, int offset, Object obj) + { + DataBuffer buffer = Buffers.createBuffer(transferType, obj, + getNumComponents()); + int numComponents = getNumComponents(); + + for (int i=0; iSampleModel whose arrangement of pixel + * data is compatible to this ColorModel. + * + * @param w the number of pixels in the horizontal direction. + * @param h the number of pixels in the vertical direction. + */ + public SampleModel createCompatibleSampleModel(int w, int h) + { + int pixelStride, scanlineStride; + int[] bandOffsets; + + pixelStride = getNumComponents(); + scanlineStride = pixelStride * w; + + /* We might be able to re-use the same bandOffsets array among + * multiple calls to this method. However, this optimization does + * not seem worthwile because setting up descriptive data + * structures (such as SampleModels) is neglectible in comparision + * to shuffling around masses of pixel data. + */ + bandOffsets = new int[pixelStride]; + for (int i = 0; i < pixelStride; i++) + bandOffsets[i] = i; + + /* FIXME: Think about whether it would make sense to return the + * possibly more efficient PixelInterleavedSampleModel for other + * transferTypes as well. It seems unlikely that this would break + * any user applications, so the Mauve tests on this method + * might be too restrictive. + */ + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + return new PixelInterleavedSampleModel(transferType, w, h, + pixelStride, + scanlineStride, + bandOffsets); + + default: + return new ComponentSampleModel(transferType, w, h, + pixelStride, + scanlineStride, + bandOffsets); + } + } + + + public boolean isCompatibleSampleModel(SampleModel sm) + { + return + (sm instanceof ComponentSampleModel) && + super.isCompatibleSampleModel(sm); + } + + public WritableRaster getAlphaRaster(WritableRaster raster) + { + if (!hasAlpha()) return null; + + SampleModel sm = raster.getSampleModel(); + int[] alphaBand = { sm.getNumBands() - 1 }; + SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand); + DataBuffer buffer = raster.getDataBuffer(); + Point origin = new Point(0, 0); + return Raster.createWritableRaster(alphaModel, buffer, origin); + } + + public boolean equals(Object obj) + { + if (!(obj instanceof ComponentColorModel)) return false; + return super.equals(obj); + } +} diff --git a/libjava/classpath/java/awt/image/ComponentSampleModel.java b/libjava/classpath/java/awt/image/ComponentSampleModel.java new file mode 100644 index 0000000..953f63c --- /dev/null +++ b/libjava/classpath/java/awt/image/ComponentSampleModel.java @@ -0,0 +1,544 @@ +/* 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 java.awt.image; + +import gnu.java.awt.Buffers; + +/* FIXME: This class does not yet support data type TYPE_SHORT */ + +/** + * ComponentSampleModel supports a flexible organization of pixel samples in + * memory, permitting pixel samples to be interleaved by band, by scanline, + * and by pixel. + * + * A DataBuffer for this sample model has K banks of data. Pixels have N + * samples, so there are N bands in the DataBuffer. Each band is completely + * contained in one bank of data, but a bank may contain more than one band. + * Each pixel sample is stored in a single data element. + * + * Within a bank, each band begins at an offset stored in bandOffsets. The + * banks containing the band is given by bankIndices. Within the bank, there + * are three dimensions - band, pixel, and scanline. The dimension ordering + * is controlled by bandOffset, pixelStride, and scanlineStride, which means + * that any combination of interleavings is supported. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class ComponentSampleModel extends SampleModel +{ + protected int[] bandOffsets; + protected int[] bankIndices; + + // FIXME: Should we really shadow the numBands in the superclass? + //protected int numBands; + + /** Used when creating data buffers. */ + protected int numBanks; + + protected int scanlineStride; + + protected int pixelStride; + + private boolean tightPixelPacking = false; + + public ComponentSampleModel(int dataType, + int w, int h, + int pixelStride, + int scanlineStride, + int[] bandOffsets) + { + this(dataType, w, h, pixelStride, scanlineStride, + new int[bandOffsets.length], bandOffsets); + } + + public ComponentSampleModel(int dataType, + int w, int h, + int pixelStride, + int scanlineStride, + int[] bankIndices, + int[] bandOffsets) + { + super(dataType, w, h, bandOffsets.length); + if ((pixelStride<0) || (scanlineStride<0) || + (bandOffsets.length<1) || + (bandOffsets.length != bankIndices.length)) + throw new IllegalArgumentException(); + + this.bandOffsets = bandOffsets; + this.bankIndices = bankIndices; + + this.numBanks = 0; + for (int b=0; bCropImageFilter instance. + * + * @param x the x-coordinate location of the top-left of the cropped rectangle + * @param y the y-coordinate location of the top-left of the cropped rectangle + * @param width the width of the cropped rectangle + * @param height the height of the cropped rectangle + */ + public CropImageFilter(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + /** + * An ImageProducer indicates the size of the image + * being produced using this method. This filter overrides this + * method in order to set the dimentions to the size of the + * cropped rectangle instead of the size of the image. + * + * @param width the width of the image + * @param height the height of the image + */ + public void setDimensions(int width, int height) + { + consumer.setDimensions(this.width, this.height); + } + + /** + * An ImageProducer can set a list of properties + * associated with this image by using this method. + *
    + * FIXME - What property is set for this class? + * + * @param props the list of properties associated with this image + */ + public void setProperties(Hashtable props) + { + props.put("filters", "CropImageFilter"); + consumer.setProperties(props); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a byte at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize) + { + Rectangle filterBounds = new Rectangle(this.x, this.y, + this.width, this.height); + Rectangle pixelBounds = new Rectangle(x, y, w, h); + + if (filterBounds.intersects(pixelBounds)) + { + Rectangle bounds = filterBounds.intersection(pixelBounds); + + byte[] cropped = new byte[bounds.width * bounds.height]; + for (int i = 0; i < bounds.height; i++) + { + int start = (bounds.y - pixelBounds.y + i) * scansize + offset; + + for (int j = 0; j < bounds.width; j++) + cropped[i * bounds.width + j] = pixels[start + bounds.x + j]; + } + + consumer.setPixels(bounds.x, bounds.y, + bounds.width, bounds.height, + model, cropped, 0, bounds.width); + } + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an int at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize) + { + Rectangle filterBounds = new Rectangle(this.x, this.y, + this.width, this.height); + Rectangle pixelBounds = new Rectangle(x, y, w, h); + + if (filterBounds.intersects(pixelBounds)) + { + Rectangle bounds = filterBounds.intersection(pixelBounds); + + int[] cropped = new int[bounds.width * bounds.height]; + for (int i = 0; i < bounds.height; i++) + { + int start = (bounds.y - pixelBounds.y + i) * scansize + offset; + + for (int j = 0; j < bounds.width; j++) + cropped[i * bounds.width + j] = pixels[start + bounds.x + j]; + } + + consumer.setPixels(bounds.x, bounds.y, + bounds.width, bounds.height, + model, cropped, 0, bounds.width); + } + } + +} + diff --git a/libjava/classpath/java/awt/image/DataBuffer.java b/libjava/classpath/java/awt/image/DataBuffer.java new file mode 100644 index 0000000..9e4f714 --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBuffer.java @@ -0,0 +1,436 @@ +/* Copyright (C) 2000, 2002, 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 java.awt.image; + +/** + * Class that manages arrays of data elements. A data buffer consists + * of one or more banks. A bank is a continuous region of data + * elements. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public abstract class DataBuffer +{ + /** + * A constant representing a data type that uses byte primitives + * as the storage unit. + */ + public static final int TYPE_BYTE = 0; + + /** + * A constant representing a data type that uses short + * primitives as the storage unit. + */ + public static final int TYPE_USHORT = 1; + + /** + * A constant representing a data type that uses short + * primitives as the storage unit. + */ + public static final int TYPE_SHORT = 2; + + /** + * A constant representing a data type that uses int + * primitives as the storage unit. + */ + public static final int TYPE_INT = 3; + + /** + * A constant representing a data type that uses float + * primitives as the storage unit. + */ + public static final int TYPE_FLOAT = 4; + + /** + * A constant representing a data type that uses double + * primitives as the storage unit. + */ + public static final int TYPE_DOUBLE = 5; + + /** + * A constant representing an undefined data type. + */ + public static final int TYPE_UNDEFINED = 32; + + /** The type of the data elements stored in the data buffer. */ + protected int dataType; + + /** The number of banks in this buffer. */ + protected int banks = 1; + + /** Offset into the default (0'th) bank). */ + protected int offset; // FIXME: Is offsets[0] always mirrored in offset? + + /** The size of the banks. */ + protected int size; + + /** Offset into each bank. */ + protected int[] offsets; + + /** + * Creates a new DataBuffer with the specified data type and + * size. The dataType should be one of the constants + * {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, {@link #TYPE_USHORT}, + * {@link #TYPE_INT}, {@link #TYPE_FLOAT} and {@link #TYPE_DOUBLE}. + *

    + * The physical (array-based) storage is allocated by a subclass. + * + * @param dataType the data type. + * @param size the number of elements in the buffer. + */ + protected DataBuffer(int dataType, int size) + { + this.dataType = dataType; + this.size = size; + } + + /** + * Creates a new DataBuffer with the specified data type, + * size and number of banks. The dataType should be one of + * the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + *

    + * The physical (array-based) storage is allocated by a subclass. + * + * @param dataType the data type. + * @param size the number of elements in the buffer. + * @param numBanks the number of data banks. + */ + protected DataBuffer(int dataType, int size, int numBanks) { + this(dataType, size); + banks = numBanks; + offsets = new int[numBanks]; + } + + /** + * Creates a new DataBuffer with the specified data type, + * size and number of banks. An offset (which applies to all banks) is + * also specified. The dataType should be one of + * the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + *

    + * The physical (array-based) storage is allocated by a subclass. + * + * @param dataType the data type. + * @param size the number of elements in the buffer. + * @param numBanks the number of data banks. + * @param offset the offset to the first element for all banks. + */ + protected DataBuffer(int dataType, int size, int numBanks, int offset) { + this(dataType, size, numBanks); + + java.util.Arrays.fill(offsets, offset); + + this.offset = offset; + } + + /** + * Creates a new DataBuffer with the specified data type, + * size and number of banks. An offset (which applies to all banks) is + * also specified. The dataType should be one of + * the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + *

    + * The physical (array-based) storage is allocated by a subclass. + * + * @param dataType the data type. + * @param size the number of elements in the buffer. + * @param numBanks the number of data banks. + * @param offsets the offsets to the first element for all banks. + * + * @throws ArrayIndexOutOfBoundsException if + * numBanks != offsets.length. + */ + protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) { + this(dataType, size); + if (numBanks != offsets.length) + throw new ArrayIndexOutOfBoundsException(); + + banks = numBanks; + this.offsets = offsets; + + offset = offsets[0]; + } + + /** + * Returns the size (number of bits) of the specified data type. Valid types + * are defined by the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + * + * @param dataType the data type. + * @return The number of bits for the specified data type. + * @throws IllegalArgumentException if dataType < 0 or + * dataType > TYPE_DOUBLE. + */ + public static int getDataTypeSize(int dataType) { + // Maybe this should be a lookup table instead. + switch (dataType) + { + case TYPE_BYTE: + return 8; + case TYPE_USHORT: + case TYPE_SHORT: + return 16; + case TYPE_INT: + case TYPE_FLOAT: + return 32; + case TYPE_DOUBLE: + return 64; + default: + throw new IllegalArgumentException(); + } + } + + /** + * Returns the type of the data elements in the data buffer. Valid types + * are defined by the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + * + * @return The type. + */ + public int getDataType() + { + return dataType; + } + + /** + * Returns the size of the data buffer. + * + * @return The size. + */ + public int getSize() + { + return size; + } + + /** + * Returns the element offset for the first data bank. + * + * @return The element offset. + */ + public int getOffset() + { + return offset; + } + + /** + * Returns the offsets for all the data banks used by this + * DataBuffer. + * + * @return The offsets. + */ + public int[] getOffsets() + { + if (offsets == null) + { + // is this necessary? + offsets = new int[1]; + offsets[0] = offset; + } + return offsets; + } + + /** + * Returns the number of data banks for this DataBuffer. + * @return The number of data banks. + */ + public int getNumBanks() + { + return banks; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return getElem(0, i); + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public abstract int getElem(int bank, int i); + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + setElem(0, i, val); + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public abstract void setElem(int bank, int i, int val); + + /** + * Returns an element from the first data bank, converted to a + * float. The offset (specified in the constructor) is added + * to i before accessing the underlying data array. + * + * @param i the element index. + * @return The element. + */ + public float getElemFloat(int i) + { + return getElem(i); + } + + /** + * Returns an element from a particular data bank, converted to a + * float. The offset (specified in the constructor) is + * added to i before accessing the underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public float getElemFloat(int bank, int i) + { + return getElem(bank, i); + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElemFloat(int i, float val) + { + setElem(i, (int) val); + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElemFloat(int bank, int i, float val) + { + setElem(bank, i, (int) val); + } + + /** + * Returns an element from the first data bank, converted to a + * double. The offset (specified in the constructor) is added + * to i before accessing the underlying data array. + * + * @param i the element index. + * @return The element. + */ + public double getElemDouble(int i) + { + return getElem(i); + } + + /** + * Returns an element from a particular data bank, converted to a + * double. The offset (specified in the constructor) is + * added to i before accessing the underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public double getElemDouble(int bank, int i) + { + return getElem(bank, i); + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElemDouble(int i, double val) + { + setElem(i, (int) val); + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElemDouble(int bank, int i, double val) + { + setElem(bank, i, (int) val); + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferByte.java b/libjava/classpath/java/awt/image/DataBufferByte.java new file mode 100644 index 0000000..1113ebb --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferByte.java @@ -0,0 +1,245 @@ +/* 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 java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of byte primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public final class DataBufferByte extends DataBuffer +{ + private byte[] data; + private byte[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of byte elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferByte(int size) + { + super(TYPE_BYTE, size, 1, 0); + bankData = new byte[1][]; + data = new byte[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of byte elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferByte(int size, int numBanks) + { + super(TYPE_BYTE, size, numBanks); + bankData = new byte[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferByte(byte[] dataArray, int size) + { + super(TYPE_BYTE, size, 1, 0); + bankData = new byte[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferByte(byte[] dataArray, int size, int offset) + { + super(TYPE_BYTE, size, 1, offset); + bankData = new byte[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferByte(byte[][] dataArray, int size) + { + super(TYPE_BYTE, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferByte(byte[][] dataArray, int size, int[] offsets) + { + super(TYPE_BYTE, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public byte[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public byte[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this DataBuffer. + * + * @return The data banks. + */ + public byte[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return data[i+offset] & 0xff; // get unsigned byte as int + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + // get unsigned byte as int + return bankData[bank][i+offsets[bank]] & 0xff; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = (byte) val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = (byte) val; + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferDouble.java b/libjava/classpath/java/awt/image/DataBufferDouble.java new file mode 100644 index 0000000..a8c4b9d --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferDouble.java @@ -0,0 +1,288 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of double primitives + * to represent each of its banks. + * + * @since 1.4 + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class DataBufferDouble + extends DataBuffer +{ + private double[] data; + private double[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of double elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferDouble(int size) + { + super(TYPE_DOUBLE, size, 1, 0); + bankData = new double[1][]; + data = new double[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of double elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferDouble(int size, int numBanks) + { + super(TYPE_DOUBLE, size, numBanks); + bankData = new double[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferDouble(double[] dataArray, int size) + { + super(TYPE_DOUBLE, size, 1, 0); + bankData = new double[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferDouble(double[] dataArray, int size, int offset) + { + super(TYPE_DOUBLE, size, 1, offset); + bankData = new double[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferDouble(double[][] dataArray, int size) + { + super(TYPE_DOUBLE, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferDouble(double[][] dataArray, int size, int[] offsets) + { + super(TYPE_DOUBLE, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public double[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public double[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this DataBuffer. + * + * @return The data banks. + */ + public double[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return (int) data[i+offset]; + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + return (int) bankData[bank][i+offsets[bank]]; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = val; + } + + public float getElemFloat(int i) + { + return (float) data[i+offset]; + } + + public float getElemFloat(int bank, int i) + { + return (float) bankData[bank][i+offsets[bank]]; + } + + public void setElemFloat(int i, float val) + { + data[i+offset] = val; + } + + public void setElemFloat(int bank, int i, float val) + { + bankData[bank][i+offsets[bank]] = val; + } + + public double getElemDouble(int i) + { + return data[i + offset]; + } + + public double getElemDouble(int bank, int i) + { + return bankData[bank][i + offsets[bank]]; + } + + public void setElemDouble(int i, double val) + { + data[i + offset] = val; + } + + public void setElemDouble(int bank, int i, double val) + { + bankData[bank][i + offsets[bank]] = val; + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferFloat.java b/libjava/classpath/java/awt/image/DataBufferFloat.java new file mode 100644 index 0000000..9cf8784 --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferFloat.java @@ -0,0 +1,286 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of float primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class DataBufferFloat + extends DataBuffer +{ + private float[] data; + private float[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of float elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferFloat(int size) + { + super(TYPE_FLOAT, size, 1, 0); + bankData = new float[1][]; + data = new float[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of float elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferFloat(int size, int numBanks) + { + super(TYPE_FLOAT, size, numBanks); + bankData = new float[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferFloat(float[] dataArray, int size) + { + super(TYPE_FLOAT, size, 1, 0); + bankData = new float[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferFloat(float[] dataArray, int size, int offset) + { + super(TYPE_FLOAT, size, 1, offset); + bankData = new float[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferFloat(float[][] dataArray, int size) + { + super(TYPE_FLOAT, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferFloat(float[][] dataArray, int size, int[] offsets) + { + super(TYPE_FLOAT, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public float[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public float[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this DataBuffer. + * + * @return The data banks. + */ + public float[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return (int) data[i+offset]; + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + return (int) bankData[bank][i+offsets[bank]]; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = val; + } + + public float getElemFloat(int i) + { + return data[i+offset]; + } + + public float getElemFloat(int bank, int i) + { + return bankData[bank][i+offsets[bank]]; + } + + public void setElemFloat(int i, float val) + { + data[i+offset] = val; + } + + public void setElemFloat(int bank, int i, float val) + { + bankData[bank][i+offsets[bank]] = val; + } + + public double getElemDouble(int i) + { + return getElemFloat(i); + } + + public double getElemDouble(int bank, int i) + { + return getElemFloat(bank, i); + } + + public void setElemDouble(int i, double val) + { + setElemFloat(i, (float) val); + } + + public void setElemDouble(int bank, int i, double val) + { + setElemFloat(bank, i, (float) val); + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferInt.java b/libjava/classpath/java/awt/image/DataBufferInt.java new file mode 100644 index 0000000..0aac940 --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferInt.java @@ -0,0 +1,244 @@ +/* Copyright (C) 2000, 2002, 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 java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of int primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public final class DataBufferInt extends DataBuffer +{ + private int[] data; + private int[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of int elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferInt(int size) + { + super(TYPE_INT, size, 1, 0); + bankData = new int[1][]; + data = new int[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of int elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferInt(int size, int numBanks) + { + super(TYPE_INT, size, numBanks); + bankData = new int[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferInt(int[] dataArray, int size) + { + super(TYPE_INT, size, 1, 0); + bankData = new int[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferInt(int[] dataArray, int size, int offset) + { + super(TYPE_INT, size, 1, offset); + bankData = new int[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferInt(int[][] dataArray, int size) + { + super(TYPE_INT, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferInt(int[][] dataArray, int size, int[] offsets) + { + super(TYPE_INT, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public int[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public int[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this DataBuffer. + * + * @return The data banks. + */ + public int[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset is + * added to the specified index before accessing the underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return data[i+offset]; + } + + /** + * Returns an element from a particular data bank. The offset + * is added to the specified index before accessing the underlying data + * array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + // get unsigned int as int + return bankData[bank][i+offsets[bank]]; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = val; + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferShort.java b/libjava/classpath/java/awt/image/DataBufferShort.java new file mode 100644 index 0000000..5c67a8d --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferShort.java @@ -0,0 +1,245 @@ +/* DataBufferShort.java -- + Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of short primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public final class DataBufferShort extends DataBuffer +{ + private short[] data; + private short[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of short elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferShort(int size) + { + super(TYPE_SHORT, size, 1, 0); + bankData = new short[1][]; + data = new short[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of short elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferShort(int size, int numBanks) + { + super(TYPE_SHORT, size, numBanks); + bankData = new short[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferShort(short[] dataArray, int size) + { + super(TYPE_SHORT, size, 1, 0); + bankData = new short[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + *

    + * Note: there is no exception when dataArray is + * null, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferShort(short[] dataArray, int size, int offset) + { + super(TYPE_SHORT, size, 1, offset); + bankData = new short[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferShort(short[][] dataArray, int size) + { + super(TYPE_SHORT, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferShort(short[][] dataArray, int size, int[] offsets) + { + super(TYPE_SHORT, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public short[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public short[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this DataBuffer. + * + * @return The data banks. + */ + public short[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return data[i+offset]; + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + return bankData[bank][i+offsets[bank]]; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = (short) val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = (short) val; + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferUShort.java b/libjava/classpath/java/awt/image/DataBufferUShort.java new file mode 100644 index 0000000..981e9e9 --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferUShort.java @@ -0,0 +1,246 @@ +/* DataBufferUShort.java -- + Copyright (C) 2000, 2002, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of short primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public final class DataBufferUShort extends DataBuffer +{ + private short[] data; + private short[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of short elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferUShort(int size) + { + super(TYPE_USHORT, size, 1, 0); + bankData = new short[1][]; + data = new short[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of short elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferUShort(int size, int numBanks) + { + super(TYPE_USHORT, size, numBanks); + bankData = new short[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if dataArray is null + */ + public DataBufferUShort(short[] dataArray, int size) + { + super(TYPE_USHORT, size, 1, 0); + if (dataArray == null) + throw new NullPointerException(); + bankData = new short[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + * + * @throws NullPointerException if dataArray is null + */ + public DataBufferUShort(short[] dataArray, int size, int offset) + { + super(TYPE_USHORT, size, 1, offset); + if (dataArray == null) + throw new NullPointerException(); + bankData = new short[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferUShort(short[][] dataArray, int size) + { + super(TYPE_USHORT, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if dataArray is + * null. + */ + public DataBufferUShort(short[][] dataArray, int size, int[] offsets) + { + super(TYPE_USHORT, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public short[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public short[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this DataBuffer. + * + * @return The data banks. + */ + public short[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return data[i+offset] & 0xffff; // get unsigned short as int + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to i before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + // get unsigned short as int + return bankData[bank][i+offsets[bank]] & 0xffff; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = (short) val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to i before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = (short) val; + } +} diff --git a/libjava/classpath/java/awt/image/DirectColorModel.java b/libjava/classpath/java/awt/image/DirectColorModel.java new file mode 100644 index 0000000..c98c3f8 --- /dev/null +++ b/libjava/classpath/java/awt/image/DirectColorModel.java @@ -0,0 +1,420 @@ +/* DirectColorModel.java -- + Copyright (C) 1999, 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 java.awt.image; + +import gnu.java.awt.Buffers; + +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; + +/** + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author C. Brian Jones (cbj@gnu.org) + * @author Mark Benvenuto (mcb54@columbia.edu) + */ +public class DirectColorModel extends PackedColorModel +{ + /** + * For the color model created with this constructor the pixels + * will have fully opaque alpha components with a value of 255. + * Each mask should describe a fully contiguous set of bits in the + * most likely order of alpha, red, green, blue from the most significant + * byte to the least significant byte. + * + * @param pixelBits the number of bits wide used for bit size of pixel values + * @param rmask the bits describing the red component of a pixel + * @param gmask the bits describing the green component of a pixel + * @param bmask the bits describing the blue component of a pixel + */ + public DirectColorModel(int pixelBits, int rmask, int gmask, int bmask) + { + this(ColorSpace.getInstance(ColorSpace.CS_sRGB), pixelBits, + rmask, gmask, bmask, 0, + false, // not alpha premultiplied + Buffers.smallestAppropriateTransferType(pixelBits) // find type + ); + } + + /** + * For the color model created with this constructor the pixels + * will have fully opaque alpha components with a value of 255. + * Each mask should describe a fully contiguous set of bits in the + * most likely order of red, green, blue from the most significant + * byte to the least significant byte. + * + * @param pixelBits the number of bits wide used for bit size of pixel values + * @param rmask the bits describing the red component of a pixel + * @param gmask the bits describing the green component of a pixel + * @param bmask the bits describing the blue component of a pixel + * @param amask the bits describing the alpha component of a pixel + */ + public DirectColorModel(int pixelBits, + int rmask, int gmask, int bmask, int amask) + { + this(ColorSpace.getInstance(ColorSpace.CS_sRGB), pixelBits, + rmask, gmask, bmask, amask, + false, // not alpha premultiplied + Buffers.smallestAppropriateTransferType(pixelBits) // find type + ); + } + + public DirectColorModel(ColorSpace cspace, int pixelBits, + int rmask, int gmask, int bmask, int amask, + boolean isAlphaPremultiplied, + int transferType) + { + super(cspace, pixelBits, + rmask, gmask, bmask, amask, isAlphaPremultiplied, + ((amask == 0) ? Transparency.OPAQUE : Transparency.TRANSLUCENT), + transferType); + } + + public final int getRedMask() + { + return getMask(0); + } + + public final int getGreenMask() + { + return getMask(1); + } + + public final int getBlueMask() + { + return getMask(2); + } + + public final int getAlphaMask() + { + return hasAlpha() ? getMask(3) : 0; + } + + /** + * Get the red component of the given pixel. + *
    + */ + public final int getRed(int pixel) + { + return extractAndNormalizeSample(pixel, 0); + } + + /** + * Get the green component of the given pixel. + *
    + */ + public final int getGreen(int pixel) + { + return extractAndNormalizeSample(pixel, 1); + } + + /** + * Get the blue component of the given pixel. + *
    + */ + public final int getBlue(int pixel) + { + return extractAndNormalizeSample(pixel, 2); + } + + /** + * Get the alpha component of the given pixel. + *
    + */ + public final int getAlpha(int pixel) + { + if (!hasAlpha()) + return 255; + return extractAndScaleSample(pixel, 3); + } + + private int extractAndNormalizeSample(int pixel, int component) + { + int value = extractAndScaleSample(pixel, component); + if (hasAlpha() && isAlphaPremultiplied()) + value = value*255/getAlpha(pixel); + return value; + } + + private int extractAndScaleSample(int pixel, int component) + { + int field = pixel & getMask(component); + int to8BitShift = + 8 - shifts[component] - getComponentSize(component); + return (to8BitShift>0) ? + (field << to8BitShift) : + (field >>> (-to8BitShift)); + } + + /** + * Get the RGB color value of the given pixel using the default + * RGB color model. + *
    + * + * @param pixel a pixel value + */ + public final int getRGB(int pixel) + { + /* FIXME: The Sun docs show that this method is overridden, but I + don't see any way to improve on the superclass + implementation. */ + return super.getRGB(pixel); + } + + public int getRed(Object inData) + { + return getRed(getPixelFromArray(inData)); + } + + public int getGreen(Object inData) + { + return getGreen(getPixelFromArray(inData)); + } + + public int getBlue(Object inData) + { + return getBlue(getPixelFromArray(inData)); + } + + public int getAlpha(Object inData) + { + return getAlpha(getPixelFromArray(inData)); + } + + public int getRGB(Object inData) + { + return getRGB(getPixelFromArray(inData)); + } + + /** + * Converts a normalized pixel int value in the sRGB color + * space to an array containing a single pixel of the color space + * of the color model. + * + *

    This method performs the inverse function of + * getRGB(Object inData). + * + * @param rgb pixel as a normalized sRGB, 0xAARRGGBB value. + * + * @param pixel to avoid needless creation of arrays, an array to + * use to return the pixel can be given. If null, a suitable array + * will be created. + * + * @return array of transferType containing a single pixel. The + * pixel should be encoded in the natural way of the color model. + * + * @see #getRGB(Object) + */ + public Object getDataElements(int rgb, Object pixel) + { + // FIXME: handle alpha multiply + + int pixelValue = 0; + int a = 0; + if (hasAlpha()) { + a = (rgb >>> 24) & 0xff; + pixelValue = valueToField(a, 3, 8); + } + + if (hasAlpha() && isAlphaPremultiplied()) + { + int r, g, b; + /* if r=0xff and a=0xff, then resulting + value will be (r*a)>>>8 == 0xfe... This seems wrong. + We should divide by 255 rather than shifting >>>8 after + multiplying. + + Too bad, shifting is probably less expensive. + r = ((rgb >>> 16) & 0xff)*a; + g = ((rgb >>> 8) & 0xff)*a; + b = ((rgb >>> 0) & 0xff)*a; */ + /* The r, g, b values we calculate are 16 bit. This allows + us to avoid discarding the lower 8 bits obtained if + multiplying with the alpha band. */ + + // using 16 bit values + r = ((rgb >>> 8) & 0xff00)*a/255; + g = ((rgb >>> 0) & 0xff00)*a/255; + b = ((rgb << 8) & 0xff00)*a/255; + pixelValue |= + valueToField(r, 0, 16) | // Red + valueToField(g, 1, 16) | // Green + valueToField(b, 2, 16); // Blue + } + else + { + int r, g, b; + // using 8 bit values + r = (rgb >>> 16) & 0xff; + g = (rgb >>> 8) & 0xff; + b = (rgb >>> 0) & 0xff; + + pixelValue |= + valueToField(r, 0, 8) | // Red + valueToField(g, 1, 8) | // Green + valueToField(b, 2, 8); // Blue + } + + /* In this color model, the whole pixel fits in the first element + of the array. */ + DataBuffer buffer = Buffers.createBuffer(transferType, pixel, 1); + buffer.setElem(0, pixelValue); + return Buffers.getData(buffer); + } + + /** + * Converts a value to the correct field bits based on the + * information derived from the field masks. + * + * @param highBit the position of the most significant bit in the + * val parameter. + */ + private int valueToField(int val, int component, int highBit) + { + int toFieldShift = + getComponentSize(component) + shifts[component] - highBit; + int ret = (toFieldShift>0) ? + (val << toFieldShift) : + (val >>> (-toFieldShift)); + return ret & getMask(component); + } + + /** + * Converts a 16 bit value to the correct field bits based on the + * information derived from the field masks. + */ + private int value16ToField(int val, int component) + { + int toFieldShift = getComponentSize(component) + shifts[component] - 16; + return (toFieldShift>0) ? + (val << toFieldShift) : + (val >>> (-toFieldShift)); + } + + /** + * Fills an array with the unnormalized component samples from a + * pixel value. I.e. decompose the pixel, but not perform any + * color conversion. + */ + public final int[] getComponents(int pixel, int[] components, int offset) + { + int numComponents = getNumComponents(); + if (components == null) components = new int[offset + numComponents]; + + for (int b=0; b>> shifts[b]; + + return components; + } + + public final int[] getComponents(Object pixel, int[] components, + int offset) + { + return getComponents(getPixelFromArray(pixel), components, offset); + } + + public final WritableRaster createCompatibleWritableRaster(int w, int h) + { + SampleModel sm = createCompatibleSampleModel(w, h); + Point origin = new Point(0, 0); + return Raster.createWritableRaster(sm, origin); + } + + public int getDataElement(int[] components, int offset) + { + int numComponents = getNumComponents(); + int pixelValue = 0; + + for (int c=0; cImageProducer indicates the size of the image + * being produced using this method. A filter can override this + * method to intercept these calls from the producer in order to + * change either the width or the height before in turn calling + * the consumer's setDimensions method. + * + * @param width the width of the image + * @param height the height of the image + */ + public void setDimensions(int width, int height) + { + consumer.setDimensions(width, height); + } + + /** + * An ImageProducer can set a list of properties + * associated with this image by using this method. + * + * @param props the list of properties associated with this image + */ + public void setProperties(Hashtable props) + { + props.put("filters", "ImageFilter"); + consumer.setProperties(props); + } + + /** + * Override this method to process calls to this method from the + * ImageProducer. By default the setColorModel + * method of the consumer is called with the specified model. + * + * @param model the color model to be used most often by setPixels + * @see ColorModel */ + public void setColorModel(ColorModel model) + { + consumer.setColorModel(model); + } + + /** + * The ImageProducer should call this method with a + * bit mask of hints from any of RANDOMPIXELORDER, + * TOPDOWNLEFTRIGHT, COMPLETESCANLINES, + * SINGLEPASS, SINGLEFRAME from the + * ImageConsumer interface. + * + * @param flags a bit mask of hints + * @see ImageConsumer + */ + public void setHints(int flags) + { + consumer.setHints(flags); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a byte at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize) + { + consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an int at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize) + { + consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + } + + /** + * The ImageProducer calls this method to indicate a + * single frame or the entire image is complete. The method is + * also used to indicate an error in loading or producing the + * image. + */ + public void imageComplete(int status) + { + consumer.imageComplete(status); + } +} + diff --git a/libjava/classpath/java/awt/image/ImageObserver.java b/libjava/classpath/java/awt/image/ImageObserver.java new file mode 100644 index 0000000..36dd013 --- /dev/null +++ b/libjava/classpath/java/awt/image/ImageObserver.java @@ -0,0 +1,129 @@ +/* ImageObserver.java -- Java interface for asynchronous updates to an image + Copyright (C) 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 java.awt.image; + +import java.awt.Image; + +/** + * An object implementing the ImageObserver interface can + * receive updates on image construction from an + * ImageProducer asynchronously. + * + * @see ImageProducer + * @author C. Brian Jones (cbj@gnu.org) + */ +public interface ImageObserver +{ + /** + * The width of the image has been provided as the + * width argument to imageUpdate. + * + * @see #imageUpdate + */ + int WIDTH = 1; + + /** + * The height of the image has been provided as the + * height argument to imageUpdate. + * + * @see #imageUpdate + */ + int HEIGHT = 2; + + /** + * The properties of the image have been provided. + * + * @see #imageUpdate + * @see java.awt.Image#getProperty (java.lang.String, java.awt.image.ImageObserver) + */ + int PROPERTIES = 4; + + /** + * More pixels are now available for drawing a scaled variation of + * the image. + * + * @see #imageUpdate + */ + int SOMEBITS = 8; + + /** + * All the pixels needed to draw a complete frame of a multi-frame + * image are available. + * + * @see #imageUpdate + */ + int FRAMEBITS = 16; + + /** + * An image with a single frame, a static image, is complete. + * + * @see #imageUpdate + */ + int ALLBITS = 32; + + /** + * An error was encountered while producing the image. + * + * @see #imageUpdate + */ + int ERROR = 64; + + /** + * Production of the image was aborted. + * + * @see #imageUpdate + */ + int ABORT = 128; + + /** + * This is a callback method for an asynchronous image producer to + * provide updates on the production of the image as it happens. + * + * @param image the image the update refers to + * @param flags a bit mask indicating what is provided with this update + * @param x the x coordinate of the image + * @param y the y coordinate of the image + * @param width the width of the image + * @param height the height of the image + * + * @see java.awt.Image + */ + boolean imageUpdate(Image image, int flags, int x, + int y, int width, int height); +} diff --git a/libjava/classpath/java/awt/image/ImageProducer.java b/libjava/classpath/java/awt/image/ImageProducer.java new file mode 100644 index 0000000..4984668 --- /dev/null +++ b/libjava/classpath/java/awt/image/ImageProducer.java @@ -0,0 +1,85 @@ +/* ImageProducer.java -- Java interface for image production + Copyright (C) 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 java.awt.image; + +/** + * An object implementing the ImageProducer interface can + * produce data for images. Each image has a corresponding + * ImageProducer which is needed for things such as + * resizing the image. + * + * @see ImageConsumer + * @author C. Brian Jones (cbj@gnu.org) + */ +public interface ImageProducer +{ + /** + * Used to register an ImageConsumer with this + * ImageProducer. + */ + void addConsumer(ImageConsumer ic); + + /** + * Used to determine if the given ImageConsumer is + * already registered with this ImageProducer. + */ + boolean isConsumer(ImageConsumer ic); + + /** + * Used to remove an ImageConsumer from the list of + * registered consumers for this ImageProducer. + */ + void removeConsumer(ImageConsumer ic); + + /** + * Used to register an ImageConsumer with this + * ImageProducer and then immediately start + * reconstruction of the image data to be delivered to all + * registered consumers. + */ + void startProduction(ImageConsumer ic); + + /** + * Used to register an ImageConsumer with this + * ImageProducer and then request that this producer + * resend the image data in the order top-down, left-right. + */ + void requestTopDownLeftRightResend(ImageConsumer ic); +} + diff --git a/libjava/classpath/java/awt/image/ImagingOpException.java b/libjava/classpath/java/awt/image/ImagingOpException.java new file mode 100644 index 0000000..ca40e9e --- /dev/null +++ b/libjava/classpath/java/awt/image/ImagingOpException.java @@ -0,0 +1,66 @@ +/* ImagingOpException.java -- indicates an imaging filter failure + Copyright (C) 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 java.awt.image; + +/** + * This exception is thrown when BufferedImageOp or + * RasterOp filters cannot process an image. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see BufferedImageOp + * @see RasterOp + * @status updated to 1.4 + */ +public class ImagingOpException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 8026288481846276658L; + + /** + * Create a new instance with a descriptive error message. + * + * @param message the descriptive error message + */ + public ImagingOpException(String message) + { + super(message); + } +} // class ImagingOpException diff --git a/libjava/classpath/java/awt/image/IndexColorModel.java b/libjava/classpath/java/awt/image/IndexColorModel.java new file mode 100644 index 0000000..299b4dc --- /dev/null +++ b/libjava/classpath/java/awt/image/IndexColorModel.java @@ -0,0 +1,697 @@ +/* IndexColorModel.java -- Java class for interpreting Pixel objects + Copyright (C) 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 java.awt.image; + +import gnu.java.awt.Buffers; + +import java.awt.color.ColorSpace; +import java.math.BigInteger; + +/** + * Color model similar to pseudo visual in X11. + *

    + * This color model maps linear pixel values to actual RGB and alpha colors. + * Thus, pixel values are indexes into the color map. Each color component is + * an 8-bit unsigned value. + *

    + * The IndexColorModel supports a map of valid pixels, allowing + * the representation of holes in the the color map. The valid map is + * represented as a {@link BigInteger} where each bit indicates the validity + * of the map entry with the same index. + *

    + * Colors can have alpha components for transparency support. If alpha + * component values aren't given, color values are opaque. The model also + * supports a reserved pixel value to represent completely transparent colors, + * no matter what the actual color component values are. + *

    + * IndexColorModel supports anywhere from 1 to 16 bit index + * values. The allowed transfer types are {@link DataBuffer#TYPE_BYTE} and + * {@link DataBuffer#TYPE_USHORT}. + * + * @author C. Brian Jones (cbj@gnu.org) + */ +public class IndexColorModel extends ColorModel +{ + private int map_size; + private boolean opaque; // no alpha, but doesn't account for trans + private int trans = -1; + private int[] rgb; + private BigInteger validBits = BigInteger.ZERO; + + /** + * Creates a new indexed color model for size color elements + * with no alpha component. Each array must contain at least + * size elements. For each array, the i-th color is described + * by reds[i], greens[i] and blues[i]. + * + * @param bits the number of bits needed to represent size + * colors. + * @param size the number of colors in the color map. + * @param reds the red component of all colors. + * @param greens the green component of all colors. + * @param blues the blue component of all colors. + * + * @throws IllegalArgumentException if bits < 1 or + * bits > 16. + * @throws NullPointerException if any of the arrays is null. + * @throws ArrayIndexOutOfBoundsException if size is greater + * than the length of the component arrays. + */ + public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, + byte[] blues) + { + this(bits, size, reds, greens, blues, (byte[]) null); + } + + /** + * Creates a new indexed color model for size color elements. + * Each array must contain at least size elements. For each + * array, the i-th color is described by reds[i], greens[i] and blues[i]. + * All the colors are opaque except for the transparent color. + * + * @param bits the number of bits needed to represent size + * colors + * @param size the number of colors in the color map + * @param reds the red component of all colors + * @param greens the green component of all colors + * @param blues the blue component of all colors + * @param trans the index of the transparent color (use -1 for no + * transparent color). + * + * @throws IllegalArgumentException if bits < 1 or + * bits > 16. + * @throws NullPointerException if any of the arrays is null. + * @throws ArrayIndexOutOfBoundsException if size is greater + * than the length of the component arrays. + */ + public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, + byte[] blues, int trans) + { + super(bits, nArray(8, (0 <= trans && trans < size) ? 4 : 3), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + (0 <= trans && trans < size), // hasAlpha + false, OPAQUE, + Buffers.smallestAppropriateTransferType(bits)); + if (bits < 1) + throw new IllegalArgumentException("bits < 1"); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + if (0 <= trans && trans < size) { + this.trans = trans; + transparency = BITMASK; + } + rgb = new int[size]; + for (int i = 0; i < size; i++) + { + rgb[i] = (0xff000000 + | ((reds[i] & 0xff) << 16) + | ((greens[i] & 0xff) << 8) + | (blues[i] & 0xff)); + } + // Generate a bigint with 1's for every pixel + validBits = validBits.setBit(size).subtract(BigInteger.ONE); + } + + /** + * Creates a new indexed color model for size color elements + * including alpha. Each array must contain at least size + * elements. For each array, the i-th color is described + * by reds[i], greens[i], blues[i] and alphas[i]. + * + * @param bits the number of bits needed to represent size + * colors. + * @param size the number of colors in the color map. + * @param reds the red component of all colors. + * @param greens the green component of all colors. + * @param blues the blue component of all colors. + * @param alphas the alpha component of all colors (null + * permitted). + * + * @throws IllegalArgumentException if bits < 1 or + * bits > 16. + * @throws NullPointerException if reds, greens or + * blues is null. + * @throws ArrayIndexOutOfBoundsException if size is greater + * than the length of the component arrays. + */ + public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, + byte[] blues, byte[] alphas) + { + super(bits, nArray(8, (alphas == null ? 3 : 4)), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + (alphas != null), false, TRANSLUCENT, + Buffers.smallestAppropriateTransferType(bits)); + if (bits < 1) + throw new IllegalArgumentException("bits < 1"); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + opaque = (alphas == null); + + rgb = new int[size]; + if (alphas == null) + { + for (int i = 0; i < size; i++) + { + rgb[i] = (0xff000000 + | ((reds[i] & 0xff) << 16) + | ((greens[i] & 0xff) << 8) + | (blues[i] & 0xff)); + } + transparency = OPAQUE; + } + else + { + byte alphaZero = (byte) 0x00; + byte alphaOne = (byte) 0xFF; + for (int i = 0; i < size; i++) + { + alphaZero = (byte) (alphaZero | alphas[i]); + alphaOne = (byte) (alphaOne & alphas[i]); + rgb[i] = ((alphas[i] & 0xff) << 24 + | ((reds[i] & 0xff) << 16) + | ((greens[i] & 0xff) << 8) + | (blues[i] & 0xff)); + } + if ((alphaZero == (byte) 0x00) || (alphaOne == (byte) 0xFF)) + transparency = BITMASK; + else + transparency = TRANSLUCENT; + } + + // Generate a bigint with 1's for every pixel + validBits = validBits.setBit(size).subtract(BigInteger.ONE); + } + + /** + * Creates a new indexed color model using the color components in + * cmap. If hasAlpha is true then + * cmap contains an alpha component after each of the red, green + * and blue components. + * + * @param bits the number of bits needed to represent size + * colors + * @param size the number of colors in the color map + * @param cmap packed color components + * @param start the offset of the first color component in cmap + * @param hasAlpha cmap has alpha values + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws NullPointerException if cmap is null. + */ + public IndexColorModel(int bits, int size, byte[] cmap, int start, + boolean hasAlpha) + { + this(bits, size, cmap, start, hasAlpha, -1); + } + + /** + * Construct an IndexColorModel from an array of red, green, blue, and + * optional alpha components. The component values are interleaved as RGB(A). + * + * @param bits the number of bits needed to represent size + * colors + * @param size the number of colors in the color map + * @param cmap interleaved color components + * @param start the offset of the first color component in cmap + * @param hasAlpha cmap has alpha values + * @param trans the index of the transparent color + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws NullPointerException if cmap is null. + */ + public IndexColorModel(int bits, int size, byte[] cmap, int start, + boolean hasAlpha, int trans) + { + super(bits, nArray(8, hasAlpha || (0 <= trans && trans < size) ? 4 : 3), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + hasAlpha || (0 <= trans && trans < size), false, OPAQUE, + Buffers.smallestAppropriateTransferType(bits)); + if (bits < 1) + throw new IllegalArgumentException("bits < 1"); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + opaque = !hasAlpha; + if (0 <= trans && trans < size) + this.trans = trans; + + rgb = new int[size]; + if (hasAlpha) + { + int alpha; + int alphaZero = 0x00; // use to detect all zeros + int alphaOne = 0xff; // use to detect all ones + for (int i = 0; i < size; i++) { + alpha = cmap[4 * i + 3 + start] & 0xff; + alphaZero = alphaZero | alpha; + alphaOne = alphaOne & alpha; + rgb[i] = + ( alpha << 24 + // red + | ((cmap[4 * i + start] & 0xff) << 16) + // green + | ((cmap[4 * i + 1 + start] & 0xff) << 8) + // blue + | (cmap[4 * i + 2 + start] & 0xff)); + } + if (alphaZero == 0) + transparency = BITMASK; + else if (alphaOne == 255) + transparency = (trans != -1 ? BITMASK : OPAQUE); + else + transparency = TRANSLUCENT; + } + else + { + for (int i = 0; i < size; i++) + rgb[i] = (0xff000000 + // red + | ((cmap[3 * i + start] & 0xff) << 16) + // green + | ((cmap[3 * i + 1 + start] & 0xff) << 8) + // blue + | (cmap[3 * i + 2 + start] & 0xff)); + if (trans != -1) + transparency = BITMASK; + } + + // Generate a bigint with 1's for every pixel + validBits = validBits.setBit(size).subtract(BigInteger.ONE); + } + + /** + * Construct an IndexColorModel from an array of size packed + * colors. Each int element contains 8-bit red, green, blue, and optional + * alpha values packed in order. If hasAlpha is false, then all the colors + * are opaque except for the transparent color. + * + * @param bits the number of bits needed to represent size + * colors + * @param size the number of colors in the color map + * @param cmap packed color components + * @param start the offset of the first color component in cmap + * @param hasAlpha cmap has alpha values + * @param trans the index of the transparent color + * @param transferType {@link DataBuffer#TYPE_BYTE} or + {@link DataBuffer#TYPE_USHORT}. + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws IllegalArgumentException if transferType is something + * other than {@link DataBuffer#TYPE_BYTE} or + * {@link DataBuffer#TYPE_USHORT}. + */ + public IndexColorModel(int bits, int size, int[] cmap, int start, + boolean hasAlpha, int trans, int transferType) + { + super(bits, + nArray(8, 4), // bits for each channel + ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB + true, // has alpha + false, // not premultiplied + TRANSLUCENT, transferType); + if (transferType != DataBuffer.TYPE_BYTE + && transferType != DataBuffer.TYPE_USHORT) + throw new IllegalArgumentException(); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + opaque = !hasAlpha; + if (0 <= trans && trans < size) + this.trans = trans; + + rgb = new int[size]; + if (!hasAlpha) + for (int i = 0; i < size; i++) + rgb[i] = cmap[i + start] | 0xff000000; + else + System.arraycopy(cmap, start, rgb, 0, size); + + // Generate a bigint with 1's for every pixel + validBits = validBits.setBit(size).subtract(BigInteger.ONE); + } + + /** + * Construct an IndexColorModel using a colormap with holes. + *

    + * The IndexColorModel is built from the array of ints defining the + * colormap. Each element contains red, green, blue, and alpha + * components. The ColorSpace is sRGB. The transparency value is + * automatically determined. + *

    + * This constructor permits indicating which colormap entries are valid, + * using the validBits argument. Each entry in cmap is valid if the + * corresponding bit in validBits is set. + * + * @param bits the number of bits needed to represent size + * colors. + * @param size the number of colors in the color map. + * @param cmap packed color components. + * @param start the offset of the first color component in cmap. + * @param transferType {@link DataBuffer#TYPE_BYTE} or + * {@link DataBuffer#TYPE_USHORT}. + * @param validBits a map of the valid entries in cmap. + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws IllegalArgumentException if transferType is something other than + * {@link DataBuffer#TYPE_BYTE} or {@link DataBuffer#TYPE_USHORT}. + */ + public IndexColorModel(int bits, int size, int[] cmap, int start, + int transferType, BigInteger validBits) + { + super(bits, // total bits, sRGB, four channels + nArray(8, 4), // bits for each channel + ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB + true, // has alpha + false, // not premultiplied + TRANSLUCENT, transferType); + if (transferType != DataBuffer.TYPE_BYTE + && transferType != DataBuffer.TYPE_USHORT) + throw new IllegalArgumentException(); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + opaque = false; + this.trans = -1; + this.validBits = validBits; + + rgb = new int[size]; + if (!hasAlpha) + for (int i = 0; i < size; i++) + rgb[i] = cmap[i + start] | 0xff000000; + else + System.arraycopy(cmap, start, rgb, 0, size); + } + + /** + * Returns the size of the color lookup table. + * + * @return The size of the color lookup table. + */ + public final int getMapSize() + { + return map_size; + } + + /** + * Get the index of the transparent color in this color model. + * + * @return The index of the color that is considered transparent, or -1 if + * there is no transparent color. + */ + public final int getTransparentPixel() + { + return trans; + } + + /** + * Fills the supplied array with the red component of each color in the + * lookup table. + * + * @param r an array that is at least as large as {@link #getMapSize()}. + * @throws NullPointerException if r is null. + * @throws ArrayIndexOutOfBoundsException if r has less + * than {@link #getMapSize()} elements. + */ + public final void getReds(byte[] r) + { + int i; + for (i = 0; i < map_size; i++) + r[i] = (byte) ((0x00FF0000 & rgb[i]) >> 16); + } + + /** + * Fills the supplied array with the green component of each color in the + * lookup table. + * + * @param g an array that is at least as large as {@link #getMapSize()}. + * @throws NullPointerException if g is null. + * @throws ArrayIndexOutOfBoundsException if g has less + * than {@link #getMapSize()} elements. + */ + public final void getGreens(byte[] g) + { + int i; + for (i = 0; i < map_size; i++) + g[i] = (byte) ((0x0000FF00 & rgb[i]) >> 8); + } + + /** + * Fills the supplied array with the blue component of each color in the + * lookup table. + * + * @param b an array that is at least as large as {@link #getMapSize()}. + * @throws NullPointerException if b is null. + * @throws ArrayIndexOutOfBoundsException if b has less + * than {@link #getMapSize()} elements. + */ + public final void getBlues(byte[] b) + { + int i; + for (i = 0; i < map_size; i++) + b[i] = (byte) (0x000000FF & rgb[i]); + } + + /** + * Fills the supplied array with the alpha component of each color in the + * lookup table. If the model has a transparent pixel specified, the alpha + * for that pixel will be 0. + * + * @param a an array that is at least as large as {@link #getMapSize()}. + * @throws NullPointerException if a is null. + * @throws ArrayIndexOutOfBoundsException if a has less + * than {@link #getMapSize()} elements. + */ + public final void getAlphas(byte[] a) + { + int i; + for (i = 0; i < map_size; i++) + if (i == trans) + a[i] = (byte) 0; + else + a[i] = (byte) ((0xFF000000 & rgb[i]) >> 24); + } + + /** + * Returns the red component of the color in the lookup table for the + * given pixel value. + * + * @param pixel the pixel lookup value. + * + * @return The red component of the color in the lookup table. + * @throws ArrayIndexOutOfBoundsException if pixel is negative. + */ + public final int getRed(int pixel) + { + if (pixel < map_size) + return (0x00FF0000 & rgb[pixel]) >> 16; + + return 0; + } + + /** + * Returns the green component of the color in the lookup table for the + * given pixel value. + * + * @param pixel the pixel lookup value. + * + * @return The green component of the color in the lookup table. + * @throws ArrayIndexOutOfBoundsException if pixel is negative. + */ + public final int getGreen(int pixel) + { + if (pixel < map_size) + return (0x0000FF00 & rgb[pixel]) >> 8; + + return 0; + } + + /** + * Returns the blue component of the color in the lookup table for the + * given pixel value. + * + * @param pixel the pixel lookup value. + * + * @return The blue component of the color in the lookup table. + * @throws ArrayIndexOutOfBoundsException if pixel is negative. + */ + public final int getBlue(int pixel) + { + if (pixel < map_size) + return 0x000000FF & rgb[pixel]; + + return 0; + } + + /** + * Returns the alpha component of the color in the lookup table for the + * given pixel value. If no alpha channel was specified when the color model + * was created, then 255 is returned for all pixels except the transparent + * pixel (if one is defined - see {@link #getTransparentPixel()}) which + * returns an alpha of 0. + * + * @param pixel the pixel lookup value. + * + * @return The alpha component of the color in the lookup table (in the + * range 0 to 255). + * @throws ArrayIndexOutOfBoundsException if pixel is negative. + */ + public final int getAlpha(int pixel) + { + if (opaque && pixel != trans) + return 255; + if ((pixel == trans && trans != -1) || pixel >= map_size) + return 0; + + return (0xFF000000 & rgb[pixel]) >> 24; + } + + /** + * Get the RGB color value of the given pixel using the default + * RGB color model. + * + * @param pixel the pixel lookup value. + * @return The RGB color value. + * @throws ArrayIndexOutOfBoundsException if pixel is negative. + */ + public final int getRGB(int pixel) + { + if (pixel >= 0 && pixel < map_size) + return rgb[pixel]; + + return 0; + } + + /** + * Get the RGB color values of all pixels in the map using the default + * RGB color model. + * + * @param rgb The destination array. + */ + public final void getRGBs(int[] rgb) + { + System.arraycopy(this.rgb, 0, rgb, 0, map_size); + } + + /** + * Return true if the lookup table contains valid data for + * pixel, and false otherwise. + * + * @param pixel the pixel value used to index the color lookup table. + * @return true if pixel is valid, + * false otherwise. + */ + public boolean isValid(int pixel) + { + if (pixel >= 0) + return validBits.testBit(pixel); + return false; + } + + /** + * Return true if all pixels are valid, false + * otherwise. + * + * @return true if all pixels are valid, false + * otherwise. + */ + public boolean isValid() + { + // Generate a bigint with 1's for every pixel + BigInteger allbits = new BigInteger("0"); + allbits = allbits.setBit(map_size); + allbits = allbits.subtract(new BigInteger("1")); + return allbits.equals(validBits); + } + + /** + * Returns a binary value ({@link BigInteger}) where each bit represents an + * entry in the color lookup table. If the bit is on, the entry is valid. + * + * @return The binary value. + */ + public BigInteger getValidPixels() + { + return validBits; + } + + /** + * Construct a {@link BufferedImage} with rgb pixel values from a + * {@link Raster}. + * + * Constructs a new BufferedImage in which each pixel is an RGBA int from + * a Raster with index-valued pixels. If this model has no alpha component + * or transparent pixel, the type of the new BufferedImage is TYPE_INT_RGB. + * Otherwise the type is TYPE_INT_ARGB. If forceARGB is true, the type is + * forced to be TYPE_INT_ARGB no matter what. + * + * @param raster The source of pixel values. + * @param forceARGB True if type must be TYPE_INT_ARGB. + * @return New BufferedImage with RBGA int pixel values. + */ + public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB) + { + int type = forceARGB ? BufferedImage.TYPE_INT_ARGB + : ((opaque && trans == -1) ? BufferedImage.TYPE_INT_RGB : + BufferedImage.TYPE_INT_ARGB); + + // FIXME: assuming that raster has only 1 band since pixels are supposed + // to be int indexes. + // FIXME: it would likely be more efficient to fetch a complete array, + // but it would take much more memory. + // FIXME: I'm not sure if transparent pixels or alpha values need special + // handling here. + BufferedImage im = new BufferedImage(raster.width, raster.height, type); + for (int x = raster.minX; x < raster.width + raster.minX; x++) + for (int y = raster.minY; y < raster.height + raster.minY; y++) + im.setRGB(x, y, rgb[raster.getSample(x, y, 0)]); + + return im; + } +} diff --git a/libjava/classpath/java/awt/image/Kernel.java b/libjava/classpath/java/awt/image/Kernel.java new file mode 100644 index 0000000..f7c29c3 --- /dev/null +++ b/libjava/classpath/java/awt/image/Kernel.java @@ -0,0 +1,143 @@ +/* Kernel.java -- Java class for an image processing kernel + 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 java.awt.image; + +/** + * Kernel represents an image processing kernel. It gets used to hold + * convolution filters among other purposes. It stores an array of float + * values representing a 2-dimensional array in row-major order. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @version 1.0 + */ +public class Kernel implements Cloneable +{ + private final int width; + private final int height; + private final float[] data; + + /** + * Creates a new Kernel instance. + * + * @param width The 2D width of data. + * @param height The 2D height of data. + * @param data The source data array. + * @exception IllegalArgumentException if width * height < data.length. + */ + public Kernel(int width, int height, float[] data) + throws IllegalArgumentException + { + this.width = width; + this.height = height; + if (data.length < width * height || width < 0 || height < 0) + throw new IllegalArgumentException(); + this.data = new float[width * height]; + System.arraycopy(data, 0, this.data, 0, width * height); + } + + /** + * Return the X origin: (width - 1) / 2 + */ + public final int getXOrigin() + { + return (width - 1) / 2; + } + + /** + * Return the Y origin: (height - 1) / 2 + */ + public final int getYOrigin() + { + return (height - 1) / 2; + } + + /** + * @return The kernel width. + */ + public final int getWidth() + { + return width; + } + + /** + * @return The kernel height. + */ + public final int getHeight() + { + return height; + } + + /** + * Return the kernel data. + * + * If data is null, allocates a new array and returns it. Otherwise, the + * kernel values are copied into data. + * + * @param data Array to copy values into, or null. + * @return The array with copied values. + * @exception IllegalArgumentException if data != null and too small. + */ + public final float[] getKernelData(float[] data) + throws IllegalArgumentException + { + if (data == null) + return (float[])this.data.clone(); + + if (data.length < this.data.length) + throw new IllegalArgumentException(); + + System.arraycopy(this.data, 0, data, 0, this.data.length); + return data; + } + + /** + * @return a clone of this Kernel. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } +} diff --git a/libjava/classpath/java/awt/image/LookupOp.java b/libjava/classpath/java/awt/image/LookupOp.java new file mode 100644 index 0000000..f131daa --- /dev/null +++ b/libjava/classpath/java/awt/image/LookupOp.java @@ -0,0 +1,252 @@ +/* LookupOp.java -- Filter that converts each pixel using a lookup table. + 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 java.awt.image; + +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * LookupOp is a filter that converts each pixel using a lookup table. + * + * For filtering Rasters, the lookup table must have either one component + * that is applied to all bands, or one component for every band in the + * Rasters. + * + * For BufferedImages, the lookup table may apply to both color and alpha + * components. If the lookup table contains one component, or if there are + * the same number of components as color components in the source, the table + * applies to all color components. Otherwise the table applies to all + * components including alpha. Alpha premultiplication is ignored during the + * lookup filtering. + * + * After filtering, if color conversion is necessary, the conversion happens, + * taking alpha premultiplication into account. + * + * @author jlquinn + */ +public class LookupOp implements BufferedImageOp, RasterOp +{ + private LookupTable lut; + private RenderingHints hints; + + /** Construct a new LookupOp. + * + * @param lookup LookupTable to use. + * @param hints Rendering hints (can be null). + */ + public LookupOp(LookupTable lookup, RenderingHints hints) + { + lut = lookup; + this.hints = hints; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage) + */ + public BufferedImage filter(BufferedImage src, BufferedImage dst) + { + if (src.getColorModel() instanceof IndexColorModel) + throw new IllegalArgumentException("LookupOp.filter: IndexColorModel " + + "not allowed"); + if (dst == null) + dst = createCompatibleDestImage(src, src.getColorModel()); + + // Set up for potential colormodel mismatch + BufferedImage tgt; + if (dst.getColorModel().equals(src.getColorModel())) + tgt = dst; + else + tgt = createCompatibleDestImage(src, src.getColorModel()); + + Raster sr = src.getRaster(); + WritableRaster dr = tgt.getRaster(); + + if (src.getColorModel().hasAlpha() && + (lut.getNumComponents() == 1 || + lut.getNumComponents() == src.getColorModel().getNumColorComponents())) + { + // Need to ignore alpha for lookup + int[] dbuf = new int[src.getColorModel().getNumComponents()]; + int tmpBands = src.getColorModel().getNumColorComponents(); + int[] tmp = new int[tmpBands]; + + // Filter the pixels + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + { + // Filter only color components, but also copy alpha + sr.getPixel(x, y, dbuf); + System.arraycopy(dbuf, 0, tmp, 0, tmpBands); + dr.setPixel(x, y, lut.lookupPixel(tmp, dbuf)); + } + } + else if (lut.getNumComponents() != 1 + && + lut.getNumComponents() != src.getColorModel().getNumComponents()) + throw new IllegalArgumentException("LookupOp.filter: " + + "Incompatible lookup " + + "table and source image"); + + // No alpha to ignore + int[] dbuf = new int[src.getColorModel().getNumComponents()]; + + // Filter the pixels + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + dr.setPixel(x, y, lut.lookupPixel(sr.getPixel(x, y, dbuf), dbuf)); + + if (tgt != dst) + { + // Convert between color models. + // TODO Check that premultiplied alpha is handled correctly here. + Graphics2D gg = dst.createGraphics(); + gg.setRenderingHints(hints); + gg.drawImage(tgt, 0, 0, null); + gg.dispose(); + } + + return dst; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) + */ + public Rectangle2D getBounds2D(BufferedImage src) + { + return src.getRaster().getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel) + */ + public BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel dstCM) + { + // FIXME: set properties to those in src + return new BufferedImage(dstCM, + src.getRaster().createCompatibleWritableRaster(), + src.isPremultiplied, null); + } + + /** Return corresponding destination point for source point. + * + * LookupOp will return the value of src unchanged. + * @param src The source point. + * @param dst The destination point. + * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D) + */ + public Point2D getPoint2D(Point2D src, Point2D dst) + { + if (dst == null) + return (Point2D) src.clone(); + + dst.setLocation(src); + return dst; + } + + /** Return the LookupTable for this op. */ + public LookupTable getTable() + { + return lut; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getRenderingHints() + */ + public RenderingHints getRenderingHints() + { + return hints; + } + + /** Filter a raster through a lookup table. + * + * Applies the lookup table for this Rasterop to each pixel of src and + * puts the results in dest. If dest is null, a new Raster is created and + * returned. + * + * @param src The source raster. + * @param dest The destination raster. + * @return The WritableRaster with the filtered pixels. + * @throws IllegalArgumentException if lookup table has more than one + * component but not the same as src and dest. + * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster) + */ + public WritableRaster filter(Raster src, WritableRaster dest) + { + if (dest == null) + // Allocate a raster if needed + dest = createCompatibleDestRaster(src); + else + if (src.getNumBands() != dest.getNumBands()) + throw new IllegalArgumentException(); + + if (lut.getNumComponents() != 1 + && lut.getNumComponents() != src.getNumBands()) + throw new IllegalArgumentException(); + + + // Allocate pixel storage. + int[] tmp = new int[src.getNumBands()]; + + // Filter the pixels + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + dest.setPixel(x, y, lut.lookupPixel(src.getPixel(x, y, tmp), tmp)); + return dest; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) + */ + public Rectangle2D getBounds2D(Raster src) + { + return src.getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) + */ + public WritableRaster createCompatibleDestRaster(Raster src) + { + return src.createCompatibleWritableRaster(); + } + +} diff --git a/libjava/classpath/java/awt/image/LookupTable.java b/libjava/classpath/java/awt/image/LookupTable.java new file mode 100644 index 0000000..f814b8e --- /dev/null +++ b/libjava/classpath/java/awt/image/LookupTable.java @@ -0,0 +1,109 @@ +/* LookupTable.java -- Java class for a pixel translation table. + 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 java.awt.image; + +/** + * LookupTable represents translation arrays for pixel values. It wraps one + * or more data arrays for each layer (or component) in an image, such as + * Alpha, R, G, and B. When doing translation, the offset is subtracted from + * the pixel values to allow a subset of an array to be used. + * + * @see ByteLookupTable + * @see ShortLookupTable + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @version 1.0 + */ +public abstract class LookupTable +{ + // Not protected since that's part of the public API. + int offset; + int numComponents; + + /** + * Creates a new LookupTable instance. + * + * If numComponents is 1, the same translation table is used for all pixel + * components. + * + * @param offset Offset to be subtracted. + * @param numComponents Number of image components. + * @exception IllegalArgumentException if offset < 0 or numComponents < 1. + */ + protected LookupTable(int offset, int numComponents) + throws IllegalArgumentException + { + if (offset < 0 || numComponents < 1) + throw new IllegalArgumentException(); + this.offset = offset; + this.numComponents = numComponents; + } + + /** Return the number of components. */ + public int getNumComponents() + { + return numComponents; + } + + /** Return the offset. */ + public int getOffset() + { + return offset; + } + + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dest Destination array for values, or null. + * @return Translated values for the pixel. + */ + public abstract int[] lookupPixel(int[] src, int[] dest); +} diff --git a/libjava/classpath/java/awt/image/MemoryImageSource.java b/libjava/classpath/java/awt/image/MemoryImageSource.java new file mode 100644 index 0000000..c27e0bf --- /dev/null +++ b/libjava/classpath/java/awt/image/MemoryImageSource.java @@ -0,0 +1,373 @@ +/* MemoryImageSource.java -- Java class for providing image data + 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 java.awt.image; + +import java.util.Hashtable; +import java.util.Vector; + +public class MemoryImageSource implements ImageProducer +{ + private boolean animated = false; + private boolean fullbuffers = false; + private int[] pixeli; + private int width; + private int height; + private int offset; + private int scansize; + private byte[] pixelb; + private ColorModel cm; + private Hashtable props = new Hashtable(); + private Vector consumers = new Vector(); + + /** + * Construct an image producer that reads image data from a byte + * array. + * + * @param w width of image + * @param h height of image + * @param cm the color model used to represent pixel values + * @param pix a byte array of pixel values + * @param off the offset into the array at which the first pixel is stored + * @param scan the number of array elements that represents a single pixel row + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte[] pix, int off, + int scan) + { + this(w, h, cm, pix, off, scan, null); + } + + /** + * Constructs an ImageProducer from memory + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte[] pix, int off, + int scan, Hashtable props) + { + width = w; + height = h; + this.cm = cm; + offset = off; + scansize = scan; + this.props = props; + int max = ((scansize > width) ? scansize : width); + pixelb = pix; + } + + /** + * Construct an image producer that reads image data from an + * integer array. + * + * @param w width of image + * @param h height of image + * @param cm the color model used to represent pixel values + * @param pix an integer array of pixel values + * @param off the offset into the array at which the first pixel is stored + * @param scan the number of array elements that represents a single pixel row + */ + public MemoryImageSource(int w, int h, ColorModel cm, int[] pix, int off, + int scan) + { + this(w, h, cm, pix, off, scan, null); + } + + /** + Constructs an ImageProducer from memory + */ + public MemoryImageSource(int w, int h, ColorModel cm, int[] pix, int off, + int scan, Hashtable props) + { + width = w; + height = h; + this.cm = cm; + offset = off; + scansize = scan; + this.props = props; + int max = ((scansize > width) ? scansize : width); + pixeli = pix; + } + + /** + * Constructs an ImageProducer from memory using the default RGB ColorModel + */ + public MemoryImageSource(int w, int h, int[] pix, int off, int scan, + Hashtable props) + { + this(w, h, ColorModel.getRGBdefault(), pix, off, scan, props); + } + + /** + * Constructs an ImageProducer from memory using the default RGB ColorModel + */ + public MemoryImageSource(int w, int h, int[] pix, int off, int scan) + { + this(w, h, ColorModel.getRGBdefault(), pix, off, scan, null); + } + + /** + * Used to register an ImageConsumer with this + * ImageProducer. + */ + public synchronized void addConsumer(ImageConsumer ic) + { + if (consumers.contains(ic)) + return; + + consumers.addElement(ic); + } + + /** + * Used to determine if the given ImageConsumer is + * already registered with this ImageProducer. + */ + public synchronized boolean isConsumer(ImageConsumer ic) + { + if (consumers.contains(ic)) + return true; + return false; + } + + /** + * Used to remove an ImageConsumer from the list of + * registered consumers for this ImageProducer. + */ + public synchronized void removeConsumer(ImageConsumer ic) + { + consumers.removeElement(ic); + } + + /** + * Used to register an ImageConsumer with this + * ImageProducer and then immediately start + * reconstruction of the image data to be delivered to all + * registered consumers. + */ + public void startProduction(ImageConsumer ic) + { + if (! (consumers.contains(ic))) + consumers.addElement(ic); + + Vector list = (Vector) consumers.clone(); + for (int i = 0; i < list.size(); i++) + { + ic = (ImageConsumer) list.elementAt(i); + sendPicture(ic); + if (animated) + ic.imageComplete(ImageConsumer.SINGLEFRAME); + else + ic.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } + + /** + * Used to register an ImageConsumer with this + * ImageProducer and then request that this producer + * resend the image data in the order top-down, left-right. + */ + public void requestTopDownLeftRightResend(ImageConsumer ic) + { + startProduction(ic); + } + + /** + * Changes a flag to indicate whether this MemoryImageSource supports + * animations. + * + * @param animated A flag indicating whether this class supports animations + */ + public synchronized void setAnimated(boolean animated) + { + this.animated = animated; + } + + /** + * A flag to indicate whether or not to send full buffer updates when + * sending animation. If this flag is set then full buffers are sent + * in the newPixels methods instead of just regions. + * + * @param fullbuffers - a flag indicating whether to send the full buffers + */ + public synchronized void setFullBufferUpdates(boolean fullbuffers) + { + this.fullbuffers = fullbuffers; + } + + /** + * Send an animation frame to the image consumers. + */ + public void newPixels() + { + if (animated == true) + { + ImageConsumer ic; + Vector list = (Vector) consumers.clone(); + for (int i = 0; i < list.size(); i++) + { + ic = (ImageConsumer) list.elementAt(i); + sendPicture(ic); + ic.imageComplete(ImageConsumer.SINGLEFRAME); + } + } + } + + private void sendPicture(ImageConsumer ic) + { + ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT); + if (props != null) + ic.setProperties(props); + ic.setDimensions(width, height); + ic.setColorModel(cm); + if (pixeli != null) + ic.setPixels(0, 0, width, height, cm, pixeli, offset, scansize); + else + ic.setPixels(0, 0, width, height, cm, pixelb, offset, scansize); + } + + /** + * Send an animation frame to the image consumers containing the specified + * pixels unless setFullBufferUpdates is set. + */ + public synchronized void newPixels(int x, int y, int w, int h) + { + if (animated == true) + { + if (fullbuffers) + newPixels(); + else + { + ImageConsumer ic; + Vector list = (Vector) consumers.clone(); + for (int i = 0; i < list.size(); i++) + { + ic = (ImageConsumer) list.elementAt(i); + ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT); + if (props != null) + ic.setProperties(props); + if (pixeli != null) + { + int[] pixelbuf = new int[w * h]; + for (int row = y; row < y + h; row++) + System.arraycopy(pixeli, row * scansize + x + offset, + pixelbuf, 0, w * h); + ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w); + } + else + { + byte[] pixelbuf = new byte[w * h]; + for (int row = y; row < y + h; row++) + System.arraycopy(pixelb, row * scansize + x + offset, + pixelbuf, 0, w * h); + + ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w); + } + ic.imageComplete(ImageConsumer.SINGLEFRAME); + } + } + } + } + + /** + * Send an animation frame to the image consumers containing the specified + * pixels unless setFullBufferUpdates is set. + * + * If framenotify is set then a notification is sent when the frame + * is sent otherwise no status is sent. + */ + public synchronized void newPixels(int x, int y, int w, int h, + boolean framenotify) + { + if (animated == true) + { + if (fullbuffers) + newPixels(); + else + { + ImageConsumer ic; + Vector list = (Vector) consumers.clone(); + for (int i = 0; i < list.size(); i++) + { + ic = (ImageConsumer) list.elementAt(i); + ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT); + if (props != null) + ic.setProperties(props); + if (pixeli != null) + { + int[] pixelbuf = new int[w * h]; + for (int row = y; row < y + h; row++) + System.arraycopy(pixeli, row * scansize + x + offset, + pixelbuf, 0, w * h); + ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w); + } + else + { + byte[] pixelbuf = new byte[w * h]; + for (int row = y; row < y + h; row++) + System.arraycopy(pixelb, row * scansize + x + offset, + pixelbuf, 0, w * h); + ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w); + } + if (framenotify == true) + ic.imageComplete(ImageConsumer.SINGLEFRAME); + } + } + } + } + + public synchronized void newPixels(byte[] newpix, ColorModel newmodel, + int offset, int scansize) + { + pixeli = null; + pixelb = newpix; + cm = newmodel; + this.offset = offset; + this.scansize = scansize; + if (animated == true) + newPixels(); + } + + public synchronized void newPixels(int[] newpix, ColorModel newmodel, + int offset, int scansize) + { + pixelb = null; + pixeli = newpix; + cm = newmodel; + this.offset = offset; + this.scansize = scansize; + if (animated == true) + newPixels(); + } +} diff --git a/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java b/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java new file mode 100644 index 0000000..18a6e55 --- /dev/null +++ b/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java @@ -0,0 +1,388 @@ +/* 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 java.awt.image; + +import gnu.java.awt.Buffers; + +/** + * MultiPixelPackedSampleModel provides a single band model that supports + * multiple pixels in a single unit. Pixels have 2^n bits and 2^k pixels fit + * per data element. + * + * @author Jerry Quinn (jlquinn@optonline.net) + */ +public class MultiPixelPackedSampleModel extends SampleModel +{ + private int scanlineStride; + private int[] bitMasks; + private int[] bitOffsets; + private int[] sampleSize; + private int dataBitOffset; + private int elemBits; + private int numberOfBits; + private int numElems; + + public MultiPixelPackedSampleModel(int dataType, int w, int h, + int numberOfBits) + { + this(dataType, w, h, numberOfBits, 0, 0); + } + + public MultiPixelPackedSampleModel(int dataType, int w, int h, + int numberOfBits, int scanlineStride, + int dataBitOffset) + { + super(dataType, w, h, 1); + + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + elemBits = 8; + break; + case DataBuffer.TYPE_USHORT: + elemBits = 16; + break; + case DataBuffer.TYPE_INT: + elemBits = 32; + break; + default: + throw new IllegalArgumentException("MultiPixelPackedSampleModel" + + " unsupported dataType"); + } + + this.dataBitOffset = dataBitOffset; + + this.numberOfBits = numberOfBits; + if (numberOfBits > elemBits) + throw new RasterFormatException("MultiPixelPackedSampleModel pixel size" + + " larger than dataType"); + switch (numberOfBits) + { + case 1: case 2: case 4: case 8: case 16: case 32: break; + default: + throw new RasterFormatException("MultiPixelPackedSampleModel pixel" + + " size not 2^n bits"); + } + numElems = elemBits / numberOfBits; + + // Compute scan line large enough for w pixels. + if (scanlineStride == 0) + scanlineStride = ((dataBitOffset + w * numberOfBits) / elemBits); + this.scanlineStride = scanlineStride; + + + sampleSize = new int[1]; + sampleSize[0] = numberOfBits; + + bitMasks = new int[numElems]; + bitOffsets = new int[numElems]; + for (int i=0; i < numElems; i++) + { + bitOffsets[numElems - i- 1] = numberOfBits * i; + bitMasks[numElems - i - 1] = ((1 << numberOfBits) - 1) << + bitOffsets[numElems - i - 1]; + } + } + + public SampleModel createCompatibleSampleModel(int w, int h) + { + /* FIXME: We can avoid recalculation of bit offsets and sample + sizes here by passing these from the current instance to a + special private constructor. */ + return new MultiPixelPackedSampleModel(dataType, w, h, numberOfBits); + } + + + /** + * Creates a DataBuffer for holding pixel data in the format and + * layout described by this SampleModel. The returned buffer will + * consist of one single bank. + */ + public DataBuffer createDataBuffer() + { + int size; + + // FIXME: The comment refers to SinglePixelPackedSampleModel. See if the + // same can be done for MultiPixelPackedSampleModel. + // We can save (scanlineStride - width) pixels at the very end of + // the buffer. The Sun reference implementation (J2SE 1.3.1 and + // 1.4.1_01) seems to do this; tested with Mauve test code. + size = scanlineStride * height; + + return Buffers.createBuffer(getDataType(), size); + } + + + public int getNumDataElements() + { + return 1; + } + + public int[] getSampleSize() + { + return sampleSize; + } + + public int getSampleSize(int band) + { + return sampleSize[0]; + } + + public int getOffset(int x, int y) + { + return scanlineStride * y + ((dataBitOffset + x*numberOfBits) / elemBits); + } + + public int getBitOffset(int x) + { + return (dataBitOffset + x*numberOfBits) % elemBits; + } + + public int getDataBitOffset() + { + return dataBitOffset; + } + + public int getScanlineStride() + { + return scanlineStride; + } + + public int getPixelBitStride() + { + return numberOfBits; + } + + + public SampleModel createSubsetSampleModel(int[] bands) + { + int numBands = bands.length; + if (numBands != 1) + throw new RasterFormatException("MultiPixelPackedSampleModel only" + + " supports one band"); + + return new MultiPixelPackedSampleModel(dataType, width, height, + numberOfBits, scanlineStride, + dataBitOffset); + } + + /** + * Extract one pixel and return in an array of transfer type. + * + * Extracts the pixel at x, y from data and stores into the 0th index of the + * array obj, since there is only one band. If obj is null, a new array of + * getTransferType() is created. + * + * @param x The x-coordinate of the pixel rectangle to store in obj. + * @param y The y-coordinate of the pixel rectangle to store in obj. + * @param obj The primitive array to store the pixels into or null to force creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + * @see java.awt.image.SampleModel#getDataElements(int, int, java.lang.Object, java.awt.image.DataBuffer) + */ + public Object getDataElements(int x, int y, Object obj, + DataBuffer data) + { + int pixel = getSample(x, y, 0, data); + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + if (obj == null) obj = new byte[1]; + ((byte[])obj)[0] = (byte)pixel; + return obj; + case DataBuffer.TYPE_USHORT: + if (obj == null) obj = new short[1]; + ((short[])obj)[0] = (short)pixel; + return obj; + case DataBuffer.TYPE_INT: + if (obj == null) obj = new int[1]; + ((int[])obj)[0] = pixel; + return obj; + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } + } + + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + if (iArray == null) iArray = new int[1]; + iArray[0] = getSample(x, y, 0, data); + + return iArray; + } + + public int[] getPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int offset = getOffset(x, y); + if (iArray == null) iArray = new int[w*h]; + int outOffset = 0; + for (y=0; y>> bitOffsets[b]; + x++; + } + } + offset += scanlineStride; + } + return iArray; + } + + public int getSample(int x, int y, int b, DataBuffer data) + { + int pos = + ((dataBitOffset + x * numberOfBits) % elemBits) / numberOfBits; + int offset = getOffset(x, y); + int samples = data.getElem(offset); + return (samples & bitMasks[pos]) >>> bitOffsets[pos]; + } + + /** + * Set the pixel at x, y to the value in the first element of the primitive + * array obj. + * + * @param x The x-coordinate of the data elements in obj. + * @param y The y-coordinate of the data elements in obj. + * @param obj The primitive array containing the data elements to set. + * @param data The DataBuffer to store the data elements into. + * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer) + */ + public void setDataElements(int x, int y, Object obj, DataBuffer data) + { + int transferType = getTransferType(); + if (getTransferType() != data.getDataType()) + { + throw new IllegalArgumentException("transfer type ("+ + getTransferType()+"), "+ + "does not match data "+ + "buffer type (" + + data.getDataType() + + ")."); + } + + int offset = getOffset(x, y); + + try + { + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + { + DataBufferByte out = (DataBufferByte) data; + byte[] in = (byte[]) obj; + out.getData()[offset] = in[0]; + return; + } + case DataBuffer.TYPE_USHORT: + { + DataBufferUShort out = (DataBufferUShort) data; + short[] in = (short[]) obj; + out.getData()[offset] = in[0]; + return; + } + case DataBuffer.TYPE_INT: + { + DataBufferInt out = (DataBufferInt) data; + int[] in = (int[]) obj; + out.getData()[offset] = in[0]; + return; + } + default: + throw new ClassCastException("Unsupported data type"); + } + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + String msg = "While writing data elements" + + ", x="+x+", y="+y+ + ", width="+width+", height="+height+ + ", scanlineStride="+scanlineStride+ + ", offset="+offset+ + ", data.getSize()="+data.getSize()+ + ", data.getOffset()="+data.getOffset()+ + ": " + + aioobe; + throw new ArrayIndexOutOfBoundsException(msg); + } + } + + public void setPixel(int x, int y, int[] iArray, DataBuffer data) + { + setSample(x, y, 0, iArray[0], data); + } + + public void setSample(int x, int y, int b, int s, DataBuffer data) + { + int bitpos = + ((dataBitOffset + x * numberOfBits) % elemBits) / numberOfBits; + int offset = getOffset(x, y); + + s = s << bitOffsets[bitpos]; + s = s & bitMasks[bitpos]; + + int sample = data.getElem(offset); + sample |= s; + data.setElem(offset, sample); + } + + /** + * Creates a String with some information about this SampleModel. + * @return A String describing this SampleModel. + * @see java.lang.Object#toString() + */ + public String toString() + { + StringBuffer result = new StringBuffer(); + result.append(getClass().getName()); + result.append("["); + result.append("scanlineStride=").append(scanlineStride); + for(int i=0; i < bitMasks.length; i+=1) + { + result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i])); + } + + result.append("]"); + return result.toString(); + } +} diff --git a/libjava/classpath/java/awt/image/PackedColorModel.java b/libjava/classpath/java/awt/image/PackedColorModel.java new file mode 100644 index 0000000..894e6e6 --- /dev/null +++ b/libjava/classpath/java/awt/image/PackedColorModel.java @@ -0,0 +1,192 @@ +/* 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 java.awt.image; + +import gnu.java.awt.BitMaskExtent; + +import java.awt.Point; +import java.awt.color.ColorSpace; + +/** + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public abstract class PackedColorModel extends ColorModel +{ + private int masks[]; + + /* Package accessibility, the DirectColorModel needs this array */ + int shifts[]; + + public PackedColorModel(ColorSpace cspace, int pixelBits, + int[] colorMaskArray, int alphaMask, + boolean isAlphaPremultiplied, + int transparency, + int transferType) + { + super(pixelBits, calcBitsPerComponent(colorMaskArray, alphaMask), + cspace, (alphaMask != 0), isAlphaPremultiplied, transparency, + transferType); + initMasks(colorMaskArray, alphaMask); + if ((pixelBits<1) || (pixelBits>32)) { + throw new IllegalArgumentException("pixels per bits must be " + + "in the range [1, 32]"); + } + } + + private static int[] calcBitsPerComponent(int[] colorMaskArray, + int alphaMask) + { + int numComponents = colorMaskArray.length; + if (alphaMask != 0) numComponents++; + + int[] bitsPerComponent = new int[numComponents]; + + BitMaskExtent extent = new BitMaskExtent(); + for (int b=0; b(x, y, w, h) within the image. The data will be + * stored in the provided pix array, which must have + * been initialized to a size of at least w * h. The + * data for a pixel (m, n) in the grab rectangle will be stored at + * pix[(n - y) * scansize + (m - x) + off]. + * + * @param img the Image from which to grab pixels + * @param x the x coordinate, relative to img's + * top-left corner, of the grab rectangle's top-left pixel + * @param y the y coordinate, relative to img's + * top-left corner, of the grab rectangle's top-left pixel + * @param w the width of the grab rectangle, in pixels + * @param h the height of the grab rectangle, in pixels + * @param pix the array in which to store grabbed RGB pixel data + * @param off the offset into the pix array at which to + * start storing RGB data + * @param scansize a set of scansize consecutive + * elements in the pix array represents one row of + * pixels in the grab rectangle + */ + public PixelGrabber(Image img, int x, int y, int w, int h, + int pix[], int off, int scansize) + { + this (img.getSource(), x, y, w, h, pix, off, scansize); + } + + /** + * Construct a PixelGrabber that will retrieve RGB data from a given + * ImageProducer. + * + * The RGB data will be retrieved from a rectangular region + * (x, y, w, h) within the image produced by + * ip. The data will be stored in the provided + * pix array, which must have been initialized to a + * size of at least w * h. The data for a pixel (m, n) + * in the grab rectangle will be stored at + * pix[(n - y) * scansize + (m - x) + off]. + * + * @param ip the ImageProducer from which to grab pixels + * @param x the x coordinate of the grab rectangle's top-left pixel, + * specified relative to the top-left corner of the image produced + * by ip + * @param y the y coordinate of the grab rectangle's top-left pixel, + * specified relative to the top-left corner of the image produced + * by ip + * @param w the width of the grab rectangle, in pixels + * @param h the height of the grab rectangle, in pixels + * @param pix the array in which to store grabbed RGB pixel data + * @param off the offset into the pix array at which to + * start storing RGB data + * @param scansize a set of scansize consecutive + * elements in the pix array represents one row of + * pixels in the grab rectangle + */ + public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, + int pix[], int off, int scansize) + { + this.ip = ip; + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.offset = off; + this.scansize = scansize; + + int_pixel_buffer = pix; + // Initialize the byte array in case ip sends us byte-formatted + // pixel data. + byte_pixel_buffer = new byte[pix.length * 4]; + } + + /** + * Construct a PixelGrabber that will retrieve data from a given + * Image. + * + * The RGB data will be retrieved from a rectangular region + * (x, y, w, h) within the image. The data will be + * stored in an internal array which can be accessed by calling + * getPixels. The data for a pixel (m, n) in the grab + * rectangle will be stored in the returned array at index + * (n - y) * scansize + (m - x) + off. + * If forceRGB is false, then the returned data will be not be + * converted to RGB from its format in img. + * + * If w is negative, the width of the grab region will + * be from x to the right edge of the image. Likewise, if + * h is negative, the height of the grab region will be + * from y to the bottom edge of the image. + * + * @param img the Image from which to grab pixels + * @param x the x coordinate, relative to img's + * top-left corner, of the grab rectangle's top-left pixel + * @param y the y coordinate, relative to img's + * top-left corner, of the grab rectangle's top-left pixel + * @param w the width of the grab rectangle, in pixels + * @param h the height of the grab rectangle, in pixels + * @param forceRGB true to force conversion of the rectangular + * region's pixel data to RGB + */ + public PixelGrabber(Image img, + int x, int y, + int w, int h, + boolean forceRGB) + { + this.ip = img.getSource(); + this.x = x; + this.y = y; + width = w; + height = h; + // If width or height is negative, postpone pixel buffer + // initialization until setDimensions is called back by ip. + if (width >= 0 && height >= 0) + { + int_pixel_buffer = new int[width * height]; + byte_pixel_buffer = new byte[width * height]; + } + this.forceRGB = forceRGB; + } + + /** + * Start grabbing pixels. + * + * Spawns an image production thread that calls back to this + * PixelGrabber's ImageConsumer methods. + */ + public synchronized void startGrabbing() + { + // Make sure we're not already grabbing. + if (grabbing == false) + { + grabbing = true; + grabberThread = new Thread () + { + public void run () + { + ip.startProduction (PixelGrabber.this); + } + }; + grabberThread.start (); + } + } + + /** + * Abort pixel grabbing. + */ + public synchronized void abortGrabbing() + { + if (grabbing) + { + // Interrupt the grabbing thread. + Thread moribund = grabberThread; + grabberThread = null; + moribund.interrupt(); + + imageComplete (ImageConsumer.IMAGEABORTED); + } + } + + /** + * Have our Image or ImageProducer start sending us pixels via our + * ImageConsumer methods and wait for all pixels in the grab + * rectangle to be delivered. + * + * @return true if successful, false on abort or error + * + * @throws InterruptedException if interrupted by another thread. + */ + public synchronized boolean grabPixels() throws InterruptedException + { + return grabPixels(0); + } + + /** + * grabPixels's behavior depends on the value of ms. + * + * If ms < 0, return true if all pixels from the source image have + * been delivered, false otherwise. Do not wait. + * + * If ms >= 0 then we request that our Image or ImageProducer start + * delivering pixels to us via our ImageConsumer methods. + * + * If ms > 0, wait at most ms milliseconds for + * delivery of all pixels within the grab rectangle. + * + * If ms == 0, wait until all pixels have been delivered. + * + * @return true if all pixels from the source image have been + * delivered, false otherwise + * + * @throws InterruptedException if this thread is interrupted while + * we are waiting for pixels to be delivered + */ + public synchronized boolean grabPixels(long ms) throws InterruptedException + { + if (ms < 0) + return ((observerStatus & (ImageObserver.FRAMEBITS + | ImageObserver.ALLBITS)) != 0); + + // Spawn a new ImageProducer thread to send us the image data via + // our ImageConsumer methods. + startGrabbing(); + + if (ms > 0) + { + long stop_time = System.currentTimeMillis() + ms; + long time_remaining; + while (grabbing) + { + time_remaining = stop_time - System.currentTimeMillis(); + if (time_remaining <= 0) + break; + wait (time_remaining); + } + abortGrabbing (); + } + else + wait (); + + // If consumerStatus is non-zero then the image is done loading or + // an error has occurred. + if (consumerStatus != 0) + return setObserverStatus (); + + return ((observerStatus & (ImageObserver.FRAMEBITS + | ImageObserver.ALLBITS)) != 0); + } + + // Set observer status flags based on the current consumer status + // flags. Return true if the consumer flags indicate that the + // image was loaded successfully, or false otherwise. + private synchronized boolean setObserverStatus () + { + boolean retval = false; + + if ((consumerStatus & IMAGEERROR) != 0) + observerStatus |= ImageObserver.ERROR; + + if ((consumerStatus & IMAGEABORTED) != 0) + observerStatus |= ImageObserver.ABORT; + + if ((consumerStatus & STATICIMAGEDONE) != 0) + { + observerStatus |= ImageObserver.ALLBITS; + retval = true; + } + + if ((consumerStatus & SINGLEFRAMEDONE) != 0) + { + observerStatus |= ImageObserver.FRAMEBITS; + retval = true; + } + + return retval; + } + + /** + * @return the status of the pixel grabbing thread, represented by a + * bitwise OR of ImageObserver flags + */ + public synchronized int getStatus() + { + return observerStatus; + } + + /** + * @return the width of the grab rectangle in pixels, or a negative + * number if the ImageProducer has not yet called our setDimensions + * method + */ + public synchronized int getWidth() + { + return width; + } + + /** + * @return the height of the grab rectangle in pixels, or a negative + * number if the ImageProducer has not yet called our setDimensions + * method + */ + public synchronized int getHeight() + { + return height; + } + + /** + * @return a byte array of pixel data if ImageProducer delivered + * pixel data using the byte[] variant of setPixels, or an int array + * otherwise + */ + public synchronized Object getPixels() + { + if (ints_delivered) + return int_pixel_buffer; + else if (bytes_delivered) + return byte_pixel_buffer; + else + return null; + } + + /** + * @return the ColorModel currently being used for the majority of + * pixel data conversions + */ + public synchronized ColorModel getColorModel() + { + return model; + } + + /** + * Our ImageProducer calls this method to indicate the + * size of the image being produced. + * + * setDimensions is an ImageConsumer method. None of PixelGrabber's + * ImageConsumer methods should be called by code that instantiates + * a PixelGrabber. They are only made public so they can be called + * by the PixelGrabber's ImageProducer. + * + * @param width the width of the image + * @param height the height of the image + */ + public synchronized void setDimensions(int width, int height) + { + // Our width wasn't set when we were constructed. Set our width + // so that the grab region includes all pixels from x to the right + // edge of the source image. + if (this.width < 0) + this.width = width - x; + + // Our height wasn't set when we were constructed. Set our height + // so that the grab region includes all pixels from y to the + // bottom edge of the source image. + if (this.height < 0) + this.height = height - y; + + if (scansize < 0) + scansize = this.width; + + if (int_pixel_buffer == null) + int_pixel_buffer = new int[this.width * this.height]; + + if (byte_pixel_buffer == null) + byte_pixel_buffer = new byte[this.width * this.height]; + } + + /** + * Our ImageProducer may call this method to send us a + * list of its image's properties. + * + * setProperties is an ImageConsumer method. None of PixelGrabber's + * ImageConsumer methods should be called by code that instantiates + * a PixelGrabber. They are only made public so they can be called + * by the PixelGrabber's ImageProducer. + * + * @param props a list of properties associated with the image being + * produced + */ + public synchronized void setProperties(Hashtable props) + { + this.props = props; + } + + /** + * Our ImageProducer will call setColorModel to + * indicate the model used by the majority of calls to + * setPixels. Each call to setPixels + * could however indicate a different ColorModel. + * + * setColorModel is an ImageConsumer method. None of PixelGrabber's + * ImageConsumer methods should be called by code that instantiates + * a PixelGrabber. They are only made public so they can be called + * by the PixelGrabber's ImageProducer. + * + * @param model the color model to be used most often by setPixels + * + * @see ColorModel + */ + public synchronized void setColorModel(ColorModel model) + { + this.model = model; + } + + /** + * Our ImageProducer may call this method with a + * bit mask of hints from any of RANDOMPIXELORDER, + * TOPDOWNLEFTRIGHT, COMPLETESCANLINES, + * SINGLEPASS, SINGLEFRAME. + * + * setHints is an ImageConsumer method. None of PixelGrabber's + * ImageConsumer methods should be called by code that instantiates + * a PixelGrabber. They are only made public so they can be called + * by the PixelGrabber's ImageProducer. + * + * @param flags a bit mask of hints + */ + public synchronized void setHints(int flags) + { + hints = flags; + } + + /** + * Our ImageProducer calls setPixels to deliver a subset of its + * pixels. + * + * Each element of the pixels array represents one pixel. The + * pixel data is formatted according to the color model model. + * The x and y parameters are the coordinates of the rectangular + * region of pixels being delivered to this ImageConsumer, + * specified relative to the top left corner of the image being + * produced. Likewise, w and h are the pixel region's dimensions. + * + * @param x x coordinate of pixel block + * @param y y coordinate of pixel block + * @param w width of pixel block + * @param h height of pixel block + * @param model color model used to interpret pixel data + * @param pixels pixel block data + * @param offset offset into pixels array + * @param scansize width of one row in the pixel block + */ + public synchronized void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, + int offset, int scansize) + { + ColorModel currentModel; + if (model != null) + currentModel = model; + else + currentModel = this.model; + + for(int yp = y; yp < (y + h); yp++) + { + for(int xp = x; xp < (x + w); xp++) + { + // Check if the coordinates (xp, yp) are within the + // pixel block that we are grabbing. + if(xp >= this.x + && yp >= this.y + && xp < (this.x + this.width) + && yp < (this.y + this.height)) + { + int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset; + int p = (yp - y) * scansize + (xp - x) + offset; + if (forceRGB) + { + ints_delivered = true; + + int_pixel_buffer[i] = currentModel.getRGB (pixels[p] & 0xFF); + } + else + { + bytes_delivered = true; + + byte_pixel_buffer[i] = pixels[p]; + } + } + } + } + } + + /** + * Our ImageProducer calls setPixels to deliver a subset of its + * pixels. + * + * Each element of the pixels array represents one pixel. The + * pixel data is formatted according to the color model model. + * The x and y parameters are the coordinates of the rectangular + * region of pixels being delivered to this ImageConsumer, + * specified relative to the top left corner of the image being + * produced. Likewise, w and h are the pixel region's dimensions. + * + * @param x x coordinate of pixel block + * @param y y coordinate of pixel block + * @param w width of pixel block + * @param h height of pixel block + * @param model color model used to interpret pixel data + * @param pixels pixel block data + * @param offset offset into pixels array + * @param scansize width of one row in the pixel block + */ + public synchronized void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, + int offset, int scansize) + { + ColorModel currentModel; + if (model != null) + currentModel = model; + else + currentModel = this.model; + + ints_delivered = true; + + for(int yp = y; yp < (y + h); yp++) + { + for(int xp = x; xp < (x + w); xp++) + { + // Check if the coordinates (xp, yp) are within the + // pixel block that we are grabbing. + if(xp >= this.x + && yp >= this.y + && xp < (this.x + this.width) + && yp < (this.y + this.height)) + { + int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset; + int p = (yp - y) * scansize + (xp - x) + offset; + if (forceRGB) + int_pixel_buffer[i] = currentModel.getRGB (pixels[p]); + else + int_pixel_buffer[i] = pixels[p]; + } + } + } + } + + /** + * Our ImageProducer calls this method to inform us + * that a single frame or the entire image is complete. The method + * is also used to inform us of an error in loading or producing the + * image. + * + * @param status the status of image production, represented by a + * bitwise OR of ImageConsumer flags + */ + public synchronized void imageComplete(int status) + { + consumerStatus = status; + setObserverStatus (); + grabbing = false; + ip.removeConsumer (this); + + notifyAll (); + } + + /** + * @return the return value of getStatus + * + * @specnote The newer getStatus should be used in place of status. + */ + public synchronized int status() + { + return getStatus(); + } +} diff --git a/libjava/classpath/java/awt/image/PixelInterleavedSampleModel.java b/libjava/classpath/java/awt/image/PixelInterleavedSampleModel.java new file mode 100644 index 0000000..4c5c436 --- /dev/null +++ b/libjava/classpath/java/awt/image/PixelInterleavedSampleModel.java @@ -0,0 +1,98 @@ +/* PixelInterleavedSampleModel.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 java.awt.image; + + +/** + * A SampleModel that uses exactly one element of the + * raster’s {@link DataBuffer} per pixel, holds all bands in a + * single bank, and stores band data in pixel-interleaved manner. + * + * @since 1.2 + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class PixelInterleavedSampleModel + extends ComponentSampleModel +{ + public PixelInterleavedSampleModel(int dataType, int width, int height, + int pixelStride, int scanlineStride, + int[] bandOffsets) + { + super(dataType, width, height, pixelStride, scanlineStride, + bandOffsets); + } + + + /** + * Creates a new SampleModel that is like this one, but + * uses the specified width and height. + * + * @param width the number of pixels in the horizontal direction. + * + * @param height the number of pixels in the vertical direction. + */ + public SampleModel createCompatibleSampleModel(int width, int height) + { + return new PixelInterleavedSampleModel(dataType, width, height, + pixelStride, scanlineStride, + bandOffsets); + } + + + /** + * Creates a new SampleModel that is like this one, but + * uses only a subset of its bands. + * + * @param bands an array whose elements indicate which bands shall + * be part of the subset. For example, [0, 2, 3] would + * create a SampleModel containing bands #0, #2 and #3. + */ + public SampleModel createSubsetSampleModel(int[] bands) + { + int[] subOffsets; + + subOffsets = new int[bands.length]; + for (int i = 0; i < bands.length; i++) + subOffsets[i] = bandOffsets[bands[i]]; + + return new PixelInterleavedSampleModel(dataType, width, height, + pixelStride, scanlineStride, + subOffsets); + } +} diff --git a/libjava/classpath/java/awt/image/RGBImageFilter.java b/libjava/classpath/java/awt/image/RGBImageFilter.java new file mode 100644 index 0000000..f7b39b9 --- /dev/null +++ b/libjava/classpath/java/awt/image/RGBImageFilter.java @@ -0,0 +1,267 @@ +/* RGBImageFilter.java -- Java class for filtering Pixels by RGB values + Copyright (C) 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 java.awt.image; + +/** + * A filter designed to filter images in the default RGBColorModel regardless of + * the ImageProducer's ColorModel. + * + * @author Mark Benvenuto (mcb54@columbia.edu) + */ +public abstract class RGBImageFilter extends ImageFilter +{ + protected ColorModel origmodel; + + protected ColorModel newmodel; + + /** + Specifies whether to apply the filter to the index entries of the + IndexColorModel. Subclasses should set this to true if the filter + does not depend on the pixel's coordinate. + */ + protected boolean canFilterIndexColorModel = false; + + /** + Construct new RGBImageFilter. + */ + public RGBImageFilter() + { + } + + /** + * Sets the ColorModel used to filter with. If the specified ColorModel is IndexColorModel + * and canFilterIndexColorModel is true, we subsitute the ColorModel for a filtered one + * here and in setPixels whenever the original one appears. Otherwise overrides the default + * ColorModel of ImageProducer and specifies the default RGBColorModel + * + * @param model the color model to be used most often by setPixels + * @see ColorModel */ + public void setColorModel(ColorModel model) + { + origmodel = model; + newmodel = model; + + if( ( model instanceof IndexColorModel) && canFilterIndexColorModel ) { + newmodel = filterIndexColorModel( (IndexColorModel) model ); + consumer.setColorModel(newmodel); + } + else { + consumer.setColorModel(ColorModel.getRGBdefault()); + } + } + + /** + Registers a new ColorModel to subsitute for the old ColorModel when + setPixels encounters the a pixel with the old ColorModel. The pixel + remains unchanged except for a new ColorModel. + + @param oldcm the old ColorModel + @param newcm the new ColorModel + */ + public void substituteColorModel(ColorModel oldcm, + ColorModel newcm) + { + origmodel = oldcm; + newmodel = newcm; + } + + /** + Filters an IndexColorModel through the filterRGB function. Uses + coordinates of -1 to indicate its filtering an index and not a pixel. + + @param icm an IndexColorModel to filter + */ + public IndexColorModel filterIndexColorModel(IndexColorModel icm) + { + int len = icm.getMapSize(), rgb; + byte reds[] = new byte[len], greens[] = new byte[len], blues[] = new byte[len], alphas[] = new byte[len]; + + icm.getAlphas( alphas ); + icm.getReds( reds ); + icm.getGreens( greens ); + icm.getBlues( blues ); + + for( int i = 0; i < len; i++ ) + { + rgb = filterRGB( -1, -1, makeColor ( alphas[i], reds[i], greens[i], blues[i] ) ); + alphas[i] = (byte)(( 0xff000000 & rgb ) >> 24); + reds[i] = (byte)(( 0xff0000 & rgb ) >> 16); + greens[i] = (byte)(( 0xff00 & rgb ) >> 8); + blues[i] = (byte)(0xff & rgb); + } + return new IndexColorModel( icm.getPixelSize(), len, reds, greens, blues, alphas ); + } + + private int makeColor( byte a, byte r, byte g, byte b ) + { + return ( 0xff000000 & (a << 24) | 0xff0000 & (r << 16) | 0xff00 & (g << 8) | 0xff & b ); + } + + /** + This functions filters a set of RGB pixels through filterRGB. + + @param x the x coordinate of the rectangle + @param y the y coordinate of the rectangle + @param w the width of the rectangle + @param h the height of the rectangle + @param pixels the array of pixel values + @param offset the index of the first pixels in the pixels array + @param scansize the width to use in extracting pixels from the pixels array + */ + public void filterRGBPixels(int x, int y, int w, int h, int[] pixels, + int offset, int scansize) + { + for (int yp = 0; yp < h; yp++) + { + for (int xp = 0; xp < w; xp++) + { + pixels[offset + xp] = filterRGB(xp + x, yp + y, pixels[offset + xp]); + } + offset += scansize; + } + } + + + /** + * If the ColorModel is the same ColorModel which as already converted + * then it converts it the converted ColorModel. Otherwise it passes the + * array of pixels through filterRGBpixels. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, + int offset, int scansize) + { + if(model == origmodel && (model instanceof IndexColorModel) && canFilterIndexColorModel) + { + consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize); + } + else + { + int intPixels[] = + convertColorModelToDefault( x, y, w, h, model, pixels, offset, scansize ); + filterRGBPixels( x, y, w, h, intPixels, offset, scansize ); + consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), intPixels, offset, scansize); + } + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an int at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, + int offset, int scansize) + { + if(model == origmodel && (model instanceof IndexColorModel) && canFilterIndexColorModel) + { + consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize); + } + else + { + //FIXME: Store the filtered pixels in a separate temporary buffer? + convertColorModelToDefault( x, y, w, h, model, pixels, offset, scansize ); + filterRGBPixels( x, y, w, h, pixels, offset, scansize ); + consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), pixels, offset, scansize); + } + } + + private int[] convertColorModelToDefault(int x, int y, int w, int h, + ColorModel model, byte pixels[], + int offset, int scansize) + { + int intPixels[] = new int[pixels.length]; + for (int i = 0; i < pixels.length; i++) + intPixels[i] = makeColorbyDefaultCM(model, pixels[i]); + return intPixels; + } + + private void convertColorModelToDefault(int x, int y, int w, int h, + ColorModel model, int pixels[], + int offset, int scansize) + { + for (int i = 0; i < pixels.length; i++) + pixels[i] = makeColorbyDefaultCM(model, pixels[i]); + } + + private int makeColorbyDefaultCM(ColorModel model, byte rgb) + { + return makeColor( model.getAlpha( rgb ) * 4, model.getRed( rgb ) * 4, model.getGreen( rgb ) * 4, model.getBlue( rgb ) * 4 ); + } + + private int makeColorbyDefaultCM(ColorModel model, int rgb) + { + return makeColor( model.getAlpha( rgb ), model.getRed( rgb ), model.getGreen( rgb ), model.getBlue( rgb ) ); + } + + private int makeColor( int a, int r, int g, int b ) + { + return (int)( 0xff000000 & (a << 24) | 0xff0000 & (r << 16) | 0xff00 & (g << 8) | 0xff & b ); + } + + + /** + Filters a single pixel from the default ColorModel. + + @param x x-coordinate + @param y y-coordinate + @param rgb color + */ + public abstract int filterRGB(int x, + int y, + int rgb); +} diff --git a/libjava/classpath/java/awt/image/Raster.java b/libjava/classpath/java/awt/image/Raster.java new file mode 100644 index 0000000..4af958a --- /dev/null +++ b/libjava/classpath/java/awt/image/Raster.java @@ -0,0 +1,546 @@ +/* Copyright (C) 2000, 2002, 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.Point; +import java.awt.Rectangle; + +/** + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class Raster +{ + protected SampleModel sampleModel; + protected DataBuffer dataBuffer; + protected int minX; + protected int minY; + protected int width; + protected int height; + protected int sampleModelTranslateX; + protected int sampleModelTranslateY; + protected int numBands; + protected int numDataElements; + protected Raster parent; + + protected Raster(SampleModel sampleModel, Point origin) + { + this(sampleModel, sampleModel.createDataBuffer(), origin); + } + + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, + Point origin) + { + this(sampleModel, dataBuffer, + new Rectangle(origin.x, origin.y, + sampleModel.getWidth(), sampleModel.getHeight()), + origin, null); + } + + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, + Rectangle aRegion, + Point sampleModelTranslate, Raster parent) + { + this.sampleModel = sampleModel; + this.dataBuffer = dataBuffer; + this.minX = aRegion.x; + this.minY = aRegion.y; + this.width = aRegion.width; + this.height = aRegion.height; + + // If sampleModelTranslate is null, use (0,0). Methods such as + // Raster.createRaster are specified to allow for a null argument. + if (sampleModelTranslate != null) + { + this.sampleModelTranslateX = sampleModelTranslate.x; + this.sampleModelTranslateY = sampleModelTranslate.y; + } + + this.numBands = sampleModel.getNumBands(); + this.numDataElements = sampleModel.getNumDataElements(); + this.parent = parent; + } + + public static WritableRaster createInterleavedRaster(int dataType, + int w, int h, + int bands, + Point location) + { + int[] bandOffsets = new int[bands]; + // TODO: Maybe not generate this every time. + for (int b=0; b getTypeBits(dataType))) + throw new IllegalArgumentException(); + + SampleModel sm; + + if (bands == 1) + sm = new MultiPixelPackedSampleModel(dataType, w, h, bitsPerBand); + else + { + int[] bandMasks = new int[bands]; + int mask = 0x1; + for (int bits = bitsPerBand; --bits != 0;) + mask = (mask << 1) | 0x1; + for (int i = 0; i < bands; i++) + { + bandMasks[i] = mask; + mask <<= bitsPerBand; + } + + sm = new SinglePixelPackedSampleModel(dataType, w, h, bandMasks); + } + return createWritableRaster(sm, location); + } + + public static WritableRaster + createInterleavedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int pixelStride, + int[] bandOffsets, Point location) + { + SampleModel sm = new ComponentSampleModel(dataBuffer.getDataType(), + w, h, + scanlineStride, + pixelStride, + bandOffsets); + return createWritableRaster(sm, dataBuffer, location); + } + + public static + WritableRaster createBandedRaster(DataBuffer dataBuffer, + int w, int h, + int scanlineStride, + int[] bankIndices, + int[] bandOffsets, + Point location) + { + SampleModel sm = new BandedSampleModel(dataBuffer.getDataType(), + w, h, scanlineStride, + bankIndices, bandOffsets); + return createWritableRaster(sm, dataBuffer, location); + } + + public static WritableRaster + createPackedRaster(DataBuffer dataBuffer, + int w, int h, + int scanlineStride, + int[] bandMasks, + Point location) + { + SampleModel sm = + new SinglePixelPackedSampleModel(dataBuffer.getDataType(), + w, h, + scanlineStride, + bandMasks); + return createWritableRaster(sm, dataBuffer, location); + } + + public static WritableRaster + createPackedRaster(DataBuffer dataBuffer, + int w, int h, + int bitsPerPixel, + Point location) + { + SampleModel sm = + new MultiPixelPackedSampleModel(dataBuffer.getDataType(), + w, h, + bitsPerPixel); + return createWritableRaster(sm, dataBuffer, location); + } + + public static Raster createRaster(SampleModel sm, DataBuffer db, + Point location) + { + return new Raster(sm, db, location); + } + + public static WritableRaster createWritableRaster(SampleModel sm, + Point location) + { + return new WritableRaster(sm, location); + } + + public static WritableRaster createWritableRaster(SampleModel sm, + DataBuffer db, + Point location) + { + return new WritableRaster(sm, db, location); + } + + public Raster getParent() + { + return parent; + } + + public final int getSampleModelTranslateX() + { + return sampleModelTranslateX; + } + + public final int getSampleModelTranslateY() + { + return sampleModelTranslateY; + } + + public WritableRaster createCompatibleWritableRaster() + { + return new WritableRaster(getSampleModel(), new Point(minX, minY)); + } + + public WritableRaster createCompatibleWritableRaster(int w, int h) + { + return createCompatibleWritableRaster(minX, minY, w, h); + } + + public WritableRaster createCompatibleWritableRaster(Rectangle rect) + { + return createCompatibleWritableRaster(rect.x, rect.y, + rect.width, rect.height); + } + + public WritableRaster createCompatibleWritableRaster(int x, int y, + int w, int h) + { + SampleModel sm = getSampleModel().createCompatibleSampleModel(w, h); + return new WritableRaster(sm, sm.createDataBuffer(), + new Point(x, y)); + } + + public Raster createTranslatedChild(int childMinX, int childMinY) { + int tcx = sampleModelTranslateX - minX + childMinX; + int tcy = sampleModelTranslateY - minY + childMinY; + + return new Raster(sampleModel, dataBuffer, + new Rectangle(childMinX, childMinY, + width, height), + new Point(tcx, tcy), + this); + } + + public Raster createChild(int parentX, int parentY, int width, + int height, int childMinX, int childMinY, + int[] bandList) + { + /* FIXME: Throw RasterFormatException if child bounds extends + beyond the bounds of this raster. */ + + SampleModel sm = (bandList == null) ? + sampleModel : + sampleModel.createSubsetSampleModel(bandList); + + /* + data origin + / + +------------------------- + |\. __ parent trans + | \`. + | \ `. parent origin + | \ `. / + | /\ +-------- - - + |trans\ /<\-- deltaTrans + |child +-+-\---- - - + | /|`| \__ parent [x, y] + |child | |`. \ + |origin| : `.\ + | | / `\ + | : / + + | child [x, y] + + parent_xy - parent_trans = child_xy - child_trans + + child_trans = parent_trans + child_xy - parent_xy + */ + + return new Raster(sm, dataBuffer, + new Rectangle(childMinX, childMinY, + width, height), + new Point(sampleModelTranslateX+childMinX-parentX, + sampleModelTranslateY+childMinY-parentY), + this); + } + + public Rectangle getBounds() + { + return new Rectangle(minX, minY, width, height); + } + + public final int getMinX() + { + return minX; + } + + public final int getMinY() + { + return minY; + } + + public final int getWidth() + { + return width; + } + + public final int getHeight() + { + return height; + } + + public final int getNumBands() + { + return numBands; + } + + public final int getNumDataElements() + { + return numDataElements; + } + + public final int getTransferType() + { + return sampleModel.getTransferType(); + } + + public DataBuffer getDataBuffer() + { + return dataBuffer; + } + + public SampleModel getSampleModel() + { + return sampleModel; + } + + public Object getDataElements(int x, int y, Object outData) + { + return sampleModel.getDataElements(x-sampleModelTranslateX, + y-sampleModelTranslateY, + outData, dataBuffer); + } + + public Object getDataElements(int x, int y, int w, int h, + Object outData) + { + return sampleModel.getDataElements(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, outData, dataBuffer); + } + + public int[] getPixel(int x, int y, int[] iArray) + { + return sampleModel.getPixel(x-sampleModelTranslateX, + y-sampleModelTranslateY, + iArray, dataBuffer); + } + + public float[] getPixel(int x, int y, float[] fArray) + { + return sampleModel.getPixel(x-sampleModelTranslateX, + y-sampleModelTranslateY, + fArray, dataBuffer); + } + + public double[] getPixel(int x, int y, double[] dArray) + { + return sampleModel.getPixel(x-sampleModelTranslateX, + y-sampleModelTranslateY, + dArray, dataBuffer); + } + + public int[] getPixels(int x, int y, int w, int h, int[] iArray) + { + return sampleModel.getPixels(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, iArray, dataBuffer); + } + + public float[] getPixels(int x, int y, int w, int h, + float[] fArray) + { + return sampleModel.getPixels(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, fArray, dataBuffer); + } + + public double[] getPixels(int x, int y, int w, int h, + double[] dArray) + { + return sampleModel.getPixels(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, dArray, dataBuffer); + } + + public int getSample(int x, int y, int b) + { + return sampleModel.getSample(x-sampleModelTranslateX, + y-sampleModelTranslateY, + b, dataBuffer); + } + + public float getSampleFloat(int x, int y, int b) + { + return sampleModel.getSampleFloat(x-sampleModelTranslateX, + y-sampleModelTranslateY, + b, dataBuffer); + } + + public double getSampleDouble(int x, int y, int b) + { + return sampleModel.getSampleDouble(x-sampleModelTranslateX, + y-sampleModelTranslateY, + b, dataBuffer); + } + + public int[] getSamples(int x, int y, int w, int h, int b, + int[] iArray) + { + return sampleModel.getSamples(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, b, iArray, dataBuffer); + } + + public float[] getSamples(int x, int y, int w, int h, int b, + float[] fArray) + { + return sampleModel.getSamples(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, b, fArray, dataBuffer); + } + + public double[] getSamples(int x, int y, int w, int h, int b, + double[] dArray) + { + return sampleModel.getSamples(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, b, dArray, dataBuffer); + } + + /** + * Create a String representing the stat of this Raster. + * @return A String representing the stat of this Raster. + * @see java.lang.Object#toString() + */ + public String toString() + { + StringBuffer result = new StringBuffer(); + + result.append(getClass().getName()); + result.append("[("); + result.append(minX).append(",").append(minY).append("), "); + result.append(width).append(" x ").append(height).append(","); + result.append(sampleModel).append(","); + result.append(dataBuffer); + result.append("]"); + + return result.toString(); + } + + // Map from datatype to bits + private static int getTypeBits(int dataType) + { + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + return 8; + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_SHORT: + return 16; + case DataBuffer.TYPE_INT: + case DataBuffer.TYPE_FLOAT: + return 32; + case DataBuffer.TYPE_DOUBLE: + return 64; + default: + return 0; + } + } +} diff --git a/libjava/classpath/java/awt/image/RasterFormatException.java b/libjava/classpath/java/awt/image/RasterFormatException.java new file mode 100644 index 0000000..582c2ae --- /dev/null +++ b/libjava/classpath/java/awt/image/RasterFormatException.java @@ -0,0 +1,65 @@ +/* RasterFormatException.java -- indicates invalid layout in Raster + 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 java.awt.image; + +/** + * This exception is thrown when there is invalid layout information in + * Raster + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Raster + * @status updated to 1.4 + */ +public class RasterFormatException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 96598996116164315L; + + /** + * Create a new instance with a descriptive error message. + * + * @param message the descriptive error message + */ + public RasterFormatException(String message) + { + super(message); + } +} // class RasterFormatException diff --git a/libjava/classpath/java/awt/image/RasterOp.java b/libjava/classpath/java/awt/image/RasterOp.java new file mode 100644 index 0000000..e081ca3 --- /dev/null +++ b/libjava/classpath/java/awt/image/RasterOp.java @@ -0,0 +1,57 @@ +/* RasterOp.java -- + Copyright (C) 2000, 2002, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +public interface RasterOp +{ + WritableRaster filter(Raster src, WritableRaster dest); + + Rectangle2D getBounds2D(Raster src); + + WritableRaster createCompatibleDestRaster(Raster src); + + Point2D getPoint2D(Point2D srcPoint, Point2D destPoint); + + RenderingHints getRenderingHints(); +} + diff --git a/libjava/classpath/java/awt/image/RenderedImage.java b/libjava/classpath/java/awt/image/RenderedImage.java new file mode 100644 index 0000000..b35f860 --- /dev/null +++ b/libjava/classpath/java/awt/image/RenderedImage.java @@ -0,0 +1,70 @@ +/* RenderedImage.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 java.awt.image; + +import java.awt.Rectangle; +import java.util.Vector; + +/** + * NEEDS DOCUMENTATION + */ +public interface RenderedImage +{ + Vector getSources(); + Object getProperty(String name); + String[] getPropertyNames(); + ColorModel getColorModel(); + SampleModel getSampleModel(); + int getWidth(); + int getHeight(); + int getMinX(); + int getMinY(); + int getNumXTiles(); + int getNumYTiles(); + int getMinTileX(); + int getMinTileY(); + int getTileWidth(); + int getTileHeight(); + int getTileGridXOffset(); + int getTileGridYOffset(); + Raster getTile(int x, int y); + Raster getData(); + Raster getData(Rectangle r); + WritableRaster copyData(WritableRaster raster); +} // interface RenderedImage diff --git a/libjava/classpath/java/awt/image/ReplicateScaleFilter.java b/libjava/classpath/java/awt/image/ReplicateScaleFilter.java new file mode 100644 index 0000000..3841e49 --- /dev/null +++ b/libjava/classpath/java/awt/image/ReplicateScaleFilter.java @@ -0,0 +1,244 @@ +/* ReplicateScaleFilter.java -- Java class for filtering images + Copyright (C) 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 java.awt.image; + +import java.util.Hashtable; + +/** + * This filter should be used for fast scaling of images where the result + * does not need to ensure straight lines are still straight, etc. The + * exact method is not defined by Sun but some sort of fast Box filter should + * probably be correct. + *
    + * Currently this filter does nothing and needs to be implemented. + * + * @author C. Brian Jones (cbj@gnu.org) + */ +public class ReplicateScaleFilter extends ImageFilter +{ + public ReplicateScaleFilter(int width, int height) { + destHeight = height; + destWidth = width; + } + + /** + * The height of the destination image. + */ + protected int destHeight; + + /** + * The width of the destination image. + */ + protected int destWidth; + + /** + * The height of the source image. + */ + protected int srcHeight; + + /** + * The width of the source image. + */ + protected int srcWidth; + + /** + * + */ + protected int srcrows[]; + + /** + * + */ + protected int srccols[]; + + /** + * + */ + protected Object outpixbuf; + + /** + * An ImageProducer indicates the size of the image + * being produced using this method. A filter can override this + * method to intercept these calls from the producer in order to + * change either the width or the height before in turn calling + * the consumer's setDimensions method. + * + * @param width the width of the image + * @param height the height of the image + */ + public void setDimensions(int width, int height) + { + srcWidth = width; + srcHeight = height; + + /* If either destHeight or destWidth is < 0, the image should + maintain its original aspect ratio. When both are < 0, + just maintain the original width and height. */ + if (destWidth < 0 && destHeight < 0) + { + destWidth = width; + destHeight = height; + } + else if (destWidth < 0) + { + destWidth = (int) (width * ((double) destHeight / srcHeight)); + } + else if (destHeight < 0) + { + destHeight = (int) (height * ((double) destWidth / srcWidth)); + } + + consumer.setDimensions(destWidth, destHeight); + } + + /** + * An ImageProducer can set a list of properties + * associated with this image by using this method. + * + * @param props the list of properties associated with this image + */ + public void setProperties(Hashtable props) + { + props.put("filters", "ReplicateScaleFilter"); + consumer.setProperties(props); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a byte at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize) + { + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + byte[] destPixels = replicatePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an int at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the ColorModel used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the pixels array + * @param scansize the width to use in extracting pixels from the pixels array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize) + { + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + int[] destPixels = replicatePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); + } + + private byte[] replicatePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, byte[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + byte[] destPixels = + new byte[(int) Math.ceil(srcw/rx) * (int) Math.ceil(srch/ry)]; + + int a, b; + for (int i = 0; i < destPixels.length; i++) + { + a = (int) ((int) ( ((double) i) / destScansize) * ry) * srcScansize; + b = (int) ((i % destScansize) * rx); + if ((a + b + srcOffset) < srcPixels.length) + destPixels[i] = srcPixels[a + b + srcOffset]; + } + + return destPixels; + } + + private int[] replicatePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, int[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + int[] destPixels = + new int[(int) Math.ceil(srcw/rx) * (int) Math.ceil(srch/ry)]; + + int a, b; + for (int i = 0; i < destPixels.length; i++) + { + a = (int) ((int) ( ((double) i) / destScansize) * ry) * srcScansize; + b = (int) ((i % destScansize) * rx); + if ((a + b + srcOffset) < srcPixels.length) + destPixels[i] = srcPixels[a + b + srcOffset]; + } + + return destPixels; + } +} + diff --git a/libjava/classpath/java/awt/image/RescaleOp.java b/libjava/classpath/java/awt/image/RescaleOp.java new file mode 100644 index 0000000..35b42f7 --- /dev/null +++ b/libjava/classpath/java/awt/image/RescaleOp.java @@ -0,0 +1,218 @@ +/* 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 java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +/** + * @author Jerry Quinn (jlquinn@optonline.net) + */ +public class RescaleOp implements BufferedImageOp, RasterOp +{ + private float[] scale; + private float[] offsets; + private RenderingHints hints = null; + + public RescaleOp(float[] scaleFactors, + float[] offsets, + RenderingHints hints) + { + this.scale = scaleFactors; + this.offsets = offsets; + this.hints = hints; + } + + public RescaleOp(float scaleFactor, + float offset, + RenderingHints hints) + { + scale = new float[]{ scaleFactor }; + offsets = new float[]{offset}; + this.hints = hints; + } + + public final float[] getScaleFactors(float[] scaleFactors) + { + if (scaleFactors == null) + scaleFactors = new float[scale.length]; + System.arraycopy(scale, 0, scaleFactors, 0, scale.length); + return scaleFactors; + } + + public final float[] getOffsets(float[] offsets) + { + if (offsets == null) + offsets = new float[this.offsets.length]; + System.arraycopy(this.offsets, 0, offsets, 0, this.offsets.length); + return offsets; + } + + public final int getNumFactors() + { + return scale.length; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getRenderingHints() + */ + public RenderingHints getRenderingHints() + { + return hints; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage) + */ + public final BufferedImage filter(BufferedImage src, BufferedImage dst) + { + // TODO Make sure premultiplied alpha is handled correctly. + // TODO See that color conversion is handled. + // TODO figure out how to use rendering hints. + if (scale.length != offsets.length) + throw new IllegalArgumentException(); + + ColorModel scm = src.getColorModel(); + if (dst == null) dst = createCompatibleDestImage(src, null); + + WritableRaster wsrc = src.getRaster(); + WritableRaster wdst = dst.getRaster(); + + // Share constant across colors except alpha + if (scale.length == 1 || scale.length == scm.getNumColorComponents()) + { + // Construct a raster that doesn't include an alpha band. + int[] subbands = new int[scm.getNumColorComponents()]; + for (int i=0; i < subbands.length; i++) subbands[i] = i; + wsrc = + wsrc.createWritableChild(wsrc.minX, wsrc.minY, wsrc.width, wsrc.height, + wsrc.minX, wsrc.minY, subbands); + } + // else all color bands + + filter(wsrc, wdst); + return dst; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster) + */ + public final WritableRaster filter(Raster src, WritableRaster dest) + { + if (dest == null) dest = src.createCompatibleWritableRaster(); + + // Required sanity checks + if (src.numBands != dest.numBands || scale.length != offsets.length) + throw new IllegalArgumentException(); + if (scale.length != 1 && scale.length != src.numBands) + throw new IllegalArgumentException(); + + // Create scaling arrays if needed + float[] lscale = scale; + float[] loff = offsets; + if (scale.length == 1) + { + lscale = new float[src.numBands]; + Arrays.fill(lscale, scale[0]); + loff = new float[src.numBands]; + Arrays.fill(loff, offsets[0]); + } + + // TODO The efficiency here can be improved for various data storage + // patterns, aka SampleModels. + float[] pixel = new float[src.numBands]; + for (int y = src.minY; y < src.height + src.minY; y++) + for (int x = src.minX; x < src.width + src.minX; x++) + { + src.getPixel(x, y, pixel); + for (int b = 0; b < src.numBands; b++) + pixel[b] = pixel[b] * lscale[b] + loff[b]; + dest.setPixel(x, y, pixel); + } + return dest; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel) + */ + public BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel dstCM) + { + if (dstCM == null) dstCM = src.getColorModel(); + WritableRaster wr = src.getRaster().createCompatibleWritableRaster(); + BufferedImage image + = new BufferedImage(dstCM, wr, src.isPremultiplied, null); + return image; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) + */ + public WritableRaster createCompatibleDestRaster(Raster src) + { + return src.createCompatibleWritableRaster(); + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) + */ + public final Rectangle2D getBounds2D(BufferedImage src) + { + return src.getRaster().getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) + */ + public final Rectangle2D getBounds2D(Raster src) + { + return src.getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D) + */ + public final Point2D getPoint2D(Point2D src, Point2D dst) { + if (dst == null) dst = (Point2D) src.clone(); + else dst.setLocation(src); + return dst; + } + +} diff --git a/libjava/classpath/java/awt/image/SampleModel.java b/libjava/classpath/java/awt/image/SampleModel.java new file mode 100644 index 0000000..257e30a --- /dev/null +++ b/libjava/classpath/java/awt/image/SampleModel.java @@ -0,0 +1,477 @@ +/* Copyright (C) 2000, 2001, 2002, 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 java.awt.image; + +/** + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public abstract class SampleModel +{ + /** Width of image described. */ + protected int width; + + /** Height of image described. */ + protected int height; + + /** Number of bands in the image described. */ + protected int numBands; + + /** + * The DataBuffer type that is used to store the data of the image + * described. + */ + protected int dataType; + + public SampleModel(int dataType, int w, int h, int numBands) + { + if ((w <= 0) || (h <= 0)) + throw new IllegalArgumentException((w <= 0 ? " width<=0" : " width is ok") + +(h <= 0 ? " height<=0" : " height is ok")); + + // FIXME: How can an int be greater than Integer.MAX_VALUE? + // FIXME: How do we identify an unsupported data type? + + this.dataType = dataType; + this.width = w; + this.height = h; + this.numBands = numBands; + } + + public final int getWidth() + { + return width; + } + + public final int getHeight() + { + return height; + } + + public final int getNumBands() + { + return numBands; + } + + public abstract int getNumDataElements(); + + public final int getDataType() + { + return dataType; + } + + public int getTransferType() + { + // FIXME: Is this a reasonable default implementation? + return dataType; + } + + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + if (iArray == null) iArray = new int[numBands]; + for (int b=0; bShortLookupTable instance. + * + * Offset is subtracted from pixel values when looking up in the translation + * tables. If data.length is one, the same table is applied to all pixel + * components. + * + * @param offset Offset to be subtracted. + * @param data Array of lookup tables. + * @exception IllegalArgumentException if offset < 0 or data.length < 1. + */ + public ShortLookupTable(int offset, short[][] data) + throws IllegalArgumentException + { + super(offset, data.length); + this.data = data; + } + + /** + * Creates a new ShortLookupTable instance. + * + * Offset is subtracted from pixel values when looking up in the translation + * table. The same table is applied to all pixel components. + * + * @param offset Offset to be subtracted. + * @param data Lookup table for all components. + * @exception IllegalArgumentException if offset < 0. + */ + public ShortLookupTable(int offset, short[] data) + throws IllegalArgumentException + { + super(offset, 1); + this.data = new short[][] {data}; + } + + /** Return the lookup tables. */ + public final short[][] getTable() + { + return data; + } + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dst Destination array for values, or null. + * @return Translated values for the pixel. + */ + public int[] lookupPixel(int[] src, int[] dst) + throws ArrayIndexOutOfBoundsException + { + if (dst == null) + dst = new int[src.length]; + + if (data.length == 1) + for (int i=0; i < src.length; i++) + dst[i] = data[0][src[i] - offset]; + else + for (int i=0; i < src.length; i++) + dst[i] = data[i][src[i] - offset]; + + return dst; + } + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dst Destination array for values, or null. + * @return Translated values for the pixel. + */ + public short[] lookupPixel(short[] src, short[] dst) + throws ArrayIndexOutOfBoundsException + { + if (dst == null) + dst = new short[src.length]; + + if (data.length == 1) + for (int i=0; i < src.length; i++) + dst[i] = data[0][((int)src[i]) - offset]; + else + for (int i=0; i < src.length; i++) + dst[i] = data[i][((int)src[i]) - offset]; + + return dst; + + } +} diff --git a/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java b/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java new file mode 100644 index 0000000..6ccce75 --- /dev/null +++ b/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java @@ -0,0 +1,449 @@ +/* Copyright (C) 2000, 2002, 2003, 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 java.awt.image; + +import gnu.java.awt.BitMaskExtent; +import gnu.java.awt.Buffers; + +/** + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class SinglePixelPackedSampleModel extends SampleModel +{ + private int scanlineStride; + private int[] bitMasks; + private int[] bitOffsets; + private int[] sampleSize; + + public SinglePixelPackedSampleModel(int dataType, int w, int h, + int[] bitMasks) + { + this(dataType, w, h, w, bitMasks); + } + + public SinglePixelPackedSampleModel(int dataType, int w, int h, + int scanlineStride, int[] bitMasks) + { + super(dataType, w, h, bitMasks.length); + + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + break; + default: + throw new IllegalArgumentException("SinglePixelPackedSampleModel unsupported dataType"); + } + + this.scanlineStride = scanlineStride; + this.bitMasks = bitMasks; + + bitOffsets = new int[numBands]; + sampleSize = new int[numBands]; + + BitMaskExtent extent = new BitMaskExtent(); + for (int b=0; bobj. + * @param y The y-coordinate of the pixel rectangle to store in obj. + * @param w The width of the pixel rectangle to store in obj. + * @param h The height of the pixel rectangle to store in obj. + * @param obj The primitive array to store the pixels into or null to force creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer) + */ + public Object getDataElements(int x, int y, int w, int h, Object obj, + DataBuffer data) + { + int size = w*h; + int dataSize = size; + Object pixelData = null; + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + pixelData = ((DataBufferByte) data).getData(); + if (obj == null) obj = new byte[dataSize]; + break; + case DataBuffer.TYPE_USHORT: + pixelData = ((DataBufferUShort) data).getData(); + if (obj == null) obj = new short[dataSize]; + break; + case DataBuffer.TYPE_INT: + pixelData = ((DataBufferInt) data).getData(); + if (obj == null) obj = new int[dataSize]; + break; + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } + if(x==0 && scanlineStride == w) + { + // The full width need to be copied therefore we can copy in one shot. + System.arraycopy(pixelData, scanlineStride*y + data.getOffset(), obj, 0, size); + } + else + { + // Since we do not need the full width we need to copy line by line. + int outOffset = 0; + int dataOffset = scanlineStride*y + x + data.getOffset(); + for (int yy = y; yy<(y+h); yy++) + { + System.arraycopy(pixelData, dataOffset, obj, outOffset, w); + dataOffset += scanlineStride; + outOffset += w; + } + } + return obj; + } + + + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + int offset = scanlineStride*y + x; + if (iArray == null) iArray = new int[numBands]; + int samples = data.getElem(offset); + + for (int b=0; b>> bitOffsets[b]; + + return iArray; + } + + public int[] getPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int offset = scanlineStride*y + x; + if (iArray == null) iArray = new int[numBands*w*h]; + int outOffset = 0; + for (y=0; y>> bitOffsets[b]; + } + offset += scanlineStride; + } + return iArray; + } + + public int getSample(int x, int y, int b, DataBuffer data) + { + int offset = scanlineStride*y + x; + int samples = data.getElem(offset); + return (samples & bitMasks[b]) >>> bitOffsets[b]; + } + + /** + * This method implements a more efficient way to set data elements than the default + * implementation of the super class. It sets the data elements line by line instead + * of pixel by pixel. + * @param x The x-coordinate of the data elements in obj. + * @param y The y-coordinate of the data elements in obj. + * @param w The width of the data elements in obj. + * @param h The height of the data elements in obj. + * @param obj The primitive array containing the data elements to set. + * @param data The DataBuffer to store the data elements into. + * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer) + */ + public void setDataElements(int x, int y, int w, int h, + Object obj, DataBuffer data) + { + + Object pixelData; + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + pixelData = ((DataBufferByte) data).getData(); + break; + case DataBuffer.TYPE_USHORT: + pixelData = ((DataBufferUShort) data).getData(); + break; + case DataBuffer.TYPE_INT: + pixelData = ((DataBufferInt) data).getData(); + break; + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } + + int inOffset = 0; + int dataOffset = scanlineStride*y + x + data.getOffset(); + for (int yy=y; yy<(y+h); yy++) + { + System.arraycopy(obj,inOffset,pixelData,dataOffset,w); + dataOffset += scanlineStride; + inOffset += w; + } + } + + + public void setDataElements(int x, int y, Object obj, DataBuffer data) + { + int offset = scanlineStride*y + x + data.getOffset(); + + int transferType = getTransferType(); + if (getTransferType() != data.getDataType()) + { + throw new IllegalArgumentException("transfer type ("+ + getTransferType()+"), "+ + "does not match data "+ + "buffer type (" + + data.getDataType() + + ")."); + } + + try + { + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + { + DataBufferByte out = (DataBufferByte) data; + byte[] in = (byte[]) obj; + out.getData()[offset] = in[0]; + return; + } + case DataBuffer.TYPE_USHORT: + { + DataBufferUShort out = (DataBufferUShort) data; + short[] in = (short[]) obj; + out.getData()[offset] = in[0]; + return; + } + case DataBuffer.TYPE_INT: + { + DataBufferInt out = (DataBufferInt) data; + int[] in = (int[]) obj; + out.getData()[offset] = in[0]; + return; + } + // FIXME: Fill in the other possible types. + default: + throw new InternalError(); + } + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + String msg = "While writing data elements" + + ", x="+x+", y="+y+ + ", width="+width+", height="+height+ + ", scanlineStride="+scanlineStride+ + ", offset="+offset+ + ", data.getSize()="+data.getSize()+ + ", data.getOffset()="+data.getOffset()+ + ": " + + aioobe; + throw new ArrayIndexOutOfBoundsException(msg); + } + } + + public void setPixel(int x, int y, int[] iArray, DataBuffer data) + { + int offset = scanlineStride*y + x; + + int samples = 0; + for (int b=0; bobj. + * @param y The y-coordinate of the pixel rectangle in obj. + * @param w The width of the pixel rectangle in obj. + * @param h The height of the pixel rectangle in obj. + * @param iArray The primitive array containing the pixels to set. + * @param data The DataBuffer to store the pixels into. + * @see java.awt.image.SampleModel#setPixels(int, int, int, int, int[], java.awt.image.DataBuffer) + */ + public void setPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int inOffset = 0; + int[] pixel = new int[numBands]; + for (int yy=y; yy<(y+h); yy++) + { + int offset = scanlineStride*yy + x; + for (int xx=x; xx<(x+w); xx++) + { + int samples = 0; + for (int b=0; b + *

  • IMAGE_OK if the image did not need to be + * validated and didn't need to be restored
  • + *
  • IMAGE_RESTORED if the image may need to be + * re-rendered.
  • + *
  • IMAGE_INCOMPATIBLE if this image's + * requirements are not fulfilled by the graphics configuration + * parameter. This implies that you need to create a new + * VolatileImage for the different GraphicsConfiguration or + * Component. This return value implies nothing about whether the + * image is valid or needs to be re-rendered.
  • + * + */ + public abstract int validate(GraphicsConfiguration gc); + + /** + * Returns true if the contents of the image buffer have been + * damaged or if the image buffer's resources have been reclaimed by + * the graphics system. You should call this method after a series + * of rendering operations to or from the image, to see if the image + * buffer needs to be revalidated or the image re-rendered. + * + * @return true if the validate should be called, false otherwise + */ + public abstract boolean contentsLost(); + + /** + * Returns the capabilities of this image buffer. + * + * @return the capabilities of this image buffer + */ + public abstract ImageCapabilities getCapabilities(); + + /** + * Returns the transparency type of this image. + * + * @return Transparency.OPAQUE, Transparency.BITMASK or + * Transparency.TRANSLUCENT + */ + public int getTransparency() + { + return transparency; + } +} diff --git a/libjava/classpath/java/awt/image/WritableRaster.java b/libjava/classpath/java/awt/image/WritableRaster.java new file mode 100644 index 0000000..2e5462f --- /dev/null +++ b/libjava/classpath/java/awt/image/WritableRaster.java @@ -0,0 +1,265 @@ +/* Copyright (C) 2000, 2002, 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.Point; +import java.awt.Rectangle; + +/** + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class WritableRaster extends Raster +{ + protected WritableRaster(SampleModel sampleModel, Point origin) + { + this(sampleModel, sampleModel.createDataBuffer(), origin); + } + + protected WritableRaster(SampleModel sampleModel, + DataBuffer dataBuffer, Point origin) + { + this(sampleModel, dataBuffer, + new Rectangle(origin != null ? origin.x : 0, + origin != null ? origin.y : 0, + sampleModel.getWidth(), sampleModel.getHeight()), + origin, + null); + } + + protected WritableRaster(SampleModel sampleModel, + DataBuffer dataBuffer, + Rectangle aRegion, + Point sampleModelTranslate, + WritableRaster parent) + { + super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, + parent); + } + + public WritableRaster getWritableParent() + { + return (WritableRaster) getParent(); + } + + public WritableRaster createWritableTranslatedChild(int childMinX, + int childMinY) + { + // This mirrors the code from the super class + int tcx = sampleModelTranslateX - minX + childMinX; + int tcy = sampleModelTranslateY - minY + childMinY; + + return new WritableRaster(sampleModel, dataBuffer, + new Rectangle(childMinX, childMinY, + width, height), + new Point(tcx, tcy), + this); + } + + public WritableRaster createWritableChild(int parentX, + int parentY, + int w, int h, + int childMinX, + int childMinY, + int[] bandList) + { + // This mirrors the code from the super class + + // FIXME: Throw RasterFormatException if child bounds extends + // beyond the bounds of this raster. + + SampleModel sm = (bandList == null) ? + sampleModel : + sampleModel.createSubsetSampleModel(bandList); + + return new + WritableRaster(sm, dataBuffer, + new Rectangle(childMinX, childMinY, + w, h), + new Point(sampleModelTranslateX+childMinX-parentX, + sampleModelTranslateY+childMinY-parentY), + this); + } + + public void setDataElements(int x, int y, Object inData) + { + sampleModel.setDataElements(x-sampleModelTranslateX, + y-sampleModelTranslateY, + inData, dataBuffer); + } + + public void setDataElements(int x, int y, Raster inRaster) + { + Object dataElements = getDataElements(0, 0, + inRaster.getWidth(), + inRaster.getHeight(), + null); + setDataElements(x, y, dataElements); + } + + public void setDataElements(int x, int y, int w, int h, + Object inData) + { + sampleModel.setDataElements(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, inData, dataBuffer); + } + + public void setRect(Raster srcRaster) + { + setRect(0, 0, srcRaster); + } + + public void setRect(int dx, int dy, Raster srcRaster) + { + Rectangle targetUnclipped = new Rectangle(srcRaster.getMinX()+dx, + srcRaster.getMinY()+dy, + srcRaster.getWidth(), + srcRaster.getHeight()); + + Rectangle target = getBounds().intersection(targetUnclipped); + + if (target.isEmpty()) return; + + int sx = target.x - dx; + int sy = target.y - dy; + + // FIXME: Do tests on rasters and use get/set data instead. + + /* The JDK documentation seems to imply this implementation. + (the trucation of higher bits), but an implementation using + get/setDataElements would be more efficient. None of the + implementations would do anything sensible when the sample + models don't match. + + But this is probably not the place to consider such + optimizations.*/ + + int[] pixels = srcRaster.getPixels(sx, sy, + target.width, target.height, + (int[]) null); + + setPixels(target.x, target.y, target.width, target.height, pixels); + } + + public void setPixel(int x, int y, int[] iArray) + { + sampleModel.setPixel(x-sampleModelTranslateX, + y-sampleModelTranslateY, + iArray, dataBuffer); + } + + public void setPixel(int x, int y, float[] fArray) + { + sampleModel.setPixel(x-sampleModelTranslateX, + y-sampleModelTranslateY, + fArray, dataBuffer); + } + + public void setPixel(int x, int y, double[] dArray) + { + sampleModel.setPixel(x-sampleModelTranslateX, + y-sampleModelTranslateY, + dArray, dataBuffer); + } + + public void setPixels(int x, int y, int w, int h, int[] iArray) + { + sampleModel.setPixels(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, iArray, dataBuffer); + } + + public void setPixels(int x, int y, int w, int h, float[] fArray) + { + sampleModel.setPixels(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, fArray, dataBuffer); + } + + public void setPixels(int x, int y, int w, int h, double[] dArray) + { + sampleModel.setPixels(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, dArray, dataBuffer); + } + + public void setSample(int x, int y, int b, int s) + { + sampleModel.setSample(x-sampleModelTranslateX, + y-sampleModelTranslateY, + b, s, dataBuffer); + } + + public void setSample(int x, int y, int b, float s) + { + sampleModel.setSample(x-sampleModelTranslateX, + y-sampleModelTranslateY, + b, s, dataBuffer); + } + + public void setSample(int x, int y, int b, double s) + { + sampleModel.setSample(x-sampleModelTranslateX, + y-sampleModelTranslateY, + b, s, dataBuffer); + } + + public void setSamples(int x, int y, int w, int h, int b, + int[] iArray) + { + sampleModel.setSamples(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, b, iArray, dataBuffer); + } + + public void setSamples(int x, int y, int w, int h, int b, + float[] fArray) + { + sampleModel.setSamples(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, b, fArray, dataBuffer); + } + + public void setSamples(int x, int y, int w, int h, int b, + double[] dArray) + { + sampleModel.setSamples(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w, h, b, dArray, dataBuffer); + } +} diff --git a/libjava/classpath/java/awt/image/WritableRenderedImage.java b/libjava/classpath/java/awt/image/WritableRenderedImage.java new file mode 100644 index 0000000..4ed9f10 --- /dev/null +++ b/libjava/classpath/java/awt/image/WritableRenderedImage.java @@ -0,0 +1,56 @@ +/* WritableRenderedImage.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 java.awt.image; + +import java.awt.Point; + +/** + * NEEDS DOCUMENTATION + */ +public interface WritableRenderedImage extends RenderedImage +{ + void addTileObserver(TileObserver to); + void removeTileObserver(TileObserver to); + WritableRaster getWritableTile(int x, int y); + void releaseWritableTile(int x, int y); + boolean isTileWritable(int x, int y); + Point[] getWritableTileIndices(); + boolean hasTileWriters(); + void setData(Raster r); +} // interface WritableRenderedImage diff --git a/libjava/classpath/java/awt/image/package.html b/libjava/classpath/java/awt/image/package.html new file mode 100644 index 0000000..50fa99d --- /dev/null +++ b/libjava/classpath/java/awt/image/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.image + + +

    Image consumers, producers and filters.

    + + + diff --git a/libjava/classpath/java/awt/image/renderable/ContextualRenderedImageFactory.java b/libjava/classpath/java/awt/image/renderable/ContextualRenderedImageFactory.java new file mode 100644 index 0000000..729d857 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/ContextualRenderedImageFactory.java @@ -0,0 +1,56 @@ +/* ContextualRenderedImageFactory.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 java.awt.image.renderable; + +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; + +/** + * STUBBED + */ +public interface ContextualRenderedImageFactory extends RenderedImageFactory +{ + RenderContext mapRenderContext(int i, RenderContext context, + ParameterBlock block, RenderableImage image); + RenderedImage create(RenderContext context, ParameterBlock block); + Rectangle2D getBounds2D(ParameterBlock block); + Object getProperty(ParameterBlock block, String name); + String[] getPropertyNames(); + boolean isDynamic(); +} // interface ContextualRenderedImageFactory diff --git a/libjava/classpath/java/awt/image/renderable/ParameterBlock.java b/libjava/classpath/java/awt/image/renderable/ParameterBlock.java new file mode 100644 index 0000000..879d3c4 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/ParameterBlock.java @@ -0,0 +1,308 @@ +/* ParameterBlock.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 java.awt.image.renderable; + +import java.awt.image.RenderedImage; +import java.io.Serializable; +import java.util.Vector; + +public class ParameterBlock implements Cloneable, Serializable +{ + private static final long serialVersionUID = -7577115551785240750L; + protected Vector sources; + protected Vector parameters; + + public ParameterBlock() + { + this(new Vector(), new Vector()); + } + + public ParameterBlock(Vector sources) + { + this(sources, new Vector()); + } + + public ParameterBlock(Vector sources, Vector parameters) + { + this.sources = sources; + this.parameters = parameters; + } + + public Object shallowClone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // impossible + } + } + + public Object clone() + { + ParameterBlock pb = (ParameterBlock) shallowClone(); + if (sources != null) + pb.sources = (Vector) sources.clone(); + if (parameters != null) + pb.parameters = (Vector) parameters.clone(); + return pb; + } + + public ParameterBlock addSource(Object source) + { + sources.add(source); + return this; + } + + public Object getSource(int index) + { + return sources.get(index); + } + + public ParameterBlock setSource(Object source, int index) + { + sources.ensureCapacity(index); + sources.set(index, source); + return this; + } + + public RenderedImage getRenderedSource(int index) + { + return (RenderedImage) sources.get(index); + } + + public RenderableImage getRenderableSource(int index) + { + return (RenderableImage) sources.get(index); + } + + public int getNumSources() + { + return sources.size(); + } + + public Vector getSources() + { + return sources; + } + + public void setSources(Vector sources) + { + this.sources = sources; + } + + public void removeSources() + { + if (sources != null) + sources.clear(); + } + + public int getNumParameters() + { + return parameters.size(); + } + + public Vector getParameters() + { + return parameters; + } + + public void setParameters(Vector parameters) + { + this.parameters = parameters; + } + + public void removeParameters() + { + if (parameters != null) + parameters.clear(); + } + + public ParameterBlock add(Object o) + { + parameters.add(o); + return this; + } + + public ParameterBlock add(byte b) + { + return add(new Byte(b)); + } + + public ParameterBlock add(char c) + { + return add(new Character(c)); + } + + public ParameterBlock add(short s) + { + return add(new Short(s)); + } + + public ParameterBlock add(int i) + { + return add(new Integer(i)); + } + + public ParameterBlock add(long l) + { + return add(new Long(l)); + } + + public ParameterBlock add(float f) + { + return add(new Float(f)); + } + + public ParameterBlock add(double d) + { + return add(new Double(d)); + } + + public ParameterBlock set(Object o, int index) + { + parameters.ensureCapacity(index); + parameters.set(index, o); + return this; + } + + public ParameterBlock set(byte b, int index) + { + return set(new Byte(b), index); + } + + public ParameterBlock set(char c, int index) + { + return set(new Character(c), index); + } + + public ParameterBlock set(short s, int index) + { + return set(new Short(s), index); + } + + public ParameterBlock set(int i, int index) + { + return set(new Integer(i), index); + } + + public ParameterBlock set(long l, int index) + { + return set(new Long(l), index); + } + + public ParameterBlock set(float f, int index) + { + return set(new Float(f), index); + } + + public ParameterBlock set(double d, int index) + { + return set(new Double(d), index); + } + + public Object getObjectParameter(int index) + { + return parameters.get(index); + } + + public byte getByteParameter(int index) + { + return ((Byte) parameters.get(index)).byteValue(); + } + + public char getCharParameter(int index) + { + return ((Character) parameters.get(index)).charValue(); + } + + public short getShortParameter(int index) + { + return ((Short) parameters.get(index)).shortValue(); + } + + public int getIntParameter(int index) + { + return ((Integer) parameters.get(index)).intValue(); + } + + public long getLongParameter(int index) + { + return ((Long) parameters.get(index)).longValue(); + } + + public float getFloatParameter(int index) + { + return ((Float) parameters.get(index)).floatValue(); + } + + public double getDoubleParameter(int index) + { + return ((Double) parameters.get(index)).doubleValue(); + } + + public Class[] getParamClasses() + { + int i = parameters.size(); + Class[] result = new Class[i]; + while (--i >= 0) + { + Class c = parameters.get(i).getClass(); + if (c == Byte.class) + result[i] = byte.class; + else if (c == Character.class) + result[i] = char.class; + else if (c == Short.class) + result[i] = short.class; + else if (c == Integer.class) + result[i] = int.class; + else if (c == Long.class) + result[i] = long.class; + else if (c == Float.class) + result[i] = float.class; + else if (c == Double.class) + result[i] = double.class; + else + result[i] = c; + } + return result; + } +} // class ParameterBlock diff --git a/libjava/classpath/java/awt/image/renderable/RenderContext.java b/libjava/classpath/java/awt/image/renderable/RenderContext.java new file mode 100644 index 0000000..67f0b8a --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderContext.java @@ -0,0 +1,141 @@ +/* RenderContext.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 java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; + +public class RenderContext implements Cloneable +{ + private AffineTransform xform; + private Shape aoi; + private RenderingHints hints; + + public RenderContext(AffineTransform xform, Shape aoi, RenderingHints hints) + { + this.xform = xform; + this.aoi = aoi; + this.hints = hints; + } + + public RenderContext(AffineTransform xform) + { + this(xform, null, null); + } + + public RenderContext(AffineTransform xform, RenderingHints hints) + { + this(xform, null, hints); + } + + public RenderContext(AffineTransform xform, Shape aoi) + { + this(xform, aoi, null); + } + + public RenderingHints getRenderingHints() + { + return hints; + } + + public void setRenderingHints(RenderingHints hints) + { + this.hints = hints; + } + + public void setTransform(AffineTransform xform) + { + this.xform = xform; + } + + public void preConcatenateTransform(AffineTransform pre) + { + preConcetenateTransform (pre); + } + + /** @deprecated */ + public void preConcetenateTransform(AffineTransform pre) + { + xform.preConcatenate (pre); + } + + public void concatenateTransform(AffineTransform post) + { + concetenateTransform (post); + } + + /** @deprecated */ + public void concetenateTransform(AffineTransform post) + { + xform.concatenate (post); + } + + public AffineTransform getTransform() + { + return xform; + } + + public void setAreaOfInterest(Shape aoi) + { + this.aoi = aoi; + } + + public Shape getAreaOfInterest() + { + return aoi; + } + + public Object clone() + { + try + { + RenderContext copy = (RenderContext) super.clone(); + if (xform != null) + copy.xform = (AffineTransform) xform.clone(); + if (hints != null) + copy.hints = (RenderingHints) hints.clone(); + return copy; + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // impossible + } + } +} // class RenderContext diff --git a/libjava/classpath/java/awt/image/renderable/RenderableImage.java b/libjava/classpath/java/awt/image/renderable/RenderableImage.java new file mode 100644 index 0000000..45d2eb7 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderableImage.java @@ -0,0 +1,62 @@ +/* RenderableImage.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 java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; +import java.util.Vector; + +public interface RenderableImage +{ + String HINTS_OBSERVED = "HINTS_OBSERVED"; + + Vector getSources(); + Object getProperty(String name); + String[] getPropertyNames(); + boolean isDynamic(); + float getWidth(); + float getHeight(); + float getMinX(); + float getMinY(); + RenderedImage createScaledRendering(int w, int h, RenderingHints hints); + RenderedImage createDefaultRendering(); + RenderedImage createRendering(RenderContext context); + +} // interface RenderableImage + diff --git a/libjava/classpath/java/awt/image/renderable/RenderableImageOp.java b/libjava/classpath/java/awt/image/renderable/RenderableImageOp.java new file mode 100644 index 0000000..5385a82 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderableImageOp.java @@ -0,0 +1,157 @@ +/* RenderableImageOp.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 java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.image.RenderedImage; +import java.util.Vector; + +public class RenderableImageOp implements RenderableImage +{ + private final ContextualRenderedImageFactory crif; + private ParameterBlock block; + + public RenderableImageOp(ContextualRenderedImageFactory crif, + ParameterBlock block) + { + this.crif = crif; + this.block = (ParameterBlock) block.clone(); + } + + public Vector getSources() + { + if (block.sources == null) + return null; + int size = block.sources.size(); + Vector v = new Vector(); + for (int i = 0; i < size; i++) + { + Object o = block.sources.get(i); + if (o instanceof RenderableImage) + v.add(o); + } + return v; + } + + public Object getProperty(String name) + { + return crif.getProperty(block, name); + } + + public String[] getPropertyNames() + { + return crif.getPropertyNames(); + } + + public boolean isDynamic() + { + return crif.isDynamic(); + } + + public float getWidth() + { + return (float) crif.getBounds2D(block).getWidth(); + } + + public float getHeight() + { + return (float) crif.getBounds2D(block).getHeight(); + } + + public float getMinX() + { + return (float) crif.getBounds2D(block).getX(); + } + + public float getMinY() + { + return (float) crif.getBounds2D(block).getY(); + } + + public ParameterBlock setParameterBlock(ParameterBlock block) + { + ParameterBlock result = this.block; + this.block = (ParameterBlock) block.clone(); + return result; + } + + public ParameterBlock getParameterBlock() + { + return block; + } + + public RenderedImage createScaledRendering(int w, int h, + RenderingHints hints) + { + if (w == 0) + if (h == 0) + throw new IllegalArgumentException(); + else + w = Math.round(h * getWidth() / getHeight()); + if (h == 0) + h = Math.round(w * getHeight() / getWidth()); + AffineTransform xform = AffineTransform.getScaleInstance(w * getWidth(), + h * getHeight()); + return createRendering(new RenderContext(xform, hints)); + } + + public RenderedImage createDefaultRendering() + { + return createRendering(new RenderContext(new AffineTransform())); + } + + public RenderedImage createRendering(RenderContext context) + { + ParameterBlock copy = (ParameterBlock) block.clone(); + int i = block.sources.size(); + while (--i >= 0) + { + Object o = block.sources.get(i); + if (o instanceof RenderableImage) + { + RenderableImage ri = (RenderableImage) o; + RenderContext rc = crif.mapRenderContext(i, context, block, ri); + copy.sources.set(i, ri.createRendering(rc)); + } + } + // Now copy.sources should be only RenderedImages. + return crif.create(context, copy); + } +} // class RenderableImageOp diff --git a/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java b/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java new file mode 100644 index 0000000..78f3051 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java @@ -0,0 +1,79 @@ +/* RenderableImageProducer.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 java.awt.image.renderable; + +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; + +public class RenderableImageProducer implements ImageProducer, Runnable +{ + public RenderableImageProducer(RenderableImage image, RenderContext context) + { + throw new Error("not implemented"); + } + + public void setRenderContext(RenderContext context) + { + } + + public void addConsumer(ImageConsumer consumer) + { + } + + public boolean isConsumer(ImageConsumer consumer) + { + return false; + } + + public void removeConsumer(ImageConsumer consumer) + { + } + + public void startProduction(ImageConsumer consumer) + { + } + + public void requestTopDownLeftRightResend(ImageConsumer consumer) + { + } + + public void run() + { + } +} // class RenderableImageProducer diff --git a/libjava/classpath/java/awt/image/renderable/RenderedImageFactory.java b/libjava/classpath/java/awt/image/renderable/RenderedImageFactory.java new file mode 100644 index 0000000..6ff4cb0 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderedImageFactory.java @@ -0,0 +1,47 @@ +/* RenderedImageFactory.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 java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; + +public interface RenderedImageFactory +{ + RenderedImage create(ParameterBlock block, RenderingHints hints); +} // interface RenderedImageFactory diff --git a/libjava/classpath/java/awt/image/renderable/package.html b/libjava/classpath/java/awt/image/renderable/package.html new file mode 100644 index 0000000..a24237e --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.image.renderable + + +

    + + + diff --git a/libjava/classpath/java/awt/package.html b/libjava/classpath/java/awt/package.html new file mode 100644 index 0000000..c5ff988 --- /dev/null +++ b/libjava/classpath/java/awt/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt + + +

    Abstract Window Toolkit classes.

    + + + diff --git a/libjava/classpath/java/awt/peer/ButtonPeer.java b/libjava/classpath/java/awt/peer/ButtonPeer.java new file mode 100644 index 0000000..a55fc22 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ButtonPeer.java @@ -0,0 +1,46 @@ +/* ButtonPeer.java -- Peer interface for buttons + Copyright (C) 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 java.awt.peer; + +public interface ButtonPeer extends ComponentPeer +{ + void setLabel (String label); + +} // interface ButtonPeer + diff --git a/libjava/classpath/java/awt/peer/CanvasPeer.java b/libjava/classpath/java/awt/peer/CanvasPeer.java new file mode 100644 index 0000000..4b33835 --- /dev/null +++ b/libjava/classpath/java/awt/peer/CanvasPeer.java @@ -0,0 +1,45 @@ +/* CanvasPeer.java -- Peer interface for a canvas + Copyright (C) 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 java.awt.peer; + +public interface CanvasPeer extends ComponentPeer +{ + +} // interface CanvasPeer + diff --git a/libjava/classpath/java/awt/peer/CheckboxMenuItemPeer.java b/libjava/classpath/java/awt/peer/CheckboxMenuItemPeer.java new file mode 100644 index 0000000..5213dc9 --- /dev/null +++ b/libjava/classpath/java/awt/peer/CheckboxMenuItemPeer.java @@ -0,0 +1,46 @@ +/* CheckboxMenuItemPeer.java -- Peer interface for checkbox menu items + Copyright (C) 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 java.awt.peer; + +public interface CheckboxMenuItemPeer extends MenuItemPeer +{ + void setState (boolean state); + +} // interface CheckboxMenuItemPeer + diff --git a/libjava/classpath/java/awt/peer/CheckboxPeer.java b/libjava/classpath/java/awt/peer/CheckboxPeer.java new file mode 100644 index 0000000..8b23b3f --- /dev/null +++ b/libjava/classpath/java/awt/peer/CheckboxPeer.java @@ -0,0 +1,52 @@ +/* CheckboxPeer.java -- Interface for checkbox peer + Copyright (C) 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 java.awt.peer; + +import java.awt.CheckboxGroup; + +public interface CheckboxPeer extends ComponentPeer +{ + void setCheckboxGroup (CheckboxGroup group); + + void setLabel (String label); + + void setState (boolean state); + +} // interface CheckboxPeer + diff --git a/libjava/classpath/java/awt/peer/ChoicePeer.java b/libjava/classpath/java/awt/peer/ChoicePeer.java new file mode 100644 index 0000000..8ed1107 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ChoicePeer.java @@ -0,0 +1,54 @@ +/* ChoicePeer.java -- Peer for choice box + Copyright (C) 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 java.awt.peer; + +public interface ChoicePeer extends ComponentPeer +{ + void add (String item, int index); + + void addItem (String item, int index); + + void remove (int index); + + void removeAll(); + + void select (int index); + +} // interface ChoicePeer + diff --git a/libjava/classpath/java/awt/peer/ComponentPeer.java b/libjava/classpath/java/awt/peer/ComponentPeer.java new file mode 100644 index 0000000..7ed8f60 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ComponentPeer.java @@ -0,0 +1,187 @@ +/* ComponentPeer.java -- Toplevel component peer + Copyright (C) 1999, 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 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.Point; +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; + +public interface ComponentPeer +{ + int checkImage(Image img, int width, int height, + ImageObserver ob); + Image createImage(ImageProducer prod); + Image createImage(int width, int height); + void disable(); + void dispose(); + void enable(); + ColorModel getColorModel(); + FontMetrics getFontMetrics(Font f); + Graphics getGraphics(); + Point getLocationOnScreen(); + Dimension getMinimumSize(); + Dimension getPreferredSize(); + Toolkit getToolkit(); + void handleEvent(AWTEvent e); + void hide(); + + /** + * Part of the earlier 1.1 API, replaced by isFocusable(). + */ + boolean isFocusTraversable(); + boolean isFocusable(); + Dimension minimumSize(); + Dimension preferredSize(); + void paint(Graphics graphics); + boolean prepareImage(Image img, int width, int height, + ImageObserver ob); + void print(Graphics graphics); + void repaint(long tm, int x, int y, int width, int height); + + /** + * Part of the earlier 1.1 API, apparently replaced by argument + * form of the same method. + */ + void requestFocus(); + boolean requestFocus (Component source, boolean bool1, boolean bool2, long x); + + void reshape(int x, int y, int width, int height); + void setBackground(Color color); + void setBounds(int x, int y, int width, int height); + + /** + * Part of the earlier 1.1 API, apparently no longer needed. + */ + void setCursor(Cursor cursor); + + void setEnabled(boolean enabled); + void setFont(Font font); + void setForeground(Color color); + void setVisible(boolean visible); + void show(); + + /** + * Get the graphics configuration of the component. The color model + * of the component can be derived from the configuration. + */ + GraphicsConfiguration getGraphicsConfiguration(); + + /** + * Part of an older API, no longer needed. + */ + void setEventMask (long mask); + + // Methods below are introduced since 1.1 + boolean isObscured(); + boolean canDetermineObscurity(); + void coalescePaintEvent(PaintEvent e); + void updateCursorImmediately(); + boolean handlesWheelScrolling(); + + /** + * 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. + * + * @param width width of the image + * @param height height of the image + * + * @see VolatileImage + * + * @since 1.2 + */ + VolatileImage createVolatileImage(int width, int height); + + /** + * Create a number of image buffers that implement a buffering + * strategy according to the given capabilities. + * + * @param numBuffers the number of buffers + * @param caps the buffering capabilities + * + * @throws AWTException if the specified buffering strategy is not + * implemented + * + * @since 1.2 + */ + void createBuffers(int numBuffers, BufferCapabilities caps) + throws AWTException; + + /** + * Return the back buffer of this component. + * + * @return the back buffer of this component. + * + * @since 1.2 + */ + Image getBackBuffer(); + + /** + * Perform a page flip, leaving the contents of the back buffer in + * the specified state. + * + * @param contents the state in which to leave the back buffer + * + * @since 1.2 + */ + void flip(BufferCapabilities.FlipContents contents); + + /** + * Destroy the resources created by createBuffers. + * + * @since 1.2 + */ + void destroyBuffers(); +} diff --git a/libjava/classpath/java/awt/peer/ContainerPeer.java b/libjava/classpath/java/awt/peer/ContainerPeer.java new file mode 100644 index 0000000..f1373a1 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ContainerPeer.java @@ -0,0 +1,59 @@ +/* ContainerPeer.java -- Interface for container peers + Copyright (C) 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 java.awt.peer; + +import java.awt.Insets; + +public interface ContainerPeer extends ComponentPeer +{ + Insets insets(); + + Insets getInsets(); + + void beginValidate(); + + void endValidate(); + + void beginLayout(); + + void endLayout(); + + boolean isPaintPending(); + +} // interface ContainerPeer + diff --git a/libjava/classpath/java/awt/peer/DialogPeer.java b/libjava/classpath/java/awt/peer/DialogPeer.java new file mode 100644 index 0000000..e26d64f --- /dev/null +++ b/libjava/classpath/java/awt/peer/DialogPeer.java @@ -0,0 +1,48 @@ +/* DialogPeer.java -- Interface for dialog box peer + Copyright (C) 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 java.awt.peer; + +public interface DialogPeer extends WindowPeer +{ + void setResizable (boolean resizeable); + + void setTitle (String title); + +} // interface DialogPeer + diff --git a/libjava/classpath/java/awt/peer/FileDialogPeer.java b/libjava/classpath/java/awt/peer/FileDialogPeer.java new file mode 100644 index 0000000..7db1798 --- /dev/null +++ b/libjava/classpath/java/awt/peer/FileDialogPeer.java @@ -0,0 +1,52 @@ +/* FileDialogPeer.java -- Interface for file selection dialog box peer + Copyright (C) 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 java.awt.peer; + +import java.io.FilenameFilter; + +public interface FileDialogPeer extends DialogPeer +{ + void setFile (String file); + + void setDirectory (String dir); + + void setFilenameFilter (FilenameFilter ff); + +} // interface FileDialogPeer + diff --git a/libjava/classpath/java/awt/peer/FontPeer.java b/libjava/classpath/java/awt/peer/FontPeer.java new file mode 100644 index 0000000..f0ba6d8 --- /dev/null +++ b/libjava/classpath/java/awt/peer/FontPeer.java @@ -0,0 +1,45 @@ +/* FontPeer.java -- Interface for font peers + Copyright (C) 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 java.awt.peer; + +public interface FontPeer +{ + +} // interface FontPeer + diff --git a/libjava/classpath/java/awt/peer/FramePeer.java b/libjava/classpath/java/awt/peer/FramePeer.java new file mode 100644 index 0000000..13498ff --- /dev/null +++ b/libjava/classpath/java/awt/peer/FramePeer.java @@ -0,0 +1,55 @@ +/* FramePeer.java -- Interface for frame peers + Copyright (C) 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 java.awt.peer; + +import java.awt.Image; +import java.awt.MenuBar; +import java.awt.Rectangle; + +public interface FramePeer extends WindowPeer +{ + void setIconImage(Image image); + void setMenuBar(MenuBar mb); + void setResizable(boolean resizable); + void setTitle(String title); + int getState(); + void setState(int state); + void setMaximizedBounds(Rectangle r); +} // interface FramePeer + diff --git a/libjava/classpath/java/awt/peer/LabelPeer.java b/libjava/classpath/java/awt/peer/LabelPeer.java new file mode 100644 index 0000000..d0fca46 --- /dev/null +++ b/libjava/classpath/java/awt/peer/LabelPeer.java @@ -0,0 +1,46 @@ +/* LabelPeer.java -- Interface for simple text lable peer + Copyright (C) 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 java.awt.peer; + +public interface LabelPeer extends ComponentPeer +{ + void setAlignment(int alignment); + void setText(String text); +} // interface LabelPeer + diff --git a/libjava/classpath/java/awt/peer/LightweightPeer.java b/libjava/classpath/java/awt/peer/LightweightPeer.java new file mode 100644 index 0000000..93cad7a --- /dev/null +++ b/libjava/classpath/java/awt/peer/LightweightPeer.java @@ -0,0 +1,45 @@ +/* LightweightPeer.java -- Interface for lightweight peers + Copyright (C) 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 java.awt.peer; + +public interface LightweightPeer extends ComponentPeer +{ + +} // interface LightweightPeer + diff --git a/libjava/classpath/java/awt/peer/ListPeer.java b/libjava/classpath/java/awt/peer/ListPeer.java new file mode 100644 index 0000000..c0f765d --- /dev/null +++ b/libjava/classpath/java/awt/peer/ListPeer.java @@ -0,0 +1,61 @@ +/* ListPeer.java -- Interface for list box peer + Copyright (C) 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 java.awt.peer; + +import java.awt.Dimension; + +public interface ListPeer extends ComponentPeer +{ + void add(String item, int index); + void addItem(String item, int index); + void clear(); + void delItems(int start_index, int end_index); + void deselect(int index); + int[] getSelectedIndexes(); + void makeVisible(int index); + Dimension minimumSize(int s); + Dimension preferredSize(int s); + void removeAll(); + void select(int index); + void setMultipleMode(boolean multi); + void setMultipleSelections(boolean multi); + Dimension getPreferredSize(int s); + Dimension getMinimumSize(int s); +} // interface ListPeer + diff --git a/libjava/classpath/java/awt/peer/MenuBarPeer.java b/libjava/classpath/java/awt/peer/MenuBarPeer.java new file mode 100644 index 0000000..c5f7c58 --- /dev/null +++ b/libjava/classpath/java/awt/peer/MenuBarPeer.java @@ -0,0 +1,48 @@ +/* MenuBarPeer.java -- Interface for menu bar peer + Copyright (C) 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 java.awt.peer; + +import java.awt.Menu; + +public interface MenuBarPeer extends MenuComponentPeer +{ + void addHelpMenu(Menu menu); + void delMenu(int index); +} // interface MenuBarPeer + diff --git a/libjava/classpath/java/awt/peer/MenuComponentPeer.java b/libjava/classpath/java/awt/peer/MenuComponentPeer.java new file mode 100644 index 0000000..1b10ca1 --- /dev/null +++ b/libjava/classpath/java/awt/peer/MenuComponentPeer.java @@ -0,0 +1,45 @@ +/* MenuComponentPeer.java -- + Copyright (C) 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 java.awt.peer; + +public interface MenuComponentPeer +{ + void dispose(); +} // interface MenuComponentPeer + diff --git a/libjava/classpath/java/awt/peer/MenuItemPeer.java b/libjava/classpath/java/awt/peer/MenuItemPeer.java new file mode 100644 index 0000000..3ba1027 --- /dev/null +++ b/libjava/classpath/java/awt/peer/MenuItemPeer.java @@ -0,0 +1,48 @@ +/* MenuItemPeer.java -- Interface for menu item peers + Copyright (C) 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 java.awt.peer; + +public interface MenuItemPeer extends MenuComponentPeer +{ + void disable(); + void enable(); + void setEnabled(boolean enabled); + void setLabel(String text); +} // interface MenuItemPeer + diff --git a/libjava/classpath/java/awt/peer/MenuPeer.java b/libjava/classpath/java/awt/peer/MenuPeer.java new file mode 100644 index 0000000..c51ea73 --- /dev/null +++ b/libjava/classpath/java/awt/peer/MenuPeer.java @@ -0,0 +1,48 @@ +/* MenuPeer.java -- Interface for menu peers + Copyright (C) 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 java.awt.peer; + +import java.awt.MenuItem; + +public interface MenuPeer extends MenuItemPeer +{ + void addItem (MenuItem item); + void delItem (int index); +} + diff --git a/libjava/classpath/java/awt/peer/PanelPeer.java b/libjava/classpath/java/awt/peer/PanelPeer.java new file mode 100644 index 0000000..192632e --- /dev/null +++ b/libjava/classpath/java/awt/peer/PanelPeer.java @@ -0,0 +1,45 @@ +/* PanelPeer.java -- Interface for panel peers + Copyright (C) 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 java.awt.peer; + +public interface PanelPeer extends ContainerPeer +{ + +} // interface PanelPeer + diff --git a/libjava/classpath/java/awt/peer/PopupMenuPeer.java b/libjava/classpath/java/awt/peer/PopupMenuPeer.java new file mode 100644 index 0000000..2e8f4bb --- /dev/null +++ b/libjava/classpath/java/awt/peer/PopupMenuPeer.java @@ -0,0 +1,53 @@ +/* PopupMenuPeer.java -- Interface for popup menu peers + Copyright (C) 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 java.awt.peer; + +import java.awt.Component; +import java.awt.Event; + +public interface PopupMenuPeer extends MenuPeer +{ + /** + * Part of the older API, replaced by event version instead. + */ + void show (Component origin, int x, int y); + + void show (Event e); +} // interface PopupMenuPeer + diff --git a/libjava/classpath/java/awt/peer/RobotPeer.java b/libjava/classpath/java/awt/peer/RobotPeer.java new file mode 100644 index 0000000..db81c80 --- /dev/null +++ b/libjava/classpath/java/awt/peer/RobotPeer.java @@ -0,0 +1,54 @@ +/* RobotPeer.java -- Interface for programatically driving GUI + 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 java.awt.peer; + +import java.awt.Rectangle; + +public interface RobotPeer +{ + void mouseMove (int x, int y); + void mousePress (int buttons); + void mouseRelease (int buttons); + void mouseWheel (int wheelAmt); + void keyPress (int keycode); + void keyRelease (int keycode); + int getRGBPixel (int x, int y); + int[] getRGBPixels (Rectangle screen); +} // interface RobotPeer + diff --git a/libjava/classpath/java/awt/peer/ScrollPanePeer.java b/libjava/classpath/java/awt/peer/ScrollPanePeer.java new file mode 100644 index 0000000..de4331e --- /dev/null +++ b/libjava/classpath/java/awt/peer/ScrollPanePeer.java @@ -0,0 +1,52 @@ +/* ScrollPanePeer.java -- Interface for scrollable panes + Copyright (C) 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 java.awt.peer; + +import java.awt.Adjustable; + +public interface ScrollPanePeer extends ContainerPeer +{ + int getHScrollbarHeight(); + int getVScrollbarWidth(); + void setScrollPosition(int h, int v); + void childResized(int width, int height); + void setUnitIncrement(Adjustable item, int inc); + void setValue(Adjustable item, int value); +} // interface ScollPanePeer + diff --git a/libjava/classpath/java/awt/peer/ScrollbarPeer.java b/libjava/classpath/java/awt/peer/ScrollbarPeer.java new file mode 100644 index 0000000..fe4f24d --- /dev/null +++ b/libjava/classpath/java/awt/peer/ScrollbarPeer.java @@ -0,0 +1,47 @@ +/* ScrollbarPeer.java -- Interface for scrollbar peers + Copyright (C) 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 java.awt.peer; + +public interface ScrollbarPeer extends ComponentPeer +{ + void setLineIncrement(int inc); + void setPageIncrement(int inc); + void setValues(int value, int visible, int min, int max); +} // interface ScrollbarPeer + diff --git a/libjava/classpath/java/awt/peer/TextAreaPeer.java b/libjava/classpath/java/awt/peer/TextAreaPeer.java new file mode 100644 index 0000000..354e46d --- /dev/null +++ b/libjava/classpath/java/awt/peer/TextAreaPeer.java @@ -0,0 +1,53 @@ +/* TextAreaPeer.java -- Interface for text area peers + Copyright (C) 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 java.awt.peer; + +import java.awt.Dimension; + +public interface TextAreaPeer extends TextComponentPeer +{ + void insert(String text, int pos); + void insertText(String text, int pos); + Dimension minimumSize(int rows, int cols); + Dimension getMinimumSize(int rows, int cols); + Dimension preferredSize(int rows, int cols); + Dimension getPreferredSize(int rows, int cols); + void replaceRange(String text, int start_pos, int end_pos); + void replaceText(String text, int start_pos, int end_pos); +} // interface TextAreaPeer diff --git a/libjava/classpath/java/awt/peer/TextComponentPeer.java b/libjava/classpath/java/awt/peer/TextComponentPeer.java new file mode 100644 index 0000000..cacc7d8 --- /dev/null +++ b/libjava/classpath/java/awt/peer/TextComponentPeer.java @@ -0,0 +1,57 @@ +/* TextComponentPeer.java -- Superclass interface for text components + Copyright (C) 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 java.awt.peer; + +import java.awt.Rectangle; + +public interface TextComponentPeer extends ComponentPeer +{ + int getSelectionEnd(); + int getSelectionStart(); + String getText(); + void setText(String text); + void select(int start_pos, int end_pos); + void setEditable(boolean editable); + int getCaretPosition(); + void setCaretPosition(int pos); + int getIndexAtPoint(int x, int y); + Rectangle getCharacterBounds(int pos); + long filterEvents(long filter); +} // interface TextComponentPeer + diff --git a/libjava/classpath/java/awt/peer/TextFieldPeer.java b/libjava/classpath/java/awt/peer/TextFieldPeer.java new file mode 100644 index 0000000..e68d666 --- /dev/null +++ b/libjava/classpath/java/awt/peer/TextFieldPeer.java @@ -0,0 +1,52 @@ +/* TextFieldPeer.java -- Interface for text field peers + Copyright (C) 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 java.awt.peer; + +import java.awt.Dimension; + +public interface TextFieldPeer extends TextComponentPeer +{ + Dimension minimumSize(int len); + Dimension preferredSize(int len); + Dimension getMinimumSize(int len); + Dimension getPreferredSize(int len); + void setEchoChar(char echo_char); + void setEchoCharacter(char echo_char); +} // interface TextFieldPeer + diff --git a/libjava/classpath/java/awt/peer/WindowPeer.java b/libjava/classpath/java/awt/peer/WindowPeer.java new file mode 100644 index 0000000..8f136dd --- /dev/null +++ b/libjava/classpath/java/awt/peer/WindowPeer.java @@ -0,0 +1,46 @@ +/* WindowPeer.java -- Interface for window peers + Copyright (C) 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 java.awt.peer; + +public interface WindowPeer extends ContainerPeer +{ + void toBack(); + void toFront(); +} // interface WindowPeer + diff --git a/libjava/classpath/java/awt/peer/package.html b/libjava/classpath/java/awt/peer/package.html new file mode 100644 index 0000000..7a7458c --- /dev/null +++ b/libjava/classpath/java/awt/peer/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.peer + + +

    Interfaces for using native interface components.

    + + + diff --git a/libjava/classpath/java/awt/print/Book.java b/libjava/classpath/java/awt/print/Book.java new file mode 100644 index 0000000..b084a17 --- /dev/null +++ b/libjava/classpath/java/awt/print/Book.java @@ -0,0 +1,159 @@ +/* Book.java -- A mixed group of pages to print. + 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 java.awt.print; + +import java.util.Vector; + +/** + * This class allows documents to be created with different paper types, + * page formatters, and painters. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Book implements Pageable +{ + /** + * Painter objects for the book. + */ + Vector printables = new Vector(); + + /** + * Page formats for the book. + */ + Vector page_formats = new Vector(); + + /** + * Initializes a new instance of Book that is empty. + */ + public Book() + { + } + + /** + * Returns the number of pages in this book. + * + * @return The number of pages in this book. + */ + public int getNumberOfPages() + { + return printables.size(); + } + + /** + * This method returns the PageFormat object for the + * specified page. + * + * @param page_number The number of the page to get information for, where + * page numbers start at 0. + * + * @return The PageFormat object for the specified page. + * + * @exception IndexOutOfBoundsException If the page number is not valid. + */ + public PageFormat getPageFormat(int page_number) + { + return (PageFormat) page_formats.elementAt(page_number); + } + + /** + * This method returns the Printable object for the + * specified page. + * + * @param page_number The number of the page to get information for, where + * page numbers start at 0. + * + * @return The Printable object for the specified page. + * + * @exception IndexOutOfBoundsException If the page number is not valid. + */ + public Printable getPrintable(int page_number) + { + return (Printable) printables.elementAt(page_number); + } + + /** + * This method appends a page to the end of the book. + * + * @param printable The Printable for this page. + * @param page_format The PageFormat for this page. + * + * @exception NullPointerException If either argument is null. + */ + public void append(Printable printable, PageFormat page_format) + { + append(printable, page_format, 1); + } + + /** + * This method appends the specified number of pages to the end of the book. + * Each one will be associated with the specified Printable + * and PageFormat. + * + * @param printable The Printable for this page. + * @param page_format The PageFormat for this page. + * @param num_pages The number of pages to append. + * + * @exception NullPointerException If any argument is null. + */ + public void append(Printable printable, PageFormat page_format, int num_pages) + { + for (int i = 0; i < num_pages; i++) + { + printables.addElement(printable); + page_formats.addElement(page_format); + } + } + + /** + * This method changes the Printable and PageFormat + * for the specified page. The page must already exist or an exception + * will be thrown. + * + * @param page_num The page number to alter. + * @param printable The new Printable for the page. + * @param page_format The new PageFormat for the page. + * + * @throws IndexOutOfBoundsException If the specified page does not exist. + */ + public void setPage(int page_num, Printable printable, PageFormat page_format) + { + printables.setElementAt(printable, page_num); + page_formats.setElementAt(page_format, page_num); + } +} diff --git a/libjava/classpath/java/awt/print/PageFormat.java b/libjava/classpath/java/awt/print/PageFormat.java new file mode 100644 index 0000000..6399552 --- /dev/null +++ b/libjava/classpath/java/awt/print/PageFormat.java @@ -0,0 +1,292 @@ +/* PageFormat.java -- Information about the page format + Copyright (C) 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 java.awt.print; + +/** + * This class contains information about the desired page format to + * use for printing a particular set of pages. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PageFormat implements Cloneable +{ + +/* + * Static Variables + */ + +/** + * A constant for a landscaped page orientation. Used by + * getOrientation and setOrientation. + */ +public static final int LANDSCAPE = 0; + +/** + * A constant for a portrait page orientation. Used by + * getOrientation and setOrientation. + */ +public static final int PORTRAIT = 1; + +/** + * A constant for a reversed landscaped page orientation. This is + * the orientation used by Macintosh's for landscape. The origin is + * in the upper right hand corner instead of the upper left. The + * X and Y axes are reversed. Used by getOrientation and + * setOrientation. + */ +public static final int REVERSE_LANDSCAPE = 2; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +// The page orientation +private int orientation; + +// The paper type +private Paper paper; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * This method creates a default page layout, which will be in portrait + * format. + */ +public +PageFormat() +{ + this.paper = new Paper(); + this.orientation = PORTRAIT; +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * This method returns the width of the page, in 1/72nd's of an inch. The + * "width" measured depends on orientation. + * + * @return The width of the page. + */ +public double +getWidth() +{ + return(paper.getWidth()); +} + +/*************************************************************************/ + +/** + * This method returns the height of the page, in 1/72nd's of an inch. + * The "height" measured depends on the orientation. + * + * @return The height of the page. + */ +public double +getHeight() +{ + return(paper.getHeight()); +} + +/*************************************************************************/ + +/** + * This method returns the X coordinate value of the upper leftmost + * drawable area of the paper. + * + * @return The upper leftmost imageable X coordinate. + */ +public double +getImageableX() +{ + return(paper.getImageableX()); +} + +/*************************************************************************/ + +/** + * This method returns the Y coordinate value of the upper leftmost + * drawable area of the paper. + * + * @return The upper leftmost imageable Y coordinate. + */ +public double +getImageableY() +{ + return(paper.getImageableY()); +} + +/*************************************************************************/ + +/** + * This method returns the imageable width of the paper, in 1/72nd's of + * an inch. + * + * @return The imageable width of the paper. + */ +public double +getImageableWidth() +{ + return(paper.getImageableWidth()); +} + +/*************************************************************************/ + +/** + * This method returns the imageable height of the paper, in 1/72nd's of + * an inch. + * + * @return The imageable height of the paper. + */ +public double getImageableHeight() +{ + return(paper.getImageableHeight()); +} + +/*************************************************************************/ + +/** + * Returns a copy of the paper object being used for this + * page format. + * + * @return A copy of the Paper object for this format. + */ +public Paper +getPaper() +{ + return((Paper)paper.clone()); +} + +/*************************************************************************/ + +/** + * Sets the Paper object to be used by this page format. + * + * @param paper The new Paper object for this page format. + */ +public void +setPaper(Paper paper) +{ + this.paper = paper; +} + +/*************************************************************************/ + +/** + * This method returns the current page orientation. The value returned + * will be one of the page orientation constants from this class. + * + * @return The current page orientation. + */ +public int +getOrientation() +{ + return(orientation); +} + +/*************************************************************************/ + +/** + * This method sets the page orientation for this format to the + * specified value. It must be one of the page orientation constants + * from this class or an exception will be thrown. + * + * @param orientation The new page orientation. + * + * @exception IllegalArgumentException If the specified page orientation + * value is not one of the constants from this class. + */ +public void +setOrientation(int orientation) throws IllegalArgumentException +{ + if ((orientation != PORTRAIT) && + (orientation != LANDSCAPE) && + (orientation != REVERSE_LANDSCAPE)) + throw new IllegalArgumentException("Bad page orientation value: " + + orientation); + + this.orientation = orientation; +} + +/*************************************************************************/ + +/** + * This method returns a matrix used for transforming user space + * coordinates to page coordinates. The value returned will be six + * doubles as described in java.awt.geom.AffineTransform. + * + * @return The transformation matrix for this page format. + */ +public double[] +getMatrix() +{ + throw new RuntimeException("Not implemented since I don't know what to do"); +} + +/*************************************************************************/ + +/** + * This method returns a copy of this object. + * + * @return A copy of this object. + */ +public Object +clone() +{ + try + { + return(super.clone()); + } + catch(CloneNotSupportedException e) + { + return(null); + } +} + +} // class PageFormat + diff --git a/libjava/classpath/java/awt/print/Pageable.java b/libjava/classpath/java/awt/print/Pageable.java new file mode 100644 index 0000000..12fa542 --- /dev/null +++ b/libjava/classpath/java/awt/print/Pageable.java @@ -0,0 +1,113 @@ +/* Pageable.java -- Pages to be printed + Copyright (C) 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 java.awt.print; + +/** + * This interface represents pages that are to be printed. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Pageable +{ + +/* + * Static Variables + */ + +/** + * This constant is returned when getNumberOfPages() + * cannot determine the number of pages available for printing. + */ +int UNKNOWN_NUMBER_OF_PAGES = -1; + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * This method returns the number of pages this object contains, or + * UNKNOWN_NUMBER_OF_PAGES if it cannot determine the number + * of pages to be printed. + * + * @return The number of pages to be printed, or + * UNKNOWN_NUMBER_OF_PAGES if this is unknown. + */ +int +getNumberOfPages(); + +/*************************************************************************/ + +/** + * This method returns the PageFormat instance for the + * specified page. Page numbers start at zero. An exception is thrown if + * the requested page does not exist. + * + * @param pageIndex The index of the page to return the + * PageFormat for. + * + * @return The PageFormat for the requested page. + * + * @exception IndexOutOfBoundsException If the requested page number does + * not exist. + */ +PageFormat +getPageFormat(int pageIndex) throws IndexOutOfBoundsException; + +/*************************************************************************/ + +/** + * This method returns the Printable instance for the + * specified page. Page numbers start at zero. An exception is thrown if + * the requested page does not exist. + * + * @param pageIndex The index of the page to return the + * Printable for. + * + * @return The Printable for the requested page. + * + * @exception IndexOutOfBoundsException If the requested page number does + * not exist. + */ +Printable +getPrintable(int pageIndex) throws IndexOutOfBoundsException; + +} // interface Pageable + diff --git a/libjava/classpath/java/awt/print/Paper.java b/libjava/classpath/java/awt/print/Paper.java new file mode 100644 index 0000000..4579da3 --- /dev/null +++ b/libjava/classpath/java/awt/print/Paper.java @@ -0,0 +1,236 @@ +/* Paper.java -- Information about a paper type. + Copyright (C) 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 java.awt.print; + +/** + * This class describes a particular type of paper. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Paper implements Cloneable +{ + +/* + * Instance Variables + */ + +// Height of the paper +private double height; + +// Width of the paper +private double width; + +// Upper left imageable X coordinate +private double imageableX; + +// Upper left imageable Y coordinate +private double imageableY; + +// Imageable width of the page +private double imageableWidth; + +// Imageable height of the page +private double imageableHeight; + +/*************************************************************************/ + +/* + * Constructor + */ + +/** + * This method creates a letter sized paper with one inch margins + */ +public +Paper() +{ + width = 8.5 * 72; + height = 11 * 72; + imageableX = 72; + imageableY = 72; + imageableWidth = width - (2 * 72); + imageableHeight = height - (2 * 72); +} + +/*************************************************************************/ + +/** + * This method returns the height of the paper in 1/72nds of an inch. + * + * @return The height of the paper in 1/72nds of an inch. + */ +public double +getHeight() +{ + return(height); +} + +/*************************************************************************/ + +/** + * Returns the width of the paper in 1/72nds of an inch. + * + * @return The width of the paper in 1/72nds of an inch. + */ +public double +getWidth() +{ + return(width); +} + +/*************************************************************************/ + +/** + * This method returns the X coordinate of the upper left hand corner + * of the imageable area of the paper. + * + * @return The X coordinate of the upper left hand corner of the imageable + * area of the paper. + */ +public double +getImageableX() +{ + return(imageableX); +} + +/*************************************************************************/ + +/** + * This method returns the Y coordinate of the upper left hand corner + * of the imageable area of the paper. + * + * @return The Y coordinate of the upper left hand corner of the imageable + * area of the paper. + */ +public double +getImageableY() +{ + return(imageableY); +} + +/*************************************************************************/ + +/** + * Returns the width of the imageable area of the paper. + * + * @return The width of the imageable area of the paper. + */ +public double +getImageableWidth() +{ + return(imageableWidth); +} + +/*************************************************************************/ + +/** + * Returns the height of the imageable area of the paper. + * + * @return The height of the imageable area of the paper. + */ +public double +getImageableHeight() +{ + return(imageableHeight); +} + +/*************************************************************************/ + +/** + * This method sets the size of the paper to the specified width and + * height, which are specified in 1/72nds of an inch. + * + * @param width The width of the paper in 1/72nds of an inch. + * @param height The height of the paper in 1/72nds of an inch. + */ +public void +setSize(double width, double height) +{ + this.width = width; + this.height = height; +} + +/*************************************************************************/ + +/** + * This method sets the imageable area of the paper by specifying the + * coordinates of the upper left hand corner of that area, and its + * length and height. All values are in 1/72nds of an inch. + * + * @param imageableX The X coordinate of the upper left hand corner of + * the imageable area, in 1/72nds of an inch. + * @param imageableY The Y coordinate of the upper left hand corner of + * the imageable area, in 1/72nds of an inch. + * @param imageableWidth The width of the imageable area of the paper, + * in 1/72nds of an inch. + * @param imageableHeight The heigth of the imageable area of the paper, + * in 1/72nds of an inch. + */ +public void +setImageableArea(double imageableX, double imageableY, + double imageableWidth, double imageableHeight) +{ + this.imageableX = imageableX; + this.imageableY = imageableY; + this.imageableWidth = imageableWidth; + this.imageableHeight = imageableHeight; +} + +/*************************************************************************/ + +/** + * This method creates a copy of this object. + * + * @return A copy of this object. + */ +public Object +clone() +{ + try + { + return(super.clone()); + } + catch(CloneNotSupportedException e) + { + return(null); + } +} + +} // class Paper + diff --git a/libjava/classpath/java/awt/print/Printable.java b/libjava/classpath/java/awt/print/Printable.java new file mode 100644 index 0000000..775167e --- /dev/null +++ b/libjava/classpath/java/awt/print/Printable.java @@ -0,0 +1,80 @@ +/* Printable.java -- Renders a page to the print device + 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 java.awt.print; + +import java.awt.Graphics; + + +/** + * This interface provides a mechanism for the actual printing of pages to the + * printer. The object implementing this interface performs the page + * rendering. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Printable +{ + /** + * This value is returned by the print() method to indicate + * that the requested page exists and has been printed. + */ + int PAGE_EXISTS = 0; + + /** + * This value is returned by the print() method to indicate + * that the requested page number does not exist. + */ + int NO_SUCH_PAGE = 1; + + /** + * This method prints the specified page to the specified graphics + * context in the specified format. The pages are numbered starting + * from zero. + * + * @param graphics The graphics context to render the pages on. + * @param format The format in which to print the page. + * @param page_number The page number to print, where numbers start at zero. + * + * @return PAGE_EXISTS if the requested page exists and was + * successfully printed, NO_SUCH_PAGE otherwise. + * + * @exception PrinterException If an error occurs during printing. + */ + int print(Graphics graphics, PageFormat format, int page_number) + throws PrinterException; +} diff --git a/libjava/classpath/java/awt/print/PrinterAbortException.java b/libjava/classpath/java/awt/print/PrinterAbortException.java new file mode 100644 index 0000000..4580630 --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterAbortException.java @@ -0,0 +1,71 @@ +/* PrinterAbortException.java -- Indicates the print job was aborted + Copyright (C) 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 java.awt.print; + +/** + * This exception is thrown when the print job is aborted, either by the + * user or by the application. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class PrinterAbortException extends PrinterException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 4725169026278854136L; + + /** + * Create a new instance with no detailed error message. + */ + public PrinterAbortException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message the descriptive error message + */ + public PrinterAbortException(String message) + { + super(message); + } +} // class PrinterAbortException diff --git a/libjava/classpath/java/awt/print/PrinterException.java b/libjava/classpath/java/awt/print/PrinterException.java new file mode 100644 index 0000000..c105f54 --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterException.java @@ -0,0 +1,71 @@ +/* PrinterException.java -- generic problem in the printing subsystem + Copyright (C) 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 java.awt.print; + +/** + * This is the generic toplevel exception for printing errors. Subclasses + * provide more detailed descriptions of the problem. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class PrinterException extends Exception +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -3757589981158265819L; + + /** + * Create a new instance with no detailed error message. + */ + public PrinterException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message the descriptive error message + */ + public PrinterException(String message) + { + super(message); + } +} // class PrinterException diff --git a/libjava/classpath/java/awt/print/PrinterGraphics.java b/libjava/classpath/java/awt/print/PrinterGraphics.java new file mode 100644 index 0000000..5ca6419 --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterGraphics.java @@ -0,0 +1,61 @@ +/* PrinterGraphics.java -- Hook to return print job controller. + Copyright (C) 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 java.awt.print; + +/** + * This interface is implemented by the Graphics instance + * that is used for rendering pages. It provides a hook to return the + * object that is controlling the print job. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface PrinterGraphics +{ + +/** + * This method returns the instance of PrinterJob that is + * controlling this print job. + * + * @return The PrinterJob that is controlling this print job. + */ +PrinterJob +getPrinterJob(); + +} // interface PrinterGraphics + diff --git a/libjava/classpath/java/awt/print/PrinterIOException.java b/libjava/classpath/java/awt/print/PrinterIOException.java new file mode 100644 index 0000000..c646acd --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterIOException.java @@ -0,0 +1,98 @@ +/* PrinterIOException.java -- The print job encountered an I/O error + Copyright (C) 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 java.awt.print; + +import java.io.IOException; + +/** + * This exception is thrown when the print job encounters an I/O problem + * of some kind. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class PrinterIOException extends PrinterException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 5850870712125932846L; + + /** + * The exception that caused this (duplicates Throwable). + * + * @serial the I/O exception that terminated the job + */ + private final IOException mException; + + /** + * Initializes a new instance with the given cause. + * + * @param mException the cause + */ + public PrinterIOException(IOException mException) + { + super(mException == null ? null : mException.toString()); + initCause(mException); + this.mException = mException; + } + + /** + * Gets the underlying IOException that caused this exception. + * This legacy method has been replaced by {@link #getCause()}. + * + * @return the cause + */ + public IOException getIOException() + { + return mException; + } + + /** + * Gets the cause. + * + * @return the cause + */ + public Throwable getCause() + { + return mException; + } +} // class PrinterIOException + diff --git a/libjava/classpath/java/awt/print/PrinterJob.java b/libjava/classpath/java/awt/print/PrinterJob.java new file mode 100644 index 0000000..e61ab61 --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterJob.java @@ -0,0 +1,299 @@ +/* PrinterJob.java -- This job is the printer control class + Copyright (C) 1999, 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 java.awt.print; + +import java.awt.HeadlessException; + +import javax.print.PrintService; +import javax.print.attribute.PrintRequestAttributeSet; + +/** + * This class controls printing. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class PrinterJob +{ + // The print service associated with this job + private PrintService printer = null; + + /** + * Creates a new print job. + * + * @return A PrinterJob object for the newly created print job. + */ + public static PrinterJob getPrinterJob() + { + // FIXME: Need to fix this to load a default implementation instance. + return null; + } + + /** + * Initializes a new instance of PrinterJob. + */ + public PrinterJob() + { + } + + /** + * Returns the number of copies to be printed. + * + * @return The number of copies to be printed. + */ + public abstract int getCopies(); + + /** + * Sets the number of copies to be printed. + * + * @param copies The number of copies to be printed. + */ + public abstract void setCopies(int copies); + + /** + * Returns the name of the print job. + * + * @return The name of the print job. + */ + public abstract String getJobName(); + + /** + * Sets the name of the print job. + * + * @param job_name The name of the print job. + */ + public abstract void setJobName(String job_name); + + /** + * Returns the printing user name. + * + * @return The printing username. + */ + public abstract String getUserName(); + + /** + * Cancels an in progress print job. + */ + public abstract void cancel(); + + /** + * Tests whether or not this job has been cancelled. + * + * @return true if this job has been cancelled, false + * otherwise. + */ + public abstract boolean isCancelled(); + + /** + * Returns an instance of the default page which will have the default + * paper and orientation. + * + * @return A default instance of PageFormat. + */ + public PageFormat defaultPage() + { + return new PageFormat(); + } + + /** + * 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 abstract PageFormat defaultPage(PageFormat page_format); + + /** + * 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 abstract PageFormat pageDialog(PageFormat page_format) + throws HeadlessException; + + /** + * @since 1.4 + */ + public PageFormat pageDialog(PrintRequestAttributeSet attributes) + throws HeadlessException + { + // FIXME: Implement this for real. + return pageDialog((PageFormat) null); + } + + /** + * Prints the pages. + */ + public abstract void print () throws PrinterException; + + /** + * Prints the page with given attributes. + */ + public abstract void print (PrintRequestAttributeSet attributes) + throws PrinterException; + + /** + * 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 abstract boolean printDialog() + throws HeadlessException; + + /** + * 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 + { + // FIXME: Implement this for real. + return printDialog(); + } + + /** + * This sets the pages that are to be printed. + * + * @param pageable The pages to be printed, which may not be null. + */ + public abstract void setPageable(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 abstract void setPrintable(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 abstract void setPrintable(Printable printable, 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 abstract PageFormat validatePage(PageFormat page_format); + + /** + * Find and return 2D image print services. + * + * This is the same as calling PrintServiceLookup.lookupPrintServices() + * with Pageable service-specified DocFlavor. + * @return Array of PrintService objects, could be empty. + * @since 1.4 + */ + public static PrintService[] lookupPrintServices() + { + return new PrintService[0]; + // FIXME: + // Enable this when javax.print has this implemented. +// return PrintServiceLookup.lookupPrintServices( +// new DocFlavor("application/x-java-jvm-local-objectref", +// "java.awt.print.Pageable"), +// null); + } + + /** + * Find and return 2D image stream print services. + * + * This is the same as calling + * StreamPrintServiceFactory.lookupStreamPrintServices() + * with Pageable service-specified DocFlavor. + * @param mimeType The output format mime type, or null for any type. + * @return Array of stream print services, could be empty. + * @since 1.4 + */ + // FIXME: + // Enable when javax.print has StreamPrintServiceFactory +// public static StreamPrintServiceFactory[] lookupStreamPrintServices(String mimeType) +// { +// return StreamPrintServiceFactory.lookupStreamServiceFactories( +// new DocFlavor("application/x-java-jvm-local-objectref", +// "java.awt.print.Pageable"), +// mimeType); +// } + + /** + * Return the printer for this job. If print services aren't supported by + * the subclass, returns null. + * + * @return The associated PrintService. + * @since 1.4 + */ + public PrintService getPrintService() + { + return null; + } + + /** + * 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 + { + throw new PrinterException(); + } +} diff --git a/libjava/classpath/java/awt/print/package.html b/libjava/classpath/java/awt/print/package.html new file mode 100644 index 0000000..50abcbf --- /dev/null +++ b/libjava/classpath/java/awt/print/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.awt.print + + +

    Classes for printer jobs, pages, paper sizes, graphics and formats.

    + + + diff --git a/libjava/classpath/java/beans/AppletInitializer.java b/libjava/classpath/java/beans/AppletInitializer.java new file mode 100644 index 0000000..69dc2ca --- /dev/null +++ b/libjava/classpath/java/beans/AppletInitializer.java @@ -0,0 +1,61 @@ +/* java.beans.AppletInitializer + Copyright (C) 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.beans; + +import java.applet.Applet; +import java.beans.beancontext.BeanContext; + + +/** This interface is a mechanism for the initialization of a Java + * Bean that is also an Applet. It is used by + * Beans.instantiate(). + * + * @author Tom Tromey (tromey@redhat.com) + * @since 1.2 + */ +public interface AppletInitializer +{ + /** Activate the applet. */ + void activate (Applet applet); + + /** This method will be called by Beans.instantiate() + * to associated the new Applet with its AppletContext, AppletStub, + * and Container. + */ + void initialize (Applet applet, BeanContext context); +} diff --git a/libjava/classpath/java/beans/BeanDescriptor.java b/libjava/classpath/java/beans/BeanDescriptor.java new file mode 100644 index 0000000..21227b2 --- /dev/null +++ b/libjava/classpath/java/beans/BeanDescriptor.java @@ -0,0 +1,89 @@ +/* java.beans.BeanDescriptor + 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 java.beans; + +/** + ** BeanDescriptor describes general information about a Bean, plus + ** stores the Bean's Class and it's customizer's Class.

    + ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 31 May 1998 + **/ + +public class BeanDescriptor extends FeatureDescriptor { + Class beanClass; + Class customizerClass; + + /** Create a new BeanDescriptor with the given beanClass and + ** no customizer class. + ** @param beanClass the class of the Bean. + **/ + public BeanDescriptor(Class beanClass) { + this(beanClass,null); + } + + /** Create a new BeanDescriptor with the given bean class and + ** customizer class. + ** @param beanClass the class of the Bean. + ** @param customizerClass the class of the Bean's Customizer. + **/ + public BeanDescriptor(Class beanClass, Class customizerClass) { + this.beanClass = beanClass; + this.customizerClass = customizerClass; + + // Set the FeatureDescriptor programmatic name. + String name = beanClass.getName(); + int lastInd = name.lastIndexOf('.'); + if (lastInd != -1) + name = name.substring(lastInd + 1); + + setName(name); + } + + /** Get the Bean's class. **/ + public Class getBeanClass() { + return beanClass; + } + + /** Get the Bean's customizer's class. **/ + public Class getCustomizerClass() { + return customizerClass; + } +} diff --git a/libjava/classpath/java/beans/BeanInfo.java b/libjava/classpath/java/beans/BeanInfo.java new file mode 100644 index 0000000..525500a --- /dev/null +++ b/libjava/classpath/java/beans/BeanInfo.java @@ -0,0 +1,181 @@ +/* java.beans.BeanInfo + 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 java.beans; + +/** + ** BeanInfo can be implemented in order to provide explicit information to the Introspector. + ** + ** When you write a BeanInfo class, you implement this interface + ** and provide explicit information by returning a non-null + ** value from the appropriate method. If you wish the + ** Introspector to determine certain information in the normal + ** way, just return null (or in the case of int methods, return + ** -1). There is a class called SimpleBeanInfo which returns + ** null from all methods, which you may extend and only + ** override the methods you wish to override.

    + ** + ** When you have written the class, give it the name + ** <Bean Class Name>BeanInfo and place it in + ** the same package as the Bean, or in the bean info search path + ** (see Introspector for information on search paths).

    + ** + ** A simple note about the way the Introspector interacts with + ** BeanInfo. Introspectors look at a Bean class and determine + ** if there is a BeanInfo class with it. If there is not a + ** BeanInfo class, it will behave as if the BeanInfo class + ** provided was a SimpleBeanInfo class (i.e. it will determine + ** all information automatically).

    If there is a BeanInfo + ** class, then any methods that do *not* return null are + ** regarded as providing definitive information about the class + ** and all of its superclasses for those information types. + ** Even if a parent BeanInfo class explicitly returns that + ** information, it will not be used. + ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 28 Jul 1998 + **/ + +public interface BeanInfo { + /** Use this as a parameter for the getIcon() command to retrieve a certain type of icon. **/ + int ICON_COLOR_16x16 = 1; + /** Use this as a parameter for the getIcon() command to retrieve a certain type of icon. **/ + int ICON_COLOR_32x32 = 2; + /** Use this as a parameter for the getIcon() command to retrieve a certain type of icon. **/ + int ICON_MONO_16x16 = 3; + /** Use this as a parameter for the getIcon() command to retrieve a certain type of icon. **/ + int ICON_MONO_32x32 = 4; + + /** Get the general description of this Bean type. + ** @return the BeanDescriptor for the Bean, or null if + ** the BeanDescriptor should be obtained by + ** Introspection. + **/ + BeanDescriptor getBeanDescriptor(); + + /** Get the events this Bean type fires. + ** @return the EventDescriptors representing events this + ** Bean fires. Returns null if the + ** events are to be acquired by Introspection. + **/ + EventSetDescriptor[] getEventSetDescriptors(); + + /** Get the "default" event, basically the one a RAD tool + ** user is most likely to select. + ** @return the index into the getEventSetDescriptors() + ** that the user is most likely to use. Returns + ** -1 if there is no default event. + **/ + int getDefaultEventIndex(); + + /** Get the properties (get/set method pairs) this Bean + ** type supports. + ** @return the PropertyDescriptors representing the + ** properties this Bean type supports. + ** Returns null if the properties + ** are to be obtained by Introspection. + **/ + PropertyDescriptor[] getPropertyDescriptors(); + + /** Get the "default" property, basically the one a RAD + ** tool user is most likely to select. + ** @return the index into the getPropertyDescriptors() + ** that the user is most likely to use. Returns + ** -1 if there is no default event. + **/ + int getDefaultPropertyIndex(); + + /** Get the methods this Bean type supports. + ** @return the MethodDescriptors representing the + ** methods this Bean type supports. Returns + ** null if the methods are to be + ** obtained by Introspection. + **/ + MethodDescriptor[] getMethodDescriptors(); + + /** Get additional BeanInfos representing this Bean. + ** In this version of JavaBeans, this method is used so + ** that space and time can be saved by reading a BeanInfo + ** for each class in the hierarchy (super, super(super), + ** and so on).

    + ** + ** The order of precedence when two pieces of BeanInfo + ** conflict (such as two PropertyDescriptors that have + ** the same name), in order from highest precedence to + ** lowest, is: + **

      + **
    1. This BeanInfo object.
    2. + **
    3. getAdditionalBeanInfo()[getAdditionalBeanInfo().length]
    4. + **
    5. ...
    6. + **
    7. getAdditionalBeanInfo()[1]
    8. + **
    9. getAdditionalBeanInfo()[0]
    10. + **

    + ** + ** Spec Note: It is possible that + ** returning null from this method could + ** stop Introspection in its tracks, but it is unclear + ** from the spec whether this is the case. + ** + ** @return additional BeanInfos representing this Bean. + ** null may be returned (see Spec + ** Note, above). + **/ + BeanInfo[] getAdditionalBeanInfo(); + + /** Get a visual icon for this Bean. + ** A Bean does not have to support icons, and if it does + ** support icons, it does not have to support every single + ** type. Sun recommends that if you only support one + ** type, you support 16x16 color. Sun also notes that you + ** should try to use a type (like GIF) that allows for + ** transparent pixels, so that the background of the RAD + ** tool can show through.

    + ** + ** Spec Note: If you do not support the + ** type of icon that is being asked for, but you do + ** support another type, it is unclear whether you should + ** return the other type or not. I would presume not. + ** + ** @param iconType the type of icon to get (see the + ** ICON_* constants in this class). + ** @return the icon, or null if that type of icon is + ** unsupported by this Bean. + **/ + java.awt.Image getIcon(int iconType); +} diff --git a/libjava/classpath/java/beans/Beans.java b/libjava/classpath/java/beans/Beans.java new file mode 100644 index 0000000..ffcb83f --- /dev/null +++ b/libjava/classpath/java/beans/Beans.java @@ -0,0 +1,368 @@ +/* java.beans.Beans + Copyright (C) 1998, 1999, 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 java.beans; + +import gnu.java.beans.DummyAppletStub; +import gnu.java.io.ClassLoaderObjectInputStream; + +import java.applet.Applet; +import java.beans.beancontext.BeanContext; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.net.URL; + +/** + * Beans provides some helper methods that allow the basic + * operations of Bean-ness. + * + * @author John Keiser + * @author Robert Schuster + * + * @since 1.1 + * @status updated to 1.4 + * + */ +public class Beans +{ + static boolean designTime = false; + static boolean guiAvailable = true; + + /** + * Once again, we have a java.beans class with only + * static methods that can be instantiated. When + * will the madness end? :) + */ + public Beans() + { + // Does intentionally nothing here. + } + + /** Creates a bean. + *

    This is a convenience method that calls instantiate(cl, beanName, null, null).

    + * + * @see instantiate(ClassLoader, String, BeanContext, AppletInitializer) + * @param cl ClassLoader to be used or null for the system classloader. + * @param beanName Name of a serialized bean or class name. + * @return A newly created bean. + * @throws IOException If access of an IO resource failed. + * @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class. + */ + public static Object instantiate(ClassLoader cl, String beanName) + throws IOException, ClassNotFoundException + { + return instantiate(cl, beanName, null, null); + } + + /** Creates a bean. + * + *

    This is a convenience method that calls instantiate(cl, beanName, beanContext, null).

    + * + * @see instantiate(ClassLoader, String, BeanContext, AppletInitializer) + * @param cl ClassLoader to be used or null for the system classloader. + * @param beanName Name of a serialized bean or class name. + * @param beanContext Context to which the newly created Bean should be added. + * @return A newly created bean. + * @throws IOException If access of an IO resource failed. + * @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class. + */ + public static Object instantiate( + ClassLoader cl, + String beanName, + BeanContext beanContext) + throws IOException, ClassNotFoundException + { + return instantiate(cl, beanName, beanContext, null); + } + + /** Instantiates a bean according to Beans 1.0. + * + *

    In Beans 1.0 the instantiation scheme is as follows:

    + *

    The name should be dot-separated (e.g "place.for.beans.myBean") and indicate either a + * serialized object or a class name. In the first case all dots in the name are replaced with + * slashes ('/') and ".ser" is appended ("place.for.beans.myBean" becomes "place/for/beans/myBean.ser"). + * The bean is then loaded as an application or system resource depending on whether a + * ClassLoader was provided.

    + * + *

    If no such resource exists or if it contains no bean the name is interpreted as a class name of + * which an instance is then created.

    + * + *

    If a BeanContext instance is available the created bean is added to it.

    + * + *

    If the created Bean is an Applet or subclass and an AppletInitializer + * instance is available the applet is initialized and afterwards activated using the initializer. Additionally + * every instantiated Applet bean is initialized using the {@link Applet.init} method. + * Furthermore every applet gets a default AppletStub. The Applet's + * document base is the location of the ".ser" file if it was deserialized or the location of its class + * file if it was instantiated.

    + * + *

    A ClassNotFoundException is not only thrown when a class name was unknown + * but even when the class has public no-argument constructor + * (IllegalAccessException is wrapped) or an exception is thrown while + * invoking such a constructor (causing exception is wrapped).

    + * + * @param cl ClassLoader to be used or null for the system classloader. + * @param beanName Name of a serialized bean or class name. + * @param beanContext Context to which the newly created Bean should be added. + * @param initializer The AppletInitializer which is used for initializing Applet beans. + * @return A newly created bean. + * @throws IOException If access of an IO resource failed. + * @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class. + */ + public static Object instantiate( + ClassLoader cl, + String beanName, + BeanContext beanContext, + AppletInitializer initializer) + throws IOException, ClassNotFoundException + { + Object bean = null; + URL beanLocation = null; + URL classLocation = null; + + // Converts bean name into a resource name (eg. "a.b.c" -> "a/b/c"). + String resourceName = beanName.replace('.', '/'); + + /* Tries to get an input stream of the Bean, reading it as a system resource + * if no ClassLoader is present or as an application resource if a classloader + * is given. + */ + beanLocation = + (cl == null) + ? ClassLoader.getSystemResource(resourceName + ".ser") + : cl.getResource(resourceName + ".ser"); + + // Reads the serialized Bean from the returned URL. + if (beanLocation != null) + { + // Deserializes the bean instance. + ObjectInputStream ois = + (cl == null) + ? new ObjectInputStream(beanLocation.openStream()) + : new ClassLoaderObjectInputStream( + beanLocation.openStream(), + cl); + + bean = ois.readObject(); + + /* Implementation note: The result of ObjectInputStream.readObject() + * may have been null at this point (its a valid value to deserialize) + * and we explicitly want to try instantiation in such a case + * (this is important for compatibility). + */ + } + + // Instantiates the Bean using reflective instantiation if it has not been created yet. + if (bean == null) + { + // Makes sure that the deserialization was NOT done. + beanLocation = null; + + Class beanClass; + if (cl == null) + { + beanClass = Class.forName(beanName); + classLocation = + ClassLoader.getSystemResource(resourceName + ".class"); + } + else + { + beanClass = cl.loadClass(beanName); + classLocation = cl.getResource(resourceName + ".class"); + } + + // Instantiates and optionally registers the new bean. + try + { + bean = beanClass.newInstance(); + } + catch(Exception e) { + /* Wraps all kinds of Exceptions in a ClassNotFoundException (this behavior + * matches with official >= 1.5, this was different for <=1.4) + */ + throw new ClassNotFoundException(null, e); + } + } + + /* Applet beans are treated in the following way: + * - all AppletS get a default AppletStub + * - all AppletS are initialized using the AppletInitializer instance (if it is available) + * - as every other Bean Applets are added to a BeanContext if one is available + * - each instantiated Applet is initialized using Applet.init() (this is not done for deserialized ones) + * - finally AppletS get activated using the AppletInitializerS activate-Method + * + * The order of operations is important for compatibility. + */ + Applet applet = null; + if (bean instanceof Applet) + { + // Makes a second instanceof call unneccessary (instanceof is expensive). + applet = (Applet) bean; + + /* The AppletStub's code and document base is set as follows: + * The code base is always the URL from where the class data originated + * (without the package name). + * If the Applet was deserialized the document base is the location of + * the serialized instance (usually the ".ser" file) otherwise its the URL + * from where the class data originated (usually the absolute directory + * location of the ".class" file). + */ + applet.setStub( + new DummyAppletStub( + applet + .getClass() + .getProtectionDomain() + .getCodeSource() + .getLocation(), + (beanLocation == null) ? classLocation : beanLocation)); + + // Runs the Applet's initialization using an AppletInitializer. + if (initializer != null) + { + initializer.initialize(applet, beanContext); + } + } + + // Adds the new bean to its BeanContext. + if (beanContext != null) + { + beanContext.add(bean); + } + + if (applet != null) + { + + // Initializes an instantiated (not deserialized) Applet using its own method. + if (beanLocation == null) + { + applet.init(); + } + + // Runs the Applet's activation using an AppletInitializer. + if (initializer != null) + { + initializer.activate(applet); + } + } + + return bean; + } + + /** + * Returns the Bean as a different class type. + * This should be used instead of casting to get a new + * type view of a Bean, because in the future there may + * be new types of Bean, even Beans spanning multiple + * Objects. + * + * @param bean the Bean to cast. + * @param newClass the Class to cast it to. + * + * @return the Bean as a new view, or if the operation + * could not be performed, the Bean itself. + */ + public static Object getInstanceOf(Object bean, Class newClass) + { + return bean; + } + + /** + * Determines whether the Bean can be cast to a different + * class type. + * This should be used instead of instanceof to determine + * a Bean's castability, because in the future there may + * be new types of Bean, even Beans spanning multiple + * Objects. + * + * @param bean the Bean to cast. + * @param newClass the Class to cast it to. + * + * @return whether the Bean can be cast to the class type + * in question. + */ + public static boolean isInstanceOf(Object bean, Class newBeanClass) + { + return newBeanClass.isInstance(bean); + } + + /** + * Returns whether the GUI is available to use. + *

    Defaults to true.

    + * + * @return whether the GUI is available to use. + */ + public static boolean isGuiAvailable() + { + return guiAvailable; + } + + /** + * Returns whether it is design time. Design time means + * we are in a RAD tool. + *

    Defaults to false.

    + * + * @return whether it is design time. + */ + public static boolean isDesignTime() + { + return designTime; + } + + /** + * Sets whether the GUI is available to use. + * + * @param guiAvailable whether the GUI is available to use. + */ + public static void setGuiAvailable(boolean guiAvailable) + throws SecurityException + { + Beans.guiAvailable = guiAvailable; + } + + /** + * Sets whether it is design time. Design time means we + * are in a RAD tool. + * + * @param designTime whether it is design time. + */ + public static void setDesignTime(boolean designTime) + throws SecurityException + { + Beans.designTime = designTime; + } + +} diff --git a/libjava/classpath/java/beans/Customizer.java b/libjava/classpath/java/beans/Customizer.java new file mode 100644 index 0000000..b36c89f --- /dev/null +++ b/libjava/classpath/java/beans/Customizer.java @@ -0,0 +1,86 @@ +/* java.beans.Customizer + 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 java.beans; + +/** + ** You may explicitly provide a Customizer for your Bean + ** class, which allows you complete control of the editing + ** of the Bean.

    + ** + ** A Customizer is meant to be embedded in an RAD tool, + ** and thus must be a descendant of java.awt.Component.

    + ** + ** It must also have a constructor with no arguments. This + ** is the constructor that will be called by the RAD tool to + ** instantiate the Customizer.

    + ** + ** Over its lifetime, an instance of a Customizer will only + ** customize one single Bean. A new instance of the + ** Customizer will be instantiated to edit any other Beans.

    + ** + ** The Customizer is responsible for notifying its + ** PropertyChangeListeners of any changes that are made, + ** according to the rules of PropertyChangeListeners (i.e. + ** notify the clients after the property has + ** changed). + ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 29 Jul 1998 + ** @see java.beans.BeanDescriptor.getCustomizerClass() + **/ + +public interface Customizer { + /** Set the object to Customize. This will always be a + ** Bean that had a BeanDescriptor indicating this + ** Customizer. + ** @param bean the Bean to customize. + **/ + void setObject(Object bean); + + /** Add a PropertyChangeListener. + ** @param l the PropertyChangeListener to add. + **/ + void addPropertyChangeListener(PropertyChangeListener l); + + /** Remove a PropertyChangeListener. + ** @param l the PropertyChangeListener to remove. + **/ + void removePropertyChangeListener(PropertyChangeListener l); +} diff --git a/libjava/classpath/java/beans/DesignMode.java b/libjava/classpath/java/beans/DesignMode.java new file mode 100644 index 0000000..39805d5 --- /dev/null +++ b/libjava/classpath/java/beans/DesignMode.java @@ -0,0 +1,93 @@ +/* java.beans.DesignMode + Copyright (C) 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 java.beans; + +/** + * BeanContextChild implementors implement this to get information about whether they are in a design time or runtime environment. + * The reason this is restricted to BeanContextChildren is that + * only things in the BeanContext hierarchy are given this + * information in the first place. + * + * @author John Keiser + * @since JDK1.2 + * @see java.beans.beancontext.BeanContextChild + */ + +public interface DesignMode { + /** + * Use this name when firing PropertyChangeEvents from your Bean. + * @fixme Check whether PROPERTYNAME is set to same value as Sun. + */ + String PROPERTYNAME = "designTime"; + + /** + * The environment will call this method on your + * BeanContextChild when it is registered in a parent + * BeanContext or when behavior needs to switch from + * design time to runtime behavior (or vice versa). + *

    + * + * BeanContexts are required to fire + * PropertyChangeEvents when properties change. + * designTime is a property, and therefore when you + * implement setDesignTime(), you need to fire a + * PropertyChangeEvent with the old value, the new + * value and using PROPERTYNAME as the property name. + * + * @param designTime the new value of design time, + * true if it is design time, + * false if it is runtime. + * + * @fixme I'm frankly not really sure whether it's the case that + * the BeanContext can change the status of the Bean from + * design time to runtime. But it appears that it may be so. + * + * @see java.util.PropertyChangeEvent + * @see java.beans.beancontext.BeanContext + * @see #PROPERTYNAME + */ + void setDesignTime(boolean designTime); + + /** + * This method should tell whether it is design time or runtime. + * @return true if design time, false if + * runtime. + */ + boolean isDesignTime(); +} diff --git a/libjava/classpath/java/beans/EventHandler.java b/libjava/classpath/java/beans/EventHandler.java new file mode 100644 index 0000000..9c85893 --- /dev/null +++ b/libjava/classpath/java/beans/EventHandler.java @@ -0,0 +1,606 @@ +/* java.beans.EventHandler + 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 java.beans; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + *

    EventHandler forms a bridge between dynamically created listeners and + * arbitrary properties and methods.

    + * + *

    You can use this class to easily create listener implementations for + * some basic interactions between an event source and its target. Using + * the three static methods named create you can create + * these listener implementations.

    + * + *

    See the documentation of each method for usage examples.

    + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Robert Schuster (thebohemian@gmx.net) + * @since 1.4 + */ +public class EventHandler implements InvocationHandler +{ + // The name of the method that will be implemented. If null, any method. + private String listenerMethod; + + // The object to call action on. + private Object target; + + // The name of the method or property setter in target. + private String action; + + // The property to extract from an event passed to listenerMethod. + private String property; + + // The target objects Class. + private Class targetClass; + + // String class doesn't already have a capitalize routine. + private String capitalize(String s) + { + return s.substring(0, 1).toUpperCase() + s.substring(1); + } + + /** + * Creates a new EventHandler instance. + * + *

    Typical creation is done with the create method, not by knewing an + * EventHandler.

    + * + *

    This constructs an EventHandler that will connect the method + * listenerMethodName to target.action, extracting eventPropertyName from + * the first argument of listenerMethodName. and sending it to action.

    + * + *

    Throws a NullPointerException if the target + * argument is null. + * + * @param target Object that will perform the action. + * @param action A property or method of the target. + * @param eventPropertyName A readable property of the inbound event. + * @param listenerMethodName The listener method name triggering the action. + */ + public EventHandler(Object target, String action, String eventPropertyName, + String listenerMethodName) + { + this.target = target; + + // Retrieving the class is done for two reasons: + // 1) The class object is needed very frequently in the invoke() method. + // 2) The constructor should throw a NullPointerException if target is null. + targetClass = target.getClass(); + + this.action = action; // Turn this into a method or do we wait till + // runtime + property = eventPropertyName; + listenerMethod = listenerMethodName; + } + + /** + * Returns the event property name. + */ + public String getEventPropertyName() + { + return property; + } + + /** + * Returns the listener's method name. + */ + public String getListenerMethodName() + { + return listenerMethod; + } + + /** + * Returns the target object. + */ + public Object getTarget() + { + return target; + } + + /** + * Returns the action method name. + */ + public String getAction() + { + return action; + } + + // Fetch a qualified property like a.b.c from object o. The properties can + // be boolean isProp or object getProp properties. + // + // Returns a length 2 array with the first entry containing the value + // extracted from the property, and the second entry contains the class of + // the method return type. + // + // We play this game because if the method returns a native type, the return + // value will be a wrapper. If we then take the type of the wrapper and use + // it to locate the action method that takes the native type, it won't match. + private Object[] getProperty(Object o, String prop) + { + // Isolate the first property name from a.b.c. + int pos; + String rest = null; + if ((pos = prop.indexOf('.')) != -1) + { + rest = prop.substring(pos + 1); + prop = prop.substring(0, pos); + } + + // Find a method named getProp. It could be isProp instead. + Method getter; + try + { + // Look for boolean property getter isProperty + getter = o.getClass().getMethod("is" + capitalize(prop), + null); + } + catch (NoSuchMethodException nsme1) + { + try { + // Look for regular property getter getProperty + getter = o.getClass().getMethod("get" + capitalize(prop), + null); + } catch(NoSuchMethodException nsme2) { + try { + // Finally look for a method of the name prop + getter = o.getClass().getMethod(prop, null); + } catch(NoSuchMethodException nsme3) { + // Ok, give up with an intelligent hint for the user. + throw new RuntimeException("Method not called: Could not find a property or method '" + prop + + "' in " + o.getClass() + " while following the property argument '" + property + "'."); + } + } + } + try { + Object val = getter.invoke(o, null); + + if (rest != null) + return getProperty(val, rest); + + return new Object[] {val, getter.getReturnType()}; + } catch(InvocationTargetException ite) { + throw new RuntimeException("Method not called: Property or method '" + prop + "' has thrown an exception.", ite); + } catch(IllegalAccessException iae) { + // This cannot happen because we looked up method with Class.getMethod() + // which returns public methods only. + throw (InternalError) new InternalError("Non-public method was invoked.").initCause(iae); + } + } + + /** + * Invokes the EventHandler. + * + *

    This method is normally called by the listener's proxy implementation.

    + * + * @param proxy The listener interface that is implemented using + * the proxy mechanism. + * @param method The method that was called on the proxy instance. + * @param arguments The arguments which where given to the method. + * @throws Throwable NoSuchMethodException is thrown when the EventHandler's + * action method or property cannot be found. + */ + public Object invoke(Object proxy, Method method, Object[] arguments) + { + try { + // The method instance of the target object. We have to find out which + // one we have to invoke. + Method actionMethod = null; + + // Listener methods that weren't specified are ignored. If listenerMethod + // is null, then all listener methods are processed. + if (listenerMethod != null && !method.getName().equals(listenerMethod)) + return null; + + // If a property is defined we definitely need a valid object at + // arguments[0] that can be used to retrieve a value to which the + // property of the target gets set. + if(property != null) { + // Extracts the argument. We will let it fail with a NullPointerException + // the caller used a listener method that has no arguments. + Object event = arguments[0]; + + // Obtains the property XXX propertyType keeps showing up null - why? + // because the object inside getProperty changes, but the ref variable + // can't change this way, dolt! need a better way to get both values out + // - need method and object to do the invoke and get return type + Object v[] = getProperty(event, property); + Object[] args = new Object[] { v[0] }; + + // Changes the class array that controls which method signature we are going + // to look up in the target object. + Class[] argTypes = new Class[] { initClass((Class) v[1]) }; + + // Tries to find a setter method to which we can apply the + while(argTypes[0] != null) { + try + { + // Look for a property setter for action. + actionMethod = targetClass.getMethod("set" + capitalize(action), argTypes); + + return actionMethod.invoke(target, args); + } + catch (NoSuchMethodException e) + { + // If action as property didn't work, try as method later. + } + + argTypes[0] = nextClass(argTypes[0]); + } + + // We could not find a suitable setter method. Now we try again interpreting + // action as the method name itself. + // Since we probably have changed the block local argTypes array + // we need to rebuild it. + argTypes = new Class[] { initClass((Class) v[1]) }; + + // Tries to find a setter method to which we can apply the + while(argTypes[0] != null) { + try + { + actionMethod = targetClass.getMethod(action, argTypes); + + return actionMethod.invoke(target, args); + } + catch (NoSuchMethodException e) + { + } + + argTypes[0] = nextClass(argTypes[0]); + } + + throw new RuntimeException("Method not called: Could not find a public method named '" + + action + "' in target " + targetClass + " which takes a '" + + v[1] + "' argument or a property of this type."); + } + + // If property was null we will search for a no-argument method here. + // Note: The ordering of method lookups is important because we want to prefer no-argument + // calls like the JDK does. This means if we have actionMethod() and actionMethod(Event) we will + // call the first *EVEN* if we have a valid argument for the second method. This is behavior compliant + // to the JDK. + // If actionMethod() is not available but there is a actionMethod(Event) we take this. That makes us + // more specification compliant than the JDK itself because this one will fail in such a case. + try + { + actionMethod = targetClass.getMethod(action, null); + } + catch(NoSuchMethodException nsme) + { + // Note: If we want to be really strict the specification says that a no-argument method should + // accept an EventObject (or subclass I guess). However since the official implementation is broken + // anyways, it's more flexible without the EventObject restriction and we are compatible on everything + // else this can stay this way. + if(arguments != null && arguments.length >= 1/* && arguments[0] instanceof EventObject*/) { + Class[] targetArgTypes = new Class[] { initClass(arguments[0].getClass()) }; + + while(targetArgTypes[0] != null) { + try + { + // If no property exists we expect the first element of the arguments to be + // an EventObject which is then applied to the target method. + + actionMethod = targetClass.getMethod(action, targetArgTypes); + + return actionMethod.invoke(target, new Object[] { arguments[0] }); + } + catch(NoSuchMethodException nsme2) + { + + } + + targetArgTypes[0] = nextClass(targetArgTypes[0]); + } + + } + } + + // If we do not have a Method instance at this point this means that all our tries + // failed. The JDK throws an ArrayIndexOutOfBoundsException in this case. + if(actionMethod == null) + throw new ArrayIndexOutOfBoundsException(0); + + // Invoke target.action(property) + return actionMethod.invoke(target, null); + } catch(InvocationTargetException ite) { + throw new RuntimeException(ite.getCause()); + } catch(IllegalAccessException iae) { + // Cannot happen because we always use getMethod() which returns public + // methods only. Otherwise there is something seriously broken in + // GNU Classpath. + throw (InternalError) new InternalError("Non-public method was invoked.").initCause(iae); + } + } + + /** + *

    Returns the primitive type for every wrapper class or the + * class itself if it is no wrapper class.

    + * + *

    This is needed because to be able to find both kinds of methods: + * One that takes a wrapper class as the first argument and one that + * accepts a primitive instead.

    + */ + private Class initClass(Class klass) { + if(klass == Boolean.class) { + return Boolean.TYPE; + } else if(klass == Byte.class) { + return Byte.TYPE; + } else if(klass == Short.class) { + return Short.TYPE; + } else if(klass == Integer.class) { + return Integer.TYPE; + } else if(klass == Long.class) { + return Long.TYPE; + } else if(klass == Float.class) { + return Float.TYPE; + } else if(klass == Double.class) { + return Double.TYPE; + } else { + return klass; + } + } + + /** + * + * + * @param klass + * @return + */ + private Class nextClass(Class klass) { + if(klass == Boolean.TYPE) { + return Boolean.class; + } else if(klass == Byte.TYPE) { + return Byte.class; + } else if(klass == Short.TYPE) { + return Short.class; + } else if(klass == Integer.TYPE) { + return Integer.class; + } else if(klass == Long.TYPE) { + return Long.class; + } else if(klass == Float.TYPE) { + return Float.class; + } else if(klass == Double.TYPE) { + return Double.class; + } else { + return klass.getSuperclass(); + } + } + + /** + *

    Constructs an implementation of listenerInterface + * to dispatch events.

    + * + *

    You can use such an implementation to simply call a public + * no-argument method of an arbitrary target object or to forward + * the first argument of the listener method to the target method.

    + * + *

    Call this method like:

    + * + * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, target, "dispose")); + * + * + *

    to achieve the following behavior:

    + * + * button.addActionListener(new ActionListener() { + * public void actionPerformed(ActionEvent ae) { + * target.dispose(); + * } + * }); + * + * + *

    That means if you need a listener implementation that simply calls a + * a no-argument method on a given instance for each + * method of the listener interface.

    + * + *

    Note: The action is interpreted as a method name. If your target object + * has no no-argument method of the given name the EventHandler tries to find + * a method with the same name but which can accept the first argument of the + * listener method. Usually this will be an event object but any other object + * will be forwarded, too. Keep in mind that using a property name instead of a + * real method here is wrong and will throw an ArrayIndexOutOfBoundsException + * whenever one of the listener methods is called.

    + * + *

    The EventHandler will automatically convert primitives + * to their wrapper class and vice versa. Furthermore it will call + * a target method if it accepts a superclass of the type of the + * first argument of the listener method.

    + * + *

    In case that the method of the target object throws an exception + * it will be wrapped in a RuntimeException and thrown out + * of the listener method.

    + * + *

    In case that the method of the target object cannot be found an + * ArrayIndexOutOfBoundsException will be thrown when the + * listener method is invoked.

    + * + *

    A call to this method is equivalent to: + * create(listenerInterface, target, action, null, null)

    + * + * @param listenerInterface Listener interface to implement. + * @param target Object to invoke action on. + * @param action Target property or method to invoke. + * @return A constructed proxy object. + */ + public static Object create(Class listenerInterface, Object target, String action) + { + return create(listenerInterface, target, action, null, null); + } + + /** + *

    Constructs an implementation of listenerInterface + * to dispatch events.

    + * + *

    Use this method if you want to create an implementation that retrieves + * a property value from the first argument of the listener method + * and applies it to the target's property or method. This first argument + * of the listener is usually an event object but any other object is + * valid, too.

    + * + *

    You can set the value of eventPropertyName to "prop" + * to denote the retrieval of a property named "prop" from the event + * object. In case that no such property exists the EventHandler + * will try to find a method with that name.

    + * + *

    If you set eventPropertyName to a value like this "a.b.c" + * EventHandler will recursively evaluate the properties "a", "b" + * and "c". Again if no property can be found the EventHandler + * tries a method name instead. This allows mixing the names, too: "a.toString" + * will retrieve the property "a" from the event object and will then call + * the method "toString" on it.

    + * + *

    An exception thrown in any of these methods will provoke a + * RuntimeException to be thrown which contains an + * InvocationTargetException containing the triggering exception.

    + * + *

    If you set eventPropertyName to a non-null value the + * action parameter will be interpreted as a property name + * or a method name of the target object.

    + * + *

    Any object retrieved from the event object and applied to the + * target will converted from primitives to their wrapper class or + * vice versa or applied to a method that accepts a superclass + * of the object.

    + * + *

    Examples:

    + *

    The following code:

    + * button.addActionListener( + * new ActionListener() { + * public void actionPerformed(ActionEvent ae) { + * Object o = ae.getSource().getClass().getName(); + * textField.setText((String) o); + * } + * }); + * + * + *

    Can be expressed using the EventHandler like this:

    + *

    + * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, textField, "text", "source.class.name"); + * + *

    + * + *

    As said above you can specify the target as a method, too:

    + *

    + * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, textField, "setText", "source.class.name"); + * + *

    + * + *

    Furthermore you can use method names in the property:

    + *

    + * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, textField, "setText", "getSource.getClass.getName"); + * + *

    + * + *

    Finally you can mix names:

    + *

    + * button.addActionListener((ActionListener) + * EventHandler.create(ActionListener.class, textField, "setText", "source.getClass.name"); + * + *

    + * + *

    A call to this method is equivalent to: + * create(listenerInterface, target, action, null, null) + *

    + * + * @param listenerInterface Listener interface to implement. + * @param target Object to invoke action on. + * @param action Target property or method to invoke. + * @param eventPropertyName Name of property to extract from event. + * @return A constructed proxy object. + */ + public static Object create(Class listenerInterface, Object target, + String action, String eventPropertyName) + { + return create(listenerInterface, target, action, eventPropertyName, null); + } + + /** + *

    Constructs an implementation of listenerInterface + * to dispatch events.

    + * + *

    Besides the functionality described for {@link create(Class, Object, String)} + * and {@link create(Class, Object, String, String)} this method allows you + * to filter the listener method that should have an effect. Look at these + * method's documentation for more information about the EventHandler's + * usage.

    + * + *

    If you want to call dispose on a JFrame instance + * when the WindowListener.windowClosing() method was invoked use + * the following code:

    + *

    + * + * EventHandler.create(WindowListener.class, jframeInstance, "dispose", null, "windowClosing"); + * + *

    + * + *

    A NullPointerException is thrown if the listenerInterface + * or target argument are null. + * + * @param listenerInterface Listener interface to implement. + * @param target Object to invoke action on. + * @param action Target method name to invoke. + * @param eventPropertyName Name of property to extract from event. + * @param listenerMethodName Listener method to implement. + * @return A constructed proxy object. + */ + public static Object create(Class listenerInterface, Object target, + String action, String eventPropertyName, + String listenerMethodName) + { + // Create EventHandler instance + EventHandler eh = new EventHandler(target, action, eventPropertyName, + listenerMethodName); + + // Create proxy object passing in the event handler + Object proxy = Proxy.newProxyInstance(listenerInterface.getClassLoader(), + new Class[] {listenerInterface}, + eh); + + return proxy; + } + +} diff --git a/libjava/classpath/java/beans/EventSetDescriptor.java b/libjava/classpath/java/beans/EventSetDescriptor.java new file mode 100644 index 0000000..8624e64 --- /dev/null +++ b/libjava/classpath/java/beans/EventSetDescriptor.java @@ -0,0 +1,442 @@ +/* java.beans.EventSetDescriptor + 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 java.beans; + +import gnu.java.lang.ClassHelper; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Vector; + +/** + ** EventSetDescriptor describes the hookup between an event source + ** class and an event listener class. + ** + ** EventSets have several attributes: the listener class, the events + ** that can be fired to the listener (methods in the listener class), and + ** an add and remove listener method from the event firer's class.

    + ** + ** The methods have these constraints on them:

    + **

      + **
    • event firing methods: must have void return value. Any + ** parameters and exceptions are allowed. May be public, protected or + ** package-protected. (Don't ask me why that is, I'm just following the spec. + ** The only place it is even mentioned is in the Java Beans white paper, and + ** there it is only implied.)
    • + **
    • add listener method: must have void return value. Must + ** take exactly one argument, of the listener class's type. May fire either + ** zero exceptions, or one exception of type java.util.TooManyListenersException. + ** Must be public.
    • + **
    • remove listener method: must have void return value. + ** Must take exactly one argument, of the listener class's type. May not + ** fire any exceptions. Must be public.
    • + **
    + ** + ** A final constraint is that event listener classes must extend from EventListener.

    + ** + ** There are also various design patterns associated with some of the methods + ** of construction. Those are explained in more detail in the appropriate + ** constructors.

    + ** + ** Documentation Convention: for proper + ** Internalization of Beans inside an RAD tool, sometimes there + ** are two names for a property or method: a programmatic, or + ** locale-independent name, which can be used anywhere, and a + ** localized, display name, for ease of use. In the + ** documentation I will specify different String values as + ** either programmatic or localized to + ** make this distinction clear. + ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 31 May 1998 + **/ + +public class EventSetDescriptor extends FeatureDescriptor { + private Method addListenerMethod; + private Method removeListenerMethod; + private Class listenerType; + private MethodDescriptor[] listenerMethodDescriptors; + private Method[] listenerMethods; + + private boolean unicast; + private boolean inDefaultEventSet = true; + + /** Create a new EventSetDescriptor. + ** This version of the constructor enforces the rules imposed on the methods + ** described at the top of this class, as well as searching for:

    + **

      + **
    1. The event-firing method must be non-private with signature + ** void <listenerMethodName>(<eventSetName>Event) + ** (where <eventSetName> has its first character capitalized + ** by the constructor and the Event is a descendant of + ** java.util.EventObject) in class listenerType + ** (any exceptions may be thrown). + ** Implementation note: Note that there could conceivably be multiple + ** methods with this type of signature (example: java.util.MouseEvent vs. + ** my.very.own.MouseEvent). In this implementation, all methods fitting the + ** description will be put into the EventSetDescriptor, even + ** though the spec says only one should be chosen (they probably weren't thinking as + ** pathologically as I was). I don't like arbitrarily choosing things. + ** If your class has only one such signature, as most do, you'll have no problems.
    2. + **
    3. The add and remove methods must be public and named + ** void add<eventSetName>Listener(<listenerType>) and + ** void remove<eventSetName>Listener(<listenerType>) in + ** in class eventSourceClass, where + ** <eventSetName> will have its first letter capitalized. + ** Standard exception rules (see class description) apply.
    4. + **
    + ** @param eventSourceClass the class containing the add/remove listener methods. + ** @param eventSetName the programmatic name of the event set, generally starting + ** with a lowercase letter (i.e. fooManChu instead of FooManChu). This will be used + ** to generate the name of the event object as well as the names of the add and + ** remove methods. + ** @param listenerType the class containing the event firing method. + ** @param listenerMethodName the name of the event firing method. + ** @exception IntrospectionException if listenerType is not an EventListener, + ** or if methods are not found or are invalid. + **/ + public EventSetDescriptor(Class eventSourceClass, + String eventSetName, + Class listenerType, + String listenerMethodName) throws IntrospectionException { + setName(eventSetName); + if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { + throw new IntrospectionException("Listener type is not an EventListener."); + } + + String[] names = new String[1]; + names[0] = listenerMethodName; + + try { + eventSetName = Character.toUpperCase(eventSetName.charAt(0)) + eventSetName.substring(1); + } catch(StringIndexOutOfBoundsException e) { + eventSetName = ""; + } + + findMethods(eventSourceClass,listenerType,names,"add"+eventSetName+"Listener","remove"+eventSetName+"Listener",eventSetName+"Event"); + this.listenerType = listenerType; + checkAddListenerUnicast(); + if(this.removeListenerMethod.getExceptionTypes().length > 0) { + throw new IntrospectionException("Listener remove method throws exceptions."); + } + } + + /** Create a new EventSetDescriptor. + ** This form of the constructor allows you to specify the names of the methods and adds + ** no new constraints on top of the rules already described at the top of the class.

    + ** + ** @param eventSourceClass the class containing the add and remove listener methods. + ** @param eventSetName the programmatic name of the event set, generally starting + ** with a lowercase letter (i.e. fooManChu instead of FooManChu). + ** @param listenerType the class containing the event firing methods. + ** @param listenerMethodNames the names of the even firing methods. + ** @param addListenerMethodName the name of the add listener method. + ** @param removeListenerMethodName the name of the remove listener method. + ** @exception IntrospectionException if listenerType is not an EventListener + ** or if methods are not found or are invalid. + **/ + public EventSetDescriptor(Class eventSourceClass, + String eventSetName, + Class listenerType, + String[] listenerMethodNames, + String addListenerMethodName, + String removeListenerMethodName) throws IntrospectionException { + setName(eventSetName); + if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { + throw new IntrospectionException("Listener type is not an EventListener."); + } + + findMethods(eventSourceClass,listenerType,listenerMethodNames,addListenerMethodName,removeListenerMethodName,null); + this.listenerType = listenerType; + checkAddListenerUnicast(); + if(this.removeListenerMethod.getExceptionTypes().length > 0) { + throw new IntrospectionException("Listener remove method throws exceptions."); + } + } + + /** Create a new EventSetDescriptor. + ** This form of constructor allows you to explicitly say which methods do what, and + ** no reflection is done by the EventSetDescriptor. The methods are, however, + ** checked to ensure that they follow the rules set forth at the top of the class. + ** @param eventSetName the programmatic name of the event set, generally starting + ** with a lowercase letter (i.e. fooManChu instead of FooManChu). + ** @param listenerType the class containing the listenerMethods. + ** @param listenerMethods the event firing methods. + ** @param addListenerMethod the add listener method. + ** @param removeListenerMethod the remove listener method. + ** @exception IntrospectionException if the listenerType is not an EventListener, + ** or any of the methods are invalid. + **/ + public EventSetDescriptor(String eventSetName, + Class listenerType, + Method[] listenerMethods, + Method addListenerMethod, + Method removeListenerMethod) throws IntrospectionException { + setName(eventSetName); + if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { + throw new IntrospectionException("Listener type is not an EventListener."); + } + + this.listenerMethods = listenerMethods; + this.addListenerMethod = addListenerMethod; + this.removeListenerMethod = removeListenerMethod; + this.listenerType = listenerType; + checkMethods(); + checkAddListenerUnicast(); + if(this.removeListenerMethod.getExceptionTypes().length > 0) { + throw new IntrospectionException("Listener remove method throws exceptions."); + } + } + + /** Create a new EventSetDescriptor. + ** This form of constructor allows you to explicitly say which methods do what, and + ** no reflection is done by the EventSetDescriptor. The methods are, however, + ** checked to ensure that they follow the rules set forth at the top of the class. + ** @param eventSetName the programmatic name of the event set, generally starting + ** with a lowercase letter (i.e. fooManChu instead of FooManChu). + ** @param listenerType the class containing the listenerMethods. + ** @param listenerMethodDescriptors the event firing methods. + ** @param addListenerMethod the add listener method. + ** @param removeListenerMethod the remove listener method. + ** @exception IntrospectionException if the listenerType is not an EventListener, + ** or any of the methods are invalid. + **/ + public EventSetDescriptor(String eventSetName, + Class listenerType, + MethodDescriptor[] listenerMethodDescriptors, + Method addListenerMethod, + Method removeListenerMethod) throws IntrospectionException { + setName(eventSetName); + if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { + throw new IntrospectionException("Listener type is not an EventListener."); + } + + this.listenerMethodDescriptors = listenerMethodDescriptors; + this.listenerMethods = new Method[listenerMethodDescriptors.length]; + for(int i=0;i 0) { + throw new IntrospectionException("Listener remove method throws exceptions."); + } + } + + /** Get the class that contains the event firing methods. **/ + public Class getListenerType() { + return listenerType; + } + + /** Get the event firing methods. **/ + public Method[] getListenerMethods() { + return listenerMethods; + } + + /** Get the event firing methods as MethodDescriptors. **/ + public MethodDescriptor[] getListenerMethodDescriptors() { + if(listenerMethodDescriptors == null) { + listenerMethodDescriptors = new MethodDescriptor[listenerMethods.length]; + for(int i=0;i 1) { + throw new IntrospectionException("Listener add method throws too many exceptions."); + } else if(addListenerExceptions.length == 1 + && !java.util.TooManyListenersException.class.isAssignableFrom(addListenerExceptions[0])) { + throw new IntrospectionException("Listener add method throws too many exceptions."); + } + } + + private void checkMethods() throws IntrospectionException { + if(!addListenerMethod.getDeclaringClass().isAssignableFrom(removeListenerMethod.getDeclaringClass()) + && !removeListenerMethod.getDeclaringClass().isAssignableFrom(addListenerMethod.getDeclaringClass())) { + throw new IntrospectionException("add and remove listener methods do not come from the same class. This is bad."); + } + if(!addListenerMethod.getReturnType().equals(java.lang.Void.TYPE) + || addListenerMethod.getParameterTypes().length != 1 + || !listenerType.equals(addListenerMethod.getParameterTypes()[0]) + || !Modifier.isPublic(addListenerMethod.getModifiers())) { + throw new IntrospectionException("Add Listener Method invalid."); + } + if(!removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE) + || removeListenerMethod.getParameterTypes().length != 1 + || !listenerType.equals(removeListenerMethod.getParameterTypes()[0]) + || removeListenerMethod.getExceptionTypes().length > 0 + || !Modifier.isPublic(removeListenerMethod.getModifiers())) { + throw new IntrospectionException("Remove Listener Method invalid."); + } + + for(int i=0;i + * + * Documentation Convention: for proper + * Internalization of Beans inside an RAD tool, sometimes there + * are two names for a property or method: a programmatic, or + * locale-independent name, which can be used anywhere, and a + * localized, display name, for ease of use. In the + * documentation I will specify different String values as + * either programmatic or localized to + * make this distinction clear. + * + * @author John Keiser + * @since 1.1 + */ + +public class FeatureDescriptor +{ + String name; + String displayName; + String shortDescription; + boolean expert; + boolean hidden; + boolean preferred; + + Hashtable valueHash; + + /** + * Instantiate this FeatureDescriptor with appropriate default values. + */ + public FeatureDescriptor() + { + valueHash = new Hashtable(); + } + + /** + * Get the programmatic name of this feature. + */ + public String getName() + { + return name; + } + + /** + * Set the programmatic name of this feature. + * + * @param name the new name for this feature. + */ + public void setName(String name) + { + this.name = name; + } + + /** + * Get the localized (display) name of this feature. + * + * @returns The localized display name of this feature or falls + * back to the programmatic name. + */ + public String getDisplayName() + { + return (displayName == null) ? name : displayName; + } + + /** + * Set the localized (display) name of this feature. + * + * @param displayName the new display name for this feature. + */ + public void setDisplayName(String displayName) + { + this.displayName = displayName; + } + + /** + * Get the localized short description for this feature. + * + * @returns A short localized description of this feature or + * what getDisplayName returns in case, that no short description + * is available. + */ + public String getShortDescription() + { + return (shortDescription == null) ? getDisplayName() : shortDescription; + } + + /** + * Set the localized short description for this feature. + * + * @param shortDescription the new short description for this feature. + */ + public void setShortDescription(String shortDescription) + { + this.shortDescription = shortDescription; + } + + /** + * Indicates whether this feature is for expert use only. + * + * @return true if for use by experts only, + * or false if anyone can use it. + */ + public boolean isExpert() + { + return expert; + } + + /** + * Set whether this feature is for expert use only. + * + * @param expert true if for use by experts only, + * or false if anyone can use it. + */ + public void setExpert(boolean expert) + { + this.expert = expert; + } + + /** + * Indicates whether this feature is for use by tools only. + * If it is for use by tools only, then it should not be displayed. + * + * @return true if tools only should use it, + * or false if anyone can see it. + */ + public boolean isHidden() + { + return hidden; + } + + /** + * Set whether this feature is for use by tools only. + * If it is for use by tools only, then it should not be displayed. + * + * @param hidden true if tools only should use it, + * or false if anyone can see it. + */ + public void setHidden(boolean hidden) + { + this.hidden = hidden; + } + + public boolean isPreferred () + { + return preferred; + } + + public void setPreferred (boolean preferred) + { + this.preferred = preferred; + } + + /** + * Get an arbitrary value set with setValue(). + * + * @param name the programmatic name of the key. + * + * @return the value associated with this name, + * or null if there is none. + */ + public Object getValue(String name) + { + return valueHash.get(name); + } + + /** + * Set an arbitrary string-value pair with this feature. + * + * @param name the programmatic name of the key. + * @param value the value to associate with the name. + */ + public void setValue(String name, Object value) + { + valueHash.put(name, value); + } + + /** + * Get a list of the programmatic key names set with setValue(). + * + * @return an Enumerator over all the programmatic key names associated + * with this feature. + */ + public Enumeration attributeNames() + { + return valueHash.keys(); + } +} diff --git a/libjava/classpath/java/beans/IndexedPropertyDescriptor.java b/libjava/classpath/java/beans/IndexedPropertyDescriptor.java new file mode 100644 index 0000000..efdc7b4 --- /dev/null +++ b/libjava/classpath/java/beans/IndexedPropertyDescriptor.java @@ -0,0 +1,307 @@ +/* java.beans.IndexedPropertyDescriptor + 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 java.beans; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; + +/** + ** IndexedPropertyDescriptor describes information about a JavaBean + ** indexed property, by which we mean an array-like property that + ** has been exposed via a pair of get and set methods and another + ** pair that allows you to get to the property by an index.

    + ** + ** An example property would have four methods like this:

    + ** FooBar[] getFoo()
    + ** void setFoo(FooBar[])
    + ** FooBar getFoo(int)
    + ** void setFoo(int,FooBar)

    + ** + ** The constraints put on get and set methods are:

    + **

      + **
    1. There must be at least a get(int) or a set(int,...) method. + ** Nothing else is required. Spec note:One nice restriction + ** would be that if there is a get() there must be a get(int), same + ** with set, but that is not in the spec and is fairly harmless.)
    2. + **
    3. A get array method must have signature + ** <propertyType>[] <getMethodName>()
    4. + **
    5. A set array method must have signature + ** void <setMethodName>(<propertyType>[])
    6. + **
    7. A get index method must have signature + ** <propertyType> <getMethodName>(int)
    8. + **
    9. A set index method must have signature + ** void <setMethodName>(int,<propertyType>)
    10. + **
    11. All these methods may throw any exception.
    12. + **
    13. All these methods must be public.
    14. + **
    + ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 26 Jul 1998 + **/ + +public class IndexedPropertyDescriptor extends PropertyDescriptor { + private Class indexedPropertyType; + private Method setIndex; + private Method getIndex; + + /** Create a new IndexedPropertyDescriptor by introspection. + ** This form of constructor creates the PropertyDescriptor by + ** looking for getter methods named get<name>() + ** and setter methods named + ** set<name>() in class + ** <beanClass>, where <name> has its + ** first letter capitalized by the constructor.

    + ** + ** Implementation note: If there is a get(int) method, + ** then the return type of that method is used to find the + ** remaining methods. If there is no get method, then the + ** set(int) method is searched for exhaustively and that type + ** is used to find the others.

    + ** + ** Spec note: + ** If there is no get(int) method and multiple set(int) methods with + ** the same name and the correct parameters (different type of course), + ** then an IntrospectionException is thrown. While Sun's spec + ** does not state this, it can make Bean behavior different on + ** different systems (since method order is not guaranteed) and as + ** such, can be treated as a bug in the spec. I am not aware of + ** whether Sun's implementation catches this. + ** + ** @param name the programmatic name of the property, usually + ** starting with a lowercase letter (e.g. fooManChu + ** instead of FooManChu). + ** @param beanClass the class the get and set methods live in. + ** @exception IntrospectionException if the methods are not found or invalid. + **/ + public IndexedPropertyDescriptor(String name, Class beanClass) throws IntrospectionException { + super(name); + String capitalized; + try { + capitalized = Character.toUpperCase(name.charAt(0)) + name.substring(1); + } catch(StringIndexOutOfBoundsException e) { + capitalized = ""; + } + findMethods(beanClass, "get" + capitalized, "set" + capitalized, "get" + capitalized, "set" + capitalized); + } + + /** Create a new IndexedPropertyDescriptor by introspection. + ** This form of constructor allows you to specify the + ** names of the get and set methods to search for.

    + ** + ** Implementation note: If there is a get(int) method, + ** then the return type of that method is used to find the + ** remaining methods. If there is no get method, then the + ** set(int) method is searched for exhaustively and that type + ** is used to find the others.

    + ** + ** Spec note: + ** If there is no get(int) method and multiple set(int) methods with + ** the same name and the correct parameters (different type of course), + ** then an IntrospectionException is thrown. While Sun's spec + ** does not state this, it can make Bean behavior different on + ** different systems (since method order is not guaranteed) and as + ** such, can be treated as a bug in the spec. I am not aware of + ** whether Sun's implementation catches this. + ** + ** @param name the programmatic name of the property, usually + ** starting with a lowercase letter (e.g. fooManChu + ** instead of FooManChu). + ** @param beanClass the class the get and set methods live in. + ** @param getMethodName the name of the get array method. + ** @param setMethodName the name of the set array method. + ** @param getIndexName the name of the get index method. + ** @param setIndexName the name of the set index method. + ** @exception IntrospectionException if the methods are not found or invalid. + **/ + public IndexedPropertyDescriptor(String name, Class beanClass, String getMethodName, String setMethodName, String getIndexName, String setIndexName) throws IntrospectionException { + super(name); + findMethods(beanClass, getMethodName, setMethodName, getIndexName, setIndexName); + } + + /** Create a new PropertyDescriptor using explicit Methods. + ** Note that the methods will be checked for conformance to standard + ** Property method rules, as described above at the top of this class. + ** + ** @param name the programmatic name of the property, usually + ** starting with a lowercase letter (e.g. fooManChu + ** instead of FooManChu). + ** @param getMethod the get array method. + ** @param setMethod the set array method. + ** @param getIndex the get index method. + ** @param setIndex the set index method. + ** @exception IntrospectionException if the methods are not found or invalid. + **/ + public IndexedPropertyDescriptor(String name, Method getMethod, Method setMethod, Method getIndex, Method setIndex) throws IntrospectionException { + super(name); + if(getMethod != null && getMethod.getParameterTypes().length > 0) { + throw new IntrospectionException("get method has parameters"); + } + if(getMethod != null && setMethod.getParameterTypes().length != 1) { + throw new IntrospectionException("set method does not have exactly one parameter"); + } + if(getMethod != null && setMethod != null) { + if(!getMethod.getReturnType().equals(setMethod.getParameterTypes()[0])) { + throw new IntrospectionException("set and get methods do not share the same type"); + } + if(!getMethod.getDeclaringClass().isAssignableFrom(setMethod.getDeclaringClass()) + && !setMethod.getDeclaringClass().isAssignableFrom(getMethod.getDeclaringClass())) { + throw new IntrospectionException("set and get methods are not in the same class."); + } + } + + if(getIndex != null && (getIndex.getParameterTypes().length != 1 + || !(getIndex.getParameterTypes()[0]).equals(java.lang.Integer.TYPE))) { + throw new IntrospectionException("get index method has wrong parameters"); + } + if(setIndex != null && (setIndex.getParameterTypes().length != 2 + || !(setIndex.getParameterTypes()[0]).equals(java.lang.Integer.TYPE))) { + throw new IntrospectionException("set index method has wrong parameters"); + } + if(getIndex != null && setIndex != null) { + if(!getIndex.getReturnType().equals(setIndex.getParameterTypes()[1])) { + throw new IntrospectionException("set index methods do not share the same type"); + } + if(!getIndex.getDeclaringClass().isAssignableFrom(setIndex.getDeclaringClass()) + && !setIndex.getDeclaringClass().isAssignableFrom(getIndex.getDeclaringClass())) { + throw new IntrospectionException("get and set index methods are not in the same class."); + } + } + + if(getIndex != null && getMethod != null && !getIndex.getDeclaringClass().isAssignableFrom(getMethod.getDeclaringClass()) + && !getMethod.getDeclaringClass().isAssignableFrom(getIndex.getDeclaringClass())) { + throw new IntrospectionException("methods are not in the same class."); + } + + if(getIndex != null && getMethod != null && !Array.newInstance(getIndex.getReturnType(),0).getClass().equals(getMethod.getReturnType())) { + throw new IntrospectionException("array methods do not match index methods."); + } + + this.getMethod = getMethod; + this.setMethod = setMethod; + this.getIndex = getIndex; + this.setIndex = setIndex; + this.indexedPropertyType = getIndex != null ? getIndex.getReturnType() : setIndex.getParameterTypes()[1]; + this.propertyType = getMethod != null ? getMethod.getReturnType() : (setMethod != null ? setMethod.getParameterTypes()[0] : Array.newInstance(this.indexedPropertyType,0).getClass()); + } + + public Class getIndexedPropertyType() { + return indexedPropertyType; + } + + public Method getIndexedReadMethod() { + return getIndex; + } + + public Method getIndexedWriteMethod() { + return setIndex; + } + + private void findMethods(Class beanClass, String getMethodName, String setMethodName, String getIndexName, String setIndexName) throws IntrospectionException { + try { + if(getIndexName != null) { + try { + Class[] getArgs = new Class[1]; + getArgs[0] = java.lang.Integer.TYPE; + getIndex = beanClass.getMethod(getIndexName,getArgs); + indexedPropertyType = getIndex.getReturnType(); + } catch(NoSuchMethodException E) { + } + } + if(getIndex != null) { + if(setIndexName != null) { + try { + Class[] setArgs = new Class[2]; + setArgs[0] = java.lang.Integer.TYPE; + setArgs[1] = indexedPropertyType; + setIndex = beanClass.getMethod(setIndexName,setArgs); + if(!setIndex.getReturnType().equals(java.lang.Void.TYPE)) { + throw new IntrospectionException(setIndexName + " has non-void return type"); + } + } catch(NoSuchMethodException E) { + } + } + } else if(setIndexName != null) { + Method[] m = beanClass.getMethods(); + for(int i=0;i + * + * Don't worry about it too much, though: you can provide + * JavaBeans with as much customized information as you + * want, or as little as you want, using the BeanInfo + * interface (see BeanInfo for details).

    + * + * Order of Operations

    + * + * When you call getBeanInfo(class c), the Introspector + * first searches for BeanInfo class to see if you + * provided any explicit information. It searches for a + * class named <bean class name>BeanInfo in different + * packages, first searching the bean class's package + * and then moving on to search the beanInfoSearchPath.

    + * + * If it does not find a BeanInfo class, it acts as though + * it had found a BeanInfo class returning null from all + * methods (meaning it should discover everything through + * Introspection). If it does, then it takes the + * information it finds in the BeanInfo class to be + * canonical (that is, the information speaks for its + * class as well as all superclasses).

    + * + * When it has introspected the class, calls + * getBeanInfo(c.getSuperclass) and adds that information + * to the information it has, not adding to any information + * it already has that is canonical.

    + * + * Introspection Design Patterns

    + * + * When the Introspector goes in to read the class, it + * follows a well-defined order in order to not leave any + * methods unaccounted for. Its job is to step over all + * of the public methods in a class and determine whether + * they are part of a property, an event, or a method (in + * that order). + * + * + * Properties:

    + * + *

      + *
    1. If there is a public boolean isXXX() + * method, then XXX is a read-only boolean property. + * boolean getXXX() may be supplied in + * addition to this method, although isXXX() is the + * one that will be used in this case and getXXX() + * will be ignored. If there is a + * public void setXXX(boolean) method, + * it is part of this group and makes it a read-write + * property.
    2. + *
    3. If there is a + * public <type> getXXX(int) + * method, then XXX is a read-only indexed property of + * type <type>. If there is a + * public void setXXX(int,<type>) + * method, then it is a read-write indexed property of + * type <type>. There may also be a + * public <type>[] getXXX() and a + * public void setXXX(<type>) + * method as well.
    4. + *
    5. If there is a + * public void setXXX(int,<type>) + * method, then it is a write-only indexed property of + * type <type>. There may also be a + * public <type>[] getXXX() and a + * public void setXXX(<type>) + * method as well.
    6. + *
    7. If there is a + * public <type> getXXX() method, + * then XXX is a read-only property of type + * <type>. If there is a + * public void setXXX(<type>) + * method, then it will be used for the property and + * the property will be considered read-write.
    8. + *
    9. If there is a + * public void setXXX(<type>) + * method, then as long as XXX is not already used as + * the name of a property, XXX is assumed to be a + * write-only property of type <type>.
    10. + *
    11. In all of the above cases, if the setXXX() method + * throws PropertyVetoException, then the + * property in question is assumed to be constrained. + * No properties are ever assumed to be bound + * (Spec Note: this is not in the + * spec, it just makes sense). See PropertyDescriptor + * for a description of bound and constrained + * properties.
    12. + *
    + * + * Events:

    + * + * If there is a pair of methods, + * public void addXXX(<type>) and + * public void removeXXX(<type>), where + * <type> is a descendant of + * java.util.EventListener, then the pair of + * methods imply that this Bean will fire events to + * listeners of type <type>.

    + * + * If the addXXX() method throws + * java.util.TooManyListenersException, then + * the event set is assumed to be unicast. See + * EventSetDescriptor for a discussion of unicast event + * sets.

    + * + * Spec Note: the spec seems to say that + * the listener type's classname must be equal to the XXX + * part of addXXX() and removeXXX(), but that is not the + * case in Sun's implementation, so I am assuming it is + * not the case in general.

    + * + * Methods:

    + * + * Any public methods (including those which were used + * for Properties or Events) are used as Methods. + * + * @author John Keiser + * @since JDK1.1 + * @see java.beans.BeanInfo + */ +public class Introspector { + + public static final int USE_ALL_BEANINFO = 1; + public static final int IGNORE_IMMEDIATE_BEANINFO = 2; + public static final int IGNORE_ALL_BEANINFO = 3; + + static String[] beanInfoSearchPath = {"gnu.java.beans.info"}; + static Hashtable beanInfoCache = new Hashtable(); + + private Introspector() {} + + /** + * Get the BeanInfo for class beanClass, + * first by looking for explicit information, next by + * using standard design patterns to determine + * information about the class. + * + * @param beanClass the class to get BeanInfo about. + * @return the BeanInfo object representing the class. + */ + public static BeanInfo getBeanInfo(Class beanClass) + throws IntrospectionException + { + BeanInfo cachedInfo; + synchronized(beanClass) + { + cachedInfo = (BeanInfo)beanInfoCache.get(beanClass); + if(cachedInfo != null) + { + return cachedInfo; + } + cachedInfo = getBeanInfo(beanClass,null); + beanInfoCache.put(beanClass,cachedInfo); + return cachedInfo; + } + } + + /** + * Flush all of the Introspector's internal caches. + * + * @since 1.2 + */ + public static void flushCaches() + { + beanInfoCache.clear(); + + // Clears all the intermediate ExplicitInfo instances which + // have been created. + // This makes sure we have to retrieve stuff like BeanDescriptors + // again. (Remember that FeatureDescriptor can be modified by the user.) + ExplicitInfo.flushCaches(); + } + + /** + * Flush the Introspector's internal cached information for a given + * class. + * + * @param clz the class to be flushed. + * @throws NullPointerException if clz is null. + * @since 1.2 + */ + public static void flushFromCaches(Class clz) + { + synchronized (clz) + { + beanInfoCache.remove(clz); + } + } + + /** + * Get the BeanInfo for class beanClass, + * first by looking for explicit information, next by + * using standard design patterns to determine + * information about the class. It crawls up the + * inheritance tree until it hits topClass. + * + * @param beanClass the Bean class. + * @param stopClass the class to stop at. + * @return the BeanInfo object representing the class. + */ + public static BeanInfo getBeanInfo(Class beanClass, Class stopClass) + throws IntrospectionException + { + ExplicitInfo explicit = new ExplicitInfo(beanClass, stopClass); + + IntrospectionIncubator ii = new IntrospectionIncubator(); + ii.setPropertyStopClass(explicit.propertyStopClass); + ii.setEventStopClass(explicit.eventStopClass); + ii.setMethodStopClass(explicit.methodStopClass); + ii.addMethods(beanClass.getMethods()); + + BeanInfoEmbryo currentInfo = ii.getBeanInfoEmbryo(); + PropertyDescriptor[] p = explicit.explicitPropertyDescriptors; + if(p!=null) + { + for(int i=0;iIf the old or new values are unknown (although why that would be I do + * not know), they may be null. Also, if the set of properties itself has + * changed, the name should be null, and the old and new values may also be + * null. Right now Sun put in a propagationId, reserved for future use. Read + * the comments on the constructor and on setPropagationId for more + * information. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status udpated to 1.4 + */ +public class PropertyChangeEvent extends EventObject +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 7042693688939648123L; + + /** + * The name of the property that changed, may be null. Package visible for + * use by PropertyChangeSupport. + * + * @serial the changed property name + */ + final String propertyName; + + /** + * The new value of the property, may be null. Package visible for use by + * PropertyChangeSupport. + * + * @serial the new property value + */ + final Object newValue; + + /** + * The old value of the property, may be null. Package visible for use by + * PropertyChangeSupport. + * + * @serial the old property value + */ + final Object oldValue; + + /** + * The propagation ID, reserved for future use. May be null. + * + * @see #getPropagationId() + * @serial the Propagation ID + */ + private Object propagationId; + + /** + * Create a new PropertyChangeEvent. Remember that if you received a + * PropertyChangeEvent and are sending a new one, you should also set the + * propagation ID from the old PropertyChangeEvent. + * + * @param source the Bean containing the property + * @param propertyName the property's name + * @param oldVal the old value of the property + * @param newVal the new value of the property + * @throws IllegalArgumentException if source is null + */ + public PropertyChangeEvent(Object source, String propertyName, + Object oldVal, Object newVal) + { + super(source); + this.propertyName = propertyName; + oldValue = oldVal; + newValue = newVal; + } + + /** + * Get the property name. May be null if multiple properties changed. + * + * @return the property name + */ + public String getPropertyName() + { + return propertyName; + } + + /** + * Get the property's new value. May be null if multiple properties changed. + * + * @return the property's new value + */ + public Object getNewValue() + { + return newValue; + } + + /** + * Get the property's old value. May be null if multiple properties changed. + * + * @return the property's old value + */ + public Object getOldValue() + { + return oldValue; + } + + /** + * Set the propagation ID. This is a way for the event to be passed from + * hand to hand and retain a little extra state. Right now it is unused, + * but it should be propagated anyway so that future versions of JavaBeans + * can use it, for God knows what. + * + * @param propagationId the propagation ID + * @see #getPropagationId() + */ + public void setPropagationId(Object propagationId) + { + this.propagationId = propagationId; + } + + /** + * Get the propagation ID. Right now, it is not used for anything. + * + * @return the propagation ID + * @see #setPropagationId(Object) + */ + public Object getPropagationId() + { + return propagationId; + } + + /** + * Utility method to rollback a change. + * + * @param event the event to rollback + * @return a new event with old and new swapped + */ + PropertyChangeEvent rollback() + { + PropertyChangeEvent result + = new PropertyChangeEvent(source, propertyName, newValue, oldValue); + result.propagationId = propagationId; + return result; + } +} // class PropertyChangeEvent diff --git a/libjava/classpath/java/beans/PropertyChangeListener.java b/libjava/classpath/java/beans/PropertyChangeListener.java new file mode 100644 index 0000000..a97e6e1 --- /dev/null +++ b/libjava/classpath/java/beans/PropertyChangeListener.java @@ -0,0 +1,61 @@ +/* PropertyChangeListener.java -- listen for changes in a bound property + 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 java.beans; + +import java.util.EventListener; + +/** + * PropertyChangeListener allows a class to monitor properties of a Bean for + * changes. A propertyChange() event will only be fired after the + * property has changed. + * + * @author John Keiser + * @see PropertyChangeSupport + * @since 1.1 + * @status updated to 1.4 + */ +public interface PropertyChangeListener extends EventListener +{ + /** + * Fired after a Bean's property has changed. + * + * @param e the change (containing the old and new values) + */ + void propertyChange(PropertyChangeEvent e); +} // interface PropertyChangeListener diff --git a/libjava/classpath/java/beans/PropertyChangeListenerProxy.java b/libjava/classpath/java/beans/PropertyChangeListenerProxy.java new file mode 100644 index 0000000..68a8153 --- /dev/null +++ b/libjava/classpath/java/beans/PropertyChangeListenerProxy.java @@ -0,0 +1,102 @@ +/* PropertyChangeListenerProxy.java -- adds a name to a property listener + 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 java.beans; + +import java.util.EventListenerProxy; + +/** + * This class provides an extension to PropertyChangeListener - + * associating a name with the listener. This can be used to filter the + * changes that one is interested in. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status udpated to 1.4 + */ +public class PropertyChangeListenerProxy extends EventListenerProxy + implements PropertyChangeListener +{ + /** + * The name of the property to listen for. Package visible for use by + * PropertyChangeSupport. + */ + final String propertyName; + + /** + * Create a new proxy which filters property change events and only passes + * changes to the named property on to the delegate. A null propertyName + * or listener does not fail now, but may cause a NullPointerException down + * the road. + * + * @param propertyName the property's name to filter on + * @param listener the delegate listener + */ + public PropertyChangeListenerProxy(String propertyName, + PropertyChangeListener listener) + { + super(listener); + this.propertyName = propertyName; + } + + /** + * Forwards the event on to the delegate if the property name matches. + * + * @param event the event to pass on, if it meets the filter + * @throws NullPointerException if the delegate this was created with is null + */ + public void propertyChange(PropertyChangeEvent event) + { + // Note: Sun does not filter, under the assumption that since + // PropertyChangeSupport unwraps proxys, this method should never be + // called by normal use of listeners. + String name = event == null ? null : event.getPropertyName(); + if (name == null ? propertyName == null : name.equals(propertyName)) + ((PropertyChangeListener) getListener()).propertyChange(event); + } + + /** + * Gets the name of the property this proxy is filtering on. + * + * @return the property name + */ + public String getPropertyName() + { + return propertyName; + } +} // class PropertyChangeListenerProxy diff --git a/libjava/classpath/java/beans/PropertyChangeSupport.java b/libjava/classpath/java/beans/PropertyChangeSupport.java new file mode 100644 index 0000000..a0e64af --- /dev/null +++ b/libjava/classpath/java/beans/PropertyChangeSupport.java @@ -0,0 +1,488 @@ +/* PropertyChangeSupport.java -- support to manage property change listeners + Copyright (C) 1998, 1999, 2000, 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 java.beans; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Vector; + +/** + * PropertyChangeSupport makes it easy to fire property change events and + * handle listeners. It allows chaining of listeners, as well as filtering + * by property name. In addition, it will serialize only those listeners + * which are serializable, ignoring the others without problem. This class + * is thread-safe. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public class PropertyChangeSupport implements Serializable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 6401253773779951803L; + + /** + * Maps property names (String) to named listeners (PropertyChangeSupport). + * If this is a child instance, this field will be null. + * + * @serial the map of property names to named listener managers + * @since 1.2 + */ + private Hashtable children; + + /** + * The non-null source object for any generated events. + * + * @serial the event source + */ + private final Object source; + + /** + * A field to compare serialization versions - this class uses version 2. + * + * @serial the serialization format + */ + private static final int propertyChangeSupportSerializedDataVersion = 2; + + /** + * The list of all registered property listeners. If this instance was + * created by user code, this only holds the global listeners (ie. not tied + * to a name), and may be null. If it was created by this class, as a + * helper for named properties, then this vector will be non-null, and this + * instance appears as a value in the children hashtable of + * another instance, so that the listeners are tied to the key of that + * hashtable entry. + */ + private transient Vector listeners; + + /** + * Create a PropertyChangeSupport to work with a specific source bean. + * + * @param source the source bean to use + * @throws NullPointerException if source is null + */ + public PropertyChangeSupport(Object source) + { + this.source = source; + if (source == null) + throw new NullPointerException(); + } + + /** + * Adds a PropertyChangeListener to the list of global listeners. All + * property change events will be sent to this listener. The listener add + * is not unique: that is, n adds with the same listener will + * result in n events being sent to that listener for every + * property change. Adding a null listener may cause a NullPointerException + * down the road. This method will unwrap a PropertyChangeListenerProxy, + * registering the underlying delegate to the named property list. + * + * @param l the listener to add + */ + public synchronized void addPropertyChangeListener(PropertyChangeListener l) + { + if (l instanceof PropertyChangeListenerProxy) + { + PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; + addPropertyChangeListener(p.propertyName, + (PropertyChangeListener) p.getListener()); + } + else + { + if (listeners == null) + listeners = new Vector(); + listeners.add(l); + } + } + + /** + * Removes a PropertyChangeListener from the list of global listeners. If + * any specific properties are being listened on, they must be deregistered + * by themselves; this will only remove the general listener to all + * properties. If add() has been called multiple times for a + * particular listener, remove() will have to be called the + * same number of times to deregister it. This method will unwrap a + * PropertyChangeListenerProxy, removing the underlying delegate from the + * named property list. + * + * @param l the listener to remove + */ + public synchronized void + removePropertyChangeListener(PropertyChangeListener l) + { + if (l instanceof PropertyChangeListenerProxy) + { + PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; + removePropertyChangeListener(p.propertyName, + (PropertyChangeListener) p.getListener()); + } + else if (listeners != null) + { + listeners.remove(l); + if (listeners.isEmpty()) + listeners = null; + } + } + + /** + * Returns an array of all registered property change listeners. Those that + * were registered under a name will be wrapped in a + * PropertyChangeListenerProxy, so you must check whether the + * listener is an instance of the proxy class in order to see what name the + * real listener is registered under. If there are no registered listeners, + * this returns an empty array. + * + * @return the array of registered listeners + * @see PropertyChangeListenerProxy + * @since 1.4 + */ + public synchronized PropertyChangeListener[] getPropertyChangeListeners() + { + ArrayList list = new ArrayList(); + if (listeners != null) + list.addAll(listeners); + if (children != null) + { + int i = children.size(); + Iterator iter = children.entrySet().iterator(); + while (--i >= 0) + { + Entry e = (Entry) iter.next(); + String name = (String) e.getKey(); + Vector v = ((PropertyChangeSupport) e.getValue()).listeners; + int j = v.size(); + while (--j >= 0) + list.add(new PropertyChangeListenerProxy + (name, (PropertyChangeListener) v.get(j))); + } + } + return (PropertyChangeListener[]) + list.toArray(new PropertyChangeListener[list.size()]); + } + + /** + * Adds a PropertyChangeListener listening on the specified property. Events + * will be sent to the listener only if the property name matches. The + * listener add is not unique; that is, n adds on a particular + * property for a particular listener will result in n events + * being sent to that listener when that property is changed. The effect is + * cumulative, too; if you are registered to listen to receive events on + * all property changes, and then you register on a particular property, + * you will receive change events for that property twice. Adding a null + * listener may cause a NullPointerException down the road. This method + * will unwrap a PropertyChangeListenerProxy, registering the underlying + * delegate to the named property list if the names match, and discarding + * it otherwise. + * + * @param propertyName the name of the property to listen on + * @param l the listener to add + * @throws NullPointerException if propertyName is null + */ + public synchronized void addPropertyChangeListener(String propertyName, + PropertyChangeListener l) + { + while (l instanceof PropertyChangeListenerProxy) + { + PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; + if (propertyName == null ? p.propertyName != null + : ! propertyName.equals(p.propertyName)) + return; + l = (PropertyChangeListener) p.getListener(); + } + PropertyChangeSupport s = null; + if (children == null) + children = new Hashtable(); + else + s = (PropertyChangeSupport) children.get(propertyName); + if (s == null) + { + s = new PropertyChangeSupport(source); + s.listeners = new Vector(); + children.put(propertyName, s); + } + s.listeners.add(l); + } + + /** + * Removes a PropertyChangeListener from listening to a specific property. + * If add() has been called multiple times for a particular + * listener on a property, remove() will have to be called the + * same number of times to deregister it. This method will unwrap a + * PropertyChangeListenerProxy, removing the underlying delegate from the + * named property list if the names match. + * + * @param propertyName the property to stop listening on + * @param l the listener to remove + * @throws NullPointerException if propertyName is null + */ + public synchronized void + removePropertyChangeListener(String propertyName, PropertyChangeListener l) + { + if (children == null) + return; + PropertyChangeSupport s + = (PropertyChangeSupport) children.get(propertyName); + if (s == null) + return; + while (l instanceof PropertyChangeListenerProxy) + { + PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; + if (propertyName == null ? p.propertyName != null + : ! propertyName.equals(p.propertyName)) + return; + l = (PropertyChangeListener) p.getListener(); + } + s.listeners.remove(l); + if (s.listeners.isEmpty()) + { + children.remove(propertyName); + if (children.isEmpty()) + children = null; + } + } + + /** + * Returns an array of all property change listeners registered under the + * given property name. If there are no registered listeners, this returns + * an empty array. + * + * @return the array of registered listeners + * @throws NullPointerException if propertyName is null + * @since 1.4 + */ + public synchronized PropertyChangeListener[] + getPropertyChangeListeners(String propertyName) + { + if (children == null) + return new PropertyChangeListener[0]; + PropertyChangeSupport s + = (PropertyChangeSupport) children.get(propertyName); + if (s == null) + return new PropertyChangeListener[0]; + return (PropertyChangeListener[]) + s.listeners.toArray(new PropertyChangeListener[s.listeners.size()]); + } + + /** + * Fire a PropertyChangeEvent containing the old and new values of the + * property to all the global listeners, and to all the listeners for the + * specified property name. This does nothing if old and new are non-null + * and equal. + * + * @param propertyName the name of the property that changed + * @param oldVal the old value + * @param newVal the new value + */ + public void firePropertyChange(String propertyName, + Object oldVal, Object newVal) + { + firePropertyChange(new PropertyChangeEvent(source, propertyName, + oldVal, newVal)); + } + + /** + * Fire a PropertyChangeEvent containing the old and new values of the + * property to all the global listeners, and to all the listeners for the + * specified property name. This does nothing if old and new are equal. + * + * @param propertyName the name of the property that changed + * @param oldVal the old value + * @param newVal the new value + */ + public void firePropertyChange(String propertyName, int oldVal, int newVal) + { + if (oldVal != newVal) + firePropertyChange(new PropertyChangeEvent(source, propertyName, + new Integer(oldVal), + new Integer(newVal))); + } + + /** + * Fire a PropertyChangeEvent containing the old and new values of the + * property to all the global listeners, and to all the listeners for the + * specified property name. This does nothing if old and new are equal. + * + * @param propertyName the name of the property that changed + * @param oldVal the old value + * @param newVal the new value + */ + public void firePropertyChange(String propertyName, + boolean oldVal, boolean newVal) + { + if (oldVal != newVal) + firePropertyChange(new PropertyChangeEvent(source, propertyName, + Boolean.valueOf(oldVal), + Boolean.valueOf(newVal))); + } + + /** + * Fire a PropertyChangeEvent to all the global listeners, and to all the + * listeners for the specified property name. This does nothing if old and + * new values of the event are equal. + * + * @param event the event to fire + * @throws NullPointerException if event is null + */ + public void firePropertyChange(PropertyChangeEvent event) + { + if (event.oldValue != null && event.oldValue.equals(event.newValue)) + return; + Vector v = listeners; // Be thread-safe. + if (v != null) + { + int i = v.size(); + while (--i >= 0) + ((PropertyChangeListener) v.get(i)).propertyChange(event); + } + Hashtable h = children; // Be thread-safe. + if (h != null && event.propertyName != null) + { + PropertyChangeSupport s + = (PropertyChangeSupport) h.get(event.propertyName); + if (s != null) + { + v = s.listeners; // Be thread-safe. + int i = v == null ? 0 : v.size(); + while (--i >= 0) + ((PropertyChangeListener) v.get(i)).propertyChange(event); + } + } + } + + /** + * Tell whether the specified property is being listened on or not. This + * will only return true if there are listeners on all + * properties or if there is a listener specifically on this property. + * + * @param propertyName the property that may be listened on + * @return whether the property is being listened on + * @throws NullPointerException if propertyName is null + */ + public synchronized boolean hasListeners(String propertyName) + { + return listeners != null || (children != null + && children.get(propertyName) != null); + } + + /** + * Saves the state of the object to the stream. + * + * @param s the stream to write to + * @throws IOException if anything goes wrong + * @serialData this writes out a null-terminated list of serializable + * global property change listeners (the listeners for a named + * property are written out as the global listeners of the + * children, when the children hashtable is saved) + */ + private synchronized void writeObject(ObjectOutputStream s) + throws IOException + { + s.defaultWriteObject(); + if (listeners != null) + { + int i = listeners.size(); + while (--i >= 0) + if (listeners.get(i) instanceof Serializable) + s.writeObject(listeners.get(i)); + } + s.writeObject(null); + } + + /** + * Reads the object back from stream (deserialization). + * + * XXX Since serialization for 1.1 streams was not documented, this may + * not work if propertyChangeSupportSerializedDataVersion is 1. + * + * @param s the stream to read from + * @throws IOException if reading the stream fails + * @throws ClassNotFoundException if deserialization fails + * @serialData this reads in a null-terminated list of serializable + * global property change listeners (the listeners for a named + * property are written out as the global listeners of the + * children, when the children hashtable is saved) + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + PropertyChangeListener l = (PropertyChangeListener) s.readObject(); + while (l != null) + { + addPropertyChangeListener(l); + l = (PropertyChangeListener) s.readObject(); + } + // Sun is not as careful with children as we are, and lets some proxys + // in that can never receive events. So, we clean up anything that got + // serialized, to make sure our invariants hold. + if (children != null) + { + int i = children.size(); + Iterator iter = children.entrySet().iterator(); + while (--i >= 0) + { + Entry e = (Entry) iter.next(); + String name = (String) e.getKey(); + PropertyChangeSupport pcs = (PropertyChangeSupport) e.getValue(); + if (pcs.listeners == null) + pcs.listeners = new Vector(); + if (pcs.children != null) + pcs.listeners.addAll + (Arrays.asList(pcs.getPropertyChangeListeners(name))); + if (pcs.listeners.size() == 0) + iter.remove(); + else + pcs.children = null; + } + if (children.size() == 0) + children = null; + } + } +} // class PropertyChangeSupport diff --git a/libjava/classpath/java/beans/PropertyDescriptor.java b/libjava/classpath/java/beans/PropertyDescriptor.java new file mode 100644 index 0000000..416d468 --- /dev/null +++ b/libjava/classpath/java/beans/PropertyDescriptor.java @@ -0,0 +1,583 @@ +/* java.beans.PropertyDescriptor + Copyright (C) 1998, 2001, 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 java.beans; + +import java.lang.reflect.Method; + +/** + ** PropertyDescriptor describes information about a JavaBean property, + ** by which we mean a property that has been exposed via a pair of + ** get and set methods. (There may be no get method, which means + ** the property is write-only, or no set method, which means the + ** the property is read-only.)

    + ** + ** The constraints put on get and set methods are:

    + **

      + **
    1. A get method must have signature + ** <propertyType> <getMethodName>()
    2. + **
    3. A set method must have signature + ** void <setMethodName>(<propertyType>)
    4. + **
    5. Either method type may throw any exception.
    6. + **
    7. Both methods must be public.
    8. + **
    + ** + ** @author John Keiser + ** @author Robert Schuster (thebohemian@gmx.net) + ** @since 1.1 + ** @status updated to 1.4 + **/ + +public class PropertyDescriptor extends FeatureDescriptor +{ + Class propertyType; + Method getMethod; + Method setMethod; + + Class propertyEditorClass; + boolean bound; + boolean constrained; + + PropertyDescriptor(String name) + { + setName(name); + } + + /** Create a new PropertyDescriptor by introspection. + ** This form of constructor creates the PropertyDescriptor by + ** looking for a getter method named get<name>() + ** (or, optionally, if the property is boolean, + ** is<name>()) and + ** set<name>() in class + ** <beanClass>, where <name> has its + ** first letter capitalized by the constructor.

    + ** + ** Note that using this constructor the given property must be read- and + ** writeable. If the implementation does not both, a read and a write method, an + ** IntrospectionException is thrown. + ** + ** Implementation note: If there is both are both isXXX and + ** getXXX methods, the former is used in preference to the latter. + ** We do not check that an isXXX method returns a boolean. In both + ** cases, this matches the behaviour of JDK 1.4

    + ** + ** @param name the programmatic name of the property, usually + ** starting with a lowercase letter (e.g. fooManChu + ** instead of FooManChu). + ** @param beanClass the class the get and set methods live in. + ** @exception IntrospectionException if the methods are not found + ** or invalid. + **/ + public PropertyDescriptor(String name, Class beanClass) + throws IntrospectionException + { + setName(name); + if (name.length() == 0) + { + throw new IntrospectionException("empty property name"); + } + String caps = Character.toUpperCase(name.charAt(0)) + name.substring(1); + findMethods(beanClass, "is" + caps, "get" + caps, "set" + caps); + + if (getMethod == null) + { + throw new IntrospectionException( + "Cannot find a is" + caps + " or get" + caps + " method"); + } + + if (setMethod == null) + { + throw new IntrospectionException( + "Cannot find a " + caps + " method"); + } + + // finally check the methods compatibility + propertyType = checkMethods(getMethod, setMethod); + } + + /** Create a new PropertyDescriptor by introspection. + ** This form of constructor allows you to specify the + ** names of the get and set methods to search for.

    + ** + ** Implementation note: If there is a get method (or + ** boolean isXXX() method), then the return type of that method + ** is used to find the set method. If there is no get method, + ** then the set method is searched for exhaustively.

    + ** + ** Spec note: + ** If there is no get method and multiple set methods with + ** the same name and a single parameter (different type of course), + ** then an IntrospectionException is thrown. While Sun's spec + ** does not state this, it can make Bean behavior different on + ** different systems (since method order is not guaranteed) and as + ** such, can be treated as a bug in the spec. I am not aware of + ** whether Sun's implementation catches this. + ** + ** @param name the programmatic name of the property, usually + ** starting with a lowercase letter (e.g. fooManChu + ** instead of FooManChu). + ** @param beanClass the class the get and set methods live in. + ** @param getMethodName the name of the get method or null if the property is write-only. + ** @param setMethodName the name of the set method or null if the property is read-only. + ** @exception IntrospectionException if the methods are not found + ** or invalid. + **/ + public PropertyDescriptor( + String name, + Class beanClass, + String getMethodName, + String setMethodName) + throws IntrospectionException + { + setName(name); + findMethods(beanClass, getMethodName, null, setMethodName); + + if (getMethod == null && getMethodName != null) + { + throw new IntrospectionException( + "Cannot find a getter method called " + getMethodName); + } + + if (setMethod == null && setMethodName != null) + { + throw new IntrospectionException( + "Cannot find a setter method called " + setMethodName); + } + + propertyType = checkMethods(getMethod, setMethod); + } + + /** Create a new PropertyDescriptor using explicit Methods. + ** Note that the methods will be checked for conformance to standard + ** Property method rules, as described above at the top of this class. + **
    + ** It is possible to call this method with both Method arguments + ** being null. In such a case the property type is null. + ** + ** @param name the programmatic name of the property, usually + ** starting with a lowercase letter (e.g. fooManChu + ** instead of FooManChu). + ** @param readMethod the read method or null if the property is write-only. + ** @param writeMethod the write method or null if the property is read-only. + ** @exception IntrospectionException if the methods are not found + ** or invalid. + **/ + public PropertyDescriptor( + String name, + Method readMethod, + Method writeMethod) + throws IntrospectionException + { + setName(name); + getMethod = readMethod; + setMethod = writeMethod; + propertyType = checkMethods(getMethod, setMethod); + } + + /** Get the property type. + ** This is the type the get method returns and the set method + ** takes in. + **/ + public Class getPropertyType() + { + return propertyType; + } + + /** Get the get method. Why they call it readMethod here and + ** get everywhere else is beyond me. + **/ + public Method getReadMethod() + { + return getMethod; + } + + /** Sets the read method.
    + * The read method is used to retrieve the value of a property. A legal + * read method must have no arguments. Its return type must not be + * void. If this methods succeeds the property type + * is adjusted to the return type of the read method.
    + *
    + * It is legal to set the read and the write method to null + * or provide method which have been declared in distinct classes. + * + * @param readMethod The new method to be used or null. + * @throws IntrospectionException If the given method is invalid. + * @since 1.2 + */ + public void setReadMethod(Method readMethod) throws IntrospectionException + { + propertyType = checkMethods(readMethod, setMethod); + + getMethod = readMethod; + } + + /** Get the set method. Why they call it writeMethod here and + ** set everywhere else is beyond me. + **/ + public Method getWriteMethod() + { + return setMethod; + } + + /** Sets the write method.
    + * The write method is used to set the value of a property. A legal write method + * must have a single argument which can be assigned to the property. If no + * read method exists the property type changes to the argument type of the + * write method.
    + *
    + * It is legal to set the read and the write method to null + * or provide method which have been declared in distinct classes. + * + * @param writeMethod The new method to be used or null. + * @throws IntrospectionException If the given method is invalid. + * @since 1.2 + */ + public void setWriteMethod(Method writeMethod) + throws IntrospectionException + { + propertyType = checkMethods(getMethod, writeMethod); + + setMethod = writeMethod; + } + + /** Get whether the property is bound. Defaults to false. **/ + public boolean isBound() + { + return bound; + } + + /** Set whether the property is bound. + ** As long as the the bean implements addPropertyChangeListener() and + ** removePropertyChangeListener(), setBound(true) may safely be called.

    + ** If these things are not true, then the behavior of the system + ** will be undefined.

    + ** + ** When a property is bound, its set method is required to fire the + ** PropertyChangeListener.propertyChange()) event + ** after the value has changed. + ** @param bound whether the property is bound or not. + **/ + public void setBound(boolean bound) + { + this.bound = bound; + } + + /** Get whether the property is constrained. Defaults to false. **/ + public boolean isConstrained() + { + return constrained; + } + + /** Set whether the property is constrained. + ** If the set method throws java.beans.PropertyVetoException + ** (or subclass thereof) and the bean implements addVetoableChangeListener() + ** and removeVetoableChangeListener(), then setConstrained(true) may safely + ** be called. Otherwise, the system behavior is undefined. + ** Spec note: given those strict parameters, it would be nice if it + ** got set automatically by detection, but oh well.

    + ** When a property is constrained, its set method is required to:

    + **

      + **
    1. Fire the VetoableChangeListener.vetoableChange() + ** event notifying others of the change and allowing them a chance to + ** say it is a bad thing.
    2. + **
    3. If any of the listeners throws a PropertyVetoException, then + ** it must fire another vetoableChange() event notifying the others + ** of a reversion to the old value (though, of course, the change + ** was never made). Then it rethrows the PropertyVetoException and + ** exits.
    4. + **
    5. If all has gone well to this point, the value may be changed.
    6. + **
    + ** @param constrained whether the property is constrained or not. + **/ + public void setConstrained(boolean constrained) + { + this.constrained = constrained; + } + + /** Get the PropertyEditor class. Defaults to null. **/ + public Class getPropertyEditorClass() + { + return propertyEditorClass; + } + + /** Set the PropertyEditor class. If the class does not implement + ** the PropertyEditor interface, you will likely get an exception + ** late in the game. + ** @param propertyEditorClass the PropertyEditor class for this + ** class to use. + **/ + public void setPropertyEditorClass(Class propertyEditorClass) + { + this.propertyEditorClass = propertyEditorClass; + } + + private void findMethods( + Class beanClass, + String getMethodName1, + String getMethodName2, + String setMethodName) + throws IntrospectionException + { + try + { + // Try the first get method name + if (getMethodName1 != null) + { + try + { + getMethod = + beanClass.getMethod(getMethodName1, new Class[0]); + } + catch (NoSuchMethodException e) + {} + } + + // Fall back to the second get method name + if (getMethod == null && getMethodName2 != null) + { + try + { + getMethod = + beanClass.getMethod(getMethodName2, new Class[0]); + } + catch (NoSuchMethodException e) + {} + } + + // Try the set method name + if (setMethodName != null) + { + if (getMethod != null) + { + // If there is a get method, use its return type to help + // select the corresponding set method. + Class propertyType = getMethod.getReturnType(); + if (propertyType == Void.TYPE) + { + String msg = + "The property's read method has return type 'void'"; + throw new IntrospectionException(msg); + } + + Class[] setArgs = new Class[] { propertyType }; + try + { + setMethod = beanClass.getMethod(setMethodName, setArgs); + } + catch (NoSuchMethodException e) + {} + } + else if (getMethodName1 == null && getMethodName2 == null) + { + // If this is a write-only property, choose the first set method + // with the required name, one parameter and return type 'void' + Method[] methods = beanClass.getMethods(); + for (int i = 0; i < methods.length; i++) + { + if (methods[i].getName().equals(setMethodName) + && methods[i].getParameterTypes().length == 1 + && methods[i].getReturnType() == Void.TYPE) + { + setMethod = methods[i]; + break; + } + } + } + } + } + catch (SecurityException e) + { + // FIXME -- shouldn't we just allow SecurityException to propagate? + String msg = + "SecurityException thrown on attempt to access methods."; + throw new IntrospectionException(msg); + } + } + + /** Checks whether the given Method instances are legal read and + * write methods. The following requirements must be met:
    + *
      + *
    • the read method must not have an argument
    • + *
    • the read method must have a non void return type
    • + *
    • the read method may not exist
    • + *
    • the write method must have a single argument
    • + *
    • the property type and the read method's return type must be assignable from the + * write method's argument type
    • + *
    • the write method may not exist
    • + *
    + * While checking the methods a common new property type is calculated. If the method + * succeeds this property type is returned.
    + *
    + * For compatibility this has to be noted:
    + * The two methods are allowed to be defined in two distinct classes and may both be null. + * + * @param readMethod The new read method to check. + * @param writeMethod The new write method to check. + * @return The common property type of the two method. + * @throws IntrospectionException If any of the above requirements are not met. + */ + private Class checkMethods(Method readMethod, Method writeMethod) + throws IntrospectionException + { + Class newPropertyType = propertyType; + + // a valid read method has zero arguments and a non-void return type. + if (readMethod != null) + { + if (readMethod.getParameterTypes().length > 0) + { + throw new IntrospectionException("read method has unexpected parameters"); + } + + newPropertyType = readMethod.getReturnType(); + + if (newPropertyType == Void.TYPE) + { + throw new IntrospectionException("read method return type is void"); + } + } + + // a valid write method has one argument which can be assigned to the property + if (writeMethod != null) + { + if (writeMethod.getParameterTypes().length != 1) + { + String msg = "write method does not have exactly one parameter"; + throw new IntrospectionException(msg); + } + + if (readMethod == null) + { + // changes the property type if there is no read method + newPropertyType = writeMethod.getParameterTypes()[0]; + } + else + { + // checks whether the write method can be assigned to the return type of the read + // method (if this is not the case, the methods are not compatible) + // note: newPropertyType may be null if no methods or method names have been + // delivered in the constructor. + if (newPropertyType != null + && !newPropertyType.isAssignableFrom( + writeMethod.getParameterTypes()[0])) + { + // note: newPropertyType is the same as readMethod.getReturnType() at this point + throw new IntrospectionException("read and write method are not compatible"); + } + + /* note: the check whether both method are defined in related classes makes sense but is not + * done in the JDK. + * I leave this code here in case someone at Sun decides to add that functionality in later versions (rschuster) + if ((!readMethod + .getDeclaringClass() + .isAssignableFrom(writeMethod.getDeclaringClass())) + && (!writeMethod + .getDeclaringClass() + .isAssignableFrom(readMethod.getDeclaringClass()))) + { + String msg = + "set and get methods are not in the same class."; + throw new IntrospectionException(msg); + } + */ + + } + } + + return newPropertyType; + } + + /** Compares this PropertyDescriptor against the + * given object. + * Two PropertyDescriptors are equals if + *
      + *
    • the read methods are equal
    • + *
    • the write methods are equal
    • + *
    • the property types are equals
    • + *
    • the property editor classes are equal
    • + *
    • the flags (constrained and bound) are equal
    • + *
    + * @return Whether both objects are equal according to the rules given above. + * @since 1.4 + */ + public boolean equals(Object o) + { + if (o instanceof PropertyDescriptor) + { + PropertyDescriptor that = (PropertyDescriptor) o; + + // compares the property types and checks the case where both are null + boolean samePropertyType = + (propertyType == null) + ? that.propertyType == null + : propertyType.equals(that.propertyType); + + // compares the property editor classes and checks the case where both are null + boolean samePropertyEditorClass = + (propertyEditorClass == null) + ? that.propertyEditorClass == null + : propertyEditorClass.equals(that.propertyEditorClass); + + // compares the flags for equality + boolean sameFlags = + bound == that.bound && constrained == that.constrained; + + // compares the read methods and checks the case where both are null + boolean sameReadMethod = + (getMethod == null) + ? that.getMethod == null + : getMethod.equals(that.getMethod); + + boolean sameWriteMethod = + (setMethod == null) + ? that.setMethod == null + : setMethod.equals(that.setMethod); + + return samePropertyType + && sameFlags + && sameReadMethod + && sameWriteMethod + && samePropertyEditorClass; + } + else + { + return false; + } + + } + +} diff --git a/libjava/classpath/java/beans/PropertyEditor.java b/libjava/classpath/java/beans/PropertyEditor.java new file mode 100644 index 0000000..d1c5103 --- /dev/null +++ b/libjava/classpath/java/beans/PropertyEditor.java @@ -0,0 +1,209 @@ +/* java.beans.PropertyEditor + 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 java.beans; + +/** + ** PropertyEditors are custom GUI editors for specific types of values. + ** + ** A PropertyEditor can be used, for example, if you are editing a type of value + ** that can be more easily represented graphically, such as a Point, or one that + ** can be more easily represented by a list, such as a boolean (true/false).

    + ** + ** A PropertyEditor must be able to display its contents when asked to and + ** be able to allow the user to change its underlying field value. However, it + ** is not the PropertyEditor's responsibility to make the change to the + ** underlying Object; in fact, the PropertyEditor does not even know about the + ** Object it is actually editing--only about the property it is currently + ** editing. When a change is made to the property, the PropertyEditor must + ** simply fire a PropertyChangeEvent and allow the RAD tool to actually set + ** the property in the underlying Bean.

    + ** + ** PropertyEditors should not change the Objects they are given by setValue(). + ** These Objects may or may not be the actual Objects which are properties of + ** the Bean being edited. Instead, PropertyEditors should create a new Object + ** and fire a PropertyChangeEvent with the old and new values.

    + ** + ** PropertyEditors also must support the ability to return a Java + ** initialization string. See the getJavaInitializationString() method for + ** details.

    + ** + ** There are several different ways a PropertyEditor may display and control + ** editing of its value. When multiple types of input and display are + ** given by a single PropertyEditor, the RAD tool may decide which of the call + ** to support. Some RAD tools may even be text-only, so even if you support + ** a graphical set and get, it may choose the text set and get whenever it can. + **

      + **
    1. Every PropertyEditor must support getValue() and setValue(). For + ** setValue(), the component must only support it when the argument is + ** the same type that the PropertyEditor supports.
    2. + **
    3. Every PropertyEditor must support getJavaInitializationString().
    4. + **
    5. You may support painting the value yourself if you wish. To do this, + ** have isPaintable() return true and implement the paintValue() method. + ** This method does not determine in any way how the value is edited; + ** merely how it is displayed.
    6. + **
    7. Let the caller of the PropertyEditor give the user a text input. Do + ** this by returning a non-null String from getAsText(). If you support + ** text input, you *must* support setAsText().
    8. + **
    9. Give the caller a set of possible values, such as "true"/"false", that + ** the user must select from. To do this, return the list of Strings + ** from the getTags() method. The RAD tool may choose to implement the + ** user input any way it wishes, and only guarantees that setAsText() will + ** only be called with one of the Strings returned from getTags().
    10. + **
    11. You may support a whole custom editing control by supporting + ** getCustomEditor(). To do this, return true from supportsCustomEditor() + ** and return a Component that does the job. It is the component's job, + ** or the PropertyEditor's job, to make sure that when the editor changes + ** its value, the PropertyChangeEvent is thrown.
    12. + **
    + ** + ** The PropertyEditor for a particular Bean can be found using the + ** PropertyEditorManager class, which goes through a series of different + ** checks to find the appropriate class.

    + ** + ** A PropertyChangeEvent should be thrown from the PropertyEditor whenever a + ** bound property (a property PropertyDescriptor.isBound() set to true) + ** changes. When this happens, the editor itself should *not* change the value + ** itself, but rather allow the RAD tool to call setValue() or setAsText(). + ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 30 June 1998 + ** @see java.beans.PropertyEditorManager + ** @see java.beans.PropertyEditorSupport + **/ + +public interface PropertyEditor { + /** Called by the RAD tool to set the value of this property for the PropertyEditor. + ** If the property type is native, it should be wrapped in the appropriate + ** wrapper type. + ** @param value the value to set this property to. + **/ + void setValue(Object value); + + /** Accessor method to get the current value the PropertyEditor is working with. + ** If the property type is native, it will be wrapped in the appropriate + ** wrapper type. + ** @return the current value of the PropertyEditor. + **/ + Object getValue(); + + + /** Set the value of this property using a String. + ** Whether or not this PropertyEditor is editing a String type, this converts + ** the String into the type of the PropertyEditor. + ** @param text the text to set it to. + ** @exception IllegalArgumentException if the String is in the wrong format or setAsText() is not supported. + **/ + void setAsText(String text) throws IllegalArgumentException; + + /** Get the value of this property in String format. + ** Many times this can simply use Object.toString().

    + ** Return null if you do not support getAsText()/setAsText(). + ** setAsText(getAsText()) should be valid; i.e. the stuff you spit out in + ** getAsText() should be able to go into setAsText(). + ** @return the value of this property in String format. + **/ + String getAsText(); + + /** Get a list of possible Strings which this property type can have. + ** The value of these will be used by the RAD tool to construct some sort + ** of list box or to check text box input, and the resulting String passed + ** to setAsText() should be one of these. Note, however, that like most things + ** with this mammoth, unwieldy interface, this is not guaranteed. Thus, you + ** must check the value in setAsText() anyway. + ** @return the list of possible String values for this property type. + **/ + String[] getTags(); + + + /** The RAD tool calls this to find out whether the PropertyEditor can paint itself. + ** @return true if it can paint itself graphically, false if it cannot. + **/ + boolean isPaintable(); + + /** The RAD tool calls this to paint the actual value of the property. + ** The Graphics context will have the same current font, color, etc. as the + ** parent Container. You may safely change the font, color, etc. and not + ** change them back.

    + ** This method should do a silent no-op if isPaintable() is false. + ** @param g the Graphics context to paint on + ** @param bounds the rectangle you have reserved to work in + **/ + void paintValue(java.awt.Graphics g, java.awt.Rectangle bounds); + + + /** The RAD tool calls this to find out whether the PropertyEditor supports a custom component to edit and display itself. + ** @return true if getCustomEditor() will return a component, false if not. + **/ + boolean supportsCustomEditor(); + + /** The RAD tool calls this to grab the component that can edit this type. + ** The component may be painted anywhere the RAD tool wants to paint it-- + ** even in its own window.

    + ** The component must hook up with the PropertyEditor and, whenever a + ** change to the value is made, fire a PropertyChangeEvent to the source.

    + ** @return the custom editor for this property type. + **/ + java.awt.Component getCustomEditor(); + + + /** Adds a property change listener to this PropertyEditor. + ** @param listener the listener to add + **/ + void addPropertyChangeListener(PropertyChangeListener listener); + + /** Removes a property change listener from this PropertyEditor. + ** @param listener the listener to remove + **/ + void removePropertyChangeListener(PropertyChangeListener listener); + + /** Get a Java language-specific String which could be used to create an Object + ** of the specified type. Every PropertyEditor must support this.

    + ** The reason for this is that while most RAD tools will serialize the Beans + ** and deserialize them at runtime, some RAD tools will generate code that + ** creates the Beans. Examples of Java initialization strings would be:

    + **

      + **
    1. 2
    2. + **
    3. "I am a String"
    4. + **
    5. new MyObject(2, "String", new StringBuffer())
    6. + **
    + ** @return the initialization string for this object in Java. + **/ + String getJavaInitializationString(); +} diff --git a/libjava/classpath/java/beans/PropertyEditorManager.java b/libjava/classpath/java/beans/PropertyEditorManager.java new file mode 100644 index 0000000..da2a567 --- /dev/null +++ b/libjava/classpath/java/beans/PropertyEditorManager.java @@ -0,0 +1,215 @@ +/* java.beans.PropertyEditorManager + 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 java.beans; + +import gnu.java.beans.editors.ColorEditor; +import gnu.java.beans.editors.FontEditor; +import gnu.java.beans.editors.NativeBooleanEditor; +import gnu.java.beans.editors.NativeByteEditor; +import gnu.java.beans.editors.NativeDoubleEditor; +import gnu.java.beans.editors.NativeFloatEditor; +import gnu.java.beans.editors.NativeIntEditor; +import gnu.java.beans.editors.NativeLongEditor; +import gnu.java.beans.editors.NativeShortEditor; +import gnu.java.beans.editors.StringEditor; +import gnu.java.lang.ClassHelper; + +import java.awt.Color; +import java.awt.Font; + +/** + * PropertyEditorManager is used to find property editors + * for various types (not necessarily Beans).

    + * + * It first checks to see if the property editor is + * already registered; if it is, that property editor is + * used. Next it takes the type's classname and appends + * "Editor" to it, and searches first in the class's + * package and then in the property editor search path. + * + *

    Default property editors are provided for:

    + * + *
      + *
    1. boolean, byte, short, int, long, float, and double
    2. + *
    3. java.lang.String
    4. + *
    5. java.awt.Color
    6. + *
    7. java.awt.Font
    8. + *
    + * + *

    Spec Suggestion: Perhaps an editor for + * Filename or something like it should be provided. As well + * as char.

    + * + * @author John Keiser + * @since 1.1 + * @version 1.1.0, 29 Jul 1998 + */ + +public class PropertyEditorManager +{ + static java.util.Hashtable editors = new java.util.Hashtable(); + static String[] editorSearchPath = { "gnu.java.beans.editors", + "sun.beans.editors" }; + + static + { + registerEditor(Boolean.TYPE, NativeBooleanEditor.class); + registerEditor(Byte.TYPE, NativeByteEditor.class); + registerEditor(Short.TYPE, NativeShortEditor.class); + registerEditor(Integer.TYPE, NativeIntEditor.class); + registerEditor(Long.TYPE, NativeLongEditor.class); + registerEditor(Float.TYPE, NativeFloatEditor.class); + registerEditor(Double.TYPE, NativeDoubleEditor.class); + registerEditor(String.class, StringEditor.class); + registerEditor(Color.class, ColorEditor.class); + registerEditor(Font.class, FontEditor.class); + } + + /** + * Beats me why this class can be instantiated, but there + * you have it. + */ + public PropertyEditorManager() + { + // Do nothing here + } + + /** + * Register an editor for a class. Replaces old editor + * if there was one registered before. + * + * @param editedClass the class that the property editor + * will edit. + * @param editorClass the PropertyEditor class. + */ + public static void registerEditor(Class editedClass, Class editorClass) + { + editors.put(editedClass, editorClass); + } + + /** + * Returns a new instance of the property editor for the + * specified class. + * + * @param editedClass the class that the property editor + * will edit. + * @return a PropertyEditor instance that can edit the + * specified class. + */ + public static PropertyEditor findEditor(Class editedClass) + { + try + { + Class found = (Class)editors.get(editedClass); + if(found != null) + { + return (PropertyEditor)found.newInstance(); + } + + ClassLoader contextClassLoader + = Thread.currentThread().getContextClassLoader(); + + try + { + found = Class.forName(editedClass.getName()+"Editor", true, + contextClassLoader); + registerEditor(editedClass,found); + return (PropertyEditor)found.newInstance(); + } + catch(ClassNotFoundException E) + { + } + + String appendName + = "." + + ClassHelper.getTruncatedClassName(editedClass) + + "Editor"; + synchronized(editorSearchPath) + { + for(int i=0;i + * + * This class does not do any painting or actual editing. + * For that, you must use or extend it. See the + * PropertyEditor class for better descriptions of what + * the various methods do. + * + * @author John Keiser + * @author Robert Schuster + * @since 1.1 + * @status updated to 1.5 + */ +public class PropertyEditorSupport implements PropertyEditor +{ + Object eventSource; + Object value; + PropertyChangeSupport pSupport; + + /** Call this constructor when you are deriving from + * PropertyEditorSupport. + * + * Using this constructor the event source is this PropertyEditorSupport + * instance itself. + * + * @since 1.5 + * @specnote this was protected prior to 1.5 + */ + public PropertyEditorSupport() + { + eventSource = this; + pSupport = new PropertyChangeSupport(this); + } + + /** Call this constructor when you are using + * PropertyEditorSupport as a helper object. + * + * This constructor throws a NullPointerException when source is null, + * for compatibility reasons with J2SDK 1.5.0 . + * + * @param source The source to use when firing + * property change events. + * @since 1.5 + * @specnote this was protected prior to 1.5 + */ + public PropertyEditorSupport(Object source) + { + // note: constructor rejects source being null for the sake of compatibility + // with official 1.5.0 implementation + if (source == null) + throw new NullPointerException("Event source must not be null."); + + eventSource = source; + pSupport = new PropertyChangeSupport(eventSource); + } + + /** Sets the current value of the property and a property change + * event is fired to all registered PropertyChangeListener instances. + * + * @param newValue The new value for the property. + */ + public void setValue(Object newValue) + { + value = newValue; + + // specification in java.beans.PropertyChangeEvent says + // that without a property name (first argument) the + // new and the old value should always be null + pSupport.firePropertyChange(null, null, null); + } + + /** Gets the current value of the property. + * + * @return the current value of the property. + */ + public Object getValue() + { + return value; + } + + /** Gets whether this object is paintable or not. + * + * @return false + */ + public boolean isPaintable() + { + return false; + } + + /** Paints this object. This class does nothing in + * this method. + */ + public void paintValue(java.awt.Graphics g, java.awt.Rectangle r) + { + } + + /** Gets the Java initialization String for the current + * value of the Object. This class returns gibberish or + * null (though the spec does not say which).

    + * Implementation Note: This class + * returns the string "@$#^" to make sure the code will + * be broken, so that you will know to override it when + * you create your own property editor. + * + * @return the Java initialization string. + */ + public String getJavaInitializationString() + { + return "@$#^"; + } + + /** Gets the value as text. + * In this class, you cannot count on getAsText() doing + * anything useful, although in this implementation I + * do toString(). + * + * @return the value as text. + */ + public String getAsText() + { + return value != null ? value.toString() : "null"; + } + + /** Sets the value as text. + * In this class, you cannot count on setAsText() doing + * anything useful across implementations. + * Implementation Note: In this + * implementation it checks if the String is "null", and + * if it is, sets the value to null, otherwise it throws + * an IllegalArgumentException. + * + * @param s the text to convert to a new value. + * @exception IllegalArgumentException if the text is + * malformed. + */ + public void setAsText(String s) throws IllegalArgumentException + { + if (s.equals("null")) + setValue(null); + else + throw new IllegalArgumentException(); + } + + /** Returns a list of possible choices for the value. + * + * @return null + */ + public String[] getTags() + { + return null; + } + + /** Returns a custom component to edit the value. + * + * @return null in this class. + */ + public java.awt.Component getCustomEditor() + { + return null; + } + + /** Finds out whether this property editor supports a + * custom component to edit its value. + * + * @return false in this class. + */ + public boolean supportsCustomEditor() + { + return false; + } + + /** Adds a property change listener to this property editor. + * + * @param l the listener to add. + */ + public void addPropertyChangeListener(PropertyChangeListener l) + { + pSupport.addPropertyChangeListener(l); + } + + /** Removes a property change listener from this property editor. + * + * @param l the listener to remove. + */ + public void removePropertyChangeListener(PropertyChangeListener l) + { + pSupport.removePropertyChangeListener(l); + } + + /** Notifies people that we've changed, although we don't + * tell them just how. + */ + public void firePropertyChange() + { + pSupport.firePropertyChange(null, null, null); + } + + /** Returns the bean that is used as the source of events. + * + * @return The event source object + * @since 1.5 + */ + public Object getSource() + { + return eventSource; + } + + /** Sets the bean that is used as the source of events + * when property changes occur. + * + * The event source bean is for informational purposes only + * and should not be changed by the PropertyEditor. + * + * @param source + * @since 1.5 + */ + public void setSource(Object source) + { + eventSource = source; + } +} diff --git a/libjava/classpath/java/beans/PropertyVetoException.java b/libjava/classpath/java/beans/PropertyVetoException.java new file mode 100644 index 0000000..1f0399b --- /dev/null +++ b/libjava/classpath/java/beans/PropertyVetoException.java @@ -0,0 +1,85 @@ +/* PropertyVetoException.java -- thrown to veto a proposed property change + 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 java.beans; + +/** + * PropertyVetoException is thrown when a VetoableChangeListener doesn't + * like the proposed change. + * + * @author John Keiser + * @see VetoableChangeListener + * @since 1.1 + * @status updated to 1.4 + */ +public class PropertyVetoException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 129596057694162164L; + + /** + * The vetoed change. + * + * @serial the event that was vetoed + */ + private final PropertyChangeEvent evt; + + /** + * Instantiate this exception with the given message and property change. + * + * @param msg the reason for the veto + * @param changeEvent the PropertyChangeEvent that was thrown + */ + public PropertyVetoException(String msg, PropertyChangeEvent changeEvent) + { + super(msg); + evt = changeEvent; + } + + /** + * Get the PropertyChange event that was vetoed. + * + * @return the vetoed change + */ + public PropertyChangeEvent getPropertyChangeEvent() + { + return evt; + } +} diff --git a/libjava/classpath/java/beans/SimpleBeanInfo.java b/libjava/classpath/java/beans/SimpleBeanInfo.java new file mode 100644 index 0000000..cfb9604 --- /dev/null +++ b/libjava/classpath/java/beans/SimpleBeanInfo.java @@ -0,0 +1,139 @@ +/* java.beans.SimpleBeanInfo + 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 java.beans; + +import java.awt.Image; +import java.awt.Toolkit; + +/** + ** SimpleBeanInfo is a class you may extend to more easily + ** provide select information to the Introspector. It + ** implements all of the methods in BeanInfo by returning + ** null and forces the Introspector to behave exactly as + ** if there were no BeanInfo class at all (Introspecting + ** everything).

    + ** + ** Overriding one or two of these functions + ** to give explicit information on only those things you + ** wish to give explicit information is perfectly safe, + ** and even desirable.

    + ** + ** See the BeanInfo class for information on what the + ** various methods actually do. + ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 29 Jul 1998 + ** @see java.beans.BeanInfo + **/ + +public class SimpleBeanInfo implements BeanInfo { + /** Force Introspection of the general bean info. + ** @return null. + **/ + public BeanDescriptor getBeanDescriptor() { + return null; + } + + /** Force Introspection of the events this Bean type + ** fires. + ** @return null + **/ + public EventSetDescriptor[] getEventSetDescriptors() { + return null; + } + + /** Say that there is no "default" event set. + ** @return -1. + **/ + public int getDefaultEventIndex() { + return -1; + } + + /** Force Introspection of the Bean properties. + ** @return null. + **/ + public PropertyDescriptor[] getPropertyDescriptors() { + return null; + } + + /** Say that there is no "default" property. + ** @return -1. + **/ + public int getDefaultPropertyIndex() { + return -1; + } + + /** Force Introspection of the Bean's methods. + ** @return null. + **/ + public MethodDescriptor[] getMethodDescriptors() { + return null; + } + + /** Tell the Introspector to go look for other BeanInfo + ** itself. + ** @return null. + **/ + public BeanInfo[] getAdditionalBeanInfo() { + return null; + } + + /** Say that this Bean has no icons. + ** @param iconType the type of icon + ** @return null. + **/ + public Image getIcon(int iconType) { + return null; + } + + /** Helper method to load an image using the Bean class + ** getResource() method on the BeanInfo class (using + ** getClass(), since you'll extend this class to get + ** the BeanInfo). Basically it's assumed that the Bean + ** and its BeanInfo are both loaded by the same + ** ClassLoader, generally a reasonable assumption. + ** @param location the URL relative + ** @return the Image in question. + **/ + public Image loadImage(String location) { + return Toolkit.getDefaultToolkit().getImage(getClass().getResource(location)); + } +} + diff --git a/libjava/classpath/java/beans/Statement.java b/libjava/classpath/java/beans/Statement.java new file mode 100644 index 0000000..01f86dd --- /dev/null +++ b/libjava/classpath/java/beans/Statement.java @@ -0,0 +1,326 @@ +/* java.beans.Statement + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.beans; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * class Statement + * + * A Statement captures the execution of an object method. It stores + * the object, the method to call, and the arguments to the method and + * provides the ability to execute the method on the object, using the + * provided arguments. + * + * @since 1.4 + */ +public class Statement +{ + private Object target; + private String methodName; + private Object[] arguments; + + // One or the other of these will get a value after execute is + // called once, but not both. + private transient Method method; + private transient Constructor ctor; + + /** + * Constructs a statement representing the invocation of + * object.methodName(arg[0], arg[1], ...); + * + * @param target The object to invoke the method on. + * @param methodName The object method to invoke. + * @param arguments An array of arguments to pass to the method. + */ + public Statement(Object target, String methodName, Object[] arguments) + { + this.target = target; + this.methodName = methodName; + this.arguments = arguments; + } + + /** + * Execute the statement. + * + * Finds the specified method in the target object and calls it with + * the arguments given in the constructor. + * + * The most specific method according to the JLS(15.11) is used when + * there are multiple methods with the same name. + * + * Execute performs some special handling for methods and + * parameters: + * + * Static methods can be executed by providing the class as a + * target. + * + * The method name new is reserved to call the constructor + * new() will construct an object and return it. Not useful unless + * an expression :-) + * + * If the target is an array, get and set as defined in + * java.util.List are recognized as valid methods and mapped to the + * methods of the same name in java.lang.reflect.Array. + * + * The native datatype wrappers Boolean, Byte, Character, Double, + * Float, Integer, Long, and Short will map to methods that have + * native datatypes as parameters, in the same way as Method.invoke. + * However, these wrappers also select methods that actually take + * the wrapper type as an argument. + * + * The Sun spec doesn't deal with overloading between int and + * Integer carefully. If there are two methods, one that takes an + * Integer and the other taking an int, the method chosen is not + * specified, and can depend on the order in which the methods are + * declared in the source file. + * + * @throws Exception if an exception occurs while locating or + * invoking the method. + */ + public void execute() throws Exception + { + doExecute(); + } + + private static Class wrappers[] = + { + Boolean.class, Byte.class, Character.class, Double.class, Float.class, + Integer.class, Long.class, Short.class + }; + + private static Class natives[] = + { + Boolean.TYPE, Byte.TYPE, Character.TYPE, Double.TYPE, Float.TYPE, + Integer.TYPE, Long.TYPE, Short.TYPE + }; + + // Given a wrapper class, return the native class for it. For + // example, if c is Integer, Integer.TYPE is returned. + private Class unwrap(Class c) + { + for (int i = 0; i < wrappers.length; i++) + if (c == wrappers[i]) + return natives[i]; + return null; + } + + // Return true if all args can be assigned to params, false + // otherwise. Arrays are guaranteed to be the same length. + private boolean compatible(Class[] params, Class[] args) + { + for (int i = 0; i < params.length; i++) + { + // Treat Integer like int if appropriate + Class nativeType = unwrap(args[i]); + if (nativeType != null && params[i].isPrimitive() + && params[i].isAssignableFrom(nativeType)) + continue; + if (params[i].isAssignableFrom(args[i])) + continue; + + return false; + } + return true; + } + + /** + * Return true if the method arguments in first are more specific + * than the method arguments in second, i.e. all args in first can + * be assigned to those in second. + * + * A method is more specific if all parameters can also be fed to + * the less specific method, because, e.g. the less specific method + * accepts a base class of the equivalent argument for the more + * specific one. + * + * @param first a Class[] value + * @param second a Class[] value + * @return a boolean value + */ + private boolean moreSpecific(Class[] first, Class[] second) + { + for (int j=0; j < first.length; j++) + { + if (second[j].isAssignableFrom(first[j])) + continue; + return false; + } + return true; + } + + final Object doExecute() throws Exception + { + Class klazz = (target instanceof Class) + ? (Class) target : target.getClass(); + Object args[] = (arguments == null) ? new Object[0] : arguments; + Class argTypes[] = new Class[args.length]; + for (int i = 0; i < args.length; i++) + argTypes[i] = args[i].getClass(); + + if (target.getClass().isArray()) + { + // FIXME: invoke may have to be used. For now, cast to Number + // and hope for the best. If caller didn't behave, we go boom + // and throw the exception. + if (methodName.equals("get") && argTypes.length == 1) + return Array.get(target, ((Number)args[0]).intValue()); + if (methodName.equals("set") && argTypes.length == 2) + { + Object obj = Array.get(target, ((Number)args[0]).intValue()); + Array.set(target, ((Number)args[0]).intValue(), args[1]); + return obj; + } + throw new NoSuchMethodException("No matching method for statement " + toString()); + } + + // If we already cached the method, just use it. + if (method != null) + return method.invoke(target, args); + else if (ctor != null) + return ctor.newInstance(args); + + // Find a matching method to call. JDK seems to go through all + // this to find the method to call. + + // if method name or length don't match, skip + // Need to go through each arg + // If arg is wrapper - check if method arg is matchable builtin + // or same type or super + // - check that method arg is same or super + + if (methodName.equals("new") && target instanceof Class) + { + Constructor ctors[] = klazz.getConstructors(); + for (int i = 0; i < ctors.length; i++) + { + // Skip methods with wrong number of args. + Class ptypes[] = ctors[i].getParameterTypes(); + System.out.println("ptypeslen = " + ptypes.length); + System.out.println("ptypes = " + ptypes); + System.out.println("ctor = " + ctors[i].getName()); + for (int j=0; j < ptypes.length; j++) { + System.out.println("param = " + ptypes[i].getName()); + + } + + + if (ptypes.length != args.length) + continue; + + // Check if method matches + if (!compatible(ptypes, argTypes)) + continue; + + // Use method[i] if it is more specific. + // FIXME: should this check both directions and throw if + // neither is more specific? + if (ctor == null) + { + ctor = ctors[i]; + continue; + } + Class mptypes[] = ctor.getParameterTypes(); + if (moreSpecific(ptypes, mptypes)) + ctor = ctors[i]; + } + if (ctor == null) + throw new InstantiationException("No matching constructor for statement " + toString()); + return ctor.newInstance(args); + } + + Method methods[] = klazz.getMethods(); + + for (int i = 0; i < methods.length; i++) + { + // Skip methods with wrong name or number of args. + if (!methods[i].getName().equals(methodName)) + continue; + Class ptypes[] = methods[i].getParameterTypes(); + if (ptypes.length != args.length) + continue; + + // Check if method matches + if (!compatible(ptypes, argTypes)) + continue; + + // Use method[i] if it is more specific. + // FIXME: should this check both directions and throw if + // neither is more specific? + if (method == null) + { + method = methods[i]; + continue; + } + Class mptypes[] = method.getParameterTypes(); + if (moreSpecific(ptypes, mptypes)) + method = methods[i]; + } + if (method == null) + throw new NoSuchMethodException("No matching method for statement " + toString()); + return method.invoke(target, args); + } + + + + /** Return the statement arguments. */ + public Object[] getArguments() { return arguments; } + + /** Return the statement method name. */ + public String getMethodName() { return methodName; } + + /** Return the statement object. */ + public Object getTarget() { return target; } + + /** Return a string representation. */ + public String toString() + { + String result = target.getClass().getName() + "." + methodName + "("; + String sep = ""; + for (int i = 0; i < arguments.length; i++) + { + result = result + sep + arguments[i].getClass().getName(); + sep = ", "; + } + result = result + ")"; + return result; + } +} diff --git a/libjava/classpath/java/beans/TODO b/libjava/classpath/java/beans/TODO new file mode 100644 index 0000000..08e1d25 --- /dev/null +++ b/libjava/classpath/java/beans/TODO @@ -0,0 +1,4 @@ +- add AppletStub and AppletContext to java.beans.Beans.instantiate(). +- make Introspector more efficient. +- basic Introspection tests are in, but more tests are probably in order. +- 1.2 support (waiting on java.lang.Package, mainly) diff --git a/libjava/classpath/java/beans/VetoableChangeListener.java b/libjava/classpath/java/beans/VetoableChangeListener.java new file mode 100644 index 0000000..5107954 --- /dev/null +++ b/libjava/classpath/java/beans/VetoableChangeListener.java @@ -0,0 +1,73 @@ +/* VetoableChangeListener.java -- listen for a change which can be vetoed + 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 java.beans; + +import java.util.EventListener; + +/** + * VetoableChangeListener allows a class to monitor proposed changes to + * properties of a Bean and, if desired, prevent them from occurring. A + * vetoableChange() event will be fired after the property change has + * been requested, but before it is permanent. If any listener rejects the + * change by throwing the PropertyChangeException, a new vetoableChange() + * event will be fired to all listeners who received a vetoableChange() event + * in the first place, informing them to revert back to the old value. Thus, + * the listener that threw the exception the first time should be prepared + * to rethrow it the second time. The value, of course, never actually changed. + * + *

    Note: This class may not be reliably used to determine + * whether a property has actually changed. Use the PropertyChangeListener + * interface for that instead. + * + * @author John Keiser + * @see java.beans.PropertyChangeListener + * @see java.beans.VetoableChangeSupport + * @since 1.1 + * @status updated to 1.4 + */ +public interface VetoableChangeListener extends EventListener +{ + /** + * Fired before a Bean's property changes. + * + * @param e the change (containing the old and new values) + * @throws PropertyVetoException if the change is vetoed by the listener + */ + void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException; +} // interface VetoableChangeListener diff --git a/libjava/classpath/java/beans/VetoableChangeListenerProxy.java b/libjava/classpath/java/beans/VetoableChangeListenerProxy.java new file mode 100644 index 0000000..56ca5a3 --- /dev/null +++ b/libjava/classpath/java/beans/VetoableChangeListenerProxy.java @@ -0,0 +1,102 @@ +/* VetoableChangeListenerProxy.java -- adds a name to a vetoable listener + 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 java.beans; + +import java.util.EventListenerProxy; + +/** + * This class provides an extension to VetoableChangeListener - + * associating a name with the listener. This can be used to filter the + * changes that one is interested in. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status udpated to 1.4 + */ +public class VetoableChangeListenerProxy extends EventListenerProxy + implements VetoableChangeListener +{ + /** + * The name of the property to listen for. Package visible for use by + * VetoableChangeSupport. + */ + final String propertyName; + + /** + * Create a new proxy which filters property change events and only passes + * changes to the named property on to the delegate. + * + * @param propertyName the property's name to filter on + * @param listener the delegate listener + */ + public VetoableChangeListenerProxy(String propertyName, + VetoableChangeListener listener) + { + super(listener); + this.propertyName = propertyName; + } + + /** + * Forwards the event on to the delegate if the property name matches. + * + * @param event the event to pass on, if it meets the filter + * @throws NullPointerException if the delegate this was created with is null + * @throws PropertyVetoException if the change is vetoed by the listener + */ + public void vetoableChange(PropertyChangeEvent event) + throws PropertyVetoException + { + // Note: Sun does not filter, under the assumption that since + // VetoableChangeSupport unwraps proxys, this method should never be + // called by normal use of listeners. + String name = event == null ? null : event.getPropertyName(); + if (name == null ? propertyName == null : name.equals(propertyName)) + ((VetoableChangeListener) getListener()).vetoableChange(event); + } + + /** + * Gets the name of the property this proxy is filtering on. + * + * @return the property name + */ + public String getPropertyName() + { + return propertyName; + } +} // class VetoableChangeListenerProxy diff --git a/libjava/classpath/java/beans/VetoableChangeSupport.java b/libjava/classpath/java/beans/VetoableChangeSupport.java new file mode 100644 index 0000000..dce8dff --- /dev/null +++ b/libjava/classpath/java/beans/VetoableChangeSupport.java @@ -0,0 +1,530 @@ +/* VetoableChangeSupport.java -- support to manage vetoable change listeners + Copyright (C) 1998, 1999, 2000, 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 java.beans; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Vector; + +/** + * VetoableChangeSupport makes it easy to fire vetoable change events and + * handle listeners. It allows chaining of listeners, as well as filtering + * by property name. In addition, it will serialize only those listeners + * which are serializable, ignoring the others without problem. This class + * is thread-safe. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public class VetoableChangeSupport implements Serializable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -5090210921595982017L; + + /** + * Maps property names (String) to named listeners (VetoableChangeSupport). + * If this is a child instance, this field will be null. + * + * @serial the map of property names to named listener managers + * @since 1.2 + */ + private Hashtable children; + + /** + * The non-null source object for any generated events. + * + * @serial the event source + */ + private final Object source; + + /** + * A field to compare serialization versions - this class uses version 2. + * + * @serial the serialization format + */ + private static final int vetoableChangeSupportSerializedDataVersion = 2; + + /** + * The list of all registered vetoable listeners. If this instance was + * created by user code, this only holds the global listeners (ie. not tied + * to a name), and may be null. If it was created by this class, as a + * helper for named properties, then this vector will be non-null, and this + * instance appears as a value in the children hashtable of + * another instance, so that the listeners are tied to the key of that + * hashtable entry. + */ + private transient Vector listeners; + + /** + * Create a VetoableChangeSupport to work with a specific source bean. + * + * @param source the source bean to use + * @throws NullPointerException if source is null + */ + public VetoableChangeSupport(Object source) + { + this.source = source; + if (source == null) + throw new NullPointerException(); + } + + /** + * Adds a VetoableChangeListener to the list of global listeners. All + * vetoable change events will be sent to this listener. The listener add + * is not unique: that is, n adds with the same listener will + * result in n events being sent to that listener for every + * vetoable change. Adding a null listener may cause a NullPointerException + * down the road. This method will unwrap a VetoableChangeListenerProxy, + * registering the underlying delegate to the named property list. + * + * @param l the listener to add + */ + public synchronized void addVetoableChangeListener(VetoableChangeListener l) + { + if (l instanceof VetoableChangeListenerProxy) + { + VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l; + addVetoableChangeListener(p.propertyName, + (VetoableChangeListener) p.getListener()); + } + else + { + if (listeners == null) + listeners = new Vector(); + listeners.add(l); + } + } + + /** + * Removes a VetoableChangeListener from the list of global listeners. If + * any specific properties are being listened on, they must be deregistered + * by themselves; this will only remove the general listener to all + * properties. If add() has been called multiple times for a + * particular listener, remove() will have to be called the + * same number of times to deregister it. This method will unwrap a + * VetoableChangeListenerProxy, removing the underlying delegate from the + * named property list. + * + * @param l the listener to remove + */ + public synchronized void + removeVetoableChangeListener(VetoableChangeListener l) + { + if (l instanceof VetoableChangeListenerProxy) + { + VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l; + removeVetoableChangeListener(p.propertyName, + (VetoableChangeListener) p.getListener()); + } + else if (listeners != null) + { + listeners.remove(l); + if (listeners.isEmpty()) + listeners = null; + } + } + + /** + * Returns an array of all registered vetoable change listeners. Those that + * were registered under a name will be wrapped in a + * VetoableChangeListenerProxy, so you must check whether the + * listener is an instance of the proxy class in order to see what name the + * real listener is registered under. If there are no registered listeners, + * this returns an empty array. + * + * @return the array of registered listeners + * @see VetoableChangeListenerProxy + * @since 1.4 + */ + public synchronized VetoableChangeListener[] getVetoableChangeListeners() + { + ArrayList list = new ArrayList(); + if (listeners != null) + list.addAll(listeners); + if (children != null) + { + int i = children.size(); + Iterator iter = children.entrySet().iterator(); + while (--i >= 0) + { + Entry e = (Entry) iter.next(); + String name = (String) e.getKey(); + Vector v = ((VetoableChangeSupport) e.getValue()).listeners; + int j = v.size(); + while (--j >= 0) + list.add(new VetoableChangeListenerProxy + (name, (VetoableChangeListener) v.get(j))); + } + } + return (VetoableChangeListener[]) + list.toArray(new VetoableChangeListener[list.size()]); + } + + /** + * Adds a VetoableChangeListener listening on the specified property. Events + * will be sent to the listener only if the property name matches. The + * listener add is not unique; that is, n adds on a particular + * property for a particular listener will result in n events + * being sent to that listener when that property is changed. The effect is + * cumulative, too; if you are registered to listen to receive events on + * all vetoable changes, and then you register on a particular property, + * you will receive change events for that property twice. Adding a null + * listener may cause a NullPointerException down the road. This method + * will unwrap a VetoableChangeListenerProxy, registering the underlying + * delegate to the named property list if the names match, and discarding + * it otherwise. + * + * @param propertyName the name of the property to listen on + * @param l the listener to add + * @throws NullPointerException if propertyName is null + */ + public synchronized void addVetoableChangeListener(String propertyName, + VetoableChangeListener l) + { + while (l instanceof VetoableChangeListenerProxy) + { + VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l; + if (propertyName == null ? p.propertyName != null + : ! propertyName.equals(p.propertyName)) + return; + l = (VetoableChangeListener) p.getListener(); + } + VetoableChangeSupport s = null; + if (children == null) + children = new Hashtable(); + else + s = (VetoableChangeSupport) children.get(propertyName); + if (s == null) + { + s = new VetoableChangeSupport(source); + s.listeners = new Vector(); + children.put(propertyName, s); + } + s.listeners.add(l); + } + + /** + * Removes a VetoableChangeListener from listening to a specific property. + * If add() has been called multiple times for a particular + * listener on a property, remove() will have to be called the + * same number of times to deregister it. This method will unwrap a + * VetoableChangeListenerProxy, removing the underlying delegate from the + * named property list if the names match. + * + * @param propertyName the property to stop listening on + * @param l the listener to remove + * @throws NullPointerException if propertyName is null + */ + public synchronized void + removeVetoableChangeListener(String propertyName, VetoableChangeListener l) + { + if (children == null) + return; + VetoableChangeSupport s + = (VetoableChangeSupport) children.get(propertyName); + if (s == null) + return; + while (l instanceof VetoableChangeListenerProxy) + { + VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l; + if (propertyName == null ? p.propertyName != null + : ! propertyName.equals(p.propertyName)) + return; + l = (VetoableChangeListener) p.getListener(); + } + s.listeners.remove(l); + if (s.listeners.isEmpty()) + { + children.remove(propertyName); + if (children.isEmpty()) + children = null; + } + } + + /** + * Returns an array of all vetoable change listeners registered under the + * given property name. If there are no registered listeners, this returns + * an empty array. + * + * @return the array of registered listeners + * @throws NullPointerException if propertyName is null + * @since 1.4 + */ + public synchronized VetoableChangeListener[] + getVetoableChangeListeners(String propertyName) + { + if (children == null) + return new VetoableChangeListener[0]; + VetoableChangeSupport s + = (VetoableChangeSupport) children.get(propertyName); + if (s == null) + return new VetoableChangeListener[0]; + return (VetoableChangeListener[]) + s.listeners.toArray(new VetoableChangeListener[s.listeners.size()]); + } + + /** + * Fire a PropertyChangeEvent containing the old and new values of the + * property to all the global listeners, and to all the listeners for the + * specified property name. This does nothing if old and new are non-null + * and equal. If the change is vetoed, a new event is fired to notify + * listeners about the rollback before the exception is thrown. + * + * @param propertyName the name of the property that changed + * @param oldVal the old value + * @param newVal the new value + * @throws PropertyVetoException if the change is vetoed by a listener + */ + public void fireVetoableChange(String propertyName, + Object oldVal, Object newVal) + throws PropertyVetoException + { + fireVetoableChange(new PropertyChangeEvent(source, propertyName, + oldVal, newVal)); + } + + /** + * Fire a PropertyChangeEvent containing the old and new values of the + * property to all the global listeners, and to all the listeners for the + * specified property name. This does nothing if old and new are equal. + * If the change is vetoed, a new event is fired to notify listeners about + * the rollback before the exception is thrown. + * + * @param propertyName the name of the property that changed + * @param oldVal the old value + * @param newVal the new value + * @throws PropertyVetoException if the change is vetoed by a listener + */ + public void fireVetoableChange(String propertyName, int oldVal, int newVal) + throws PropertyVetoException + { + if (oldVal != newVal) + fireVetoableChange(new PropertyChangeEvent(source, propertyName, + new Integer(oldVal), + new Integer(newVal))); + } + + /** + * Fire a PropertyChangeEvent containing the old and new values of the + * property to all the global listeners, and to all the listeners for the + * specified property name. This does nothing if old and new are equal. + * If the change is vetoed, a new event is fired to notify listeners about + * the rollback before the exception is thrown. + * + * @param propertyName the name of the property that changed + * @param oldVal the old value + * @param newVal the new value + * @throws PropertyVetoException if the change is vetoed by a listener + */ + public void fireVetoableChange(String propertyName, + boolean oldVal, boolean newVal) + throws PropertyVetoException + { + if (oldVal != newVal) + fireVetoableChange(new PropertyChangeEvent(source, propertyName, + Boolean.valueOf(oldVal), + Boolean.valueOf(newVal))); + } + + /** + * Fire a PropertyChangeEvent to all the global listeners, and to all the + * listeners for the specified property name. This does nothing if old and + * new values of the event are equal. If the change is vetoed, a new event + * is fired to notify listeners about the rollback before the exception is + * thrown. + * + * @param event the event to fire + * @throws NullPointerException if event is null + * @throws PropertyVetoException if the change is vetoed by a listener + */ + public void fireVetoableChange(PropertyChangeEvent event) + throws PropertyVetoException + { + if (event.oldValue != null && event.oldValue.equals(event.newValue)) + return; + Vector v = listeners; // Be thread-safe. + if (v != null) + { + int i = v.size(); + try + { + while (--i >= 0) + ((VetoableChangeListener) v.get(i)).vetoableChange(event); + } + catch (PropertyVetoException e) + { + event = event.rollback(); + int limit = i; + i = v.size(); + while (--i >= limit) + ((VetoableChangeListener) v.get(i)).vetoableChange(event); + throw e; + } + } + Hashtable h = children; // Be thread-safe. + if (h != null && event.propertyName != null) + { + VetoableChangeSupport s + = (VetoableChangeSupport) h.get(event.propertyName); + if (s != null) + { + Vector v1 = s.listeners; // Be thread-safe. + int i = v1 == null ? 0 : v1.size(); + try + { + while (--i >= 0) + ((VetoableChangeListener) v1.get(i)).vetoableChange(event); + } + catch (PropertyVetoException e) + { + event = event.rollback(); + int limit = i; + i = v.size(); + while (--i >= 0) + ((VetoableChangeListener) v.get(i)).vetoableChange(event); + i = v1.size(); + while (--i >= limit) + ((VetoableChangeListener) v1.get(i)).vetoableChange(event); + throw e; + } + } + } + } + + /** + * Tell whether the specified property is being listened on or not. This + * will only return true if there are listeners on all + * properties or if there is a listener specifically on this property. + * + * @param propertyName the property that may be listened on + * @return whether the property is being listened on + * @throws NullPointerException if propertyName is null + */ + public synchronized boolean hasListeners(String propertyName) + { + return listeners != null || (children != null + && children.get(propertyName) != null); + } + + /** + * Saves the state of the object to the stream. + * + * @param s the stream to write to + * @throws IOException if anything goes wrong + * @serialData this writes out a null-terminated list of serializable + * global vetoable change listeners (the listeners for a named + * property are written out as the global listeners of the + * children, when the children hashtable is saved) + */ + private synchronized void writeObject(ObjectOutputStream s) + throws IOException + { + s.defaultWriteObject(); + if (listeners != null) + { + int i = listeners.size(); + while (--i >= 0) + if (listeners.get(i) instanceof Serializable) + s.writeObject(listeners.get(i)); + } + s.writeObject(null); + } + + /** + * Reads the object back from stream (deserialization). + * + * XXX Since serialization for 1.1 streams was not documented, this may + * not work if vetoableChangeSupportSerializedDataVersion is 1. + * + * @param s the stream to read from + * @throws IOException if reading the stream fails + * @throws ClassNotFoundException if deserialization fails + * @serialData this reads in a null-terminated list of serializable + * global vetoable change listeners (the listeners for a named + * property are written out as the global listeners of the + * children, when the children hashtable is saved) + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + VetoableChangeListener l = (VetoableChangeListener) s.readObject(); + while (l != null) + { + addVetoableChangeListener(l); + l = (VetoableChangeListener) s.readObject(); + } + // Sun is not as careful with children as we are, and lets some proxys + // in that can never receive events. So, we clean up anything that got + // serialized, to make sure our invariants hold. + if (children != null) + { + int i = children.size(); + Iterator iter = children.entrySet().iterator(); + while (--i >= 0) + { + Entry e = (Entry) iter.next(); + String name = (String) e.getKey(); + VetoableChangeSupport vcs = (VetoableChangeSupport) e.getValue(); + if (vcs.listeners == null) + vcs.listeners = new Vector(); + if (vcs.children != null) + vcs.listeners.addAll + (Arrays.asList(vcs.getVetoableChangeListeners(name))); + if (vcs.listeners.size() == 0) + iter.remove(); + else + vcs.children = null; + } + if (children.size() == 0) + children = null; + } + } +} // class VetoableChangeSupport diff --git a/libjava/classpath/java/beans/Visibility.java b/libjava/classpath/java/beans/Visibility.java new file mode 100644 index 0000000..428f3a2 --- /dev/null +++ b/libjava/classpath/java/beans/Visibility.java @@ -0,0 +1,85 @@ +/* java.beans.Visibility + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.beans; + +/** + * Visibility is an interface a Bean may implement so that the environment + * can tell the Bean whether there is a GUI or not, and so that the Bean + * can tell the environment whether it needs one or can run without one. + *

    + * + * Sun decided not to use standard Introspection patterns so that these + * methods did not get included when the Introspector made its sweep on + * the class. + * + * @author John Keiser + * @since JDK1.1 + * @version 1.1.0, 29 Jul 1998 + */ + +public interface Visibility { + /** + * Tells whether the Bean can run without a GUI or not. + * @return false if Bean can run without a GUI, else true. + */ + boolean needsGui(); + + /** + * Tells whether Bean is trying not to use the GUI. + * If needsGui() is true, this method should always return false. + * @return true if definitely not using GUI, otherwise false. + */ + boolean avoidingGui(); + + /** + * Tells the Bean not to use GUI methods. + * If needsGUI() is false, then after this method is called, + * avoidingGui() should return true. + */ + void dontUseGui(); + + /** + * Tells the Bean it may use the GUI. + * The Bean is not required to use the GUI in this case, it is + * merely being permitted to use it. If needsGui() is + * false, avoidingGui() may return true or false after this method + * is called. + */ + void okToUseGui(); +} diff --git a/libjava/classpath/java/beans/XMLDecoder.java b/libjava/classpath/java/beans/XMLDecoder.java new file mode 100644 index 0000000..238fd6b --- /dev/null +++ b/libjava/classpath/java/beans/XMLDecoder.java @@ -0,0 +1,307 @@ +/* java.beans.XMLDecoder -- + 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 java.beans; + +import gnu.java.beans.decoder.DefaultExceptionListener; +import gnu.java.beans.decoder.PersistenceParser; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * The XMLDecoder reads XML data that is structured according to + * this DTD + * and creates objects according to the content. Usually such data is generated using the + * {@link XMLEncoder} class. + *

    + * An example XML document might look like this: + * + * <java> + * <string>Hello World</string> + * <int>200</int> + * </java> + * + *

    To read the String and the Integer instance the following can be used (assume + * the XML data can be obtained from the InputStream):

    + * + * XMLDecoder decoder = new XMLDecoder(inputStreamContainingXMLData); + * String message = (String) decoder.readObject(); + * Integer number = (Integer) decoder.readObject(); + * + *

    Besides this basic functionality the XMLDecoder has some more features that might come + * handy in certain situations:

    + *

    An owner object can be set using the setOwner method which can then be accessed when + * decoding. This feature is only useful if the XML data is aware of the owner object. Such data may + * look like this (assume that the owner object is a JFrame instance):

    + * + * <java> + * <void method="getOwner"> + * <void method="setVisible"> + * <boolean>true<boolean> + * </void> + * </void> + * </java> + * + * This accesses the JFrame and makes it visible using the setVisible method. + *

    Please note that changing the owner after the having read the first object has no effect, + * because all object have been decoded then.

    + *

    If the XMLDecoder is created with no {@link ExceptionListener} instance a default one + * is used that prints an error message to System.err whenever a recoverable exception + * is thrown. Recovarable exceptions occur when the XML data cannot be interpreted correctly (e.g + * unknown classes or methods, invocation on null, ...). In general be very careful when the + * XMLDecoder provoked such exceptions because the resulting object(s) may be in an + * undesirable state.

    + *

    Note that changing the ExceptionListener instance after readObject has been called + * once has no effect because the decoding is completed then.

    + *

    At last one can provide a specific ClassLoader which is then used when Class + * objects are accessed. See {@link java.lang.Class#forName(String, boolean, ClassLoader)} for details + * on this.

    + *

    Note: If the InputStream instance given to any of the constructors is null + * the resulting XMLDecoder will be silently (without any exception) useless. Each call + * to readObject will return null and never throws an + * ArrayIndexOutOfBoundsException.

    + * + * @author Robert Schuster + * @since 1.4 + * @status updated to 1.5 + */ +public class XMLDecoder +{ + private Object owner; + + private ExceptionListener exceptionListener; + + private InputStream inputStream; + + private boolean isStreamClosed; + + private ClassLoader classLoader; + + private Iterator iterator; + + /** Creates a XMLDecoder instance that parses the XML data of the given input stream. + * Using this constructor no special ClassLoader, a default ExceptionListener + * and no owner object is used. + * + * @param in InputStream to read XML data from. + */ + public XMLDecoder(InputStream in) + { + this(in, null); + } + + /** Creates a XMLDecoder instance that parses the XML data of the given input stream. + * Using this constructor no special ClassLoader and a default ExceptionListener + * is used. + * + * @param in InputStream to read XML data from. + * @param owner Owner object which can be accessed and modified while parsing. + */ + public XMLDecoder(InputStream in, Object owner) + { + this(in, owner, null); + } + + /** Creates a XMLDecoder instance that parses the XML data of the given input stream. + * If the ExceptionListener argument is null a default implementation is used. + * + * @param in InputStream to read XML data from. + * @param owner Owner object which can be accessed and modified while parsing. + * @param exceptionListener ExceptionListener instance to which exception notifications are send. + */ + public XMLDecoder( + InputStream in, + Object owner, + ExceptionListener exceptionListener) + { + this( + in, + owner, + exceptionListener, + Thread.currentThread().getContextClassLoader()); + } + + /** Creates a XMLDecoder instance that parses the XML data of the given input stream. + * If the ExceptionListener argument is null a default implementation is used. + * + * @param in InputStream to read XML data from. + * @param owner Owner object which can be accessed and modified while parsing. + * @param exceptionListener ExceptionListener instance to which exception notifications are send. + * @param cl ClassLoader instance that is used for calls to Class.forName(String, boolean, ClassLoader) + * @since 1.5 + */ + public XMLDecoder( + InputStream in, + Object owner, + ExceptionListener listener, + ClassLoader cl) + { + // initially here was a check for the validity of the InputStream argument but some + // great engineers decided that this API should silently discard this and behave rather + // odd: readObject will always return null ... + inputStream = in; + + setExceptionListener(listener); + + // validity of this object is checked in Class.forName() and therefore may be null + classLoader = cl; + + this.owner = owner; + } + + /** Closes the stream associated with this decoder. This should be done after having read all + * decoded objects. + *

    See the description of the {@link #readObject()} for the effect caused by close.

    + */ + public void close() + { + if (isStreamClosed) + { + return; + } + + try + { + inputStream.close(); + isStreamClosed = true; + } + catch (IOException e) + { + // bad style forced by original API design ... + } + } + + /** Returns the ExceptionListener instance associated with this decoder. + *

    See the description of {@link XMLDecoder} class for more information on the ExceptionListener.

    + * + * @return Current ExceptionListener of the decoder. + */ + public ExceptionListener getExceptionListener() + { + return exceptionListener; + } + + /** Returns the owner object of the decoder. This method is usually called + * from within the parsed XML data. + *

    See the description of {@link XMLDecoder} class for more information on the owner object.

    + * + * @return The owner object of this decoder. + */ + public Object getOwner() + { + return owner; + } + + /** Returns the next available decoded object. + *

    Note that the actual decoding takes place when the method is called for the first time.

    + *

    If the close method was already called a NoSuchElementException + * is thrown.

    + *

    If the InputStream instance used in the constructors was null this method + * will always return null itself.

    + * + * @return The next object in a sequence decoded from XML data. + * @throws ArrayIndexOutOfBoundsException When no more objects are available. + */ + public Object readObject() throws ArrayIndexOutOfBoundsException + { + // note: the RI does it this way ... + if(inputStream == null) { + return null; + } + + // note: the original API documentation says nothing on what to do + // when the stream was closed before readObject is called but it actually + // throws a NoSuchElementException - this behaviour is imitated here + if (isStreamClosed) + { + throw new NoSuchElementException("Cannot read any objects - XMLDecoder was already closed."); + } + + // creates the PersistenceParser (doing the parsing and decoding) and returns its + // Iterator on first invocation + if (iterator == null) + { + iterator = + new PersistenceParser( + inputStream, + exceptionListener, + classLoader, + this) + .iterator(); + } + + // note: done according to the official documentation + if (!iterator.hasNext()) + { + throw new ArrayIndexOutOfBoundsException("No more objects available from this XMLDecoder."); + } + + // returns just the next object if there was no problem + return iterator.next(); + } + + /** Sets the ExceptionListener instance to which notifications of exceptions are send + * while parsing the XML data. + *

    See the description of {@link XMLDecoder} class for more information on the ExceptionListener.

    + * + * @param listener + */ + public void setExceptionListener(ExceptionListener listener) + { + // uses a default implementation when null + if (listener == null) + { + listener = new DefaultExceptionListener(); + } + exceptionListener = listener; + } + + /** Sets the owner object which can be accessed from the parsed XML data. + *

    See the description of {@link XMLDecoder} class for more information on the owner object.

    + * + * @param newOwner + */ + public void setOwner(Object newOwner) + { + owner = newOwner; + } + +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContext.java b/libjava/classpath/java/beans/beancontext/BeanContext.java new file mode 100644 index 0000000..3d1be7f --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContext.java @@ -0,0 +1,272 @@ +/* java.beans.beancontext.BeanContext + Copyright (C) 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 java.beans.beancontext; + +import java.beans.DesignMode; +import java.beans.Visibility; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Collection; + +/** + * Acts as a container for sub-beans and as a sub-bean, + * so that an entire hierarchy of beans can be made up of + * BeanContexts. + *

    + * + * Since I can't sprinkle the Collections interface + * documentation with special information for BeanContext + * implementors, I'll have to document special requirements for + * implementors of those functions here. + *

    + * + * add() or addAll(): + *
    + *

      + *
    1. + * May add any Object into the hierarchy as well as a + * BeanContextChild, BeanContext or + * BeanContextProxy object. + * This way, any Bean can be in the hierarchy. + *
    2. + *
    3. + * Must synchronize on BeanContext.globalHierarchyLock. + *
    4. + *
    5. + * Don't add the Object if it's already there (only once + * per BeanContext). + *
    6. + *
    7. + * If it is a BeanContextChild implementor, call + * setBeanContext() on it. If it's a + * BeanContextProxy implementor, call + * getBeanContextProxy().setBeanContext() on it. + * If setBeanContext() vetoes the change, back out + * all changes so far and throw IllegalStateException. + *
    8. + *
    9. + * If it (or its proxy) implements Visibility, call + * dontUseGui() or okToUseGui() on it, + * depending on whether you (the BeanContext) feel like + * allowing it to use the GUI or not. + *
    10. + *
    11. + * If it implements BeanContextChild or + * BeanContextProxy, register yourself (the + * BeanContext) as both a + * PropertyChangeListener and + * VetoableChangeListener on the "beanContext" + * property (it may also add itself on any other properties it wishes + * to). + *
    12. + *
    13. + * If it is a listener or event source that you (the + * BeanContext) are interested in, you may register + * yourself to it or register it to you. + *
    14. + *
    15. + * Fire a java.beans.beancontext.BeanContextMembershipEvent + * before exiting. addAll() should wait until everything + * is done changing before firing the event (or events) so that if a + * failure occurs, the backing-out process can proceed without any + * events being fired at all. + *
    16. + *
    + *

    + * + * remove() or removeAll(): + *
    + *

      + *
    1. + * Must synchronize on BeanContext.globalHierarchyLock. + *
    2. + *
    3. + * If the specified Object is not a child of this + * BeanContext, just exit without performing any actions. + *
    4. + *
    5. + * Remove the Object from your collection of children. + *
    6. + *
    7. + * If it is a BeanContextChild implementor, call + * setBeanContext(null) on it. If it's a + * BeanContextProxy implementor, call + * getBeanContextProxy().setBeanContext(null) on it. + * If setBeanContext() vetoes the change, back out + * all changes so far and throw IllegalStateException. + *
    8. + *
    9. + * If you registered the Object to listen to you or + * registered yourself as a listener on the Object during + * add() or addAll(), undo the registration + * bycalling the appropriate removeListener() method. + *
    10. + *
    11. + * Fire a java.beans.beancontext.BeanContextMembershipEvent + * before exiting. removeAll() should wait until + * everything is done changing before firing the event (or events) so + * that if a failure occurs, the backing-out process can proceed + * without any events being fired at all. + *
    12. + *
    + *

    + * + * addAll(), removeAll(), + * retainAll() and clear() do not need to be + * implemented, but may be if so desired. + *

    + * + * Similarly, Visibility and DesignMode methods + * should propagate changed values to children that implement interfaces + * of the same name. + *

    + * + * A hierarchy of beans is mainly useful so that different sets of beans + * can be established, each with their own set of resources. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContext + extends Collection, BeanContextChild, Visibility, DesignMode { + + /** + * The global lock on changing any BeanContext hierarchy. + * It kinda sucks that there is only one lock, since there can be + * multiple hierarchies. Oh well, I didn't design, I just code. + *

    + * + * Methods that must (or do) synchronize on the global lock: + *
    + *

      + *
    • + * Implementors of BeanContext.add() and addAll() + *
    • + *
    + * @fixme fill in the rest of the methods which use the global lock. + */ + Object globalHierarchyLock = new Object(); + + /** + * Instantiate a Bean using this Bean's ClassLoader + * and this BeanContext as the parent. + *

    + * + * This method exists mainly so that BeanContext + * implementations can perform extra actions on Beans that are + * created within them. + * + * @param beanName the name of the bean to instantiate + * @return the created Bean + * + * @see java.beans.Beans#instantiate(java.lang.ClassLoader,java.lang.String) + * @see java.beans.Beans#instantiate(java.lang.ClassLoader,java.lang.String,java.lang.BeanContext) + * @exception IOException if there is an I/O problem during + * instantiation. + * @exception ClassNotFoundException if a serialized Bean's class + * is not found. + */ + Object instantiateChild(String beanName) + throws IOException, + ClassNotFoundException; + + /** + * Get a resource. The BeanContext will typically + * call ClassLoader.getResource(), but may do it any + * way it wants to. This allows a BeanContext to + * have its own set of resources separate from the rest of the + * system. + *

    + * + * Beans should call this method on their parent rather than the + * associated ClassLoader method. + *

    + * + * I am assuming, but am not entirely sure, that if a + * BeanContext cannot find a resource, its + * responsibility is to call the getResource method + * of its parent BeanContext. + * + * @return a URL to the requested resource. + * @param resourceName the name of the resource requested. + * @param requestor a reference to the child requesting the resource. + * @see java.lang.ClassLoader#getResource(java.lang.String) + */ + URL getResource(String resourceName, BeanContextChild requestor); + + /** + * Get a resource as a stream. The BeanContext will + * typically call ClassLoader.getResourceAsStream(), + * but may do it any way it wants to. This allows a + * BeanContext's children to have their own set of + * resources separate from the rest of the system. + *

    + * + * Beans should call this method on their parent rather than the + * associated ClassLoader method. + *

    + * + * I am assuming, but am not entirely sure, that if a + * BeanContext cannot find a resource, its + * responsibility is to call the getResourceAsStream + * method of its parent BeanContext. + * + * @return the requested resource as a stream. + * @param resourceName the name of the resource requested. + * @param requestor a reference to the child requesting the resource. + * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String) + */ + InputStream getResourceAsStream(String resourceName, BeanContextChild requestor); + + /** + * Add a listener on changes to the membership of this + * BeanContext object. + * @param listener the listener to add. + */ + void addBeanContextMembershipListener(BeanContextMembershipListener listener); + + /** + * Remove a listener on changes to the membership of this + * BeanContext object. + * @param listener the listener to remove. + */ + void removeBeanContextMembershipListener(BeanContextMembershipListener listener); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextChild.java b/libjava/classpath/java/beans/beancontext/BeanContextChild.java new file mode 100644 index 0000000..d1115ef --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextChild.java @@ -0,0 +1,174 @@ +/* java.beans.beancontext.BeanContextChild + Copyright (C) 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 java.beans.beancontext; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; + +/** + * Beans implement this to get information about the execution environment and + * its services and to be placed in the hierarchy. + *

    + * + * The difference between a BeanContext and a + * BeanContextChild, mainly, is that a + * BeanContext may be a parent. + *

    + * + * BeanContextChild instances will be serialized at some + * point in their life, but you need to make sure your bean context does + * not contain a serializable reference (directly or indirectly) to the + * parent BeanContext, to any of the other + * BeanContexts in the tree, or to any resources obtained + * via the BeanContextServices interface. One way to do this + * is to mark any fields that contain such references as + * transient. Another way is to use a custom serializer. + *

    + * + * If you do not do this, when the BeanContext is serialized, + * all the other BeanContexts and other unnecessary things + * will be serialized along with it. + *

    + * + * Before dying, a BeanContextChild should call + * getBeanContext().remove(this) to detach from the + * hierarchy and exit cleanly. + * + * @author John Keiser + * @since JDK1.2 + * @see java.beans.beancontext.BeanContext + */ + +public interface BeanContextChild { + /** + * Set the parent BeanContext. + *

    + * + * This method is called from BeanContext.add() and + * should not be called directly. + *

    + * + * When this Object is being added to a new BeanContext or moved + * from an old one, a non-null value will be passed in. + *

    + * + * When this Object is being removed from the current + * BeanContext, setBeanContext() will + * receive the parameter null. + *

    + * + * When being removed from the current BeanContext, + * it is the BeanContextChild's responsibility to + * release all services it has obtained. + *

    + * + * This change should generate PropertyChangeEvent + * and VetoableChangeEvents with the property name + * "beanContext". If the change is vetoed, it must re-throw the + * exception and not change anything. In this way, the parent + * BeanContextChild, who has registered himself with + * you, will have a chance to remove this child from its + * collection. + *

    + * + * If the Bean does not wish to change the parent or be removed + * from one, it may throw the PropertyVetoException. + * If you veto a setBeanContext(null) call, then you + * should try your hardest to remedy whatever problem is keeping + * you from being removed from the BeanContext so + * that you can not veto it the next time. + * Otherwise, nasty pathological recursion stuff could occur in + * certain situations. + *

    + * + * If you do veto the change, you must first back out any changes + * you made prior to the veto. Best not to make any such changes + * prior to the veto in the first place. + *

    + * + * This method is called from BeanContext.add() and + * should not be called directly. + * + * @param parent the new parent for the BeanContextChild, + * or null to signify removal from a tree. + * @exception PropertyVetoException if the + * BeanContextChild implementor does not + * wish to have its parent changed. + */ + void setBeanContext(BeanContext parent) + throws PropertyVetoException; + + /** + * Get the parent BeanContext. + * @return the parent BeanContext. + */ + BeanContext getBeanContext(); + + /** + * Add a listener that will be notified when a specific property changes. + * @param prop the name of the property to listen on + * @param listener the listener to listen on the property. + */ + void addPropertyChangeListener(String prop, PropertyChangeListener listener); + + /** + * Remove a listener to a certain property. + * @param prop the name of the property being listened on + * @param listener the listener listening on the property. + */ + void removePropertyChangeListener(String prop, PropertyChangeListener listener); + + /** + * Add a listener that will be notified when a specific property + * change is requested (a PropertyVetoException may be thrown) as + * well as after the change is successfully made. + * + * @param prop the name of the property to listen on + * @param listener the listener to listen on the property. + */ + void addVetoableChangeListener(String prop, VetoableChangeListener listener); + + /** + * Remove a listener to a certain property. + * @param prop the name of the property being listened on + * @param listener the listener listening on the property. + */ + void removeVetoableChangeListener(String prop, VetoableChangeListener listener); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextChildComponentProxy.java b/libjava/classpath/java/beans/beancontext/BeanContextChildComponentProxy.java new file mode 100644 index 0000000..a8d6e34 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextChildComponentProxy.java @@ -0,0 +1,60 @@ +/* java.beans.beancontext.BeanContextChildComponentProxy + Copyright (C) 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 java.beans.beancontext; + +import java.awt.Component; + +/** + * Interface for BeanContextChilds which wish to associate an + * AWT component with them. The proxy is provided because the + * addPropertyChangeListener() method would conflict with + * Component if you tried to extend. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextChildComponentProxy { + /** + * Get the Component associated with this BeanContextChild. + * @return the Component associated with this + * BeanContextChild. + */ + Component getComponent(); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextChildSupport.java b/libjava/classpath/java/beans/beancontext/BeanContextChildSupport.java new file mode 100644 index 0000000..4444ad7 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextChildSupport.java @@ -0,0 +1,381 @@ +/* java.beans.beancontext.BeanContextChildSupport + Copyright (C) 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 java.beans.beancontext; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.beans.VetoableChangeSupport; +import java.io.Serializable; + +/** + * Support for creating a BeanContextChild. + * This class contains the most common implementations of the methods in + * the BeanContextChild + * + * @specnote This class is not very well specified. I had to "fill in the + * blanks" in most places with what I thought was reasonable + * behavior. If there are problems, let me know. + * + * @author John Keiser + * @since 1.2 + * @see java.beans.beancontext.BeanContextChild + */ +public class BeanContextChildSupport + implements BeanContextChild, BeanContextServicesListener, Serializable +{ + static final long serialVersionUID = 6328947014421475877L; + + /** + * The peer on which to perform set actions. + * This is here so that this class can be used as a peer. + *

    + * + * When extending this class, this variable will be set to + * this. + */ + public BeanContextChild beanContextChildPeer; + + /** + * The parent BeanContext. + */ + protected transient BeanContext beanContext; + + /** + * If setBeanContext() was vetoed once before, this + * is set to true so that the next time, vetoes will + * be ignored. + */ + protected transient boolean rejectedSetBCOnce; + + /** + * Listeners are registered here and events are fired through here. + */ + protected PropertyChangeSupport pcSupport; + + /** + * Listeners are registered here and events are fired through here. + */ + protected VetoableChangeSupport vcSupport; + + /** + * Create a new BeanContextChildSupport with itself as the peer. + * This is meant to be used when you subclass + * BeanContextChildSupport to create your child. + */ + public BeanContextChildSupport() + { + this (null); + } + + /** + * Create a new BeanContextChildSupport with the specified peer. + * @param peer the peer to use, or null to specify + * this. + */ + public BeanContextChildSupport (BeanContextChild peer) + { + if (peer == null) + { + peer = this; + } + + beanContextChildPeer = peer; + pcSupport = new PropertyChangeSupport (peer); + vcSupport = new VetoableChangeSupport (peer); + } + + /** + * Set the parent BeanContext. + *

    + * + * When this Object is being added to a new BeanContext or moved + * from an old one, a non-null value will be passed in. + *

    + * + * When this Object is being removed from the current + * BeanContext, setBeanContext() will + * receive the parameter null. + *

    + * + * Order of events: + *

      + *
    1. + * If the new BeanContext is the same as the old + * one, nothing happens. + *
    2. + *
    3. + * If the change has not been rejected or vetoed before, call + * validatePendingSetBeanContext(). If this call + * returns false, the change is rejected and a + * PropertyVetoException is thrown. + *
    4. + *
    5. + * If the change has not been rejected or vetoed before, + * VetoableChangeEvents are fired with the name + * "beanContext", using the + * fireVetoableChange() method. If a veto + * occurs, reversion events are fired using the same method, + * the change is rejected, and the veto is rethrown. + *
    6. + *
    7. + * releaseBeanContextResources() is called. + *
    8. + *
    9. + * The change is made. + *
    10. + *
    11. + * PropertyChangeEvents are fired using the + * firePropertyChange() method. + *
    12. + *
    13. + * initializeBeanContextResources() is called. + *
    14. + *
    + *

    + * + * @param newBeanContext the new parent for the + * BeanContextChild, or null to + * signify removal from a tree. + * @exception PropertyVetoException if the + * BeanContextChild implementor does not + * wish to have its parent changed. + */ + public void setBeanContext(BeanContext newBeanContext) + throws PropertyVetoException + { + synchronized (beanContextChildPeer) + { + if (newBeanContext == beanContext) + return; + + if (!rejectedSetBCOnce) + { + if (!validatePendingSetBeanContext (newBeanContext)) + { + rejectedSetBCOnce = true; + throw new PropertyVetoException ("validatePendingSetBeanContext() rejected change", + new PropertyChangeEvent(beanContextChildPeer, "beanContext", beanContext, newBeanContext)); + } + + try + { + fireVetoableChange ("beanContext", beanContext, newBeanContext); + } + catch (PropertyVetoException e) + { + rejectedSetBCOnce = true; + throw e; + } + } + + releaseBeanContextResources (); + + beanContext = newBeanContext; + rejectedSetBCOnce = false; + + firePropertyChange ("beanContext", beanContext, newBeanContext); + + initializeBeanContextResources (); + } + } + + /** + * Get the parent BeanContext. + * @return the parent BeanContext. + */ + public BeanContext getBeanContext() + { + return beanContext; + } + + /** + * Get the peer (or this if there is no peer). + * @return the peer, or this if there is no peer. + */ + public BeanContextChild getBeanContextChildPeer() { + return beanContextChildPeer; + } + + /** + * Determine whether there is a peer. + * This is true iff getBeanContextChildPeer() == this. + * @return whether there is a peer. + */ + public boolean isDelegated() { + return beanContextChildPeer == this; + } + + /** + * Add a listener that will be notified when a specific property changes. + * @param propertyName the name of the property to listen on. + * @param listener the listener to listen on the property. + */ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcSupport.addPropertyChangeListener(propertyName, listener); + } + + /** + * Remove a listener to a certain property. + * + * @param propertyName the name of the property being listened on. + * @param listener the listener listening on the property. + */ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcSupport.removePropertyChangeListener(propertyName, listener); + } + + /** + * Add a listener that will be notified when a specific property + * change is requested (a PropertyVetoException may be thrown) as + * well as after the change is successfully made. + * + * @param propertyName the name of the property to listen on. + * @param listener the listener to listen on the property. + */ + public void addVetoableChangeListener(String propertyName, VetoableChangeListener listener) { + vcSupport.addVetoableChangeListener(propertyName, listener); + } + + /** + * Remove a listener to a certain property. + * + * @param propertyName the name of the property being listened on + * @param listener the listener listening on the property. + */ + public void removeVetoableChangeListener(String propertyName, VetoableChangeListener listener) { + vcSupport.removeVetoableChangeListener(propertyName, listener); + } + + /** + * Fire a property change. + * + * @param propertyName the name of the property that changed + * @param oldVal the old value of the property + * @param newVal the new value of the property + */ + public void firePropertyChange(String propertyName, Object oldVal, Object newVal) { + pcSupport.firePropertyChange(propertyName, oldVal, newVal); + } + + /** + * Fire a vetoable property change. + * + * @param propertyName the name of the property that changed + * @param oldVal the old value of the property + * @param newVal the new value of the property + * @exception PropertyVetoException if the change is vetoed. + */ + public void fireVetoableChange(String propertyName, Object oldVal, Object newVal) + throws PropertyVetoException { + vcSupport.fireVetoableChange(propertyName, oldVal, newVal); + } + + /** + * Called by BeanContextServices.revokeService() to indicate that a service has been revoked. + * If you have a reference to such a service, it should be + * discarded and may no longer function properly. + * getService() will no longer work on the specified + * service class after this event has been fired. + *

    + * + * This method is meant to be overriden. + * BeanContextChildSupport's implementation does + * nothing. + * + * @param event the service revoked event. + * @see java.beans.beancontext.BeanContextServices#revokeService(java.lang.Class,java.beans.beancontext.BeanContextServiceProvider,boolean) + */ + public void serviceRevoked(BeanContextServiceRevokedEvent event) { + } + + /** + * Called by BeanContextServices whenever a service is made available. + *

    + * + * This method is meant to be overriden. + * BeanContextChildSupport's implementation does + * nothing. + * + * @param event the service revoked event, with useful information + * about the new service. + */ + public void serviceAvailable(BeanContextServiceAvailableEvent event) { + } + + /** + * Called by setBeanContext() to determine whether the set should be rejected. + *

    + * + * This method is meant to be overriden. + * BeanContextChildSupport's implementation simply + * returns true. + * + * @param newBeanContext the new parent. + * @return whether to allow the parent to be changed to the new + * value. + */ + public boolean validatePendingSetBeanContext(BeanContext newBeanContext) { + return true; + } + + /** + * Called by setBeanContext() to release resources of a what will soon no longer be the parent. + *

    + * + * This method is meant to be overriden. + * BeanContextChildSupport's implementation does + * nothing. + */ + protected void releaseBeanContextResources() { + } + + /** + * Called by setBeanContext() to grab resources when the parent has been set. + *

    + * + * This method is meant to be overriden. + * BeanContextChildSupport's implementation does + * nothing. + */ + protected void initializeBeanContextResources() { + } +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextContainerProxy.java b/libjava/classpath/java/beans/beancontext/BeanContextContainerProxy.java new file mode 100644 index 0000000..3df9103 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextContainerProxy.java @@ -0,0 +1,63 @@ +/* java.beans.beancontext.BeanContextContainerProxy + Copyright (C) 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 java.beans.beancontext; + +import java.awt.Container; + +/** + * Interface for BeanContexts which wish to associate an + * AWT container with them. The proxy is provided because the + * addPropertyChangeListener() and add() methods + * would conflict with Component and Container + * if you tried to extend. + * + * @specnote It is unclear whether anything besides BeanContexts + * are allowed to implement this interface. + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextContainerProxy { + /** + * Get the Container associated with this BeanContext. + * @return the Container associated with this + * BeanContext. + */ + Container getContainer(); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextEvent.java b/libjava/classpath/java/beans/beancontext/BeanContextEvent.java new file mode 100644 index 0000000..f326541 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextEvent.java @@ -0,0 +1,110 @@ +/* java.beans.beancontext.BeanContextEvent + Copyright (C) 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 java.beans.beancontext; + +import java.util.EventObject; + +/** + * Generic superclass for events fired by BeanContexts. + * + * @author John Keiser + * @since 1.2 + */ + +public abstract class BeanContextEvent extends EventObject +{ + private static final long serialVersionUID = 7267998073569045052L; + + /** + * The BeanContext that most recently passed this + * event on. + */ + protected BeanContext propagatedFrom; + + /** + * Create a new event, from the specified BeanContext. + * propagatedFrom will be initialized to + * null. + * + * @param source the source of the event. + */ + protected BeanContextEvent(BeanContext source) + { + super(source); + } + + /** + * Get the BeanContext that originated this event. + * @return the originator of this event. + */ + public BeanContext getBeanContext() + { + return (BeanContext)getSource(); + } + + /** + * Get the most recent propagator of this event. + * If this value is null, you have received the event + * straight from the source. + * + * @return the most recent propagator of this event. + */ + public BeanContext getPropagatedFrom() + { + return propagatedFrom; + } + + /** + * Tell whether this event has been propagated. + * @return true iff getPropagatedFrom() != null. + */ + public boolean isPropagated() + { + return propagatedFrom != null; + } + + /** + * Set the most recent propagator of this event. + * @param propagator the most recent propagator of this event. + */ + public void setPropagatedFrom(BeanContext propagator) + { + propagatedFrom = propagator; + } +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java b/libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java new file mode 100644 index 0000000..3176542 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextMembershipEvent.java @@ -0,0 +1,112 @@ +/* java.beans.beancontext.BeanContextMembershipEvent + 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 java.beans.beancontext; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; + +/** + * Event fired when children are added to or removed from a BeanContext. + * Whether they were added or removed depends entirely on which method + * of the listener interface was called. + * + * @author John Keiser + * @since 1.2 + * @see java.beans.beancontext.BeanContextMembershipListener + */ +public class BeanContextMembershipEvent extends BeanContextEvent { + /** + * The children that were added or removed. + */ + protected Collection children; + + /** + * Create a new membership event. + * @param context the event source. + * @param children the children added to or removed from the source. + */ + public BeanContextMembershipEvent(BeanContext context, Collection children) { + super(context); + this.children = children; + } + + /** + * Create a new membership event. + * @param context the event source. + * @param children the children added to or removed from the source. + */ + public BeanContextMembershipEvent(BeanContext context, Object[] children) { + super(context); + this.children = Arrays.asList(children); + } + + /** + * The number of children removed or added. + * @return the number of children removed or added. + */ + public int size() { + return children.size(); + } + + /** + * An iterator that will step through all the children. + * @return an iterator over all the children. + */ + public Iterator iterator() { + return children.iterator(); + } + + /** + * An array of the children. + * @return an array of the children. + */ + public Object[] toArray() { + return children.toArray(); + } + + /** + * Tell whether the Object is one of the children added or removed. + * @param child the child to check. + * @return whether the Object is added or removed. + */ + public boolean contains(Object child) { + return children.contains(child); + } +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextMembershipListener.java b/libjava/classpath/java/beans/beancontext/BeanContextMembershipListener.java new file mode 100644 index 0000000..d39c36c --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextMembershipListener.java @@ -0,0 +1,70 @@ +/* java.beans.beancontext.BeanContextMembershipListener + Copyright (C) 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 java.beans.beancontext; + +import java.util.EventListener; + +/** + * This is the interface to which BeanContextMembershipEvents are sent. + * This happens when children are added to or removed from a + * BeanContext. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextMembershipListener extends EventListener { + /** + * When beans are added to a BeanContext, + * this method is called to fire the event. + * + * @param event the event, including which children were added. + * @see java.beans.beancontext.BeanContext#add(java.lang.Object) + */ + void childrenAdded(BeanContextMembershipEvent event); + + /** + * When beans are removed from a BeanContext, + * this method is called to fire the event. + * + * @param event the event, including which children were removed. + * @see java.beans.beancontext.BeanContext#remove(java.lang.Object) + */ + void childrenRemoved(BeanContextMembershipEvent event); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextProxy.java b/libjava/classpath/java/beans/beancontext/BeanContextProxy.java new file mode 100644 index 0000000..49dd7a7 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextProxy.java @@ -0,0 +1,65 @@ +/* java.beans.beancontext.BeanContextProxy + Copyright (C) 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 java.beans.beancontext; + +/** + * Beans that wish to have a BeanContextChild or BeanContext associated with them + * but do not wish to implement those interfaces directly, can implement this interface. + *

    + * + * Don't shoot yourself in the foot: if you already implement + * BeanContextChild, directly or indirectly, the whole + * workings of this package will be unpredictable because it is + * indeterminate as to whether the BeanContextChild is used + * in preference to its proxy or vice versa. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextProxy { + /** + * Return the BeanContextChild associated with this + * Object. + * + * @return the BeanContextChild associated with this + * Object. + */ + BeanContextChild getBeanContextProxy(); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java new file mode 100644 index 0000000..eea10f2 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceAvailableEvent.java @@ -0,0 +1,95 @@ +/* java.beans.beancontext.BeanContextServiceAvailableEvent + Copyright (C) 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 java.beans.beancontext; + +import java.util.Iterator; + +/** + * Event fired when new services become available through a BeanContextServices. + * + * @author John Keiser + * @since JDK1.2 + * @see java.beans.beancontext.BeanContextServicesListener + */ + +public class BeanContextServiceAvailableEvent extends BeanContextEvent { + /** + * The Class representing the service which is now + * available. + */ + protected Class serviceClass; + + /** + * Create a new service available event. + * @param services the BeanContextServices through + * which the service is available. This is also the source + * of the event. + * @param serviceClass the service class that is now available. + */ + public BeanContextServiceAvailableEvent(BeanContextServices services, Class serviceClass) { + super(services); + this.serviceClass = serviceClass; + } + + /** + * Get the current service selectors of the service class. + * This is identical to getSourceAsBeanContextServices().getCurrentServiceSelectors(getServiceClass()) + * @return the current service selectors of the service class. + */ + public Iterator getCurrentServiceSelectors() { + return getSourceAsBeanContextServices().getCurrentServiceSelectors(serviceClass); + } + + /** + * Get the newly available service class. + * @return the service class. + */ + public Class getServiceClass() { + return serviceClass; + } + + /** + * Get the BeanContextServices through which the new service is available. + * @return the BeanContextServices through which the + * new service is available. + */ + public BeanContextServices getSourceAsBeanContextServices() { + return (BeanContextServices)getSource(); + } +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceProvider.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceProvider.java new file mode 100644 index 0000000..c09b581 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceProvider.java @@ -0,0 +1,138 @@ +/* java.beans.beancontext.BeanContextServiceProvider + Copyright (C) 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 java.beans.beancontext; + +import java.util.Iterator; + +/** + * An actual factory for services. + *

    + * + * It is the BeanContextServiceProvider's responsibility to + * register itself with whatever BeanContextServices object + * it wishes to provide services through using the + * addService() method. + *

    + * + * If for some reason it can no longer provide services for a particular + * class, this class must invoke + * BeanContextServices.revokeService(serviceClass,this,true) + * for all the places it has registered the service. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextServiceProvider { + /** + * Get a service. + * Called from BeanContextServices.getService(). + * + *

    If the requested service class is not available, or if this + * BeanContextServiceProvider chooses not honor the + * request for some reason, then this method will return + * null.

    + * + * This method may throw unchecked exceptions, so watch out. + * + * @param services the BeanContextServices that wants + * to get the service. Only weak references to this will + * be retained, and it will never be changed, only queried + * in a read-only manner. + * @param requestor the actual requestor of the service. Only + * weak references to this will be retained, and it will + * never be changed, only queried in a read-only manner. + * @param serviceClass the Class of the service being + * requested. + * @param serviceSelector a parameter to customize the service + * returned with. + * @return an instance of serviceClass (such that + * instanceof serviceClass is true), or + * null. + * @see java.beans.beancontext.BeanContextServices#getService(java.beans.beancontext.BeanContextChild,java.lang.Object,java.lang.Class,java.lang.Object,java.beans.beancontext.BeanContextServiceRevokedListener) + */ + Object getService(BeanContextServices services, Object requestor, Class serviceClass, Object serviceSelector); + + /** + * Release the service. + *

    + * + * Called by BeanContextServices.releaseService(). + *

    + * + * Most BeanContextServiceProviders won't have to do + * anything here. + * + * @param services the BeanContextServices that wants + * to release the service. Only weak references to this will + * be retained, and it will never be changed, only queried + * in a read-only manner. + * @param requestor the original requestor of the service. + * @param service the service to relinquish + * @see java.beans.beancontext.BeanContextServices#releaseService(java.beans.beancontext.BeanContextChild,java.lang.Object,java.lang.Object) + */ + void releaseService(BeanContextServices services, Object requestor, Object service); + + /** + * Get a list of valid service selectors for the specified service class. + * This method is called from + * BeanContextServices.getCurrentServiceSelectors(). + *

    + * + * If the specified service class does not have a finite number of + * valid service selectors, it should return null. + * If it takes a general Integer parameter, for + * example, you may as well return null or the poor + * soul who called this method will be iterating all day. + *

    + * + * If it has no valid service selectors, it should still return an empty + * Iterator. + * + * @param services the BeanContextServices that wants + * to get the service selectors. Only weak references to this will + * be retained, and it will never be changed, only queried + * in a read-only manner. + * @param serviceClass the service class to get selectors for. + * @return a list of valid service selectors for the service + * class, or null. + * @see java.beans.beancontext.BeanContextServices#getCurrentServiceSelectors(java.lang.Class) + */ + Iterator getCurrentServiceSelectors(BeanContextServices services, Class serviceClass); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceProviderBeanInfo.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceProviderBeanInfo.java new file mode 100644 index 0000000..690b94e --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceProviderBeanInfo.java @@ -0,0 +1,60 @@ +/* java.beans.beancontext.BeanContextServiceProviderBeanInfo + Copyright (C) 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 java.beans.beancontext; + +import java.beans.BeanInfo; + +/** + * BeanContextServiceProviders implement this to provide information about all of the services they provide. + *

    + * + * This is apparently so that you can import a bunch of services into a + * RAD tool and it will know about all of them and export them to the + * user in a readable manner. + * + * @author John Keiser + * @since JDK1.2 + */ +public interface BeanContextServiceProviderBeanInfo extends BeanInfo { + /** + * Get BeanInfos for all of the service classes of this BeanInfoServiceProvider. + * @return BeanInfos for all provided service classes. + */ + BeanInfo[] getServicesBeanInfo(); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java new file mode 100644 index 0000000..dfa2b89 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedEvent.java @@ -0,0 +1,110 @@ +/* java.beans.beancontext.BeanContextServiceRevokedEvent + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.beans.beancontext; + +/** + * Event fired when services are revoked from a BeanContextServices. + * + * @author John Keiser + * @since JDK1.2 + * @see java.beans.beancontext.BeanContextServiceRevokedListener + */ + +public class BeanContextServiceRevokedEvent extends BeanContextEvent { + /** + * The Class representing the service which is now + * available. + */ + protected Class serviceClass; + private boolean invalidateRefs; + + /** + * Create a new service revoked event. + * @param services the BeanContextServices through + * which the service was available. This is also the source + * of the event. + * @param serviceClass the service class that is now revoked. + * @param revokeNow whether the revocation is immediate for all + * classes or just a suggestion. + */ + public BeanContextServiceRevokedEvent(BeanContextServices services, Class serviceClass, boolean revokeNow) { + super(services); + this.serviceClass = serviceClass; + invalidateRefs = revokeNow; + } + + /** + * Get the revoked service class. + * @return the service class. + */ + public Class getServiceClass() { + return serviceClass; + } + + /** + * Tell whether the revoked service class is the same as the specified class. + * Identical to getServiceClass().equals(c). + * @param c the class to compare. + * @return whether the clases are equal. + */ + public boolean isServiceClass(Class c) { + return serviceClass.equals(c); + } + + /** + * Get the BeanContextServices through which the service was available. + * @return the BeanContextServices through which the + * service was available. + */ + public BeanContextServices getSourceAsBeanContextServices() { + return (BeanContextServices)getSource(); + } + + /** + * Tell whether current instances of the revoked service are usable or not. + * This is determined by whether the service was revoked + * immediately. + * + * @return whether current instances of the revoked service are + * usable. + */ + public boolean isCurrentServiceInvalidNow() { + return invalidateRefs; + } +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedListener.java b/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedListener.java new file mode 100644 index 0000000..101e6e1 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServiceRevokedListener.java @@ -0,0 +1,62 @@ +/* java.beans.beancontext.BeanContextServiceRevokedListener + Copyright (C) 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 java.beans.beancontext; + +import java.util.EventListener; + +/** + * Listens for service revoke events. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextServiceRevokedListener extends EventListener { + /** + * Called by BeanContextServices.revokeService() to indicate that a service has been revoked. + * If you have a reference to such a service, it should be + * discarded and may no longer function properly. + * getService() will no longer work on the specified + * service class after this event has been fired. + * + * @param event the service revoked event. + * @see java.beans.beancontext.BeanContextServices#revokeService(java.lang.Class,java.beans.beancontext.BeanContextServiceProvider,boolean) + */ + void serviceRevoked(BeanContextServiceRevokedEvent event); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServices.java b/libjava/classpath/java/beans/beancontext/BeanContextServices.java new file mode 100644 index 0000000..cb19503 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServices.java @@ -0,0 +1,216 @@ +/* java.beans.beancontext.BeanContextServices + Copyright (C) 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 java.beans.beancontext; + +import java.util.Iterator; +import java.util.TooManyListenersException; + +/** + * Allows a BeanContext to provide services to its children. + * + * @specnote it is unclear whether a BeanContextServices + * should delegate unhandled requests to parents. I assume so. + * @author John Keiser + * @since 1.2 + */ + +public interface BeanContextServices + extends BeanContext, BeanContextServicesListener +{ + /** + * Register a service to make it available to others. + * This class may refuse to add the service based on whatever + * information it can gather, including whether the service + * provider is trusted. + * + * @param serviceClass the service class. + * @param provider the factory that will actually provide the service. + * @return whether the service was added or not. + */ + boolean addService (Class serviceClass, + BeanContextServiceProvider provider); + + /** + * Make it so that no one else can use this service. + *

    + * + * If revokeNow is false, the only + * effect of this method is to make all subsequent calls to + * getService() on this service class fail. + *

    + * + * If it is true, a message is also sent out to all + * listeners on the service and all references to it are released. + * + * @param serviceClass the service class to revoke. + * @param provider the service provider providing the service class. + * @param revokeNow whether to release all current references to + * the service. + */ + void revokeService (Class serviceClass, + BeanContextServiceProvider provider, + boolean revokeNow); + + /** + * Release your copy of this service. + *

    + * + * If all copies of the service's class have been relinquished by + * the requestor, the BeanContextServiceRevokedListener + * previously registered by getService() will be + * unregistered. + * + * @param requestorChild the original BeanContextChild + * requesting the service. + * @param requestor the original requestor of the service. + * @param service the service to relinquish + * @see #getService(java.beans.beancontext.BeanContextChild,java.lang.Object,java.lang.Class,java.lang.Object,java.beans.beancontext.BeanContextServiceRevokedListener) + */ + void releaseService (BeanContextChild requestorChild, Object requestor, + Object service); + + /** + * Get a service from this BeanContextServices. + *

    + * + * The specified listener will be registered to receive a + * revocation notice for the specified serviceClass. One + * notification per service class per requestor object will be + * sent. + *

    + * + * The listener will be unregistered when all services that were + * obtained by that requestor for that service class are released. + *

    + * + * If the requested service class is not available, or if this + * BeanContextServices object chooses not honor the + * request because the service class has been revoked or for some + * other reason, then this method will return null. + *

    + * + * This method may throw unchecked exceptions, so watch out. + * + * @specnote it is not specified what happens when two subsequent + * calls are made to getService() with the + * same requestor object and service class but different + * listeners. Which listener is to be notified? + * + * @param requestorChild the BeanContextChild + * associated with the requestor. Typically this will be + * the same as the requestor itself, but since any + * Object, even one outside the hierarchy, may + * make a request, this parameter is necessary. Only weak + * references to this will be retained, and it will never + * be changed, only queried in a read-only manner. + * @param requestor the actual requestor of the service. Only + * weak references to this will be retained, and it will + * never be changed, only queried in a read-only manner. + * @param serviceClass the Class of the service being + * requested. + * @param serviceSelector a parameter to customize the service + * returned with. + * @param listener a listener that will be notified if the service + * being requested is revoked. + * @return an instance of serviceClass (such that + * instanceof serviceClass is true), or + * null. + */ + Object getService (BeanContextChild requestorChild, Object requestor, + Class serviceClass, Object serviceSelector, + BeanContextServiceRevokedListener listener) + throws TooManyListenersException; + + /** + * Get a list of all service classes supported. + *

    + * + * This method must synchronize on + * BeanContext.globalHierarchyLock. + * + * @return a list of all service classes supported. + * @see java.beans.beancontext.BeanContext#globalHierarchyLock + */ + Iterator getCurrentServiceClasses (); + + /** + * Get a list of valid service selectors for the specified service class. + *

    + * + * If the specified service class does not have a finite number of + * valid service selectors, it should return null. + * If it takes a general Integer parameter, for + * example, you may as well return null or the poor + * soul who called this method will be iterating all day. + *

    + * + * If it has no valid service selectors, it should still return an empty + * Iterator. + * + * @param serviceClass the service class to get selectors for. + * @return a list of valid service selectors for the service + * class, or null. + */ + Iterator getCurrentServiceSelectors (Class serviceClass); + + /** + * Tell whether the specified service class is available. + * Iff getService() could return a non-null value for the + * specified service, this method will return true. + * + * @param serviceClass the service class to check on. + * @return whether the specified service class is available. + */ + boolean hasService (Class serviceClass); + + /** + * Add a listener on all adds and removes of services. + * @param listener the listener to add. + */ + void addBeanContextServicesListener (BeanContextServicesListener listener); + + /** + * Remove a listener on all adds and removes of services. + * @specnote it is not certain whether this should remove this + * listener if it was specified in + * getService(). + * @param listener the listener to add. + */ + void removeBeanContextServicesListener (BeanContextServicesListener listener); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServicesListener.java b/libjava/classpath/java/beans/beancontext/BeanContextServicesListener.java new file mode 100644 index 0000000..becc7cd --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServicesListener.java @@ -0,0 +1,56 @@ +/* java.beans.beancontext.BeanContextServicesListener + Copyright (C) 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 java.beans.beancontext; + +/** + * Listens for service add and revoke events. + * + * @author John Keiser + * @since JDK1.2 + */ + +public interface BeanContextServicesListener extends BeanContextServiceRevokedListener { + /** + * Called by BeanContextServices whenever a service is made available. + * + * @param event the service revoked event, with useful information + * about the new service. + */ + void serviceAvailable(BeanContextServiceAvailableEvent event); +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java b/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java new file mode 100644 index 0000000..b7c4a49 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java @@ -0,0 +1,300 @@ +/* BeanContextServicesSupport.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 java.beans.beancontext; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.TooManyListenersException; + +/** + * @author Michael Koch + * @since 1.2 + */ +public class BeanContextServicesSupport + extends BeanContextSupport + implements BeanContextServices +{ + private static final long serialVersionUID = -8494482757288719206L; + + protected class BCSSChild + extends BeanContextSupport.BCSChild + { + private static final long serialVersionUID = -6848044915271367103L; + } + + protected class BCSSProxyServiceProvider + implements BeanContextServiceProvider, + BeanContextServiceRevokedListener + { + private static final long serialVersionUID = 7078212910685744490L; + + public Iterator getCurrentServiceSelectors (BeanContextServices bcs, + Class serviceClass) + { + throw new Error ("Not implemented"); + } + + public Object getService (BeanContextServices bcs, + Object requestor, + Class serviceClass, + Object serviceSelector) + { + throw new Error ("Not implemented"); + } + + public void releaseService (BeanContextServices bcs, + Object requestor, + Object service) + { + throw new Error ("Not implemented"); + } + + public void serviceRevoked (BeanContextServiceRevokedEvent bcsre) + { + throw new Error ("Not implemented"); + } + } + + protected static class BCSSServiceProvider + implements Serializable + { + private static final long serialVersionUID = 861278251667444782L; + + protected BeanContextServiceProvider serviceProvider; + + protected BeanContextServiceProvider getServiceProvider() + { + return serviceProvider; + } + } + + protected transient ArrayList bcsListeners; + + protected transient BCSSProxyServiceProvider proxy; + + protected transient int serializable; + + protected transient HashMap services; + + public BeanContextServicesSupport () + { + super(); + } + + public BeanContextServicesSupport (BeanContextServices peer) + { + super(peer); + } + + public BeanContextServicesSupport(BeanContextServices peer, Locale locale) + { + super(peer, locale); + } + + public BeanContextServicesSupport(BeanContextServices peer, Locale locale, + boolean dtime) + { + super(peer, locale, dtime); + } + + public BeanContextServicesSupport(BeanContextServices peer, Locale locale, + boolean dtime, boolean visible) + { + super(peer, locale, dtime, visible); + } + + public void addBeanContextServicesListener + (BeanContextServicesListener listener) + { + if (! bcsListeners.contains(listener)) + bcsListeners.add(listener); + } + + public boolean addService (Class serviceClass, BeanContextServiceProvider bcsp) + { + throw new Error ("Not implemented"); + } + + protected boolean addService (Class serviceClass, + BeanContextServiceProvider bcsp, + boolean fireEvent) + { + throw new Error ("Not implemented"); + } + + protected void bcsPreDeserializationHook (ObjectInputStream ois) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + protected void bcsPreSerializationHook (ObjectOutputStream oos) + throws IOException + { + throw new Error ("Not implemented"); + } + + protected void childJustRemovedHook (Object child, + BeanContextSupport.BCSChild bcsc) + { + throw new Error ("Not implemented"); + } + + protected BeanContextSupport.BCSChild createBCSChild (Object targetChild, + Object peer) + { + throw new Error ("Not implemented"); + } + + protected BeanContextServicesSupport.BCSSServiceProvider + createBCSSServiceProvider (Class sc, BeanContextServiceProvider bcsp) + { + throw new Error ("Not implemented"); + } + + protected final void fireServiceAdded (BeanContextServiceAvailableEvent bcssae) + { + throw new Error ("Not implemented"); + } + + protected final void fireServiceAdded (Class serviceClass) + { + throw new Error ("Not implemented"); + } + + protected final void fireServiceRevoked(BeanContextServiceRevokedEvent event) + { + throw new Error ("Not implemented"); + } + + protected final void fireServiceRevoked (Class serviceClass, + boolean revokeNow) + { + throw new Error ("Not implemented"); + } + + public BeanContextServices getBeanContextServicesPeer () + { + throw new Error ("Not implemented"); + } + + protected static final BeanContextServicesListener + getChildBeanContextServicesListener (Object child) + { + throw new Error ("Not implemented"); + } + + public Iterator getCurrentServiceClasses () + { + throw new Error ("Not implemented"); + } + + public Iterator getCurrentServiceSelectors (Class serviceClass) + { + throw new Error ("Not implemented"); + } + + public Object getService (BeanContextChild child, Object requestor, + Class serviceClass, Object serviceSelector, + BeanContextServiceRevokedListener bcsrl) + throws TooManyListenersException + { + throw new Error ("Not implemented"); + } + + public boolean hasService (Class serviceClass) + { + throw new Error ("Not implemented"); + } + + public void initialize () + { + super.initialize(); + + bcsListeners = new ArrayList(); + services = new HashMap(); + } + + protected void initializeBeanContextResources () + { + throw new Error ("Not implemented"); + } + + protected void releaseBeanContextResources () + { + throw new Error ("Not implemented"); + } + + public void releaseService (BeanContextChild child, Object requestor, + Object service) + { + throw new Error ("Not implemented"); + } + + public void removeBeanContextServicesListener + (BeanContextServicesListener listener) + { + int index = bcsListeners.indexOf(listener); + + if (index > -1) + bcsListeners.remove(index); + } + + public void revokeService (Class serviceClass, BeanContextServiceProvider bcsp, + boolean revokeCurrentServicesNow) + { + throw new Error ("Not implemented"); + } + + public void serviceAvailable (BeanContextServiceAvailableEvent bcssae) + { + throw new Error ("Not implemented"); + } + + public void serviceRevoked (BeanContextServiceRevokedEvent bcssre) + { + throw new Error ("Not implemented"); + } +} diff --git a/libjava/classpath/java/beans/beancontext/BeanContextSupport.java b/libjava/classpath/java/beans/beancontext/BeanContextSupport.java new file mode 100644 index 0000000..7e024e2 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/BeanContextSupport.java @@ -0,0 +1,460 @@ +/* BeanContextSupport.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 java.beans.beancontext; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.beans.Visibility; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; + +/** + * @author Michael Koch + * @since 1.2 + */ +public class BeanContextSupport extends BeanContextChildSupport + implements BeanContext, Serializable, PropertyChangeListener, + VetoableChangeListener +{ + private static final long serialVersionUID = -4879613978649577204L; + + private void readObject (ObjectInputStream s) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + private void writeObject (ObjectOutputStream s) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + protected class BCSChild implements Serializable + { + private static final long serialVersionUID = 3289144128843950629L; + } + + protected static final class BCSIterator implements Iterator + { + public boolean hasNext () + { + throw new Error ("Not implemented"); + } + + public Object next () + { + throw new Error ("Not implemented"); + } + + public void remove () + { + // This must be a noop remove operation. + } + } + + protected transient ArrayList bcmListeners; + + protected transient HashMap children; + + protected transient boolean designTime; + + protected transient Locale locale; + + protected transient boolean okToUseGui; + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport () + { + this (null, null, true, true); + } + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport (BeanContext peer) + { + this (peer, null, true, true); + } + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport (BeanContext peer, Locale lcle) + { + this (peer, lcle, true, true); + } + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport (BeanContext peer, Locale lcle, boolean dtime) + { + this (peer, lcle, dtime, true); + } + + /** + * Construct a BeanContextSupport instance. + */ + public BeanContextSupport (BeanContext peer, Locale lcle, boolean dtime, + boolean visible) + { + locale = lcle; + designTime = dtime; + okToUseGui = visible; + + initialize (); + } + + public boolean add (Object targetChild) + { + if (targetChild == null) + throw new IllegalArgumentException(); + + if (children.containsKey(targetChild)) + return false; + + // FIXME: The second argument is surely wrong. + children.put(targetChild, targetChild); + return true; + } + + public boolean addAll (Collection c) + { + throw new UnsupportedOperationException(); + } + + public void addBeanContextMembershipListener + (BeanContextMembershipListener listener) + { + if (! bcmListeners.contains(listener)) + bcmListeners.add(listener); + } + + public boolean avoidingGui () + { + throw new Error ("Not implemented"); + } + + protected Iterator bcsChildren () + { + throw new Error ("Not implemented"); + } + + protected void bcsPreDeserializationHook (ObjectInputStream ois) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + protected void bcsPreSerializationHook (ObjectOutputStream oos) + throws IOException + { + throw new Error ("Not implemented"); + } + + protected void childDeserializedHook (Object child, BeanContextSupport.BCSChild bcsc) + { + throw new Error ("Not implemented"); + } + + protected void childJustAddedHook (Object child, BeanContextSupport.BCSChild bcsc) + { + throw new Error ("Not implemented"); + } + + protected void childJustRemovedHook (Object child, BeanContextSupport.BCSChild bcsc) + { + throw new Error ("Not implemented"); + } + + protected static final boolean classEquals (Class first, Class second) + { + throw new Error ("Not implemented"); + } + + public void clear () + { + throw new UnsupportedOperationException(); + } + + public boolean contains (Object o) + { + throw new Error ("Not implemented"); + } + + public boolean containsAll (Collection c) + { + throw new Error ("Not implemented"); + } + + public boolean containsKey (Object o) + { + throw new Error ("Not implemented"); + } + + protected final Object[] copyChildren () + { + throw new Error ("Not implemented"); + } + + protected BeanContextSupport.BCSChild createBCSChild (Object targetChild, Object peer) + { + throw new Error ("Not implemented"); + } + + protected final void deserialize (ObjectInputStream ois, Collection coll) + throws ClassNotFoundException, IOException + { + throw new Error ("Not implemented"); + } + + public void dontUseGui () + { + throw new Error ("Not implemented"); + } + + protected final void fireChildrenAdded (BeanContextMembershipEvent bcme) + { + throw new Error ("Not implemented"); + } + + protected final void fireChildrenRemoved (BeanContextMembershipEvent bcme) + { + throw new Error ("Not implemented"); + } + + public BeanContext getBeanContextPeer () + { + throw new Error ("Not implemented"); + } + + protected static final BeanContextChild getChildBeanContextChild (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final BeanContextMembershipListener getChildBeanContextMembershipListener (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final PropertyChangeListener getChildPropertyChangeListener (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final Serializable getChildSerializable (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final VetoableChangeListener getChildVetoableChangeListener (Object child) + { + throw new Error ("Not implemented"); + } + + protected static final Visibility getChildVisibility (Object child) + { + throw new Error ("Not implemented"); + } + + public Locale getLocale () + { + return locale; + } + + public URL getResource (String name, BeanContextChild bcc) + { + throw new Error ("Not implemented"); + } + + public InputStream getResourceAsStream (String name, BeanContextChild bcc) + { + throw new Error ("Not implemented"); + } + + protected void initialize () + { + bcmListeners = new ArrayList(); + children = new HashMap(); + } + + public Object instantiateChild (String beanName) + throws IOException, ClassNotFoundException + { + throw new Error ("Not implemented"); + } + + public boolean isDesignTime () + { + throw new Error ("Not implemented"); + } + + public boolean isEmpty () + { + throw new Error ("Not implemented"); + } + + public boolean isSerializing () + { + throw new Error ("Not implemented"); + } + + public Iterator iterator () + { + return children.keySet().iterator(); + } + + public boolean needsGui () + { + throw new Error ("Not implemented"); + } + + public void okToUseGui () + { + throw new Error ("Not implemented"); + } + + public void propertyChange (PropertyChangeEvent pce) + { + throw new Error ("Not implemented"); + } + + public final void readChildren (ObjectInputStream ois) + throws IOException, ClassNotFoundException + { + throw new Error ("Not implemented"); + } + + public boolean remove (Object targetChild) + { + return remove(targetChild, true); + } + + protected boolean remove (Object targetChild, boolean callChildSetBC) + { + if (targetChild == null) + throw new IllegalArgumentException(); + + throw new Error ("Not implemented"); + } + + public boolean removeAll (Collection c) + { + throw new UnsupportedOperationException(); + } + + public void removeBeanContextMembershipListener (BeanContextMembershipListener bcml) + { + throw new Error ("Not implemented"); + } + + public boolean retainAll (Collection c) + { + throw new UnsupportedOperationException(); + } + + protected final void serialize (ObjectOutputStream oos, Collection coll) + throws IOException + { + throw new Error ("Not implemented"); + } + + public void setDesignTime (boolean dtime) + { + throw new Error ("Not implemented"); + } + + public void setLocale (Locale newLocale) + throws PropertyVetoException + { + throw new Error ("Not implemented"); + } + + public int size () + { + throw new Error ("Not implemented"); + } + + public Object[] toArray () + { + return children.keySet().toArray(); + } + + public Object[] toArray(Object[] array) + { + return children.keySet().toArray(array); + } + + protected boolean validatePendingAdd (Object targetChild) + { + throw new Error ("Not implemented"); + } + + protected boolean validatePendingRemove (Object targetChild) + { + throw new Error ("Not implemented"); + } + + public void vetoableChange (PropertyChangeEvent pce) + throws PropertyVetoException + { + throw new Error ("Not implemented"); + } + + public final void writeChildren (ObjectOutputStream oos) + throws IOException + { + throw new Error ("Not implemented"); + } +} diff --git a/libjava/classpath/java/beans/beancontext/package.html b/libjava/classpath/java/beans/beancontext/package.html new file mode 100644 index 0000000..55e3bd7 --- /dev/null +++ b/libjava/classpath/java/beans/beancontext/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.beans.beancontext + + +

    Containers and execution environments for beans.

    + + + diff --git a/libjava/classpath/java/beans/package.html b/libjava/classpath/java/beans/package.html new file mode 100644 index 0000000..5ca8000 --- /dev/null +++ b/libjava/classpath/java/beans/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.beans + + +

    Listeners and descriptors for managing beans.

    + + + diff --git a/libjava/classpath/java/io/BufferedInputStream.java b/libjava/classpath/java/io/BufferedInputStream.java new file mode 100644 index 0000000..6fb0246 --- /dev/null +++ b/libjava/classpath/java/io/BufferedInputStream.java @@ -0,0 +1,379 @@ +/* BufferedInputStream.java -- An input stream that implements buffering + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This subclass of FilterInputStream buffers input from an + * underlying implementation to provide a possibly more efficient read + * mechanism. It maintains the buffer and buffer state in instance + * variables that are available to subclasses. The default buffer size + * of 2048 bytes can be overridden by the creator of the stream. + *

    + * This class also implements mark/reset functionality. It is capable + * of remembering any number of input bytes, to the limits of + * system memory or the size of Integer.MAX_VALUE + *

    + * Please note that this class does not properly handle character + * encodings. Consider using the BufferedReader class which + * does. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @author Jeroen Frijters (jeroen@frijters.net) + */ +public class BufferedInputStream extends FilterInputStream +{ + + /** + * This is the default buffer size + */ + private static final int DEFAULT_BUFFER_SIZE = 2048; + + /** + * The buffer used for storing data from the underlying stream. + */ + protected byte[] buf; + + /** + * The number of valid bytes currently in the buffer. It is also the index + * of the buffer position one byte past the end of the valid data. + */ + protected int count; + + /** + * The index of the next character that will by read from the buffer. + * When pos == count, the buffer is empty. + */ + protected int pos; + + /** + * The value of pos when the mark() method was + * called. + * This is set to -1 if there is no mark set. + */ + protected int markpos = -1; + + /** + * This is the maximum number of bytes than can be read after a + * call to mark() before the mark can be discarded. + * After this may bytes are read, the reset() method + * may not be called successfully. + */ + protected int marklimit; + + /** + * This is the initial buffer size. When the buffer is grown because + * of marking requirements, it will be grown by bufferSize increments. + * The underlying stream will be read in chunks of bufferSize. + */ + private final int bufferSize; + + /** + * This method initializes a new BufferedInputStream that will + * read from the specified subordinate stream with a default buffer size + * of 2048 bytes + * + * @param in The subordinate stream to read from + */ + public BufferedInputStream(InputStream in) + { + this(in, DEFAULT_BUFFER_SIZE); + } + + /** + * This method initializes a new BufferedInputStream that will + * read from the specified subordinate stream with a buffer size that + * is specified by the caller. + * + * @param in The subordinate stream to read from + * @param size The buffer size to use + * + * @exception IllegalArgumentException when size is smaller then 1 + */ + public BufferedInputStream(InputStream in, int size) + { + super(in); + if (size <= 0) + throw new IllegalArgumentException(); + buf = new byte[size]; + // initialize pos & count to bufferSize, to prevent refill from + // allocating a new buffer (if the caller starts out by calling mark()). + pos = count = bufferSize = size; + } + + /** + * This method returns the number of bytes that can be read from this + * stream before a read can block. A return of 0 indicates that blocking + * might (or might not) occur on the very next read attempt. + *

    + * The number of available bytes will be the number of read ahead bytes + * stored in the internal buffer plus the number of available bytes in + * the underlying stream. + * + * @return The number of bytes that can be read before blocking could occur + * + * @exception IOException If an error occurs + */ + public synchronized int available() throws IOException + { + return count - pos + super.available(); + } + + /** + * This method closes the underlying input stream and frees any + * resources associated with it. Sets buf to null. + * + * @exception IOException If an error occurs. + */ + public void close() throws IOException + { + // Free up the array memory. + buf = null; + pos = count = 0; + markpos = -1; + super.close(); + } + + /** + * This method marks a position in the input to which the stream can be + * "reset" by calling the reset() method. The parameter + * readlimit is the number of bytes that can be read from the + * stream after setting the mark before the mark becomes invalid. For + * example, if mark() is called with a read limit of 10, then + * when 11 bytes of data are read from the stream before the + * reset() method is called, then the mark is invalid and the + * stream object instance is not required to remember the mark. + *

    + * Note that the number of bytes that can be remembered by this method + * can be greater than the size of the internal read buffer. It is also + * not dependent on the subordinate stream supporting mark/reset + * functionality. + * + * @param readlimit The number of bytes that can be read before the mark + * becomes invalid + */ + public synchronized void mark(int readlimit) + { + marklimit = readlimit; + markpos = pos; + } + + /** + * This method returns true to indicate that this class + * supports mark/reset functionality. + * + * @return true to indicate that mark/reset functionality is + * supported + * + */ + public boolean markSupported() + { + return true; + } + + /** + * This method reads an unsigned byte from the input stream and returns it + * as an int in the range of 0-255. This method also will return -1 if + * the end of the stream has been reached. + *

    + * This method will block until the byte can be read. + * + * @return The byte read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public synchronized int read() throws IOException + { + if (pos >= count && !refill()) + return -1; // EOF + + return buf[pos++] & 0xFF; + } + + /** + * This method reads bytes from a stream and stores them into a caller + * supplied buffer. It starts storing the data at index off + * into the buffer and attempts to read len bytes. This method + * can return before reading the number of bytes requested, but it will try + * to read the requested number of bytes by repeatedly calling the underlying + * stream as long as available() for this stream continues to return a + * non-zero value (or until the requested number of bytes have been read). + * The actual number of bytes read is returned as an int. A -1 is returned + * to indicate the end of the stream. + *

    + * This method will block until some data can be read. + * + * @param b The array into which the bytes read should be stored + * @param off The offset into the array to start storing bytes + * @param len The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + * @exception IndexOutOfBoundsException when off or + * len are negative, or when off + len + * is larger then the size of b, + */ + public synchronized int read(byte[] b, int off, int len) throws IOException + { + if (off < 0 || len < 0 || b.length - off < len) + throw new IndexOutOfBoundsException(); + + if (len == 0) + return 0; + + if (pos >= count && !refill()) + return -1; // No bytes were read before EOF. + + int totalBytesRead = Math.min(count - pos, len); + System.arraycopy(buf, pos, b, off, totalBytesRead); + pos += totalBytesRead; + off += totalBytesRead; + len -= totalBytesRead; + + while (len > 0 && super.available() > 0 && refill()) + { + int remain = Math.min(count - pos, len); + System.arraycopy(buf, pos, b, off, remain); + pos += remain; + off += remain; + len -= remain; + totalBytesRead += remain; + } + + return totalBytesRead; + } + + /** + * This method resets a stream to the point where the mark() + * method was called. Any bytes that were read after the mark point was + * set will be re-read during subsequent reads. + *

    + * This method will throw an IOException if the number of bytes read from + * the stream since the call to mark() exceeds the mark limit + * passed when establishing the mark. + * + * @exception IOException If mark() was never called or more + * then marklimit bytes were read since the last + * call to mark() + */ + public synchronized void reset() throws IOException + { + if (markpos == -1) + throw new IOException(buf == null ? "Stream closed." : "Invalid mark."); + + pos = markpos; + } + + /** + * This method skips the specified number of bytes in the stream. It + * returns the actual number of bytes skipped, which may be less than the + * requested amount. + * + * @param n The requested number of bytes to skip + * + * @return The actual number of bytes skipped. + * + * @exception IOException If an error occurs + */ + public synchronized long skip(long n) throws IOException + { + if (buf == null) + throw new IOException("Stream closed."); + + final long origN = n; + + while (n > 0L) + { + if (pos >= count && !refill()) + break; + + int numread = (int) Math.min((long) (count - pos), n); + pos += numread; + n -= numread; + } + + return origN - n; + } + + /** + * Called to refill the buffer (when count is equal to pos). + * + * @return true when at least one additional byte was read + * into buf, false otherwise (at EOF). + */ + private boolean refill() throws IOException + { + if (buf == null) + throw new IOException("Stream closed."); + + if (markpos == -1 || count - markpos >= marklimit) + { + markpos = -1; + pos = count = 0; + } + else + { + byte[] newbuf = buf; + if (markpos < bufferSize) + { + newbuf = new byte[count - markpos + bufferSize]; + } + System.arraycopy(buf, markpos, newbuf, 0, count - markpos); + buf = newbuf; + count -= markpos; + pos -= markpos; + markpos = 0; + } + + int numread = super.read(buf, count, bufferSize); + + if (numread <= 0) // EOF + return false; + + count += numread; + return true; + } +} diff --git a/libjava/classpath/java/io/BufferedOutputStream.java b/libjava/classpath/java/io/BufferedOutputStream.java new file mode 100644 index 0000000..ce7ebc7 --- /dev/null +++ b/libjava/classpath/java/io/BufferedOutputStream.java @@ -0,0 +1,192 @@ +/* BufferedOutputStream.java -- Buffer output into large blocks before writing + Copyright (C) 1998, 2000, 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 java.io; + +/** + * This class accumulates bytes written in a buffer instead of immediately + * writing the data to the underlying output sink. The bytes are instead + * as one large block when the buffer is filled, or when the stream is + * closed or explicitly flushed. This mode operation can provide a more + * efficient mechanism for writing versus doing numerous small unbuffered + * writes. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class BufferedOutputStream extends FilterOutputStream +{ + /** + * This is the default buffer size + */ + private static final int DEFAULT_BUFFER_SIZE = 512; + + /** + * This is the internal byte array used for buffering output before + * writing it. + */ + protected byte[] buf; + + /** + * This is the number of bytes that are currently in the buffer and + * are waiting to be written to the underlying stream. It always points to + * the index into the buffer where the next byte of data will be stored + */ + protected int count; + + /** + * This method initializes a new BufferedOutputStream instance + * that will write to the specified subordinate OutputStream + * and which will use a default buffer size of 512 bytes. + * + * @param out The underlying OutputStream to write data to + */ + public BufferedOutputStream(OutputStream out) + { + this(out, DEFAULT_BUFFER_SIZE); + } + + /** + * This method initializes a new BufferedOutputStream instance + * that will write to the specified subordinate OutputStream + * and which will use the specified buffer size + * + * @param out The underlying OutputStream to write data to + * @param size The size of the internal buffer + */ + public BufferedOutputStream(OutputStream out, int size) + { + super(out); + + buf = new byte[size]; + } + + /** + * This method causes any currently buffered bytes to be immediately + * written to the underlying output stream. + * + * @exception IOException If an error occurs + */ + public synchronized void flush() throws IOException + { + if (count == 0) + return; + + out.write(buf, 0, count); + count = 0; + out.flush(); + } + + /** + * This method flushes any remaining buffered bytes then closes the + * underlying output stream. Any further attempts to write to this stream + * may throw an exception + * + public synchronized void close() throws IOException + { + flush(); + out.close(); + } + */ + + /** + * This method runs when the object is garbage collected. It is + * responsible for ensuring that all buffered bytes are written and + * for closing the underlying stream. + * + * @exception IOException If an error occurs (ignored by the Java runtime) + * + protected void finalize() throws IOException + { + close(); + } + */ + + /** + * This method writes a single byte of data. This will be written to the + * buffer instead of the underlying data source. However, if the buffer + * is filled as a result of this write request, it will be flushed to the + * underlying output stream. + * + * @param b The byte of data to be written, passed as an int + * + * @exception IOException If an error occurs + */ + public synchronized void write(int b) throws IOException + { + if (count == buf.length) + flush(); + + buf[count] = (byte)(b & 0xFF); + ++count; + } + + /** + * This method writes len bytes from the byte array + * buf starting at position offset in the buffer. + * These bytes will be written to the internal buffer. However, if this + * write operation fills the buffer, the buffer will be flushed to the + * underlying output stream. + * + * @param buf The array of bytes to write. + * @param offset The index into the byte array to start writing from. + * @param len The number of bytes to write. + * + * @exception IOException If an error occurs + */ + public synchronized void write(byte[] buf, int offset, int len) + throws IOException + { + // Buffer can hold everything. Note that the case where LEN < 0 + // is automatically handled by the downstream write. + if (len < (this.buf.length - count)) + { + System.arraycopy(buf, offset, this.buf, count, len); + count += len; + } + else + { + // The write was too big. So flush the buffer and write the new + // bytes directly to the underlying stream, per the JDK 1.2 + // docs. + flush(); + out.write (buf, offset, len); + } + } + +} // class BufferedOutputStream + diff --git a/libjava/classpath/java/io/BufferedReader.java b/libjava/classpath/java/io/BufferedReader.java new file mode 100644 index 0000000..4849949 --- /dev/null +++ b/libjava/classpath/java/io/BufferedReader.java @@ -0,0 +1,581 @@ +/* BufferedReader.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 java.io; + +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This subclass of FilterReader buffers input from an + * underlying implementation to provide a possibly more efficient read + * mechanism. It maintains the buffer and buffer state in instance + * variables that are available to subclasses. The default buffer size + * of 8192 chars can be overridden by the creator of the stream. + *

    + * This class also implements mark/reset functionality. It is capable + * of remembering any number of input chars, to the limits of + * system memory or the size of Integer.MAX_VALUE + * + * @author Per Bothner (bothner@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class BufferedReader extends Reader +{ + Reader in; + char[] buffer; + /* Index of current read position. Must be >= 0 and <= limit. */ + /* There is a special case where pos may be equal to limit+1; this + * is used as an indicator that a readLine was done with a '\r' was + * the very last char in the buffer. Since we don't want to read-ahead + * and potentially block, we set pos this way to indicate the situation + * and deal with it later. Doing it this way rather than having a + * separate boolean field to indicate the condition has the advantage + * that it is self-clearing on things like mark/reset. + */ + int pos; + /* Limit of valid data in buffer. Must be >= pos and <= buffer.length. */ + /* This can be < pos in the one special case described above. */ + int limit; + + /* The value -1 means there is no mark, or the mark has been invalidated. + Otherwise, markPos is the index in the buffer of the marked position. + Must be >= 0 and <= pos. + Note we do not explicitly store the read-limit. + The implicit read-limit is (buffer.length - markPos), which is + guaranteed to be >= the read-limit requested in the call to mark. */ + int markPos = -1; + + // The JCL book specifies the default buffer size as 8K characters. + // This is package-private because it is used by LineNumberReader. + static final int DEFAULT_BUFFER_SIZE = 8192; + + /** + * The line buffer for readLine. + */ + private StringBuffer sbuf = null; + + /** + * Create a new BufferedReader that will read from the + * specified subordinate stream with a default buffer size of 8192 chars. + * + * @param in The subordinate stream to read from + */ + public BufferedReader(Reader in) + { + this(in, DEFAULT_BUFFER_SIZE); + } + + /** + * Create a new BufferedReader that will read from the + * specified subordinate stream with a buffer size that is specified by the + * caller. + * + * @param in The subordinate stream to read from + * @param size The buffer size to use + * + * @exception IllegalArgumentException if size <= 0 + */ + public BufferedReader(Reader in, int size) + { + super(in.lock); + if (size <= 0) + throw new IllegalArgumentException("Illegal buffer size: " + size); + this.in = in; + buffer = new char[size]; + } + + /** + * This method closes the underlying stream and frees any associated + * resources. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + synchronized (lock) + { + if (in != null) + in.close(); + in = null; + buffer = null; + } + } + + /** + * Returns true to indicate that this class supports mark/reset + * functionality. + * + * @return true + */ + public boolean markSupported() + { + return true; + } + + /** + * Mark a position in the input to which the stream can be + * "reset" by calling the reset() method. The parameter + * readLimit is the number of chars that can be read from the + * stream after setting the mark before the mark becomes invalid. For + * example, if mark() is called with a read limit of 10, then + * when 11 chars of data are read from the stream before the + * reset() method is called, then the mark is invalid and the + * stream object instance is not required to remember the mark. + *

    + * Note that the number of chars that can be remembered by this method + * can be greater than the size of the internal read buffer. It is also + * not dependent on the subordinate stream supporting mark/reset + * functionality. + * + * @param readLimit The number of chars that can be read before the mark + * becomes invalid + * + * @exception IOException If an error occurs + * @exception IllegalArgumentException if readLimit is negative. + */ + public void mark(int readLimit) throws IOException + { + if (readLimit < 0) + throw new IllegalArgumentException("Read-ahead limit is negative"); + + synchronized (lock) + { + checkStatus(); + // In this method we need to be aware of the special case where + // pos + 1 == limit. This indicates that a '\r' was the last char + // in the buffer during a readLine. We'll want to maintain that + // condition after we shift things around and if a larger buffer is + // needed to track readLimit, we'll have to make it one element + // larger to ensure we don't invalidate the mark too early, if the + // char following the '\r' is NOT a '\n'. This is ok because, per + // the spec, we are not required to invalidate when passing readLimit. + // + // Note that if 'pos > limit', then doing 'limit -= pos' will cause + // limit to be negative. This is the only way limit will be < 0. + + if (pos + readLimit > limit) + { + char[] old_buffer = buffer; + int extraBuffSpace = 0; + if (pos > limit) + extraBuffSpace = 1; + if (readLimit + extraBuffSpace > limit) + buffer = new char[readLimit + extraBuffSpace]; + limit -= pos; + if (limit >= 0) + { + System.arraycopy(old_buffer, pos, buffer, 0, limit); + pos = 0; + } + } + + if (limit < 0) + { + // Maintain the relationship of 'pos > limit'. + pos = 1; + limit = markPos = 0; + } + else + markPos = pos; + // Now pos + readLimit <= buffer.length. thus if we need to read + // beyond buffer.length, then we are allowed to invalidate markPos. + } + } + + /** + * Reset the stream to the point where the mark() method + * was called. Any chars that were read after the mark point was set will + * be re-read during subsequent reads. + *

    + * This method will throw an IOException if the number of chars read from + * the stream since the call to mark() exceeds the mark limit + * passed when establishing the mark. + * + * @exception IOException If an error occurs; + */ + public void reset() throws IOException + { + synchronized (lock) + { + checkStatus(); + if (markPos < 0) + throw new IOException("mark never set or invalidated"); + + // Need to handle the extremely unlikely case where a readLine was + // done with a '\r' as the last char in the buffer; which was then + // immediately followed by a mark and a reset with NO intervening + // read of any sort. In that case, setting pos to markPos would + // lose that info and a subsequent read would thus not skip a '\n' + // (if one exists). The value of limit in this rare case is zero. + // We can assume that if limit is zero for other reasons, then + // pos is already set to zero and doesn't need to be readjusted. + if (limit > 0) + pos = markPos; + } + } + + /** + * This method determines whether or not a stream is ready to be read. If + * this method returns false then this stream could (but is + * not guaranteed to) block on the next read attempt. + * + * @return true if this stream is ready to be read, + * false otherwise + * + * @exception IOException If an error occurs + */ + public boolean ready() throws IOException + { + synchronized (lock) + { + checkStatus(); + return pos < limit || in.ready(); + } + } + + /** + * This method read chars from a stream and stores them into a caller + * supplied buffer. It starts storing the data at index + * offset into + * the buffer and attempts to read len chars. This method can + * return before reading the number of chars requested. The actual number + * of chars read is returned as an int. A -1 is returned to indicate the + * end of the stream. + *

    + * This method will block until some data can be read. + * + * @param buf The array into which the chars read should be stored + * @param offset The offset into the array to start storing chars + * @param count The requested number of chars to read + * + * @return The actual number of chars read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + * @exception IndexOutOfBoundsException If offset and count are not + * valid regarding buf. + */ + public int read(char[] buf, int offset, int count) throws IOException + { + if (offset < 0 || offset + count > buf.length || count < 0) + throw new IndexOutOfBoundsException(); + + synchronized (lock) + { + checkStatus(); + // Once again, we need to handle the special case of a readLine + // that has a '\r' at the end of the buffer. In this case, we'll + // need to skip a '\n' if it is the next char to be read. + // This special case is indicated by 'pos > limit'. + boolean retAtEndOfBuffer = false; + + int avail = limit - pos; + if (count > avail) + { + if (avail > 0) + count = avail; + else // pos >= limit + { + if (limit == buffer.length) + markPos = -1; // read too far - invalidate the mark. + if (pos > limit) + { + // Set a boolean and make pos == limit to simplify things. + retAtEndOfBuffer = true; + --pos; + } + if (markPos < 0) + { + // Optimization: can read directly into buf. + if (count >= buffer.length && !retAtEndOfBuffer) + return in.read(buf, offset, count); + pos = limit = 0; + } + avail = in.read(buffer, limit, buffer.length - limit); + if (retAtEndOfBuffer && avail > 0 && buffer[limit] == '\n') + { + --avail; + limit++; + } + if (avail < count) + { + if (avail <= 0) + return avail; + count = avail; + } + limit += avail; + } + } + System.arraycopy(buffer, pos, buf, offset, count); + pos += count; + return count; + } + } + + /* Read more data into the buffer. Update pos and limit appropriately. + Assumes pos==limit initially. May invalidate the mark if read too much. + Return number of chars read (never 0), or -1 on eof. */ + private int fill() throws IOException + { + checkStatus(); + // Handle the special case of a readLine that has a '\r' at the end of + // the buffer. In this case, we'll need to skip a '\n' if it is the + // next char to be read. This special case is indicated by 'pos > limit'. + boolean retAtEndOfBuffer = false; + if (pos > limit) + { + retAtEndOfBuffer = true; + --pos; + } + + if (markPos >= 0 && limit == buffer.length) + markPos = -1; + if (markPos < 0) + pos = limit = 0; + int count = in.read(buffer, limit, buffer.length - limit); + if (count > 0) + limit += count; + + if (retAtEndOfBuffer && buffer[pos] == '\n') + { + --count; + // If the mark was set to the location of the \n, then we + // must change it to fully pretend that the \n does not + // exist. + if (markPos == pos) + ++markPos; + ++pos; + } + + return count; + } + + public int read() throws IOException + { + synchronized (lock) + { + checkStatus(); + if (pos >= limit && fill () <= 0) + return -1; + return buffer[pos++]; + } + } + + /* Return the end of the line starting at this.pos and ending at limit. + * The index returns is *before* any line terminators, or limit + * if no line terminators were found. + */ + private int lineEnd(int limit) + { + int i = pos; + for (; i < limit; i++) + { + char ch = buffer[i]; + if (ch == '\n' || ch == '\r') + break; + } + return i; + } + + /** + * This method reads a single line of text from the input stream, returning + * it as a String. A line is terminated by "\n", a "\r", or + * an "\r\n" sequence. The system dependent line separator is not used. + * The line termination characters are not returned in the resulting + * String. + * + * @return The line of text read, or null if end of stream. + * + * @exception IOException If an error occurs + */ + public String readLine() throws IOException + { + checkStatus(); + // Handle the special case where a previous readLine (with no intervening + // reads/skips) had a '\r' at the end of the buffer. + // In this case, we'll need to skip a '\n' if it's the next char to be read. + // This special case is indicated by 'pos > limit'. + if (pos > limit) + { + int ch = read(); + if (ch < 0) + return null; + if (ch != '\n') + --pos; + } + int i = lineEnd(limit); + if (i < limit) + { + String str = String.valueOf(buffer, pos, i - pos); + pos = i + 1; + // If the last char in the buffer is a '\r', we must remember + // to check if the next char to be read after the buffer is refilled + // is a '\n'. If so, skip it. To indicate this condition, we set pos + // to be limit + 1, which normally is never possible. + if (buffer[i] == '\r') + if (pos == limit || buffer[pos] == '\n') + pos++; + return str; + } + if (sbuf == null) + sbuf = new StringBuffer(200); + else + sbuf.setLength(0); + sbuf.append(buffer, pos, i - pos); + pos = i; + // We only want to return null when no characters were read before + // EOF. So we must keep track of this separately. Otherwise we + // would treat an empty `sbuf' as an EOF condition, which is wrong + // when there is just a newline. + boolean eof = false; + for (;;) + { + // readLine should block. So we must not return until a -1 is reached. + if (pos >= limit) + { + // here count == 0 isn't sufficient to give a failure. + int count = fill(); + if (count < 0) + { + eof = true; + break; + } + continue; + } + int ch = buffer[pos++]; + if (ch == '\n' || ch == '\r') + { + // Check here if a '\r' was the last char in the buffer; if so, + // mark it as in the comment above to indicate future reads + // should skip a newline that is the next char read after + // refilling the buffer. + if (ch == '\r') + if (pos == limit || buffer[pos] == '\n') + pos++; + break; + } + i = lineEnd(limit); + sbuf.append(buffer, pos - 1, i - (pos - 1)); + pos = i; + } + return (sbuf.length() == 0 && eof) ? null : sbuf.toString(); + } + + /** + * This method skips the specified number of chars in the stream. It + * returns the actual number of chars skipped, which may be less than the + * requested amount. + *

    + * This method first discards chars in the buffer, then calls the + * skip method on the underlying stream to skip the + * remaining chars. + * + * @param count The requested number of chars to skip + * + * @return The actual number of chars skipped. + * + * @exception IOException If an error occurs. + * @exception IllegalArgumentException If count is negative. + */ + public long skip(long count) throws IOException + { + synchronized (lock) + { + checkStatus(); + if (count < 0) + throw new IllegalArgumentException("skip value is negative"); + if (count == 0) + return 0; + // Yet again, we need to handle the special case of a readLine + // that has a '\r' at the end of the buffer. In this case, we need + // to ignore a '\n' if it is the next char to be read. + // This special case is indicated by 'pos > limit' (i.e. avail < 0). + // To simplify things, if we're dealing with the special case for + // readLine, just read the next char (since the fill method will + // skip the '\n' for us). By doing this, we'll have to back up pos. + // That's easier than trying to keep track of whether we've skipped + // one element or not. + if (pos > limit) + { + if (read() < 0) + return 0; + else + --pos; + } + + int avail = limit - pos; + + if (count < avail) + { + pos += count; + return count; + } + + pos = limit; + long todo = count - avail; + if (todo > buffer.length) + { + markPos = -1; + todo -= in.skip(todo); + } + else + { + while (todo > 0) + { + avail = fill(); + if (avail <= 0) + break; + if (avail > todo) + avail = (int) todo; + pos += avail; + todo -= avail; + } + } + return count - todo; + } + } + + private void checkStatus() throws IOException + { + if (in == null) + throw new IOException("Stream closed"); + } +} diff --git a/libjava/classpath/java/io/BufferedWriter.java b/libjava/classpath/java/io/BufferedWriter.java new file mode 100644 index 0000000..185a534 --- /dev/null +++ b/libjava/classpath/java/io/BufferedWriter.java @@ -0,0 +1,262 @@ +/* BufferedWriter.java -- Buffer output into large blocks before writing + Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.1. + */ + +/** + * This class accumulates chars written in a buffer instead of immediately + * writing the data to the underlying output sink. The chars are instead + * as one large block when the buffer is filled, or when the stream is + * closed or explicitly flushed. This mode operation can provide a more + * efficient mechanism for writing versus doing numerous small unbuffered + * writes. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @date September 25, 1998 + */ +public class BufferedWriter extends Writer +{ + /** + * This is the default buffer size + */ + private static final int DEFAULT_BUFFER_SIZE = 8192; + + /** + * This is the underlying Writer to which this object + * sends its output. + */ + private Writer out; + + /** + * This is the internal char array used for buffering output before + * writing it. + */ + char[] buffer; + + /** + * This is the number of chars that are currently in the buffer and + * are waiting to be written to the underlying stream. It always points to + * the index into the buffer where the next char of data will be stored + */ + int count; + + /** + * This method initializes a new BufferedWriter instance + * that will write to the specified subordinate Writer + * and which will use a default buffer size of 8192 chars. + * + * @param out The underlying Writer to write data to + */ + public BufferedWriter (Writer out) + { + this (out, DEFAULT_BUFFER_SIZE); + } + + /** + * This method initializes a new BufferedWriter instance + * that will write to the specified subordinate Writer + * and which will use the specified buffer size + * + * @param out The underlying Writer to write data to + * @param size The size of the internal buffer + */ + public BufferedWriter (Writer out, int size) + { + super(out.lock); + this.out = out; + this.buffer = new char[size]; + this.count = 0; + } + + /** + * This method flushes any remaining buffered chars then closes the + * underlying output stream. Any further attempts to write to this stream + * may throw an exception + * + * @exception IOException If an error occurs. + */ + public void close () throws IOException + { + synchronized (lock) + { + // It is safe to call localFlush even if the stream is already + // closed. + localFlush (); + out.close(); + buffer = null; + } + } + + /** + * This method causes any currently buffered chars to be immediately + * written to the underlying output stream. + * + * @exception IOException If an error occurs + */ + public void flush () throws IOException + { + synchronized (lock) + { + if (buffer == null) + throw new IOException ("Stream closed"); + localFlush (); + out.flush(); + } + } + + /** + * This method writes out a system depedent line separator sequence. The + * actual value written is detemined from the

    line.separator + * system property. + * + * @exception IOException If an error occurs + */ + public void newLine () throws IOException + { + write (System.getProperty("line.separator")); + } + + /** + * This method writes a single char of data. This will be written to the + * buffer instead of the underlying data source. However, if the buffer + * is filled as a result of this write request, it will be flushed to the + * underlying output stream. + * + * @param oneChar The char of data to be written, passed as an int + * + * @exception IOException If an error occurs + */ + public void write (int oneChar) throws IOException + { + synchronized (lock) + { + if (buffer == null) + throw new IOException ("Stream closed"); + buffer[count++] = (char) oneChar; + if (count == buffer.length) + localFlush (); + } + } + + /** + * This method writes len chars from the char array + * buf starting at position offset in the buffer. + * These chars will be written to the internal buffer. However, if this + * write operation fills the buffer, the buffer will be flushed to the + * underlying output stream. + * + * @param buf The array of chars to write. + * @param offset The index into the char array to start writing from. + * @param len The number of chars to write. + * + * @exception IOException If an error occurs + */ + public void write (char[] buf, int offset, int len) throws IOException + { + synchronized (lock) + { + if (buffer == null) + throw new IOException ("Stream closed"); + + // Bypass buffering if there is too much incoming data. + if (count + len > buffer.length) + { + localFlush (); + out.write(buf, offset, len); + } + else + { + System.arraycopy(buf, offset, buffer, count, len); + count += len; + if (count == buffer.length) + localFlush (); + } + } + } + + /** + * This method writes len chars from the String + * str starting at position offset in the string. + * These chars will be written to the internal buffer. However, if this + * write operation fills the buffer, the buffer will be flushed to the + * underlying output stream. + * + * @param str The String to write. + * @param offset The index into the string to start writing from. + * @param len The number of chars to write. + * + * @exception IOException If an error occurs + */ + public void write (String str, int offset, int len) throws IOException + { + synchronized (lock) + { + if (buffer == null) + throw new IOException ("Stream closed"); + + if (count + len > buffer.length) + { + localFlush (); + out.write(str, offset, len); + } + else + { + str.getChars(offset, offset + len, buffer, count); + count += len; + if (count == buffer.length) + localFlush (); + } + } + } + + // This should only be called with the lock held. + private void localFlush () throws IOException + { + if (count > 0) + { + out.write(buffer, 0, count); + count = 0; + } + } +} diff --git a/libjava/classpath/java/io/ByteArrayInputStream.java b/libjava/classpath/java/io/ByteArrayInputStream.java new file mode 100644 index 0000000..2bbde95 --- /dev/null +++ b/libjava/classpath/java/io/ByteArrayInputStream.java @@ -0,0 +1,251 @@ +/* ByteArrayInputStream.java -- Read an array as a stream + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/** + * This class permits an array of bytes to be read as an input stream. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class ByteArrayInputStream extends InputStream +{ + /** + * The array that contains the data supplied during read operations + */ + protected byte[] buf; + + /** + * The array index of the next byte to be read from the buffer + * buf + */ + protected int pos; + + /** + * The currently marked position in the stream. This defaults to 0, so a + * reset operation on the stream resets it to read from array index 0 in + * the buffer - even if the stream was initially created with an offset + * greater than 0 + */ + protected int mark; + + /** + * This indicates the maximum number of bytes that can be read from this + * stream. It is the array index of the position after the last valid + * byte in the buffer buf + */ + protected int count; + + /** + * Create a new ByteArrayInputStream that will read bytes from the passed + * in byte array. This stream will read from the beginning to the end + * of the array. It is identical to calling an overloaded constructor + * as ByteArrayInputStream(buf, 0, buf.length). + *

    + * Note that this array is not copied. If its contents are changed + * while this stream is being read, those changes will be reflected in the + * bytes supplied to the reader. Please use caution in changing the + * contents of the buffer while this stream is open. + * + * @param buffer The byte array buffer this stream will read from. + */ + public ByteArrayInputStream(byte[] buffer) + { + this(buffer, 0, buffer.length); + } + + /** + * Create a new ByteArrayInputStream that will read bytes from the + * passed in byte array. This stream will read from position + * offset in the array for a length of + * length bytes past offset. If the + * stream is reset to a position before offset then + * more than length bytes can be read from the stream. + * The length value should be viewed as the array index + * one greater than the last position in the buffer to read. + *

    + * Note that this array is not copied. If its contents are changed + * while this stream is being read, those changes will be reflected in the + * bytes supplied to the reader. Please use caution in changing the + * contents of the buffer while this stream is open. + * + * @param buffer The byte array buffer this stream will read from. + * @param offset The index into the buffer to start reading bytes from + * @param length The number of bytes to read from the buffer + */ + public ByteArrayInputStream(byte[] buffer, int offset, int length) + { + if (offset < 0 || length < 0 || offset > buffer.length) + throw new IllegalArgumentException(); + + buf = buffer; + + count = offset + length; + if (count > buf.length) + count = buf.length; + + pos = offset; + mark = pos; + } + + /** + * This method returns the number of bytes available to be read from this + * stream. The value returned will be equal to count - pos. + * + * @return The number of bytes that can be read from this stream + * before blocking, which is all of them + */ + public synchronized int available() + { + return count - pos; + } + + /** + * This method sets the mark position in this stream to the current + * position. Note that the readlimit parameter in this + * method does nothing as this stream is always capable of + * remembering all the bytes int it. + *

    + * Note that in this class the mark position is set by default to + * position 0 in the stream. This is in constrast to some other + * stream types where there is no default mark position. + * + * @param readLimit The number of bytes this stream must remember. + * This parameter is ignored. + */ + public synchronized void mark(int readLimit) + { + // readLimit is ignored per Java Class Lib. book, p.220. + mark = pos; + } + + /** + * This method overrides the markSupported method in + * InputStream in order to return true - + * indicating that this stream class supports mark/reset + * functionality. + * + * @return true to indicate that this class supports + * mark/reset. + */ + public boolean markSupported() + { + return true; + } + + /** + * This method reads one byte from the stream. The pos + * counter is advanced to the next byte to be read. The byte read is + * returned as an int in the range of 0-255. If the stream position + * is already at the end of the buffer, no byte is read and a -1 is + * returned in order to indicate the end of the stream. + * + * @return The byte read, or -1 if end of stream + */ + public synchronized int read() + { + if (pos < count) + return ((int) buf[pos++]) & 0xFF; + return -1; + } + + /** + * This method reads bytes from the stream and stores them into a + * caller supplied buffer. It starts storing the data at index + * offset into the buffer and attempts to read + * len bytes. This method can return before reading + * the number of bytes requested if the end of the stream is + * encountered first. The actual number of bytes read is returned. + * If no bytes can be read because the stream is already at the end + * of stream position, a -1 is returned. + *

    + * This method does not block. + * + * @param buffer The array into which the bytes read should be stored. + * @param offset The offset into the array to start storing bytes + * @param length The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of stream. + */ + public synchronized int read(byte[] buffer, int offset, int length) + { + if (pos >= count) + return -1; + + int numBytes = Math.min(count - pos, length); + System.arraycopy(buf, pos, buffer, offset, numBytes); + pos += numBytes; + return numBytes; + } + + /** + * This method sets the read position in the stream to the mark + * point by setting the pos variable equal to the + * mark variable. Since a mark can be set anywhere in + * the array, the mark/reset methods int this class can be used to + * provide random search capabilities for this type of stream. + */ + public synchronized void reset() + { + pos = mark; + } + + /** + * This method attempts to skip the requested number of bytes in the + * input stream. It does this by advancing the pos + * value by the specified number of bytes. It this would exceed the + * length of the buffer, then only enough bytes are skipped to + * position the stream at the end of the buffer. The actual number + * of bytes skipped is returned. + * + * @param num The requested number of bytes to skip + * + * @return The actual number of bytes skipped. + */ + public synchronized long skip(long num) + { + // Even though the var numBytes is a long, in reality it can never + // be larger than an int since the result of subtracting 2 positive + // ints will always fit in an int. Since we have to return a long + // anyway, numBytes might as well just be a long. + long numBytes = Math.min((long) (count - pos), num < 0 ? 0L : num); + pos += numBytes; + return numBytes; + } +} diff --git a/libjava/classpath/java/io/ByteArrayOutputStream.java b/libjava/classpath/java/io/ByteArrayOutputStream.java new file mode 100644 index 0000000..e996ebb --- /dev/null +++ b/libjava/classpath/java/io/ByteArrayOutputStream.java @@ -0,0 +1,283 @@ +/* BufferedReader.java + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.1. + */ + +/** + * This class allows data to be written to a byte array buffer and + * and then retrieved by an application. The internal byte array + * buffer is dynamically resized to hold all the data written. Please + * be aware that writing large amounts to data to this stream will + * cause large amounts of memory to be allocated. + *

    + * The size of the internal buffer defaults to 32 and it is resized + * by doubling the size of the buffer. This default size can be + * overridden by using the + * gnu.java.io.ByteArrayOutputStream.initialBufferSize + * property. + *

    + * There is a constructor that specified the initial buffer size and + * that is the preferred way to set that value because it it portable + * across all Java class library implementations. + *

    + * Note that this class also has methods that convert the byte array + * buffer to a String using either the system default or an + * application specified character encoding. Thus it can handle + * multibyte character encodings. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @date September 24, 1998 + */ +public class ByteArrayOutputStream extends OutputStream +{ + /** + * This method initializes a new ByteArrayOutputStream + * with the default buffer size of 32 bytes. If a different initial + * buffer size is desired, see the constructor + * ByteArrayOutputStream(int size). For applications + * where the source code is not available, the default buffer size + * can be set using the system property + * gnu.java.io.ByteArrayOutputStream.initialBufferSize + */ + public ByteArrayOutputStream () + { + this (initial_buffer_size); + } + + /** + * This method initializes a new ByteArrayOutputStream with + * a specified initial buffer size. + * + * @param size The initial buffer size in bytes + */ + public ByteArrayOutputStream (int size) + { + buf = new byte[size]; + count = 0; + } + + /** + * This method discards all of the bytes that have been written to + * the internal buffer so far by setting the count + * variable to 0. The internal buffer remains at its currently + * allocated size. + */ + public synchronized void reset () + { + count = 0; + } + + /** + * This method returns the number of bytes that have been written to + * the buffer so far. This is the same as the value of the protected + * count variable. If the reset method is + * called, then this value is reset as well. Note that this method does + * not return the length of the internal buffer, but only the number + * of bytes that have been written to it. + * + * @return The number of bytes in the internal buffer + * + * @see #reset() + */ + public int size () + { + return count; + } + + /** + * This method returns a byte array containing the bytes that have been + * written to this stream so far. This array is a copy of the valid + * bytes in the internal buffer and its length is equal to the number of + * valid bytes, not necessarily to the the length of the current + * internal buffer. Note that since this method allocates a new array, + * it should be used with caution when the internal buffer is very large. + */ + public synchronized byte[] toByteArray () + { + byte[] ret = new byte[count]; + System.arraycopy(buf, 0, ret, 0, count); + return ret; + } + + /** + * Returns the bytes in the internal array as a String. The + * bytes in the buffer are converted to characters using the system default + * encoding. There is an overloaded toString() method that + * allows an application specified character encoding to be used. + * + * @return A String containing the data written to this + * stream so far + */ + public String toString () + { + return new String (buf, 0, count); + } + + /** + * Returns the bytes in the internal array as a String. The + * bytes in the buffer are converted to characters using the specified + * encoding. + * + * @param enc The name of the character encoding to use + * + * @return A String containing the data written to this + * stream so far + * + * @exception UnsupportedEncodingException If the named encoding is + * not available + */ + public String toString (String enc) throws UnsupportedEncodingException + { + return new String (buf, 0, count, enc); + } + + /** + * This method returns the bytes in the internal array as a + * String. It uses each byte in the array as the low + * order eight bits of the Unicode character value and the passed in + * parameter as the high eight bits. + *

    + * This method does not convert bytes to characters in the proper way and + * so is deprecated in favor of the other overloaded toString + * methods which use a true character encoding. + * + * @param hibyte The high eight bits to use for each character in + * the String + * + * @return A String containing the data written to this + * stream so far + * + * @deprecated + */ + public String toString (int hibyte) + { + return new String (buf, 0, count, hibyte); + } + + // Resize buffer to accommodate new bytes. + private void resize (int add) + { + if (count + add > buf.length) + { + int newlen = buf.length * 2; + if (count + add > newlen) + newlen = count + add; + byte[] newbuf = new byte[newlen]; + System.arraycopy(buf, 0, newbuf, 0, count); + buf = newbuf; + } + } + + /** + * This method writes the writes the specified byte into the internal + * buffer. + * + * @param oneByte The byte to be read passed as an int + */ + public synchronized void write (int oneByte) + { + resize (1); + buf[count++] = (byte) oneByte; + } + + /** + * This method writes len bytes from the passed in array + * buf starting at index offset into the + * internal buffer. + * + * @param buffer The byte array to write data from + * @param offset The index into the buffer to start writing data from + * @param add The number of bytes to write + */ + public synchronized void write (byte[] buffer, int offset, int add) + { + // If ADD < 0 then arraycopy will throw the appropriate error for + // us. + if (add >= 0) + resize (add); + System.arraycopy(buffer, offset, buf, count, add); + count += add; + } + + /** + * This method writes all the bytes that have been written to this stream + * from the internal buffer to the specified OutputStream. + * + * @param out The OutputStream to write to + * + * @exception IOException If an error occurs + */ + public synchronized void writeTo (OutputStream out) throws IOException + { + out.write(buf, 0, count); + } + + /** + * The internal buffer where the data written is stored + */ + protected byte[] buf; + + /** + * The number of bytes that have been written to the buffer + */ + protected int count; + + /** + * The default initial buffer size. Specified by the JCL. + */ + private static final int DEFAULT_INITIAL_BUFFER_SIZE = 32; + + // The default buffer size which can be overridden by the user. + private static final int initial_buffer_size; + + static + { + int r + = Integer.getInteger ("gnu.java.io.ByteArrayOutputStream.initialBufferSize", + DEFAULT_INITIAL_BUFFER_SIZE).intValue (); + if (r <= 0) + r = DEFAULT_INITIAL_BUFFER_SIZE; + initial_buffer_size = r; + } +} diff --git a/libjava/classpath/java/io/CharArrayReader.java b/libjava/classpath/java/io/CharArrayReader.java new file mode 100644 index 0000000..c14fa07 --- /dev/null +++ b/libjava/classpath/java/io/CharArrayReader.java @@ -0,0 +1,305 @@ +/* CharArrayReader.java -- Read an array of characters as a stream + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/** + * This class permits an array of chars to be read as an input stream. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class CharArrayReader extends Reader +{ + /** + * The array that contains the data supplied during read operations + */ + protected char[] buf; + + /** + * The array index of the next char to be read from the buffer + * buf + */ + protected int pos; + + /** + * The currently marked position in the stream. This defaults to 0, so a + * reset operation on the stream resets it to read from array index 0 in + * the buffer - even if the stream was initially created with an offset + * greater than 0 + */ + protected int markedPos; + + /** + * This indicates the maximum number of chars that can be read from this + * stream. It is the array index of the position after the last valid + * char in the buffer buf + */ + protected int count; + + /** + * Create a new CharArrayReader that will read chars from the passed + * in char array. This stream will read from the beginning to the end + * of the array. It is identical to calling an overloaded constructor + * as CharArrayReader(buf, 0, buf.length). + *

    + * Note that this array is not copied. If its contents are changed + * while this stream is being read, those changes will be reflected in the + * chars supplied to the reader. Please use caution in changing the + * contents of the buffer while this stream is open. + * + * @param buffer The char array buffer this stream will read from. + */ + public CharArrayReader(char[] buffer) + { + this(buffer, 0, buffer.length); + } + + /** + * Create a new CharArrayReader that will read chars from the passed + * in char array. This stream will read from position + * offset in the array for a length of + * length chars past offset. If the + * stream is reset to a position before offset then + * more than length chars can be read from the stream. + * The length value should be viewed as the array index + * one greater than the last position in the buffer to read. + *

    + * Note that this array is not copied. If its contents are changed + * while this stream is being read, those changes will be reflected in the + * chars supplied to the reader. Please use caution in changing the + * contents of the buffer while this stream is open. + * + * @param buffer The char array buffer this stream will read from. + * @param offset The index into the buffer to start reading chars from + * @param length The number of chars to read from the buffer + */ + public CharArrayReader(char[] buffer, int offset, int length) + { + super(); + if (offset < 0 || length < 0 || offset > buffer.length) + throw new IllegalArgumentException(); + + buf = buffer; + + count = offset + length; + if (count > buf.length) + count = buf.length; + + pos = offset; + markedPos = pos; + } + + /** + * This method closes the stream. + */ + public void close() + { + synchronized (lock) + { + buf = null; + } + } + + /** + * This method sets the mark position in this stream to the current + * position. Note that the readlimit parameter in this + * method does nothing as this stream is always capable of + * remembering all the chars int it. + *

    + * Note that in this class the mark position is set by default to + * position 0 in the stream. This is in constrast to some other + * stream types where there is no default mark position. + * + * @param readAheadLimit The number of chars this stream must + * remember. This parameter is ignored. + * + * @exception IOException If an error occurs + */ + public void mark(int readAheadLimit) throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + // readAheadLimit is ignored per Java Class Lib. book, p. 318. + markedPos = pos; + } + } + + /** + * This method overrides the markSupported method in + * Reader in order to return true - + * indicating that this stream class supports mark/reset + * functionality. + * + * @return true to indicate that this class supports + * mark/reset. + */ + public boolean markSupported() + { + return true; + } + + /** + * This method reads one char from the stream. The pos + * counter is advanced to the next char to be read. The char read + * is returned as an int in the range of 0-65535. If the stream + * position is already at the end of the buffer, no char is read and + * a -1 is returned in order to indicate the end of the stream. + * + * @return The char read, or -1 if end of stream + */ + public int read() throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + + if (pos < 0) + throw new ArrayIndexOutOfBoundsException(pos); + + if (pos < count) + return ((int) buf[pos++]) & 0xFFFF; + return -1; + } + } + + /** + * This method reads chars from the stream and stores them into a + * caller supplied buffer. It starts storing the data at index + * offset into the buffer and attempts to read + * len chars. This method can return before reading + * the number of chars requested if the end of the stream is + * encountered first. The actual number of chars read is returned. + * If no chars can be read because the stream is already at the end + * of stream position, a -1 is returned. + *

    + * This method does not block. + * + * @param b The array into which the chars read should be stored. + * @param off The offset into the array to start storing chars + * @param len The requested number of chars to read + * + * @return The actual number of chars read, or -1 if end of stream. + */ + public int read(char[] b, int off, int len) throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + + /* Don't need to check pos value, arraycopy will check it. */ + if (off < 0 || len < 0 || off + len > b.length) + throw new IndexOutOfBoundsException(); + + if (pos >= count) + return -1; + + int numChars = Math.min(count - pos, len); + System.arraycopy(buf, pos, b, off, numChars); + pos += numChars; + return numChars; + } + } + + /** + * Return true if more characters are available to be read. + * + * @return true to indicate that this stream is ready + * to be read. + * + * @specnote The JDK 1.3 API docs are wrong here. This method will + * return false if there are no more characters available. + */ + public boolean ready() throws IOException + { + if (buf == null) + throw new IOException("Stream closed"); + + return (pos < count); + } + + /** + * This method sets the read position in the stream to the mark + * point by setting the pos variable equal to the + * mark variable. Since a mark can be set anywhere in + * the array, the mark/reset methods int this class can be used to + * provide random search capabilities for this type of stream. + */ + public void reset() throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + + pos = markedPos; + } + } + + /** + * This method attempts to skip the requested number of chars in the + * input stream. It does this by advancing the pos value by the + * specified number of chars. It this would exceed the length of the + * buffer, then only enough chars are skipped to position the stream at + * the end of the buffer. The actual number of chars skipped is returned. + * + * @param n The requested number of chars to skip + * + * @return The actual number of chars skipped. + */ + public long skip(long n) throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + + // Even though the var numChars is a long, in reality it can never + // be larger than an int since the result of subtracting 2 positive + // ints will always fit in an int. Since we have to return a long + // anyway, numChars might as well just be a long. + long numChars = Math.min((long) (count - pos), n < 0 ? 0L : n); + pos += numChars; + return numChars; + } + } +} diff --git a/libjava/classpath/java/io/CharArrayWriter.java b/libjava/classpath/java/io/CharArrayWriter.java new file mode 100644 index 0000000..f9b338f --- /dev/null +++ b/libjava/classpath/java/io/CharArrayWriter.java @@ -0,0 +1,274 @@ +/* CharArrayWriter.java -- Write chars to a buffer + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * This class allows data to be written to a char array buffer and + * and then retrieved by an application. The internal char array + * buffer is dynamically resized to hold all the data written. Please + * be aware that writing large amounts to data to this stream will + * cause large amounts of memory to be allocated. + *

    + * The size of the internal buffer defaults to 32 and it is resized + * in increments of 1024 chars. This behavior can be over-ridden by using the + * following two properties: + *

    + *

      + *
    • gnu.java.io.CharArrayWriter.initialBufferSize
    • + *
    • gnu.java.io.CharArrayWriter.bufferIncrementSize
    • + *
    + *

    + * There is a constructor that specified the initial buffer size and + * that is the preferred way to set that value because it it portable + * across all Java class library implementations. + *

    + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class CharArrayWriter extends Writer +{ + /** + * The default initial buffer size + */ + private static final int DEFAULT_INITIAL_BUFFER_SIZE = 32; + + /** + * This method initializes a new CharArrayWriter with + * the default buffer size of 32 chars. If a different initial + * buffer size is desired, see the constructor + * CharArrayWriter(int size). + */ + public CharArrayWriter () + { + this (DEFAULT_INITIAL_BUFFER_SIZE); + } + + /** + * This method initializes a new CharArrayWriter with + * a specified initial buffer size. + * + * @param size The initial buffer size in chars + */ + public CharArrayWriter (int size) + { + super (); + buf = new char[size]; + } + + /** + * Closes the stream. This method is guaranteed not to free the contents + * of the internal buffer, which can still be retrieved. + */ + public void close () + { + } + + /** + * This method flushes all buffered chars to the stream. + */ + public void flush () + { + } + + /** + * This method discards all of the chars that have been written to the + * internal buffer so far by setting the count variable to + * 0. The internal buffer remains at its currently allocated size. + */ + public void reset () + { + synchronized (lock) + { + count = 0; + } + } + + /** + * This method returns the number of chars that have been written to + * the buffer so far. This is the same as the value of the protected + * count variable. If the reset method is + * called, then this value is reset as well. Note that this method does + * not return the length of the internal buffer, but only the number + * of chars that have been written to it. + * + * @return The number of chars in the internal buffer + * + * @see #reset() + */ + public int size () + { + return count; + } + + /** + * This method returns a char array containing the chars that have been + * written to this stream so far. This array is a copy of the valid + * chars in the internal buffer and its length is equal to the number of + * valid chars, not necessarily to the the length of the current + * internal buffer. Note that since this method allocates a new array, + * it should be used with caution when the internal buffer is very large. + */ + public char[] toCharArray () + { + synchronized (lock) + { + char[] nc = new char[count]; + System.arraycopy(buf, 0, nc, 0, count); + return nc; + } + } + + /** + * Returns the chars in the internal array as a String. The + * chars in the buffer are converted to characters using the system default + * encoding. There is an overloaded toString() method that + * allows an application specified character encoding to be used. + * + * @return A String containing the data written to this + * stream so far + */ + public String toString () + { + synchronized (lock) + { + return new String (buf, 0, count); + } + } + + /** + * This method writes the writes the specified char into the internal + * buffer. + * + * @param oneChar The char to be read passed as an int + */ + public void write (int oneChar) + { + synchronized (lock) + { + resize (1); + buf[count++] = (char) oneChar; + } + } + + /** + * This method writes len chars from the passed in array + * buf starting at index offset into that buffer + * + * @param buffer The char array to write data from + * @param offset The index into the buffer to start writing data from + * @param len The number of chars to write + */ + public void write (char[] buffer, int offset, int len) + { + synchronized (lock) + { + if (len >= 0) + resize (len); + System.arraycopy(buffer, offset, buf, count, len); + count += len; + } + } + + /** + * This method writes len chars from the passed in + * String buf starting at index + * offset into the internal buffer. + * + * @param str The String to write data from + * @param offset The index into the string to start writing data from + * @param len The number of chars to write + */ + public void write (String str, int offset, int len) + { + synchronized (lock) + { + if (len >= 0) + resize (len); + str.getChars(offset, offset + len, buf, count); + count += len; + } + } + + /** + * This method writes all the chars that have been written to this stream + * from the internal buffer to the specified Writer. + * + * @param out The Writer to write to + * + * @exception IOException If an error occurs + */ + public void writeTo (Writer out) throws IOException + { + synchronized (lock) + { + out.write(buf, 0, count); + } + } + + /** + * This private method makes the buffer bigger when we run out of room + * by allocating a larger buffer and copying the valid chars from the + * old array into it. This is obviously slow and should be avoided by + * application programmers by setting their initial buffer size big + * enough to hold everything if possible. + */ + private void resize (int len) + { + if (count + len >= buf.length) + { + int newlen = buf.length * 2; + if (count + len > newlen) + newlen = count + len; + char[] newbuf = new char[newlen]; + System.arraycopy(buf, 0, newbuf, 0, count); + buf = newbuf; + } + } + + /** + * The internal buffer where the data written is stored + */ + protected char[] buf; + + /** + * The number of chars that have been written to the buffer + */ + protected int count; +} diff --git a/libjava/classpath/java/io/CharConversionException.java b/libjava/classpath/java/io/CharConversionException.java new file mode 100644 index 0000000..a7a6084 --- /dev/null +++ b/libjava/classpath/java/io/CharConversionException.java @@ -0,0 +1,73 @@ +/* CharConversionException.java -- Character conversion exceptions + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * This exception is thrown to indicate that a problem occurred with + * an attempted character conversion. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class CharConversionException extends IOException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -8680016352018427031L; + + /** + * Create an exception without a descriptive error message. + */ + public CharConversionException() + { + } + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + public CharConversionException(String message) + { + super(message); + } +} // class CharConversionException diff --git a/libjava/classpath/java/io/Closeable.java b/libjava/classpath/java/io/Closeable.java new file mode 100644 index 0000000..b8523d7 --- /dev/null +++ b/libjava/classpath/java/io/Closeable.java @@ -0,0 +1,63 @@ +/* Closeable.java -- Closeable object + Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +/** + * A Closeable class represents a stream of + * data, which can be closed when it is no longer needed. + * Closing a stream allows the resources it uses to be + * freed for an alternate use. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface Closeable +{ + + /** + * Closes the stream represented by this class, thus freeing + * system resources. In that case that the stream is already + * in the closed state, this method has no effect. + * + * @throws IOException if an I/O error occurs in closing. + */ + void close() + throws IOException; + +} diff --git a/libjava/classpath/java/io/DataInput.java b/libjava/classpath/java/io/DataInput.java new file mode 100644 index 0000000..45cb0c1 --- /dev/null +++ b/libjava/classpath/java/io/DataInput.java @@ -0,0 +1,456 @@ +/* DataInput.java -- Interface for reading data from a stream + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. */ + +/** + * This interface is implemented by classes that can data from streams + * into Java primitive types. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public interface DataInput +{ + + /** + * This method reads a Java boolean value from an input stream. It does + * so by reading a single byte of data. If that byte is zero, then the + * value returned is false. If the byte is non-zero, then + * the value returned is true. + *

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

    + * This method can read a byte written by an object + * implementing the + * writeByte() method in the DataOutput interface. + *

    + * @return The byte value read + * + * @exception EOFException If end of file is reached before reading the byte + * @exception IOException If any other error occurs + * + * @see DataOutput#writeByte + */ + byte readByte() throws EOFException, IOException; + + /** + * This method reads 8 unsigned bits into a Java int value from + * the stream. The value returned is in the range of 0 to 255. + *

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

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

    + * (char)((byte1 << 8) + byte2) + *

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    + * + * @return The line read as a String + * + * @exception IOException If an error occurs + */ + String readLine() throws IOException; + + /** + * This method reads a String from an input stream that is + * encoded in a modified UTF-8 format. This format has a leading two byte + * sequence that contains the remaining number of bytes to read. + * This two byte + * sequence is read using the readUnsignedShort() method of this + * interface. + * + * After the number of remaining bytes have been determined, these bytes + * are read an transformed into char values. These + * char values are encoded in the stream using either a one, + * two, or three byte format. + * The particular format in use can be determined by examining the first + * byte read. + *

    + * If the first byte has a high order bit of 0, then + * that character consists on only one byte. This character value consists + * of seven bits that are at positions 0 through 6 of the byte. As an + * example, if byte1 is the byte read from the stream, it would + * be converted to a char like so: + *

    + * (char)byte1 + *

    + * If the first byte has 110 as its high order bits, then the + * character consists of two bytes. The bits that make up the character + * value are in positions 0 through 4 of the first byte and bit positions + * 0 through 5 of the second byte. (The second byte should have + * 10 as its high order bits). These values are in most significant + * byte first (i.e., "big endian") order. + *

    + * As an example, if byte1 and byte2 are the first + * two bytes read respectively, and the high order bits of them match the + * patterns which indicate a two byte character encoding, then they would be + * converted to a Java char like so: + *

    + * (char)(((byte1 & 0x1F) << 6) + (byte2 & 0x3F)) + *

    + * If the first byte has a 1110 as its high order bits, then the + * character consists of three bytes. The bits that make up the character + * value are in positions 0 through 3 of the first byte and bit positions + * 0 through 5 of the other two bytes. (The second and third bytes should + * have 10 as their high order bits). These values are in most + * significant byte first (i.e., "big endian") order. + *

    + * As an example, if byte1, byte2, and + * byte3 are the three bytes read, and the high order bits of + * them match the patterns which indicate a three byte character encoding, + * then they would be converted to a Java char like so: + * + * + * (char)(((byte1 & 0x0F) << 12) + ((byte2 & 0x3F) + (byte3 & 0x3F)) + * + * + * Note that all characters are encoded in the method that requires the + * fewest number of bytes with the exception of the character with the + * value of \<llll>u0000 which is encoded as two bytes. + * This is a modification of the UTF standard used to prevent C language + * style NUL values from appearing in the byte stream. + *

    + * This method can read data that was written by an object implementing the + * writeUTF() method in DataOutput. + * + * @return The String read + * + * @exception EOFException If end of file is reached before reading the + * String + * @exception UTFDataFormatException If the data is not in UTF-8 format + * @exception IOException If any other error occurs + * + * @see DataOutput#writeUTF + */ + String readUTF() throws EOFException, UTFDataFormatException, IOException; + + /** + * This method reads raw bytes into the passed array until the array is + * full. Note that this method blocks until the data is available and + * throws an exception if there is not enough data left in the stream to + * fill the buffer. Note also that zero length buffers are permitted. + * In this case, the method will return immediately without reading any + * bytes from the stream. + * + * @param buf The buffer into which to read the data + * + * @exception EOFException If end of file is reached before filling the + * buffer + * @exception IOException If any other error occurs + */ + void readFully(byte[] buf) throws EOFException, IOException; + + /** + * This method reads raw bytes into the passed array buf + * starting + * offset bytes into the buffer. The number of bytes read + * will be + * exactly len. Note that this method blocks until the data is + * available and throws an exception if there is not enough data left in + * the stream to read len bytes. Note also that zero length + * buffers are permitted. In this case, the method will return immediately + * without reading any bytes from the stream. + * + * @param buf The buffer into which to read the data + * @param offset The offset into the buffer to start storing data + * @param len The number of bytes to read into the buffer + * + * @exception EOFException If end of file is reached before filling the + * buffer + * @exception IOException If any other error occurs + */ + void readFully(byte[] buf, int offset, int len) + throws EOFException, IOException; + + /** + * This method skips and discards the specified number of bytes in an + * input stream. Note that this method may skip less than the requested + * number of bytes. The actual number of bytes skipped is returned. + * No bytes are skipped if a negative number is passed to this method. + * + * @param numBytes The number of bytes to skip + * + * @return The number of bytes actually skipped, which will always be + * numBytes + * + * @exception EOFException If end of file is reached before all bytes can be + * skipped + * @exception IOException If any other error occurs + */ + int skipBytes(int numBytes) throws EOFException, IOException; + +} // interface DataInput diff --git a/libjava/classpath/java/io/DataInputStream.java b/libjava/classpath/java/io/DataInputStream.java new file mode 100644 index 0000000..d2604b5 --- /dev/null +++ b/libjava/classpath/java/io/DataInputStream.java @@ -0,0 +1,739 @@ +/* DataInputStream.java -- FilteredInputStream that implements DataInput + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This subclass of FilteredInputStream implements the + * DataInput interface that provides method for reading primitive + * Java data types from a stream. + * + * @see DataInput + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @date October 20, 1998. + */ +public class DataInputStream extends FilterInputStream implements DataInput +{ + // Byte buffer, used to make primitive read calls more efficient. + byte[] buf = new byte [8]; + + /** + * This constructor initializes a new DataInputStream + * to read from the specified subordinate stream. + * + * @param in The subordinate InputStream to read from + */ + public DataInputStream (InputStream in) + { + super (in); + } + + /** + * This method reads bytes from the underlying stream into the specified + * byte array buffer. It will attempt to fill the buffer completely, but + * may return a short count if there is insufficient data remaining to be + * read to fill the buffer. + * + * @param b The buffer into which bytes will be read. + * + * @return The actual number of bytes read, or -1 if end of stream reached + * before reading any bytes. + * + * @exception IOException If an error occurs. + */ + public final int read (byte[] b) throws IOException + { + return in.read (b, 0, b.length); + } + + /** + * This method reads bytes from the underlying stream into the specified + * byte array buffer. It will attempt to read len bytes and + * will start storing them at position off into the buffer. + * This method can return a short count if there is insufficient data + * remaining to be read to complete the desired read length. + * + * @param b The buffer into which bytes will be read. + * @param off The offset into the buffer to start storing bytes. + * @param len The requested number of bytes to read. + * + * @return The actual number of bytes read, or -1 if end of stream reached + * before reading any bytes. + * + * @exception IOException If an error occurs. + */ + public final int read (byte[] b, int off, int len) throws IOException + { + return in.read (b, off, len); + } + + /** + * This method reads a Java boolean value from an input stream. It does + * so by reading a single byte of data. If that byte is zero, then the + * value returned is false. If the byte is non-zero, then + * the value returned is true. + *

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    + * This method can read an unsigned short written by an object + * implementing the writeUnsignedShort() method in the + * DataOutput interface. + * + * @return The unsigned short value read as a Java int + * + * @exception EOFException If end of file is reached before reading the value + * @exception IOException If any other error occurs + * + * @see DataOutput#writeShort + */ + public final int readUnsignedShort () throws IOException + { + readFully (buf, 0, 2); + return convertToUnsignedShort (buf); + } + + /** + * This method reads a String from an input stream that + * is encoded in a modified UTF-8 format. This format has a leading + * two byte sequence that contains the remaining number of bytes to + * read. This two byte sequence is read using the + * readUnsignedShort() method of this interface. + *

    + * After the number of remaining bytes have been determined, these + * bytes are read an transformed into char values. + * These char values are encoded in the stream using + * either a one, two, or three byte format. The particular format + * in use can be determined by examining the first byte read. + *

    + * If the first byte has a high order bit of 0, then that character + * consists on only one byte. This character value consists of + * seven bits that are at positions 0 through 6 of the byte. As an + * example, if byte1 is the byte read from the stream, + * it would be converted to a char like so: + *

    + * (char)byte1 + *

    + * If the first byte has 110 as its high order bits, then the + * character consists of two bytes. The bits that make up the character + * value are in positions 0 through 4 of the first byte and bit positions + * 0 through 5 of the second byte. (The second byte should have + * 10 as its high order bits). These values are in most significant + * byte first (i.e., "big endian") order. + *

    + * As an example, if byte1 and byte2 are + * the first two bytes read respectively, and the high order bits of + * them match the patterns which indicate a two byte character + * encoding, then they would be converted to a Java + * char like so: + *

    + * (char)(((byte1 & 0x1F) << 6) | (byte2 & 0x3F)) + *

    + * If the first byte has a 1110 as its high order bits, then the + * character consists of three bytes. The bits that make up the character + * value are in positions 0 through 3 of the first byte and bit positions + * 0 through 5 of the other two bytes. (The second and third bytes should + * have 10 as their high order bits). These values are in most + * significant byte first (i.e., "big endian") order. + *

    + * As an example, if byte1 byte2 and + * byte3 are the three bytes read, and the high order + * bits of them match the patterns which indicate a three byte + * character encoding, then they would be converted to a Java + * char like so: + *

    + * (char)(((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | + * (byte3 & 0x3F)) + *

    + * Note that all characters are encoded in the method that requires + * the fewest number of bytes with the exception of the character + * with the value of \u0000 which is encoded as two + * bytes. This is a modification of the UTF standard used to + * prevent C language style NUL values from appearing + * in the byte stream. + *

    + * This method can read data that was written by an object implementing the + * writeUTF() method in DataOutput + * + * @return The String read + * + * @exception EOFException If end of file is reached before reading + * the String + * @exception UTFDataFormatException If the data is not in UTF-8 format + * @exception IOException If any other error occurs + * + * @see DataOutput#writeUTF + */ + public final String readUTF () throws IOException + { + return readUTF (this); + } + + /** + * This method reads a String encoded in UTF-8 format from the + * specified DataInput source. + * + * @param in The DataInput source to read from + * + * @return The String read from the source + * + * @exception IOException If an error occurs + * + * @see DataInput#readUTF + */ + public static final String readUTF(DataInput in) throws IOException + { + final int UTFlen = in.readUnsignedShort (); + byte[] buf = new byte [UTFlen]; + + // This blocks until the entire string is available rather than + // doing partial processing on the bytes that are available and then + // blocking. An advantage of the latter is that Exceptions + // could be thrown earlier. The former is a bit cleaner. + in.readFully (buf, 0, UTFlen); + + return convertFromUTF (buf); + } + + /** + * This method attempts to skip and discard the specified number of bytes + * in the input stream. It may actually skip fewer bytes than requested. + * This method will not skip any bytes if passed a negative number of bytes + * to skip. + * + * @param n The requested number of bytes to skip. + * + * @return The requested number of bytes to skip. + * + * @exception IOException If an error occurs. + * @specnote The JDK docs claim that this returns the number of bytes + * actually skipped. The JCL claims that this method can throw an + * EOFException. Neither of these appear to be true in the JDK 1.3's + * implementation. This tries to implement the actual JDK behaviour. + */ + public final int skipBytes (int n) throws IOException + { + if (n <= 0) + return 0; + try + { + return (int) in.skip (n); + } + catch (EOFException x) + { + // do nothing. + } + return n; + } + + static boolean convertToBoolean (int b) throws EOFException + { + if (b < 0) + throw new EOFException (); + + return (b != 0); + } + + static byte convertToByte (int i) throws EOFException + { + if (i < 0) + throw new EOFException (); + + return (byte) i; + } + + static int convertToUnsignedByte (int i) throws EOFException + { + if (i < 0) + throw new EOFException (); + + return (i & 0xFF); + } + + static char convertToChar (byte[] buf) + { + return (char) ((buf [0] << 8) + | (buf [1] & 0xff)); + } + + static short convertToShort (byte[] buf) + { + return (short) ((buf [0] << 8) + | (buf [1] & 0xff)); + } + + static int convertToUnsignedShort (byte[] buf) + { + return (((buf [0] & 0xff) << 8) + | (buf [1] & 0xff)); + } + + static int convertToInt (byte[] buf) + { + return (((buf [0] & 0xff) << 24) + | ((buf [1] & 0xff) << 16) + | ((buf [2] & 0xff) << 8) + | (buf [3] & 0xff)); + } + + static long convertToLong (byte[] buf) + { + return (((long)(buf [0] & 0xff) << 56) | + ((long)(buf [1] & 0xff) << 48) | + ((long)(buf [2] & 0xff) << 40) | + ((long)(buf [3] & 0xff) << 32) | + ((long)(buf [4] & 0xff) << 24) | + ((long)(buf [5] & 0xff) << 16) | + ((long)(buf [6] & 0xff) << 8) | + ((long)(buf [7] & 0xff))); + } + + // FIXME: This method should be re-thought. I suspect we have multiple + // UTF-8 decoders floating around. We should use the standard charset + // converters, maybe and adding a direct call into one of the new + // NIO converters for a super-fast UTF8 decode. + static String convertFromUTF (byte[] buf) + throws EOFException, UTFDataFormatException + { + // Give StringBuffer an initial estimated size to avoid + // enlarge buffer frequently + StringBuffer strbuf = new StringBuffer (buf.length / 2 + 2); + + for (int i = 0; i < buf.length; ) + { + if ((buf [i] & 0x80) == 0) // bit pattern 0xxxxxxx + strbuf.append ((char) (buf [i++] & 0xFF)); + else if ((buf [i] & 0xE0) == 0xC0) // bit pattern 110xxxxx + { + if (i + 1 >= buf.length + || (buf [i + 1] & 0xC0) != 0x80) + throw new UTFDataFormatException (); + + strbuf.append((char) (((buf [i++] & 0x1F) << 6) + | (buf [i++] & 0x3F))); + } + else if ((buf [i] & 0xF0) == 0xE0) // bit pattern 1110xxxx + { + if (i + 2 >= buf.length + || (buf [i + 1] & 0xC0) != 0x80 + || (buf [i + 2] & 0xC0) != 0x80) + throw new UTFDataFormatException (); + + strbuf.append ((char) (((buf [i++] & 0x0F) << 12) + | ((buf [i++] & 0x3F) << 6) + | (buf [i++] & 0x3F))); + } + else // must be ((buf [i] & 0xF0) == 0xF0 || (buf [i] & 0xC0) == 0x80) + throw new UTFDataFormatException (); // bit patterns 1111xxxx or + // 10xxxxxx + } + + return strbuf.toString (); + } +} diff --git a/libjava/classpath/java/io/DataOutput.java b/libjava/classpath/java/io/DataOutput.java new file mode 100644 index 0000000..0d43623 --- /dev/null +++ b/libjava/classpath/java/io/DataOutput.java @@ -0,0 +1,326 @@ +/* DataOutput.java -- Interface for writing data from a stream + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.1. + */ + +/** + * This interface is implemented by classes that can wrte data to streams + * from Java primitive types. This data can subsequently be read back + * by classes implementing the DataInput interface. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * + * @see DataInput + */ +public interface DataOutput +{ + /** + * This method writes a Java boolean value to an output stream. If + * value is true, a byte with the value of + * 1 will be written, otherwise a byte with the value of 0 will be + * written. + * + * The value written can be read using the readBoolean + * method in DataInput. + * + * @param value The boolean value to write + * + * @exception IOException If an error occurs + * + * @see DataInput#readBoolean + */ + void writeBoolean(boolean value) throws IOException; + + /** + * This method writes a Java byte value to an output stream. The + * byte to be written will be in the lowest 8 bits of the + * int value passed. + * + * The value written can be read using the readByte or + * readUnsignedByte methods in DataInput. + * + * @param value The int value to write + * + * @exception IOException If an error occurs + * + * @see DataInput#readByte + * @see DataInput#readUnsignedByte + */ + void writeByte(int value) throws IOException; + + /** + * This method writes a Java char value to an output stream. The + * char to be written will be in the lowest 16 bits of the int + * value passed. These bytes will be written "big endian". That is, + * with the high byte written first in the following manner: + *

    + * byte0 = (byte)((value & 0xFF00) >> 8);
    + * byte1 = (byte)(value & 0x00FF);
    + *

    + * + * The value written can be read using the readChar + * method in DataInput. + * + * @param value The char value to write + * + * @exception IOException If an error occurs + * + * @see DataInput#readChar + */ + void writeChar(int value) throws IOException; + + /** + * This method writes a Java short value to an output stream. The + * char to be written will be in the lowest 16 bits of the int + * value passed. These bytes will be written "big endian". That is, + * with the high byte written first in the following manner: + *

    + * byte0 = (byte)((value & 0xFF00) >> 8);
    + * byte1 = (byte)(value & 0x00FF);
    + *

    + * + * The value written can be read using the readShort and + * readUnsignedShort methods in DataInput. + * + * @param value The int value to write as a 16-bit value + * + * @exception IOException If an error occurs + * + * @see DataInput#readShort + * @see DataInput#readUnsignedShort + */ + void writeShort(int value) throws IOException; + + /** + * This method writes a Java int value to an output stream. The 4 bytes + * of the passed value will be written "big endian". That is, with + * the high byte written first in the following manner: + *

    + * byte0 = (byte)((value & 0xFF000000) >> 24);
    + * byte1 = (byte)((value & 0x00FF0000) >> 16);
    + * byte2 = (byte)((value & 0x0000FF00) >> 8);
    + * byte3 = (byte)(value & 0x000000FF);
    + *

    + * + * The value written can be read using the readInt + * method in DataInput. + * + * @param value The int value to write + * + * @exception IOException If an error occurs + * + * @see DataInput#readInt + */ + void writeInt(int value) throws IOException; + + /** + * This method writes a Java long value to an output stream. The 8 bytes + * of the passed value will be written "big endian". That is, with + * the high byte written first in the following manner: + *

    + * byte0 = (byte)((value & 0xFF00000000000000L) >> 56);
    + * byte1 = (byte)((value & 0x00FF000000000000L) >> 48);
    + * byte2 = (byte)((value & 0x0000FF0000000000L) >> 40);
    + * byte3 = (byte)((value & 0x000000FF00000000L) >> 32);
    + * byte4 = (byte)((value & 0x00000000FF000000L) >> 24);
    + * byte5 = (byte)((value & 0x0000000000FF0000L) >> 16);
    + * byte6 = (byte)((value & 0x000000000000FF00L) >> 8);
    + * byte7 = (byte)(value & 0x00000000000000FFL);
    + *

    + * + * The value written can be read using the readLong + * method in DataInput. + * + * @param value The long value to write + * + * @exception IOException If an error occurs + * + * @see DataInput#readLong + */ + void writeLong(long value) throws IOException; + + /** + * This method writes a Java float value to the stream. This + * value is written by first calling the method + * Float.floatToIntBits + * to retrieve an int representing the floating point number, + * then writing this int value to the stream exactly the same + * as the writeInt() method does. + * + * The value written can be read using the readFloat + * method in DataInput. + * + * @param value The float value to write + * + * @exception IOException If an error occurs + * + * @see #writeInt + * @see DataInput#readFloat + * @see Float#floatToIntBits + */ + void writeFloat(float value) throws IOException; + + /** + * This method writes a Java double value to the stream. This + * value is written by first calling the method + * Double.doubleToLongBits + * to retrieve an long representing the floating point number, + * then writing this long value to the stream exactly the same + * as the writeLong() method does. + * + * The value written can be read using the readDouble + * method in DataInput. + * + * @param value The double value to write + * + * @exception IOException If any other error occurs + * + * @see #writeLong + * @see DataInput#readDouble + * @see Double#doubleToLongBits + */ + void writeDouble(double value) throws IOException; + + /** + * This method writes all the bytes in a String out to the + * stream. One byte is written for each character in the + * String. + * The high eight bits of each character are discarded, thus this + * method is inappropriate for completely representing Unicode characters. + * + * @param value The String to write + * + * @exception IOException If an error occurs + */ + void writeBytes(String value) throws IOException; + + /** + * This method writes all the characters of a String to an + * output stream as an array of char's. Each character + * is written using the method specified in the writeChar + * method. + * + * @param value The String to write + * + * @exception IOException If an error occurs + * + * @see #writeChar(int) + */ + void writeChars(String value) throws IOException; + + /** + * This method writes a Java String to the stream in a modified + * UTF-8 format. First, two bytes are written to the stream indicating the + * number of bytes to follow. This is written in the form of a Java + * short value in the same manner used by the + * writeShort method. Note that this is the number of + * bytes in the + * encoded String not the String length. Next + * come the encoded characters. Each character in the String + * is encoded as either one, two or three bytes. For characters in the + * range of \u0001 to \u007F, one byte is used. + * The character + * value goes into bits 0-7 and bit eight is 0. For characters in the range + * of \u0080 to \u007FF, two bytes are used. Bits + * 6-10 of the character value are encoded bits 0-4 of the first byte, with + * the high bytes having a value of "110". Bits 0-5 of the character value + * are stored in bits 0-5 of the second byte, with the high bits set to + * "10". This type of encoding is also done for the null character + * \u0000. This eliminates any C style NUL character values + * in the output. All remaining characters are stored as three bytes. + * Bits 12-15 of the character value are stored in bits 0-3 of the first + * byte. The high bits of the first bytes are set to "1110". Bits 6-11 + * of the character value are stored in bits 0-5 of the second byte. The + * high bits of the second byte are set to "10". And bits 0-5 of the + * character value are stored in bits 0-5 of byte three, with the high bits + * of that byte set to "10". + * + * The value written can be read using the readUTF + * method in DataInput. + * + * @param value The String to write + * + * @exception IOException If an error occurs + * + * @see DataInput#readUTF + */ + void writeUTF(String value) throws IOException; + + /** + * This method writes an 8-bit value (passed into the method as a Java + * int) to an output stream. The low 8 bits of the + * passed value are written. + * + * @param value The byte to write to the output stream + * + * @exception IOException If an error occurs + */ + void write(int value) throws IOException; + + /** + * This method writes the raw byte array passed in to the output stream. + * + * @param buf The byte array to write + * + * @exception IOException If an error occurs + */ + void write(byte[] buf) throws IOException; + + /** + * This method writes raw bytes from the passed array buf + * starting + * offset bytes into the buffer. The number of bytes + * written will be exactly len. + * + * @param buf The buffer from which to write the data + * @param offset The offset into the buffer to start writing data from + * @param len The number of bytes to write from the buffer to the output + * stream + * + * @exception IOException If any other error occurs + */ + void write(byte[] buf, int offset, int len) throws IOException; + +} // interface DataOutput + diff --git a/libjava/classpath/java/io/DataOutputStream.java b/libjava/classpath/java/io/DataOutputStream.java new file mode 100644 index 0000000..39f7ed1f --- /dev/null +++ b/libjava/classpath/java/io/DataOutputStream.java @@ -0,0 +1,455 @@ +/* DataOutputStream.java -- Writes primitive Java datatypes to streams + Copyright (C) 1998, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.1. + */ + +/** + * This class provides a mechanism for writing primitive Java datatypes + * to an OutputStream in a portable way. Data written to + * a stream using this class can be read back in using the + * DataInputStream class on any platform. + * + * @see DataInputStream + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class DataOutputStream extends FilterOutputStream implements DataOutput +{ + /** + * This is the total number of bytes that have been written to the + * stream by this object instance. + */ + protected int written; + + /** + * This method initializes an instance of DataOutputStream to + * write its data to the specified underlying OutputStream + * + * @param out The subordinate OutputStream to which this + * object will write + */ + public DataOutputStream (OutputStream out) + { + super (out); + written = 0; + } + + /** + * This method flushes any unwritten bytes to the underlying stream. + * + * @exception IOException If an error occurs. + */ + public void flush () throws IOException + { + out.flush(); + } + + /** + * This method returns the total number of bytes that have been written to + * the underlying output stream so far. This is the value of the + * written instance variable + * + * @return The number of bytes written to the stream. + */ + public final int size () + { + return written; + } + + /** + * This method writes the specified byte (passed as an int) + * to the underlying output stream. + * + * @param value The byte to write, passed as an int. + * + * @exception IOException If an error occurs. + */ + public synchronized void write (int value) throws IOException + { + out.write (value); + ++written; + } + + /** + * This method writes len bytes from the specified byte array + * buf starting at position offset into the + * buffer to the underlying output stream. + * + * @param buf The byte array to write from. + * @param offset The index into the byte array to start writing from. + * @param len The number of bytes to write. + * + * @exception IOException If an error occurs. + */ + public synchronized void write (byte[] buf, int offset, int len) + throws IOException + { + out.write(buf, offset, len); + written += len; + } + + /** + * This method writes a Java boolean value to an output stream. If + * value is true, a byte with the value of + * 1 will be written, otherwise a byte with the value of 0 will be + * written. + * + * The value written can be read using the readBoolean + * method in DataInput. + * + * @param value The boolean value to write to the stream + * + * @exception IOException If an error occurs + * + * @see DataInput#readBoolean + */ + public final void writeBoolean (boolean value) throws IOException + { + write (value ? 1 : 0); + } + + /** + * This method writes a Java byte value to an output stream. The + * byte to be written will be in the lowest 8 bits of the + * int value passed. + * + * The value written can be read using the readByte or + * readUnsignedByte methods in DataInput. + * + * @param value The byte to write to the stream, passed as + * the low eight bits of an int. + * + * @exception IOException If an error occurs + * + * @see DataInput#readByte + * @see DataInput#readUnsignedByte + */ + public final void writeByte (int value) throws IOException + { + write (value & 0xff); + } + + /** + * This method writes a Java short value to an output stream. The + * char to be written will be in the lowest 16 bits of the int + * value passed. These bytes will be written "big endian". That is, + * with the high byte written first in the following manner: + *

    + * byte0 = (byte)((value & 0xFF00) >> 8);
    + * byte1 = (byte)(value & 0x00FF);
    + *

    + * + * The value written can be read using the readShort and + * readUnsignedShort methods in DataInput. + * + * @param value The short value to write to the stream, + * passed as an int. + * + * @exception IOException If an error occurs + * + * @see DataInput#readShort + * @see DataInput#readUnsignedShort + */ + public final synchronized void writeShort (int value) throws IOException + { + write ((byte) (0xff & (value >> 8))); + write ((byte) (0xff & value)); + } + + /** + * This method writes a Java char value to an output stream. The + * char to be written will be in the lowest 16 bits of the int + * value passed. These bytes will be written "big endian". That is, + * with the high byte written first in the following manner: + *

    + * byte0 = (byte)((value & 0xFF00) >> 8);
    + * byte1 = (byte)(value & 0x00FF);
    + *

    + * + * The value written can be read using the readChar + * method in DataInput. + * + * @param value The char value to write, + * passed as an int. + * + * @exception IOException If an error occurs + * + * @see DataInput#readChar + */ + public final synchronized void writeChar (int value) throws IOException + { + write ((byte) (0xff & (value >> 8))); + write ((byte) (0xff & value)); + } + + /** + * This method writes a Java int value to an output stream. The 4 bytes + * of the passed value will be written "big endian". That is, with + * the high byte written first in the following manner: + *

    + * byte0 = (byte)((value & 0xFF000000) >> 24);
    + * byte1 = (byte)((value & 0x00FF0000) >> 16);
    + * byte2 = (byte)((value & 0x0000FF00) >> 8);
    + * byte3 = (byte)(value & 0x000000FF);
    + *

    + * + * The value written can be read using the readInt + * method in DataInput. + * + * @param value The int value to write to the stream + * + * @exception IOException If an error occurs + * + * @see DataInput#readInt + */ + public final synchronized void writeInt (int value) throws IOException + { + write ((byte) (0xff & (value >> 24))); + write ((byte) (0xff & (value >> 16))); + write ((byte) (0xff & (value >> 8))); + write ((byte) (0xff & value)); + } + + /** + * This method writes a Java long value to an output stream. The 8 bytes + * of the passed value will be written "big endian". That is, with + * the high byte written first in the following manner: + *

    + * byte0 = (byte)((value & 0xFF00000000000000L) >> 56);
    + * byte1 = (byte)((value & 0x00FF000000000000L) >> 48);
    + * byte2 = (byte)((value & 0x0000FF0000000000L) >> 40);
    + * byte3 = (byte)((value & 0x000000FF00000000L) >> 32);
    + * byte4 = (byte)((value & 0x00000000FF000000L) >> 24);
    + * byte5 = (byte)((value & 0x0000000000FF0000L) >> 16);
    + * byte6 = (byte)((value & 0x000000000000FF00L) >> 8);
    + * byte7 = (byte)(value & 0x00000000000000FFL);
    + *

    + * + * The value written can be read using the readLong + * method in DataInput. + * + * @param value The long value to write to the stream + * + * @exception IOException If an error occurs + * + * @see DataInput#readLong + */ + public final synchronized void writeLong (long value) throws IOException + { + write ((byte) (0xff & (value >> 56))); + write ((byte) (0xff & (value>> 48))); + write ((byte) (0xff & (value>> 40))); + write ((byte) (0xff & (value>> 32))); + write ((byte) (0xff & (value>> 24))); + write ((byte) (0xff & (value>> 16))); + write ((byte) (0xff & (value>> 8))); + write ((byte) (0xff & value)); + } + + /** + * This method writes a Java float value to the stream. This + * value is written by first calling the method + * Float.floatToIntBits + * to retrieve an int representing the floating point number, + * then writing this int value to the stream exactly the same + * as the writeInt() method does. + * + * The value written can be read using the readFloat + * method in DataInput. + * + * @param value The float value to write to the stream + * + * @exception IOException If an error occurs + * + * @see writeInt + * @see DataInput#readFloat + * @see Float#floatToIntBits + */ + public final void writeFloat (float value) throws IOException + { + writeInt (Float.floatToIntBits (value)); + } + + /** + * This method writes a Java double value to the stream. This + * value is written by first calling the method + * Double.doubleToLongBits + * to retrieve an long representing the floating point number, + * then writing this long value to the stream exactly the same + * as the writeLong() method does. + * + * The value written can be read using the readDouble + * method in DataInput. + * + * @param value The double value to write to the stream + * + * @exception IOException If an error occurs + * + * @see writeLong + * @see DataInput#readDouble + * @see Double#doubleToLongBits + */ + public final void writeDouble (double value) throws IOException + { + writeLong (Double.doubleToLongBits (value)); + } + + /** + * This method writes all the bytes in a String out to the + * stream. One byte is written for each character in the + * String. + * The high eight bits of each character are discarded, thus this + * method is inappropriate for completely representing Unicode characters. + * + * @param value The String to write to the stream + * + * @exception IOException If an error occurs + */ + public final void writeBytes (String value) throws IOException + { + int len = value.length(); + for (int i = 0; i < len; ++i) + writeByte (value.charAt(i)); + } + + /** + * This method writes all the characters of a String to an + * output stream as an array of char's. Each character + * is written using the method specified in the writeChar + * method. + * + * @param value The String to write to the stream + * + * @exception IOException If an error occurs + * + * @see writeChar + */ + public final void writeChars (String value) throws IOException + { + int len = value.length(); + for (int i = 0; i < len; ++i) + writeChar (value.charAt(i)); + } + + /** + * This method writes a Java String to the stream in a modified + * UTF-8 format. First, two bytes are written to the stream indicating the + * number of bytes to follow. Note that this is the number of bytes in the + * encoded String not the String length. Next + * come the encoded characters. Each character in the String + * is encoded as either one, two or three bytes. For characters in the + * range of \u0001 to <\u007F>, one byte is used. The character + * value goes into bits 0-7 and bit eight is 0. For characters in the range + * of \u0080 to \u007FF, two bytes are used. Bits + * 6-10 of the character value are encoded bits 0-4 of the first byte, with + * the high bytes having a value of "110". Bits 0-5 of the character value + * are stored in bits 0-5 of the second byte, with the high bits set to + * "10". This type of encoding is also done for the null character + * \u0000. This eliminates any C style NUL character values + * in the output. All remaining characters are stored as three bytes. + * Bits 12-15 of the character value are stored in bits 0-3 of the first + * byte. The high bits of the first bytes are set to "1110". Bits 6-11 + * of the character value are stored in bits 0-5 of the second byte. The + * high bits of the second byte are set to "10". And bits 0-5 of the + * character value are stored in bits 0-5 of byte three, with the high bits + * of that byte set to "10". + * + * The value written can be read using the readUTF + * method in DataInput. + * + * @param value The String to write to the output in UTF format + * + * @exception IOException If an error occurs + * + * @see DataInput#readUTF + */ + public final synchronized void writeUTF(String value) throws IOException + { + int len = value.length(); + int sum = 0; + + for (int i = 0; i < len && sum <= 65535; ++i) + { + char c = value.charAt(i); + if (c >= '\u0001' && c <= '\u007f') + sum += 1; + else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff')) + sum += 2; + else + sum += 3; + } + + if (sum > 65535) + throw new UTFDataFormatException (); + + int pos = 0; + byte[] buf = new byte[sum]; + + for (int i = 0; i < len; ++i) + { + char c = value.charAt(i); + if (c >= '\u0001' && c <= '\u007f') + buf[pos++] = (byte) c; + else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff')) + { + buf[pos++] = (byte) (0xc0 | (0x1f & (c >> 6))); + buf[pos++] = (byte) (0x80 | (0x3f & c)); + } + else + { + // JSL says the first byte should be or'd with 0xc0, but + // that is a typo. Unicode says 0xe0, and that is what is + // consistent with DataInputStream. + buf[pos++] = (byte) (0xe0 | (0x0f & (c >> 12))); + buf[pos++] = (byte) (0x80 | (0x3f & (c >> 6))); + buf[pos++] = (byte) (0x80 | (0x3f & c)); + } + } + + writeShort (sum); + write(buf, 0, sum); + } + +} // class DataOutputStream + diff --git a/libjava/classpath/java/io/DeleteFileHelper.java b/libjava/classpath/java/io/DeleteFileHelper.java new file mode 100644 index 0000000..d73628c --- /dev/null +++ b/libjava/classpath/java/io/DeleteFileHelper.java @@ -0,0 +1,109 @@ +/* DeleteFileHelper.java -- Helper class to delete files on VM exit + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * @author Guilhem Lavaux (guilhem@kaffe.org) + * @author Jeroen Frijters (jeroen@sumatra.nl) + * @author Michael Koch (konqueror@gmx.de) + */ +final class DeleteFileHelper extends Thread +{ + private static ArrayList filesToDelete; + + static synchronized void add(File file) + { + if (filesToDelete == null) + { + filesToDelete = new ArrayList(); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + try + { + Runtime.getRuntime().addShutdownHook(new DeleteFileHelper()); + } + catch (IllegalStateException e) + { + // Shutdown is already in progress, so we can't + // register ours. + } + + return null; + } + }); + } + + filesToDelete.add(file); + } + + private static synchronized void deleteFiles() + { + Iterator it = filesToDelete.iterator(); + + while (it.hasNext()) + { + try + { + File file = (File) it.next(); + file.delete(); + } + catch (Exception e) + { + // Do nothing here. + } + } + } + + // Package-private to avoid a trampoline constructor. + DeleteFileHelper() + { + } + + public void run() + { + deleteFiles(); + } +} diff --git a/libjava/classpath/java/io/EOFException.java b/libjava/classpath/java/io/EOFException.java new file mode 100644 index 0000000..cfedb7d --- /dev/null +++ b/libjava/classpath/java/io/EOFException.java @@ -0,0 +1,76 @@ +/* EOFException.java -- unexpected end of file exception + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * This exception is thrown when the end of the file or stream was + * encountered unexpectedly. This is not the normal way that an EOF + * condition is reported; such as a special value like -1 being returned. + * However, certain types of streams expecting certain data in a certain + * format might reach EOF before reading their expected data pattern and + * thus throw this exception. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class EOFException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 6433858223774886977L; + + /** + * Create an exception without a descriptive error message. + */ + public EOFException() + { + } + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + public EOFException(String message) + { + super(message); + } +} // class EOFException diff --git a/libjava/classpath/java/io/Externalizable.java b/libjava/classpath/java/io/Externalizable.java new file mode 100644 index 0000000..113c19f --- /dev/null +++ b/libjava/classpath/java/io/Externalizable.java @@ -0,0 +1,107 @@ +/* Externalizable.java -- Interface for saving and restoring object data + 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 java.io; + +/** + * This interface provides a way that classes can completely control how + * the data of their object instances are written and read to and from + * streams. It has two methods which are used to write the data to a stream + * and to read the data from a stream. The read method must read the data + * in exactly the way it was written by the write method. + *

    + * Note that classes which implement this interface must take into account + * that all superclass data must also be written to the stream as well. + * The class implementing this interface must figure out how to make that + * happen. + *

    + * This interface can be used to provide object persistence. When an + * object is to be stored externally, the writeExternal method is + * called to save state. When the object is restored, an instance is + * created using the default no-argument constructor and the + * readExternal method is used to restore the state. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Externalizable extends Serializable +{ + /** + * This method restores an object's state by reading in the instance data + * for the object from the passed in stream. Note that this stream is not + * a subclass of InputStream, but rather is a class that + * implements + * the ObjectInput interface. That interface provides a + * mechanism for + * reading in Java data types from a stream. + *

    + * Note that this method must be compatible with writeExternal. + * It must read back the exact same types that were written by that + * method in the exact order they were written. + *

    + * If this method needs to read back an object instance, then the class + * for that object must be found and loaded. If that operation fails, + * then this method throws a ClassNotFoundException + * + * @param in An ObjectInput instance for reading in the object + * state + * + * @exception ClassNotFoundException If the class of an object being + * restored cannot be found + * @exception IOException If any other error occurs + */ + void readExternal(ObjectInput in) + throws ClassNotFoundException, IOException; + + /** + * This method is responsible for writing the instance data of an object + * to the passed in stream. Note that this stream is not a subclass of + * OutputStream, but rather is a class that implements the + * ObjectOutput interface. That interface provides a + * number of methods + * for writing Java data values to a stream. + *

    + * Not that the implementation of this method must be coordinated with + * the implementation of readExternal. + * + * @param out An ObjectOutput instance for writing the + * object state + * + * @exception IOException If an error occurs + */ + void writeExternal(ObjectOutput out) throws IOException; +} diff --git a/libjava/classpath/java/io/File.java b/libjava/classpath/java/io/File.java new file mode 100644 index 0000000..3b747e6 --- /dev/null +++ b/libjava/classpath/java/io/File.java @@ -0,0 +1,1357 @@ +/* File.java -- Class representing a file on disk + 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 java.io; + +import gnu.classpath.SystemProperties; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.3. + */ + +/** + * This class represents a file or directory on a local disk. It provides + * facilities for dealing with a variety of systems that use various + * types of path separators ("/" versus "\", for example). It also + * contains method useful for creating and deleting files and directories. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class File implements Serializable, Comparable +{ + private static final long serialVersionUID = 301077366599181567L; + + /** + * This is the path separator string for the current host. This field + * contains the value of the file.separator system property. + * An example separator string would be "/" on the GNU system. + */ + public static final String separator = SystemProperties.getProperty("file.separator"); + private static final String dupSeparator = separator + separator; + + /** + * This is the first character of the file separator string. On many + * hosts (for example, on the GNU system), this represents the entire + * separator string. The complete separator string is obtained from the + * file.separatorsystem property. + */ + public static final char separatorChar = separator.charAt(0); + + /** + * This is the string that is used to separate the host name from the + * path name in paths than include the host name. It is the value of + * the path.separator system property. + */ + public static final String pathSeparator + = SystemProperties.getProperty("path.separator"); + + /** + * This is the first character of the string used to separate the host name + * from the path name in paths that include a host. The separator string + * is taken from the path.separator system property. + */ + public static final char pathSeparatorChar = pathSeparator.charAt(0); + + /** + * This is the path to the file set when the object is created. It + * may be an absolute or relative path name. + */ + private String path; + + /** + * This method tests whether or not the current thread is allowed to + * to read the file pointed to by this object. This will be true if and + * and only if 1) the file exists and 2) the SecurityManager + * (if any) allows access to the file via it's checkRead + * method 3) the file is readable. + * + * @return true if reading is allowed, + * false otherwise + * + * @exception SecurityException If the SecurityManager + * does not allow access to the file + */ + public boolean canRead() + { + // Test for existence. This also does the SecurityManager check + if (!exists()) + return false; + + return VMFile.canRead(path); + } + + /** + * This method test whether or not the current thread is allowed to + * write to this object. This will be true if and only if 1) The + * SecurityManager (if any) allows write access to the + * file and 2) The file exists and 3) The file is writable. To determine + * whether or not a non-existent file can be created, check the parent + * directory for write access. + * + * @return true if writing is allowed, false + * otherwise + * + * @exception SecurityException If the SecurityManager + * does not allow access to the file + */ + public boolean canWrite() + { + // First do a SecurityCheck before doing anything else. + checkWrite(); + + // Test for existence. This is required by the spec + if (! VMFile.exists(path)) + return false; + + if (VMFile.isDirectory(path)) + return VMFile.canWriteDirectory(this); + else + return VMFile.canWrite(path); + } + + /** + * This method creates a new file of zero length with the same name as + * the path of this File object if an only if that file + * does not already exist. + *

    + * A SecurityManager.checkWrite check is done prior + * to performing this action. + * + * @return true if the file was created, false if + * the file alread existed. + * + * @exception IOException If an I/O error occurs + * @exception SecurityException If the SecurityManager will + * not allow this operation to be performed. + * + * @since 1.2 + */ + public boolean createNewFile() throws IOException + { + checkWrite(); + return VMFile.create(path); + } + /** + * This method deletes the file represented by this object. If this file + * is a directory, it must be empty in order for the delete to succeed. + * + * @return true if the file was deleted, false + * otherwise + * + * @exception SecurityException If deleting of the file is not allowed + */ + public synchronized boolean delete() + { + SecurityManager s = System.getSecurityManager(); + + if (s != null) + s.checkDelete(path); + + return VMFile.delete(path); + } + + /** + * This method tests two File objects for equality by + * comparing the path of the specified File against the path + * of this object. The two objects are equal if an only if 1) The + * argument is not null 2) The argument is a File object and + * 3) The path of the Fileargument is equal to the path + * of this object. + *

    + * The paths of the files are determined by calling the + * getPath() + * method on each object. + * + * @return true if the two objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof File)) + return false; + + File other = (File) obj; + + if (VMFile.IS_CASE_SENSITIVE) + return path.equals(other.path); + else + return path.equalsIgnoreCase(other.path); + } + + /** + * This method tests whether or not the file represented by the object + * actually exists on the filesystem. + * + * @return true if the file exists, falseotherwise. + * + * @exception SecurityException If reading of the file is not permitted + */ + public boolean exists() + { + checkRead(); + return VMFile.exists(path); + } + + /** + * This method initializes a new File object to represent + * a file with the specified path. + * + * @param name The path name of the file + */ + public File(String name) + { + path = normalizePath (name); + } + + // Remove duplicate and redundant separator characters. + private String normalizePath(String p) + { + // On Windows, convert any '/' to '\'. This appears to be the same logic + // that Sun's Win32 Java performs. + if (separatorChar == '\\') + { + p = p.replace ('/', '\\'); + // We have to special case the "\c:" prefix. + if (p.length() > 2 && p.charAt(0) == '\\' && + ((p.charAt(1) >= 'a' && p.charAt(1) <= 'z') || + (p.charAt(1) >= 'A' && p.charAt(1) <= 'Z')) && + p.charAt(2) == ':') + p = p.substring(1); + } + + int dupIndex = p.indexOf(dupSeparator); + int plen = p.length(); + + // Special case: permit Windows UNC path prefix. + if (dupSeparator.equals("\\\\") && dupIndex == 0) + dupIndex = p.indexOf(dupSeparator, 1); + + if (dupIndex == -1) + { + // Ignore trailing separator (though on Windows "a:\", for + // example, is a valid and minimal path). + if (plen > 1 && p.charAt (plen - 1) == separatorChar) + { + if (! (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':')) + return p.substring (0, plen - 1); + } + else + return p; + } + + StringBuffer newpath = new StringBuffer(plen); + int last = 0; + while (dupIndex != -1) + { + newpath.append(p.substring(last, dupIndex)); + // Ignore the duplicate path characters. + while (p.charAt(dupIndex) == separatorChar) + { + dupIndex++; + if (dupIndex == plen) + return newpath.toString(); + } + newpath.append(separatorChar); + last = dupIndex; + dupIndex = p.indexOf(dupSeparator, last); + } + + // Again, ignore possible trailing separator (except special cases + // like "a:\" on Windows). + int end; + if (plen > 1 && p.charAt (plen - 1) == separatorChar) + { + if (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':') + end = plen; + else + end = plen - 1; + } + else + end = plen; + newpath.append(p.substring(last, end)); + + return newpath.toString(); + } + + /** + * This method initializes a new File object to represent + * a file in the specified named directory. The path name to the file + * will be the directory name plus the separator string plus the file + * name. If the directory path name ends in the separator string, another + * separator string will still be appended. + * + * @param dirPath The path to the directory the file resides in + * @param name The name of the file + */ + public File(String dirPath, String name) + { + if (name == null) + throw new NullPointerException(); + if (dirPath != null) + { + if (dirPath.length() > 0) + { + // Try to be smart about the number of separator characters. + if (dirPath.charAt(dirPath.length() - 1) == separatorChar + || name.length() == 0) + path = normalizePath(dirPath + name); + else + path = normalizePath(dirPath + separatorChar + name); + } + else + { + // If dirPath is empty, use a system dependant + // default prefix. + // Note that the leading separators in name have + // to be chopped off, to prevent them forming + // a UNC prefix on Windows. + if (separatorChar == '\\' /* TODO use ON_WINDOWS */) + { + int skip = 0; + while(name.length() > skip + && (name.charAt(skip) == separatorChar + || name.charAt(skip) == '/')) + { + skip++; + } + name = name.substring(skip); + } + path = normalizePath(separatorChar + name); + } + } + else + path = normalizePath(name); + } + + /** + * This method initializes a new File object to represent + * a file in the specified directory. If the directory + * argument is null, the file is assumed to be in the + * current directory as specified by the user.dir system + * property + * + * @param directory The directory this file resides in + * @param name The name of the file + */ + public File(File directory, String name) + { + this (directory == null ? null : directory.path, name); + } + + /** + * This method initializes a new File object to represent + * a file corresponding to the specified file: protocol URI. + * + * @param uri The uri. + */ + public File(URI uri) + { + if (uri == null) + throw new NullPointerException("uri is null"); + + if (!uri.getScheme().equals("file")) + throw new IllegalArgumentException("invalid uri protocol"); + + path = normalizePath(uri.getPath()); + } + + /** + * This method returns the path of this file as an absolute path name. + * If the path name is already absolute, then it is returned. Otherwise + * the value returned is the current directory plus the separatory + * string plus the path of the file. The current directory is determined + * from the user.dir system property. + * + * @return The absolute path of this file + */ + public String getAbsolutePath() + { + if (isAbsolute()) + return path; + else if (separatorChar == '\\' + && path.length() > 0 && path.charAt (0) == '\\') + { + // On Windows, even if the path starts with a '\\' it is not + // really absolute until we prefix the drive specifier from + // the current working directory to it. + return System.getProperty ("user.dir").substring (0, 2) + path; + } + else if (separatorChar == '\\' + && path.length() > 1 && path.charAt (1) == ':' + && ((path.charAt (0) >= 'a' && path.charAt (0) <= 'z') + || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z'))) + { + // On Windows, a process has a current working directory for + // each drive and a path like "G:foo\bar" would mean the + // absolute path "G:\wombat\foo\bar" if "\wombat" is the + // working directory on the G drive. + String drvDir = null; + try + { + drvDir = new File (path.substring (0, 2)).getCanonicalPath(); + } + catch (IOException e) + { + drvDir = path.substring (0, 2) + "\\"; + } + + // Note: this would return "C:\\." for the path "C:.", if "\" + // is the working folder on the C drive, but this is + // consistent with what Sun's JRE 1.4.1.01 actually returns! + if (path.length() > 2) + return drvDir + '\\' + path.substring (2, path.length()); + else + return drvDir; + } + else + return System.getProperty ("user.dir") + separatorChar + path; + } + + /** + * This method returns a File object representing the + * absolute path of this object. + * + * @return A File with the absolute path of the object. + * + * @since 1.2 + */ + public File getAbsoluteFile() + { + return new File(getAbsolutePath()); + } + + /** + * This method returns a canonical representation of the pathname of + * this file. The actual form of the canonical representation is + * different. On the GNU system, the canonical form differs from the + * absolute form in that all relative file references to "." and ".." + * are resolved and removed. + *

    + * Note that this method, unlike the other methods which return path + * names, can throw an IOException. This is because native method + * might be required in order to resolve the canonical path + * + * @exception IOException If an error occurs + */ + public String getCanonicalPath() throws IOException + { + // On Windows, getAbsolutePath might end up calling us, so we + // have to special case that call to avoid infinite recursion. + if (separatorChar == '\\' && path.length() == 2 && + ((path.charAt(0) >= 'a' && path.charAt(0) <= 'z') || + (path.charAt(0) >= 'A' && path.charAt(0) <= 'Z')) && + path.charAt(1) == ':') + { + return VMFile.toCanonicalForm(path); + } + // Call getAbsolutePath first to make sure that we do the + // current directory handling, because the native code + // may have a different idea of the current directory. + return VMFile.toCanonicalForm(getAbsolutePath()); + } + + /** + * This method returns a File object representing the + * canonical path of this object. + * + * @return A File instance representing the canonical path of + * this object. + * + * @exception IOException If an error occurs. + * + * @since 1.2 + */ + public File getCanonicalFile() throws IOException + { + return new File(getCanonicalPath()); + } + + /** + * This method returns the name of the file. This is everything in the + * complete path of the file after the last instance of the separator + * string. + * + * @return The file name + */ + public String getName() + { + return VMFile.getName(path); + } + + /** + * This method returns a String the represents this file's + * parent. null is returned if the file has no parent. The + * parent is determined via a simple operation which removes the + * + * @return The parent directory of this file + */ + public String getParent() + { + String prefix = null; + int nameSeqIndex = 0; + + // The "prefix", if present, is the leading "/" on UNIX and + // either the drive specifier (e.g. "C:") or the leading "\\" + // of a UNC network path on Windows. + if (separatorChar == '/' && path.charAt (0) == '/') + { + prefix = "/"; + nameSeqIndex = 1; + } + else if (separatorChar == '\\' && path.length() > 1) + { + if ((path.charAt (0) == '\\' && path.charAt (1) == '\\') + || (((path.charAt (0) >= 'a' && path.charAt (0) <= 'z') + || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z')) + && path.charAt (1) == ':')) + { + prefix = path.substring (0, 2); + nameSeqIndex = 2; + } + } + + // According to the JDK docs, the returned parent path is the + // portion of the name sequence before the last separator + // character, if found, prefixed by the prefix, otherwise null. + if (nameSeqIndex < path.length()) + { + String nameSeq = path.substring (nameSeqIndex, path.length()); + int last = nameSeq.lastIndexOf (separatorChar); + if (last == -1) + return prefix; + else if (last == (nameSeq.length() - 1)) + // Note: The path would not have a trailing separator + // except for cases like "C:\" on Windows (see + // normalizePath( )), where Sun's JRE 1.4 returns null. + return null; + else if (last == 0) + last++; + + if (prefix != null) + return prefix + nameSeq.substring (0, last); + else + return nameSeq.substring (0, last); + } + else + // Sun's JRE 1.4 returns null if the prefix is the only + // component of the path - so "/" gives null on UNIX and + // "C:", "\\", etc. return null on Windows. + return null; + } + + /** + * This method returns a File object representing the parent + * file of this one. + * + * @return a File for the parent of this object. + * null + * will be returned if this object does not have a parent. + * + * @since 1.2 + */ + public File getParentFile() + { + String parent = getParent(); + return parent != null ? new File(parent) : null; + } + + /** + * Returns the path name that represents this file. May be a relative + * or an absolute path name + * + * @return The pathname of this file + */ + public String getPath() + { + return path; + } + + /** + * This method returns a hash code representing this file. It is the + * hash code of the path of this file (as returned by getPath()) + * exclusived or-ed with the value 1234321. + * + * @return The hash code for this object + */ + public int hashCode() + { + if (VMFile.IS_CASE_SENSITIVE) + return path.hashCode() ^ 1234321; + else + return path.toLowerCase().hashCode() ^ 1234321; + } + + /** + * This method returns true if this object represents an absolute file + * path and false if it does not. The definition of an absolute path varies + * by system. As an example, on GNU systems, a path is absolute if it starts + * with a "/". + * + * @return true if this object represents an absolute + * file name, false otherwise. + */ + public boolean isAbsolute() + { + if (separatorChar == '\\') + return path.startsWith(dupSeparator) || + (path.length() > 2 && + ((path.charAt(0) >= 'a' && path.charAt(0) <= 'z') || + (path.charAt(0) >= 'A' && path.charAt(0) <= 'Z')) && + path.charAt(1) == ':' && + path.charAt(2) == '\\'); + else + return path.startsWith(separator); + } + + /** + * This method tests whether or not the file represented by this object + * is a directory. In order for this method to return true, + * the file represented by this object must exist and be a directory. + * + * @return true if this file is a directory, false + * otherwise + * + * @exception SecurityException If reading of the file is not permitted + */ + public boolean isDirectory() + { + checkRead(); + return VMFile.isDirectory(path); + } + + /** + * This method tests whether or not the file represented by this object + * is a "plain" file. A file is a plain file if and only if it 1) Exists, + * 2) Is not a directory or other type of special file. + * + * @return true if this is a plain file, false + * otherwise + * + * @exception SecurityException If reading of the file is not permitted + */ + public boolean isFile() + { + checkRead(); + return VMFile.isFile(path); + } + + /** + * This method tests whether or not this file represents a "hidden" file. + * On GNU systems, a file is hidden if its name begins with a "." + * character. Files with these names are traditionally not shown with + * directory listing tools. + * + * @return true if the file is hidden, false + * otherwise. + * + * @since 1.2 + */ + public boolean isHidden() + { + return VMFile.isHidden(path); + } + + /** + * This method returns the last modification time of this file. The + * time value returned is an abstract value that should not be interpreted + * as a specified time value. It is only useful for comparing to other + * such time values returned on the same system. In that case, the larger + * value indicates a more recent modification time. + *

    + * If the file does not exist, then a value of 0 is returned. + * + * @return The last modification time of the file + * + * @exception SecurityException If reading of the file is not permitted + */ + public long lastModified() + { + checkRead(); + return VMFile.lastModified(path); + } + + /** + * This method returns the length of the file represented by this object, + * or 0 if the specified file does not exist. + * + * @return The length of the file + * + * @exception SecurityException If reading of the file is not permitted + */ + public long length() + { + checkRead(); + return VMFile.length(path); + } + + /** + * This method returns a array of String's representing the + * list of files is then directory represented by this object. If this + * object represents a non-directory file or a non-existent file, then + * null is returned. The list of files will not contain + * any names such as "." or ".." which indicate the current or parent + * directory. Also, the names are not guaranteed to be sorted. + *

    + * In this form of the list() method, a filter is specified + * that allows the caller to control which files are returned in the + * list. The FilenameFilter specified is called for each + * file returned to determine whether or not that file should be included + * in the list. + *

    + * A SecurityManager check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @param filter An object which will identify files to exclude from + * the directory listing. + * + * @return An array of files in the directory, or null + * if this object does not represent a valid directory. + * + * @exception SecurityException If read access is not allowed to the + * directory by the SecurityManager + */ + public String[] list(FilenameFilter filter) + { + checkRead(); + + if (!exists() || !isDirectory()) + return null; + + // Get the list of files + String files[] = VMFile.list(path); + + // Check if an error occured in listInternal(). + if (files == null) + return null; + + if (filter == null) + return files; + + // Apply the filter + int count = 0; + for (int i = 0; i < files.length; i++) + { + if (filter.accept(this, files[i])) + ++count; + else + files[i] = null; + } + + String[] retfiles = new String[count]; + count = 0; + for (int i = 0; i < files.length; i++) + if (files[i] != null) + retfiles[count++] = files[i]; + + return retfiles; + } + + /** + * This method returns a array of String's representing the + * list of files is then directory represented by this object. If this + * object represents a non-directory file or a non-existent file, then + * null is returned. The list of files will not contain + * any names such as "." or ".." which indicate the current or parent + * directory. Also, the names are not guaranteed to be sorted. + *

    + * A SecurityManager check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @return An array of files in the directory, or null if + * this object does not represent a valid directory. + * + * @exception SecurityException If read access is not allowed to the + * directory by the SecurityManager + */ + public String[] list() + { + return list(null); + } + + /** + * This method returns an array of File objects representing + * all the files in the directory represented by this object. If this + * object does not represent a directory, null is returned. + * Each of the returned File object is constructed with this + * object as its parent. + *

    + * A SecurityManager check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @return An array of File objects for this directory. + * + * @exception SecurityException If the SecurityManager denies + * access to this directory. + * + * @since 1.2 + */ + public File[] listFiles() + { + return listFiles((FilenameFilter) null); + } + + /** + * This method returns an array of File objects representing + * all the files in the directory represented by this object. If this + * object does not represent a directory, null is returned. + * Each of the returned File object is constructed with this + * object as its parent. + *

    + * In this form of the listFiles() method, a filter is specified + * that allows the caller to control which files are returned in the + * list. The FilenameFilter specified is called for each + * file returned to determine whether or not that file should be included + * in the list. + *

    + * A SecurityManager check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @return An array of File objects for this directory. + * + * @exception SecurityException If the SecurityManager denies + * access to this directory. + * + * @since 1.2 + */ + public File[] listFiles(FilenameFilter filter) + { + String[] filelist = list(filter); + + if (filelist == null) + return null; + + File[] fobjlist = new File [filelist.length]; + + for (int i = 0; i < filelist.length; i++) + fobjlist [i] = new File(this, filelist [i]); + + return fobjlist; + } + + /** + * This method returns an array of File objects representing + * all the files in the directory represented by this object. If this + * object does not represent a directory, null is returned. + * Each of the returned File object is constructed with this + * object as its parent. + *

    + * In this form of the listFiles() method, a filter is specified + * that allows the caller to control which files are returned in the + * list. The FileFilter specified is called for each + * file returned to determine whether or not that file should be included + * in the list. + *

    + * A SecurityManager check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @return An array of File objects for this directory. + * + * @exception SecurityException If the SecurityManager denies + * access to this directory. + * + * @since 1.2 + */ + public File[] listFiles(FileFilter filter) + { + File[] fobjlist = listFiles((FilenameFilter) null); + + if (fobjlist == null) + return null; + + if (filter == null) + return fobjlist; + + int count = 0; + for (int i = 0; i < fobjlist.length; i++) + if (filter.accept(fobjlist[i]) == true) + ++count; + + File[] final_list = new File[count]; + count = 0; + for (int i = 0; i < fobjlist.length; i++) + if (filter.accept(fobjlist[i]) == true) + { + final_list[count] = fobjlist[i]; + ++count; + } + + return final_list; + } + + /** + * This method returns a String that is the path name of the + * file as returned by getPath. + * + * @return A String representation of this file + */ + public String toString() + { + return path; + } + + /** + * @return A URI for this object. + */ + public URI toURI() + { + String abspath = getAbsolutePath(); + + if (isDirectory()) + abspath = abspath + separatorChar; + + if (separatorChar == '\\') + abspath = separatorChar + abspath; + + try + { + return new URI("file", null, null, -1, + abspath.replace(separatorChar, '/'), + null, null); + } + catch (URISyntaxException use) + { + // Can't happen. + throw (InternalError) new InternalError("Unconvertible file: " + + this).initCause(use); + } + } + + /** + * This method returns a URL with the file: + * protocol that represents this file. The exact form of this URL is + * system dependent. + * + * @return A URL for this object. + * + * @exception MalformedURLException If the URL cannot be created + * successfully. + */ + public URL toURL() throws MalformedURLException + { + // On Win32, Sun's JDK returns URLs of the form "file:/c:/foo/bar.txt", + // while on UNIX, it returns URLs of the form "file:/foo/bar.txt". + if (separatorChar == '\\') + return new URL ("file:/" + getAbsolutePath().replace ('\\', '/') + + (isDirectory() ? "/" : "")); + else + return new URL ("file:" + getAbsolutePath() + + (isDirectory() ? "/" : "")); + } + + + /** + * This method creates a directory for the path represented by this object. + * + * @return true if the directory was created, + * false otherwise + * + * @exception SecurityException If write access is not allowed to this file + */ + public boolean mkdir() + { + checkWrite(); + return VMFile.mkdir(path); + } + + /** + * This method creates a directory for the path represented by this file. + * It will also create any intervening parent directories if necessary. + * + * @return true if the directory was created, + * false otherwise + * + * @exception SecurityException If write access is not allowed to this file + */ + public boolean mkdirs() + { + String parent = getParent(); + if (parent == null) + { + return mkdir(); + } + + File f = new File(parent); + if (!f.exists()) + { + boolean rc = f.mkdirs(); + if (rc == false) + return false; + } + + return mkdir(); + } + + /** + * This method creates a temporary file in the specified directory. If + * the directory name is null, then this method uses the system temporary + * directory. The files created are guaranteed not to currently exist and + * the same file name will never be used twice in the same virtual + * machine instance. + * The system temporary directory is determined by examinging the + * java.io.tmpdir system property. + *

    + * The prefix parameter is a sequence of at least three + * characters that are used as the start of the generated filename. The + * suffix parameter is a sequence of characters that is used + * to terminate the file name. This parameter may be null + * and if it is, the suffix defaults to ".tmp". + *

    + * If a SecurityManager exists, then its checkWrite + * method is used to verify that this operation is permitted. + * + * @param prefix The character prefix to use in generating the path name. + * @param suffix The character suffix to use in generating the path name. + * @param directory The directory to create the file in, or + * null for the default temporary directory + * + * @exception IllegalArgumentException If the patterns is not valid + * @exception SecurityException If there is no permission to perform + * this operation + * @exception IOException If an error occurs + * + * @since 1.2 + */ + public static File createTempFile(String prefix, String suffix, + File directory) + throws IOException + { + // Grab the system temp directory if necessary + if (directory == null) + { + String dirname = System.getProperty("java.io.tmpdir"); + if (dirname == null) + throw new IOException("Cannot determine system temporary directory"); + + directory = new File(dirname); + if (! VMFile.exists(directory.path)) + throw new IOException("System temporary directory " + + directory.getName() + " does not exist."); + if (! VMFile.isDirectory(directory.path)) + throw new IOException("System temporary directory " + + directory.getName() + + " is not really a directory."); + } + + // Check if prefix is at least 3 characters long + if (prefix.length() < 3) + throw new IllegalArgumentException("Prefix too short: " + prefix); + + // Set default value of suffix + if (suffix == null) + suffix = ".tmp"; + + // Now identify a file name and make sure it doesn't exist. + File file; + if (!VMFile.IS_DOS_8_3) + { + do + { + String filename = prefix + System.currentTimeMillis() + suffix; + file = new File(directory, filename); + } + while (VMFile.exists(file.path)); + } + else + { + // make sure prefix is not longer than 7 characters + if (prefix.length() >= 8) + throw new IllegalArgumentException("Prefix too long: " + prefix + "(valid length 3..7)"); + + long mask = 0x000000ffffFFFFL >> (prefix.length() * 4); + do + { + int n = (int) (System.currentTimeMillis() & mask); + String filename = prefix + java.lang.Integer.toHexString(n) + suffix; + file = new File(directory, filename); + } + while (VMFile.exists(file.path)); + } + + // Verify that we are allowed to create this file + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkWrite(file.getAbsolutePath()); + + // Now create the file and return our file object + // XXX - FIXME race condition. + VMFile.create(file.getAbsolutePath()); + return file; + } + + /** + * This method sets the file represented by this object to be read only. + * A read only file or directory cannot be modified. Please note that + * GNU systems allow read only files to be deleted if the directory it + * is contained in is writable. + * + * @return true if the operation succeeded, false + * otherwise. + * + * @exception SecurityException If the SecurityManager does + * not allow this operation. + * + * @since 1.2 + */ + public boolean setReadOnly() + { + // Do a security check before trying to do anything else. + checkWrite(); + + // Test for existence. + if (! VMFile.exists(path)) + return false; + + return VMFile.setReadOnly(path); + } + + /** + * This method returns an array of filesystem roots. Some operating systems + * have volume oriented filesystem. This method provides a mechanism for + * determining which volumes exist. GNU systems use a single hierarchical + * filesystem, so will have only one "/" filesystem root. + * + * @return An array of File objects for each filesystem root + * available. + * + * @since 1.2 + */ + public static File[] listRoots() + { + return VMFile.listRoots(); + } + + /** + * This method creates a temporary file in the system temporary directory. + * The files created are guaranteed not to currently exist and the same file + * name will never be used twice in the same virtual machine instance. The + * system temporary directory is determined by examinging the + * java.io.tmpdir system property. + *

    + * The prefix parameter is a sequence of at least three + * characters that are used as the start of the generated filename. The + * suffix parameter is a sequence of characters that is used + * to terminate the file name. This parameter may be null + * and if it is, the suffix defaults to ".tmp". + *

    + * If a SecurityManager exists, then its checkWrite + * method is used to verify that this operation is permitted. + *

    + * This method is identical to calling + * createTempFile(prefix, suffix, null). + * + * @param prefix The character prefix to use in generating the path name. + * @param suffix The character suffix to use in generating the path name. + * + * @exception IllegalArgumentException If the prefix or suffix are not valid. + * @exception SecurityException If there is no permission to perform + * this operation + * @exception IOException If an error occurs + */ + public static File createTempFile(String prefix, String suffix) + throws IOException + { + return createTempFile(prefix, suffix, null); + } + + /** + * This method compares the specified File to this one + * to test for equality. It does this by comparing the canonical path names + * of the files. + *

    + * The canonical paths of the files are determined by calling the + * getCanonicalPath method on each object. + *

    + * This method returns a 0 if the specified Object is equal + * to this one, a negative value if it is less than this one + * a positive value if it is greater than this one. + * + * @return An integer as described above + * + * @since 1.2 + */ + public int compareTo(File other) + { + if (VMFile.IS_CASE_SENSITIVE) + return path.compareTo (other.path); + else + return path.compareToIgnoreCase (other.path); + } + + /** + * This method compares the specified Object to this one + * to test for equality. It does this by comparing the canonical path names + * of the files. This method is identical to compareTo(File) + * except that if the Object passed to it is not a + * File, it throws a ClassCastException + *

    + * The canonical paths of the files are determined by calling the + * getCanonicalPath method on each object. + *

    + * This method returns a 0 if the specified Object is equal + * to this one, a negative value if it is less than this one + * a positive value if it is greater than this one. + * + * @return An integer as described above + * + * @exception ClassCastException If the passed Object is + * not a File + * + * @since 1.2 + */ + public int compareTo(Object obj) + { + return compareTo((File) obj); + } + + /** + * This method renames the file represented by this object to the path + * of the file represented by the argument File. + * + * @param dest The File object representing the target name + * + * @return true if the rename succeeds, false + * otherwise. + * + * @exception SecurityException If write access is not allowed to the + * file by the SecurityMananger. + */ + public synchronized boolean renameTo(File dest) + { + checkWrite(); + dest.checkWrite(); + // Call our native rename method + return VMFile.renameTo(path, dest.path); + } + + /** + * This method sets the modification time on the file to the specified + * value. This is specified as the number of seconds since midnight + * on January 1, 1970 GMT. + * + * @param time The desired modification time. + * + * @return true if the operation succeeded, false + * otherwise. + * + * @exception IllegalArgumentException If the specified time is negative. + * @exception SecurityException If the SecurityManager will + * not allow this operation. + * + * @since 1.2 + */ + public boolean setLastModified(long time) + { + if (time < 0) + throw new IllegalArgumentException("Negative modification time: " + time); + + checkWrite(); + return VMFile.setLastModified(path, time); + } + + private void checkWrite() + { + // Check the SecurityManager + SecurityManager s = System.getSecurityManager(); + + if (s != null) + s.checkWrite(path); + } + + private void checkRead() + { + // Check the SecurityManager + SecurityManager s = System.getSecurityManager(); + + if (s != null) + s.checkRead(path); + } + + /** + * Calling this method requests that the file represented by this object + * be deleted when the virtual machine exits. Note that this request cannot + * be cancelled. Also, it will only be carried out if the virtual machine + * exits normally. + * + * @exception SecurityException If deleting of the file is not allowed + * + * @since 1.2 + */ + public void deleteOnExit() + { + // Check the SecurityManager + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkDelete(path); + + DeleteFileHelper.add(this); + } + + private void writeObject(ObjectOutputStream oos) throws IOException + { + oos.defaultWriteObject(); + oos.writeChar(separatorChar); + } + + private void readObject(ObjectInputStream ois) + throws ClassNotFoundException, IOException + { + ois.defaultReadObject(); + + // If the file was from an OS with a different dir separator, + // fixup the path to use the separator on this OS. + char oldSeparatorChar = ois.readChar(); + + if (oldSeparatorChar != separatorChar) + path = path.replace(oldSeparatorChar, separatorChar); + } + +} // class File + diff --git a/libjava/classpath/java/io/FileDescriptor.java b/libjava/classpath/java/io/FileDescriptor.java new file mode 100644 index 0000000..d300c9c --- /dev/null +++ b/libjava/classpath/java/io/FileDescriptor.java @@ -0,0 +1,139 @@ +/* FileDescriptor.java -- Opaque file handle class + Copyright (C) 1998, 1999, 2000, 2001, 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 java.io; + +import gnu.java.nio.channels.FileChannelImpl; + +import java.nio.channels.ByteChannel; +import java.nio.channels.FileChannel; + +/** + * This class represents an opaque file handle as a Java class. It should + * be used only to pass to other methods that expect an object of this + * type. No system specific information can be obtained from this object. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @date September 24, 1998 + */ +public final class FileDescriptor +{ + /** + * A FileDescriptor representing the system standard input + * stream. This will usually be accessed through the + * System.invariable. + */ + public static final FileDescriptor in + = new FileDescriptor (FileChannelImpl.in); + + /** + * A FileDescriptor representing the system standard output + * stream. This will usually be accessed through the + * System.outvariable. + */ + public static final FileDescriptor out + = new FileDescriptor (FileChannelImpl.out); + + /** + * A FileDescriptor representing the system standard error + * stream. This will usually be accessed through the + * System.errvariable. + */ + public static final FileDescriptor err + = new FileDescriptor (FileChannelImpl.err); + + final ByteChannel channel; + + /** + * This method is used to initialize an invalid FileDescriptor object. + */ + public FileDescriptor() + { + channel = null; + } + + /** + * This method is used to initialize a FileDescriptor object. + */ + FileDescriptor(ByteChannel channel) + { + this.channel = channel; + } + + + /** + * This method forces all data that has not yet been physically written to + * the underlying storage medium associated with this + * FileDescriptor + * to be written out. This method will not return until all data has + * been fully written to the underlying device. If the device does not + * support this functionality or if an error occurs, then an exception + * will be thrown. + */ + public void sync () throws SyncFailedException + { + if (channel instanceof FileChannel) + { + try + { + ((FileChannel) channel).force(true); + } + catch (IOException ex) + { + if (ex instanceof SyncFailedException) + throw (SyncFailedException) ex; + else + throw new SyncFailedException(ex.toString()); + } + } + } + + /** + * This methods tests whether or not this object represents a valid open + * native file handle. + * + * @return true if this object represents a valid + * native file handle, false otherwise + */ + public boolean valid () + { + return channel != null && channel.isOpen(); + } +} diff --git a/libjava/classpath/java/io/FileFilter.java b/libjava/classpath/java/io/FileFilter.java new file mode 100644 index 0000000..e57ac9f --- /dev/null +++ b/libjava/classpath/java/io/FileFilter.java @@ -0,0 +1,65 @@ +/* FileFilter.java -- Filter a list of pathnames + 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 java.io; + +/** + * This interface has one method which is used for filtering pathnames + * returned in a pathname listing. It is currently used by the + * File.listFiles(FileFilter) method. + *

    + * The method in this interface determines if a particular pathname should + * or should not be included in the pathname listing. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * + * @see File#listFiles(java.io.FileFilter) + */ +public interface FileFilter +{ + /** + * This method determines whether or not a given pathname should be included + * in a pathname listing. + * + * @param pathname The pathname to test + * + * @return true if the path should be included in the list, + * false otherwise. + */ + boolean accept(File pathname); +} diff --git a/libjava/classpath/java/io/FileInputStream.java b/libjava/classpath/java/io/FileInputStream.java new file mode 100644 index 0000000..8ca38b0 --- /dev/null +++ b/libjava/classpath/java/io/FileInputStream.java @@ -0,0 +1,309 @@ +/* FileInputStream.java -- An input stream that reads from disk files. + Copyright (C) 1998, 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 java.io; + +import gnu.java.nio.channels.FileChannelImpl; + +import java.nio.channels.FileChannel; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This class is a stream that reads its bytes from a file. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class FileInputStream extends InputStream +{ + /** + * This is the native file handle for the file this stream is reading from + */ + private FileDescriptor fd; + + private FileChannelImpl ch; + + /** + * This method initializes a FileInputStream to read from the + * specified named file. A security check is first made to determine + * whether or not access to this file is allowed. This is done by + * calling the checkRead() method of the + * SecurityManager + * (if one exists) with the name of this file. An exception is thrown + * if reading is not allowed. If the file does not exist, an exception + * is also thrown. + * + * @param name The name of the file this stream should read from + * + * @exception SecurityException If read access to the file is not allowed + * @exception FileNotFoundException If the file does not exist + * or if it is a directory + */ + public FileInputStream(String name) throws FileNotFoundException + { + this(new File(name)); + } + + /** + * This method initializes a FileInputStream to read from the + * specified File object. A security check is first + * made to determine + * whether or not access to this file is allowed. This is done by + * calling the checkRead() method of the + * SecurityManager + * (if one exists) with the name of this file. An exception is thrown + * if reading is not allowed. If the file does not exist, an exception + * is also thrown. + * + * @param file The File object this stream should read from + * + * @exception SecurityException If read access to the file is not allowed + * @exception FileNotFoundException If the file does not exist + * or if it is a directory. + */ + public FileInputStream(File file) throws FileNotFoundException + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkRead(file.getPath()); + + ch = FileChannelImpl.create(file, FileChannelImpl.READ); + } + + /** + * This method initializes a FileInputStream to read from the + * specified FileDescriptor object. A security + * check is first made to + * determine whether or not access to this file is allowed. This is done by + * calling the checkRead() method of the + * SecurityManager + * (if one exists) with the specified FileDescriptor + * An exception is + * thrown if reading is not allowed. + * + * @param fdObj The FileDescriptor object this stream + * should read from + * + * @exception SecurityException If read access to the file is not allowed + */ + public FileInputStream(FileDescriptor fdObj) + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkRead(fdObj); + + fd = fdObj; + ch = (FileChannelImpl) fdObj.channel; + } + + FileInputStream(FileChannelImpl ch) + { + this.ch = ch; + } + + /** + * This method returns the number of bytes that can be read from this + * stream before a read can block. A return of 0 indicates that blocking + * might (or might not) occur on the very next read attempt. + *

    + * This method returns the number of unread bytes remaining in the file if + * the descriptor being read from is an actual file. If this method is + * reading from a ''special'' file such a the standard input, this method + * will return the appropriate value for the stream being read. + *

    + * Be aware that reads on plain files that do not reside locally might + * possibly block even if this method says they should not. For example, + * a remote server might crash, preventing an NFS mounted file from being + * read. + * + * @return The number of bytes that can be read before blocking could occur + * + * @exception IOException If an error occurs + */ + public int available() throws IOException + { + return ch.available(); + } + + /** + * This method closes the stream. Any futher attempts to read from the + * stream will likely generate an IOException since the underlying file + * will be closed. + * + * @exception IOException If an error occurs. + */ + public void close() throws IOException + { + ch.close(); + } + + protected void finalize() throws IOException + { + // We don't actually need this, but we include it because it is + // mentioned in the JCL. + } + + /** + * This method returns a FileDescriptor object representing the + * underlying native file handle of the file this stream is reading + * from + * + * @return A FileDescriptor for this stream + * + * @exception IOException If an error occurs + */ + public final FileDescriptor getFD() throws IOException + { + synchronized (this) + { + if (fd == null) + fd = new FileDescriptor (ch); + return fd; + } + } + + /** + * This method reads an unsigned byte from the input stream and returns it + * as an int in the range of 0-255. This method also will return -1 if + * the end of the stream has been reached. + *

    + * This method will block until the byte can be read. + * + * @return The byte read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + return ch.read(); + } + + /** + * This method reads bytes from a stream and stores them into a caller + * supplied buffer. This method attempts to completely fill the buffer, + * but can return before doing so. The actual number of bytes read is + * returned as an int. A -1 is returned to indicate the end of the stream. + *

    + * This method will block until some data can be read. + *

    + * This method operates by calling an overloaded read method like so: + * read(buf, 0, buf.length) + * + * @param buf The buffer into which the bytes read will be stored. + * + * @return The number of bytes read or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + /** + * This method read bytes from a stream and stores them into a caller + * supplied buffer. It starts storing the data at index + * offset into + * the buffer and attempts to read len bytes. This method can + * return before reading the number of bytes requested. The actual number + * of bytes read is returned as an int. A -1 is returned to indicate the + * end of the stream. + *

    + * This method will block until some data can be read. + * + * @param buf The array into which the bytes read should be stored + * @param offset The offset into the array to start storing bytes + * @param len The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public int read(byte[] buf, int offset, int len) throws IOException + { + if (offset < 0 + || len < 0 + || offset + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + + return ch.read(buf, offset, len); + } + + /** + * This method skips the specified number of bytes in the stream. It + * returns the actual number of bytes skipped, which may be less than the + * requested amount. + *

    + * @param numBytes The requested number of bytes to skip + * + * @return The actual number of bytes skipped. + * + * @exception IOException If an error occurs + */ + public synchronized long skip (long numBytes) throws IOException + { + if (numBytes < 0) + throw new IllegalArgumentException ("Can't skip negative bytes: " + + numBytes); + + if (numBytes == 0) + return 0; + + long oldPos = ch.position (); + ch.position(oldPos + numBytes); + return ch.position() - oldPos; + } + + /** + * This method creates a java.nio.channels.FileChannel. + * Nio does not allow one to create a file channel directly. + * A file channel must be created by first creating an instance of + * Input/Output/RandomAccessFile and invoking the getChannel() method on it. + */ + public synchronized FileChannel getChannel () + { + return ch; + } + +} // class FileInputStream + diff --git a/libjava/classpath/java/io/FileNotFoundException.java b/libjava/classpath/java/io/FileNotFoundException.java new file mode 100644 index 0000000..3c11e29 --- /dev/null +++ b/libjava/classpath/java/io/FileNotFoundException.java @@ -0,0 +1,73 @@ +/* FileNotFoundException.java -- the requested file could not be found + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * This exception is thrown when an attempt is made to access a file that + * does not exist, or is inaccessible for some other reason (such as writing + * a read-only file). + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class FileNotFoundException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -897856973823710492L; + + /** + * Create an exception without a descriptive error message. + */ + public FileNotFoundException() + { + } + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + public FileNotFoundException(String message) + { + super(message); + } +} // class FileNotFoundException diff --git a/libjava/classpath/java/io/FileOutputStream.java b/libjava/classpath/java/io/FileOutputStream.java new file mode 100644 index 0000000..10ea6b5 --- /dev/null +++ b/libjava/classpath/java/io/FileOutputStream.java @@ -0,0 +1,296 @@ +/* FileOutputStream.java -- Writes to a file on disk. + Copyright (C) 1998, 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 java.io; + +import gnu.java.nio.channels.FileChannelImpl; + +import java.nio.channels.FileChannel; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.1. + */ + +/** + * This classes allows a stream of data to be written to a disk file or + * any open FileDescriptor. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class FileOutputStream extends OutputStream +{ + private FileDescriptor fd; + + private FileChannelImpl ch; + + /** + * This method initializes a FileOutputStream object to write + * to the named file. The file is created if it does not exist, and + * the bytes written are written starting at the beginning of the file if + * the append argument is false or at the end + * of the file if the append argument is true. + *

    + * Before opening a file, a security check is performed by calling the + * checkWrite method of the SecurityManager (if + * one exists) with the name of the file to be opened. An exception is + * thrown if writing is not allowed. + * + * @param path The name of the file this stream should write to + * @param append true to append bytes to the end of the file, + * or false to write bytes to the beginning + * + * @exception SecurityException If write access to the file is not allowed + * @exception FileNotFoundException If a non-security error occurs + */ + public FileOutputStream (String path, boolean append) + throws SecurityException, FileNotFoundException + { + this (new File(path), append); + } + + /** + * This method initializes a FileOutputStream object to write + * to the named file. The file is created if it does not exist, and + * the bytes written are written starting at the beginning of the file. + *

    + * Before opening a file, a security check is performed by calling the + * checkWrite method of the SecurityManager (if + * one exists) with the name of the file to be opened. An exception is + * thrown if writing is not allowed. + * + * @param path The name of the file this stream should write to + * + * @exception SecurityException If write access to the file is not allowed + * @exception FileNotFoundException If a non-security error occurs + */ + public FileOutputStream (String path) + throws SecurityException, FileNotFoundException + { + this (path, false); + } + + /** + * This method initializes a FileOutputStream object to write + * to the specified File object. The file is created if it + * does not exist, and the bytes written are written starting at the + * beginning of the file. + *

    + * Before opening a file, a security check is performed by calling the + * checkWrite method of the SecurityManager (if + * one exists) with the name of the file to be opened. An exception is + * thrown if writing is not allowed. + * + * @param file The File object this stream should write to + * + * @exception SecurityException If write access to the file is not allowed + * @exception FileNotFoundException If a non-security error occurs + */ + public FileOutputStream (File file) + throws SecurityException, FileNotFoundException + { + this (file, false); + } + + /** + * This method initializes a FileOutputStream object to write + * to the specified File object. The file is created if it + * does not exist, and the bytes written are written starting at the + * beginning of the file if the append parameter is + * false. Otherwise bytes are written at the end of the + * file. + *

    + * Before opening a file, a security check is performed by calling the + * checkWrite method of the SecurityManager (if + * one exists) with the name of the file to be opened. An exception is + * thrown if writing is not allowed. + * + * @param file The File object this stream should write to + * @param append true to append bytes to the end of the file, + * or false to write bytes to the beginning + * + * @exception SecurityException If write access to the file is not allowed + * @exception FileNotFoundException If a non-security error occurs + */ + public FileOutputStream (File file, boolean append) + throws FileNotFoundException + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkWrite(file.getPath()); + + ch = FileChannelImpl.create(file, (append + ? FileChannelImpl.WRITE + | FileChannelImpl.APPEND + : FileChannelImpl.WRITE)); + } + + /** + * This method initializes a FileOutputStream object to write + * to the file represented by the specified FileDescriptor + * object. This method does not create any underlying disk file or + * reposition the file pointer of the given descriptor. It assumes that + * this descriptor is ready for writing as is. + *

    + * Before opening a file, a security check is performed by calling the + * checkWrite method of the SecurityManager (if + * one exists) with the specified FileDescriptor as an argument. + * An exception is thrown if writing is not allowed. + * + * @param fdObj The FileDescriptor this stream should write to + * + * @exception SecurityException If write access to the file is not allowed + */ + public FileOutputStream (FileDescriptor fdObj) + throws SecurityException + { + // Hmm, no other exception but this one to throw, but if the descriptor + // isn't valid, we surely don't have "permission" to write to it. + if (!fdObj.valid()) + throw new SecurityException("Invalid FileDescriptor"); + + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkWrite(fdObj); + + fd = fdObj; + ch = (FileChannelImpl) fdObj.channel; + } + + FileOutputStream(FileChannelImpl ch) + { + this.ch = ch; + } + + protected void finalize () throws IOException + { + // We don't actually need this, but we include it because it is + // mentioned in the JCL. + } + + /** + * This method returns a FileDescriptor object representing + * the file that is currently being written to + * + * @return A FileDescriptor object for this stream + * + * @exception IOException If an error occurs + */ + public final FileDescriptor getFD () throws IOException + { + synchronized (this) + { + if (fd == null) + fd = new FileDescriptor (ch); + return fd; + } + } + + /** + * This method writes a single byte of data to the file. + * + * @param b The byte of data to write, passed as an int + * + * @exception IOException If an error occurs + */ + public void write (int b) throws IOException + { + ch.write (b); + } + + /** + * This method writes all the bytes in the specified array to the + * file. + * + * @param buf The array of bytes to write to the file + * + * @exception IOException If an error occurs + */ + public void write (byte[] buf) + throws IOException + { + write (buf, 0, buf.length); + } + + /** + * This method writes len bytes from the byte array + * buf to the file starting at index offset. + * + * @param buf The array of bytes to write to the file + * @param offset The offset into the array to start writing bytes from + * @param len The number of bytes to write to the file + * + * @exception IOException If an error occurs + */ + public void write (byte[] buf, int offset, int len) + throws IOException + { + if (offset < 0 + || len < 0 + || offset + len > buf.length) + throw new ArrayIndexOutOfBoundsException (); + + ch.write (buf, offset, len); + } + + /** + * This method closes the underlying file. Any further attempts to + * write to this stream will likely generate an exception since the + * file is closed. + * + * @exception IOException If an error occurs + */ + public void close () throws IOException + { + ch.close(); + } + + /** + * This method creates a java.nio.channels.FileChannel. + * Nio does not allow one to create a file channel directly. + * A file channel must be created by first creating an instance of + * Input/Output/RandomAccessFile and invoking the getChannel() method on it. + */ + public synchronized FileChannel getChannel() + { + return ch; + } + +} // class FileOutputStream + diff --git a/libjava/classpath/java/io/FilePermission.java b/libjava/classpath/java/io/FilePermission.java new file mode 100644 index 0000000..356787b --- /dev/null +++ b/libjava/classpath/java/io/FilePermission.java @@ -0,0 +1,292 @@ +/* FilePermission.java -- + Copyright (C) 1998, 2000, 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 java.io; + +import java.security.Permission; + +public final class FilePermission extends Permission implements Serializable +{ + private static final long serialVersionUID = 7930732926638008763L; + + private static final String CURRENT_DIRECTORY = + System.getProperty("user.dir"); + + private static final String ALL_FILES = "<>"; + + private boolean readPerm = false; + private boolean writePerm = false; + private boolean executePerm = false; + private boolean deletePerm = false; + private final String actionsString; + + // Checks and caches the actions + private void checkPerms() throws IllegalArgumentException + { + String action; + int i = actionsString.indexOf(','); + int startI = 0; + while (i != -1) + { + action = actionsString.substring(startI, i).trim().toLowerCase(); + if (action.equals("read")) + readPerm = true; + else if (action.equals("write")) + writePerm = true; + else if (action.equals("execute")) + executePerm = true; + else if (action.equals("delete")) + deletePerm = true; + else + throw new IllegalArgumentException("Unknown action: " + action); + + startI = i + 1; + i = actionsString.indexOf(',', startI); + } + + action = actionsString.substring(startI).trim().toLowerCase(); + if (action.equals("read")) + readPerm = true; + else if (action.equals("write")) + writePerm = true; + else if (action.equals("execute")) + executePerm = true; + else if (action.equals("delete")) + deletePerm = true; + else + throw new IllegalArgumentException("Unknown action: " + action); + } + + /** + * Create a new FilePermission. + * + * @param pathExpression an expression specifying the paths this + * permission represents. + * @param actionsString a comma-separated list of the actions this + * permission represents. The actions must be "read", "write", + * "execute" and/or "delete". + */ + public FilePermission(String pathExpression, String actionsString) + { + // FIXME: what to do when the file string is malformed? + super(pathExpression); + if (pathExpression == null) + throw new NullPointerException("pathExpression"); + if (actionsString == null) + throw new IllegalArgumentException("actionsString"); + this.actionsString = actionsString; + checkPerms(); + } + + /** + * Get the actions this FilePermission supports. + * @return the String representing the actions this FilePermission supports. + */ + public String getActions() + { + return actionsString; + } + + /** + * Get the hash code for this Object.

    + * FilePermission's hash code is calculated as the exclusive or of the + * target + * String's hash code and the action String's hash code. + * @specnote Sun did not specify how to calculate the hash code; + * I made this up. + * @return the hash code for this Object. + */ + public int hashCode() + { + return getName().hashCode() ^ actionsString.hashCode(); + } + + /** + * Check two FilePermissions for semantic equality. + * Two FilePermissions are exactly equivalent if they have identical path + * expressions and have exactly the same access permissions. + * @param o the Object to compare to. + * @return whether the Objects are semantically equivalent. + */ + public boolean equals(Object o) + { + if (! (o instanceof FilePermission)) + return false; + FilePermission p = (FilePermission) o; + + String f1 = getName(); + String f2 = p.getName(); + + // Compare names, taking into account if they refer to a directory + // and one has a separator and the other does not. + if (f1.length() > 0 && f1.charAt(f1.length() - 1) == File.separatorChar) + { + if (f2.length() > 0 + && f2.charAt(f2.length() - 1) == File.separatorChar) + { + if (! f2.equals(f1)) + return false; + } + else + { + if (! f2.equals(f1.substring(0, f1.length() - 1))) + return false; + } + } + else + { + if (f2.length() > 0 + && f2.charAt(f2.length() - 1) == File.separatorChar) + { + if (! f1.equals(f2.substring(0, f2.length() - 1))) + return false; + } + else + { + if (! f1.equals(f2)) + return false; + } + } + return (readPerm == p.readPerm + && writePerm == p.writePerm + && executePerm == p.executePerm + && deletePerm == p.deletePerm); + } + + /** + * Check to see if this permission implies another. + * Permission A implies permission B if these things are all true: + *

      + *
    1. A and B are both FilePermissions.
    2. + *
    3. All possible files in B are included in A + * (possibly more are in A).
    4. + *
    5. All actions B supports, A also supports.
    6. + *
    + * @param p the Permission to compare against. + * @return whether this Permission implies p + */ + public boolean implies(Permission p) + { + if (! (p instanceof FilePermission)) + return false; + + String f1 = getName(); + + if (f1.equals(ALL_FILES)) + return true; + + FilePermission fp = (FilePermission) p; + String f2 = fp.getName(); + + if (f1.charAt(0) != File.separatorChar) + f1 = CURRENT_DIRECTORY + f1; + if (f2.charAt(0) != File.separatorChar) + f2 = CURRENT_DIRECTORY + f2; + + String sub1; + + switch (f1.charAt(f1.length() - 1)) + { + case '*': + sub1 = f1.substring(0, f1.length() - 1); // chop off "*" + if (f2.length() <= sub1.length()) + { + // If it's smaller, there is no way it could be part of + // this directory. If it's the same (or length - 1), it + // could be the same directory but specifies access to + // the directory rather than the files in it. + return false; + } + else if (f2.charAt(sub1.length() - 1) == File.separatorChar) + { + // Make sure the part before the "/" is the same. + if (! f2.substring(0, sub1.length()).equals(sub1)) + return false; + // Make sure there are no subdirectories specified + // underneath this one. + if (f2.substring(sub1.length() + 1).indexOf(File.separatorChar) + != -1) + return false; + } + else + { + // Obviously not equal: f2 is either not a directory or + // is not the same directory (its name continues further + // than we want). + return false; + } + break; + case '-': + // Chop off "/-". + sub1 = f1.substring(0, f1.length() - 2); + if (f2.length() < sub1.length()) + { + // If it's smaller, there is no way it could be part of + // this directory. + return false; + } + else if (f2.length() > sub1.length() + && f2.charAt(sub1.length()) != File.separatorChar) + return false; + else if (! f2.substring(0, sub1.length()).equals(sub1)) + return false; + break; + + default: + if (f2.charAt(f2.length() - 1) == File.separatorChar) + { + if (! f1.equals(f2.substring(0, f2.length() - 1))) + return false; + } + else if (!f1.equals(f2)) + return false; + break; + } + + if (readPerm && ! fp.readPerm) + return false; + if (writePerm && ! fp.writePerm) + return false; + if (executePerm && ! fp.executePerm) + return false; + if (deletePerm && ! fp.deletePerm) + return false; + + return true; + } +} diff --git a/libjava/classpath/java/io/FileReader.java b/libjava/classpath/java/io/FileReader.java new file mode 100644 index 0000000..4a1dd5f --- /dev/null +++ b/libjava/classpath/java/io/FileReader.java @@ -0,0 +1,92 @@ +/* FileReader.java -- Convenience class for reading characters from a file + Copyright (C) 1998, 2000, 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 java.io; + +/** + * This class provides a convenient way to set up a Reader + * to read from a file. It opens the specified file for reading and creates + * the InputStreamReader to read from the + * resulting FileInputStream. This class can only be used + * to read from files using the default character encoding. Use + * InputStreamReader directly to use a non-default encoding. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class FileReader extends InputStreamReader +{ + /** + * This method initializes a FileReader instance to read from + * the specified File object. + * + * @param file The File object representing the file to read from + * + * @exception FileNotFoundException If the file is not found or some other + * error occurs + */ + public FileReader(File file) throws FileNotFoundException + { + super(new FileInputStream(file)); + } + + /** + * This method initializes a FileReader instance to read from + * this specified FileDescriptor object. + * + * @param fd The FileDescriptor to read from. + */ + public FileReader(FileDescriptor fd) + { + super(new FileInputStream(fd)); + } + + /** + * This method initializes a FileReader instance to read from + * the specified named file. + * + * @param name The name of the file to read from + * + * @exception FileNotFoundException If the file is not found or some other + * error occurs + */ + public FileReader(String name) throws FileNotFoundException + { + super(new FileInputStream(name)); + } +} // class FileReader + diff --git a/libjava/classpath/java/io/FileWriter.java b/libjava/classpath/java/io/FileWriter.java new file mode 100644 index 0000000..b34db83 --- /dev/null +++ b/libjava/classpath/java/io/FileWriter.java @@ -0,0 +1,137 @@ +/* FileWriter.java -- Convenience class for writing to files. + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.1. + */ + +/** + * This is a convenience class for writing to files. It creates an + * FileOutputStream and initializes an + * OutputStreamWriter to write to it. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class FileWriter extends OutputStreamWriter +{ + /** + * This method initializes a new FileWriter object to write + * to the specified File object. + * + * @param file The File object to write to. + * + * @throws SecurityException If writing to this file is forbidden by the + * SecurityManager. + * @throws IOException If any other error occurs + */ + public FileWriter(File file) throws SecurityException, IOException + { + super(new FileOutputStream(file)); + } + + /** + * This method initializes a new FileWriter object to write + * to the specified File object. + * + * @param file The File object to write to. + * @param append true to start adding data at the end of the + * file, false otherwise. + * + * @throws SecurityException If writing to this file is forbidden by the + * SecurityManager. + * @throws IOException If any other error occurs + */ + public FileWriter(File file, boolean append) throws IOException + { + super(new FileOutputStream(file, append)); + } + + /** + * This method initializes a new FileWriter object to write + * to the specified FileDescriptor object. + * + * @param fd The FileDescriptor object to write to + * + * @throws SecurityException If writing to this file is forbidden by the + * SecurityManager. + */ + public FileWriter(FileDescriptor fd) throws SecurityException + { + super(new FileOutputStream(fd)); + } + + /** + * This method intializes a new FileWriter object to + * write to the + * specified named file. + * + * @param name The name of the file to write to + * + * @throws SecurityException If writing to this file is forbidden by the + * SecurityManager. + * @throws IOException If any other error occurs + */ + public FileWriter(String name) throws IOException + { + super(new FileOutputStream(name)); + } + + /** + * This method intializes a new FileWriter object to + * write to the + * specified named file. This form of the constructor allows the caller + * to determin whether data should be written starting at the beginning or + * the end of the file. + * + * @param name The name of the file to write to + * @param append true to start adding data at the end of the + * file, false otherwise. + * + * @throws SecurityException If writing to this file is forbidden by the + * SecurityManager. + * @throws IOException If any other error occurs + */ + public FileWriter(String name, boolean append) throws IOException + { + super(new FileOutputStream(name, append)); + } +} diff --git a/libjava/classpath/java/io/FilenameFilter.java b/libjava/classpath/java/io/FilenameFilter.java new file mode 100644 index 0000000..57b4d3b --- /dev/null +++ b/libjava/classpath/java/io/FilenameFilter.java @@ -0,0 +1,76 @@ +/* FilenameFilter.java -- Filter a list of filenames + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to 1.1. + */ + +/** + * This interface has one method which is used for filtering filenames + * returned in a directory listing. It is currently used by the + * File.list(FilenameFilter) method and by the filename + * dialog in AWT. + *

    + * The method in this interface determines if a particular file should + * or should not be included in the file listing. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * + * @see File#listFiles(java.io.FilenameFilter) + * @see java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter) + */ +public interface FilenameFilter +{ + /** + * This method determines whether or not a given file should be included + * in a directory listing. + * + * @param dir The File instance for the directory being read + * @param name The name of the file to test + * + * @return true if the file should be included in the list, + * false otherwise. + */ + boolean accept(File dir, String name); + +} // interface FilenameFilter + diff --git a/libjava/classpath/java/io/FilterInputStream.java b/libjava/classpath/java/io/FilterInputStream.java new file mode 100644 index 0000000..d3cb9e4 --- /dev/null +++ b/libjava/classpath/java/io/FilterInputStream.java @@ -0,0 +1,203 @@ +/* FilterInputStream.java -- Base class for classes that filter input + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This is the common superclass of all standard classes that filter + * input. It acts as a layer on top of an underlying InputStream + * and simply redirects calls made to it to the subordinate InputStream + * instead. Subclasses of this class perform additional filtering + * functions in addition to simply redirecting the call. + *

    + * This class is not abstract. However, since it only redirects calls + * to a subordinate InputStream without adding any functionality + * on top of it, this class should not be used directly. Instead, various + * subclasses of this class should be used. This is enforced with a + * protected constructor. Do not try to hack around it. + *

    + * When creating a subclass of FilterInputStream, override the + * appropriate methods to implement the desired filtering. However, note + * that the read(byte[]) method does not need to be overridden + * as this class redirects calls to that method to + * read(byte[], int, int) instead of to the subordinate + * InputStream read(byte[]) method. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class FilterInputStream extends InputStream +{ + /** + * This is the subordinate InputStream to which method calls + * are redirected + */ + protected InputStream in; + + /** + * Create a FilterInputStream with the specified subordinate + * InputStream. + * + * @param in The subordinate InputStream + */ + protected FilterInputStream(InputStream in) + { + this.in = in; + } + + /** + * Calls the in.mark(int) method. + * + * @param readlimit The parameter passed to in.mark(int) + */ + public void mark(int readlimit) + { + in.mark(readlimit); + } + + /** + * Calls the in.markSupported() method. + * + * @return true if mark/reset is supported, false + * otherwise + */ + public boolean markSupported() + { + return in.markSupported(); + } + + /** + * Calls the in.reset() method. + * + * @exception IOException If an error occurs + */ + public void reset() throws IOException + { + in.reset(); + } + + /** + * Calls the in.available() method. + * + * @return The value returned from in.available() + * + * @exception IOException If an error occurs + */ + public int available() throws IOException + { + return in.available(); + } + + /** + * Calls the in.skip(long) method + * + * @param numBytes The requested number of bytes to skip. + * + * @return The value returned from in.skip(long) + * + * @exception IOException If an error occurs + */ + public long skip(long numBytes) throws IOException + { + return in.skip(numBytes); + } + + /** + * Calls the in.read() method + * + * @return The value returned from in.read() + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + return in.read(); + } + + /** + * Calls the read(byte[], int, int) overloaded method. + * Note that + * this method does not redirect its call directly to a corresponding + * method in in. This allows subclasses to override only the + * three argument version of read. + * + * @param buf The buffer to read bytes into + * + * @return The value retured from in.read(byte[], int, int) + * + * @exception IOException If an error occurs + */ + public int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + /** + * Calls the in.read(byte[], int, int) method. + * + * @param buf The buffer to read bytes into + * @param offset The index into the buffer to start storing bytes + * @param len The maximum number of bytes to read. + * + * @return The value retured from in.read(byte[], int, int) + * + * @exception IOException If an error occurs + */ + public int read(byte[] buf, int offset, int len) throws IOException + { + return in.read(buf, offset, len); + } + + /** + * This method closes the input stream by closing the input stream that + * this object is filtering. Future attempts to access this stream may + * throw an exception. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + in.close(); + } +} diff --git a/libjava/classpath/java/io/FilterOutputStream.java b/libjava/classpath/java/io/FilterOutputStream.java new file mode 100644 index 0000000..4c2dfc0 --- /dev/null +++ b/libjava/classpath/java/io/FilterOutputStream.java @@ -0,0 +1,150 @@ +/* FilterOutputStream.java -- Parent class for output streams that filter + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.1. + */ + +/** + * This class is the common superclass of output stream classes that + * filter the output they write. These classes typically transform the + * data in some way prior to writing it out to another underlying + * OutputStream. This class simply overrides all the + * methods in OutputStream to redirect them to the + * underlying stream. Subclasses provide actual filtering. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class FilterOutputStream extends OutputStream +{ + /** + * This is the subordinate OutputStream that this class + * redirects its method calls to. + */ + protected OutputStream out; + + /** + * This method initializes an instance of FilterOutputStream + * to write to the specified subordinate OutputStream. + * + * @param out The OutputStream to write to + */ + public FilterOutputStream(OutputStream out) + { + this.out = out; + } + + /** + * This method closes the underlying OutputStream. Any + * further attempts to write to this stream may throw an exception. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + flush(); + out.close(); + } + + /** + * This method attempt to flush all buffered output to be written to the + * underlying output sink. + * + * @exception IOException If an error occurs + */ + public void flush() throws IOException + { + out.flush(); + } + + /** + * This method writes a single byte of output to the underlying + * OutputStream. + * + * @param b The byte to write, passed as an int. + * + * @exception IOException If an error occurs + */ + public void write(int b) throws IOException + { + out.write(b); + } + + /** + * This method writes all the bytes in the specified array to the underlying + * OutputStream. It does this by calling the three parameter + * version of this method - write(byte[], int, int) in this + * class instead of writing to the underlying OutputStream + * directly. This allows most subclasses to avoid overriding this method. + * + * @param buf The byte array to write bytes from + * + * @exception IOException If an error occurs + */ + public void write(byte[] buf) throws IOException + { + // Don't do checking here, per Java Lang Spec. + write(buf, 0, buf.length); + } + + /** + * This method calls the write(int) method len + * times for all bytes from the array buf starting at index + * offset. Subclasses should overwrite this method to get a + * more efficient implementation. + * + * @param buf The byte array to write bytes from + * @param offset The index into the array to start writing bytes 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 + { + // Don't do checking here, per Java Lang Spec. + for (int i=0; i < len; i++) + write(buf[offset + i]); + + } + +} // class FilterOutputStream + diff --git a/libjava/classpath/java/io/FilterReader.java b/libjava/classpath/java/io/FilterReader.java new file mode 100644 index 0000000..2bd040a --- /dev/null +++ b/libjava/classpath/java/io/FilterReader.java @@ -0,0 +1,185 @@ +/* FilterReader.java -- Base class for char stream classes that filter input + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This is the common superclass of all standard classes that filter + * input. It acts as a layer on top of an underlying Reader + * and simply redirects calls made to it to the subordinate Reader + * instead. Subclasses of this class perform additional filtering + * functions in addition to simply redirecting the call. + *

    + * When creating a subclass of FilterReader, override the + * appropriate methods to implement the desired filtering. However, note + * that the read(char[]) method does not need to be overridden + * as this class redirects calls to that method to + * read(yte[], int, int) instead of to the subordinate + * Reader} read(yte[]) method. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public abstract class FilterReader extends Reader +{ + /** + * This is the subordinate Reader to which method calls + * are redirected + */ + protected Reader in; + + /** + * Create a FilterReader with the specified subordinate + * Reader. + * The lock of the new FilterReader will be set + * to in.lock. + * + * @param in The subordinate Reader + */ + protected FilterReader(Reader in) + { + super(in.lock); + this.in = in; + } + + /** + * Calls the in.mark(int) method. + * + * @param readlimit The parameter passed to in.mark(int) + * + * @exception IOException If an error occurs + */ + public void mark(int readlimit) throws IOException + { + in.mark(readlimit); + } + + /** + * Calls the in.markSupported() method. + * + * @return true if mark/reset is supported, + * false otherwise + */ + public boolean markSupported() + { + return(in.markSupported()); + } + + /** + * Calls the in.reset() method. + * + * @exception IOException If an error occurs + */ + public void reset() throws IOException + { + in.reset(); + } + + /** + * Calls the in.read() method. + * + * @return The value returned from in.available() + * + * @exception IOException If an error occurs + */ + public boolean ready() throws IOException + { + return(in.ready()); + } + + /** + * Calls the in.skip(long) method + * + * @param numBytes The requested number of chars to skip. + * + * @return The value returned from in.skip(long) + * + * @exception IOException If an error occurs + */ + public long skip(long num_chars) throws IOException + { + return(in.skip(num_chars)); + } + + /** + * Calls the in.read() method + * + * @return The value returned from in.read() + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + return(in.read()); + } + + /** + * Calls the in.read(char[], int, int) method. + * + * @param buf The buffer to read chars into + * @param offset The index into the buffer to start storing chars + * @param len The maximum number of chars to read. + * + * @return The value retured from in.read(char[], int, int) + * + * @exception IOException If an error occurs + */ + public int read(char[] buf, int offset, int len) throws IOException + { + return(in.read(buf, offset, len)); + } + + /** + * This method closes the stream by calling the close() method + * of the underlying stream. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + in.close(); + } + +} // class FilterReader + diff --git a/libjava/classpath/java/io/FilterWriter.java b/libjava/classpath/java/io/FilterWriter.java new file mode 100644 index 0000000..9b9ce33 --- /dev/null +++ b/libjava/classpath/java/io/FilterWriter.java @@ -0,0 +1,147 @@ +/* FilterWriter.java -- Parent class for output streams that filter + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.1. + */ + +/** + * This class is the common superclass of output character stream classes + * that filter the output they write. These classes typically transform the + * data in some way prior to writing it out to another underlying + * Writer. This class simply overrides all the + * methods in Writer to redirect them to the + * underlying stream. Subclasses provide actual filtering. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public abstract class FilterWriter extends Writer +{ + /** + * This is the subordinate Writer that this class + * redirects its method calls to. + */ + protected Writer out; + + /** + * This method initializes an instance of FilterWriter + * to write to the specified subordinate Writer. + * The given Writer will be used as lock for + * the newly created FilterWriter. + * + * @param out The Writer to write to + */ + protected FilterWriter(Writer out) + { + super(out.lock); + this.out = out; + } + + /** + * This method closes the underlying Writer. Any + * further attempts to write to this stream may throw an exception. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + out.close(); + } + + /** + * This method attempt to flush all buffered output to be written to the + * underlying output sink. + * + * @exception IOException If an error occurs + */ + public void flush() throws IOException + { + out.flush(); + } + + /** + * This method writes a single char of output to the underlying + * Writer. + * + * @param b The char to write, passed as an int. + * + * @exception IOException If an error occurs + */ + public void write(int b) throws IOException + { + out.write(b); + } + + /** + * This method writes len chars from the array buf + * starting at index offset to the underlying + * Writer. + * + * @param buf The char array to write chars from + * @param offset The index into the array to start writing chars from + * @param len The number of chars to write + * + * @exception IOException If an error occurs + */ + public void write(char[] buf, int offset, int len) throws IOException + { + out.write(buf, offset, len); + } + + /** + * This method writes len chars from the String + * starting at position offset. + * + * @param str The String that is to be written + * @param offset The character offset into the String + * to start writing from + * @param len The number of chars to write + * + * @exception IOException If an error occurs + */ + public void write(String str, int offset, int len) throws IOException + { + out.write(str, offset, len); + } + +} // class FilterWriter + diff --git a/libjava/classpath/java/io/Flushable.java b/libjava/classpath/java/io/Flushable.java new file mode 100644 index 0000000..e9718d6 --- /dev/null +++ b/libjava/classpath/java/io/Flushable.java @@ -0,0 +1,62 @@ +/* Flushable.java -- Flushable object + Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +/** + * A Flushable class represents a stream of + * data, for which internally buffered data can be `flushed'. + * Flushing such a stream causes the buffered data to be + * written to the stream. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface Flushable +{ + + /** + * Flushes the stream represented by this class, + * so that any buffered data is written to the stream. + * + * @throws IOException if an I/O error occurs in flushing. + */ + void flush() + throws IOException; + +} diff --git a/libjava/classpath/java/io/IOException.java b/libjava/classpath/java/io/IOException.java new file mode 100644 index 0000000..cf3ad19 --- /dev/null +++ b/libjava/classpath/java/io/IOException.java @@ -0,0 +1,74 @@ +/* IOException.java -- Generic input/output exception + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * This exception is thrown to indicate an I/O problem of some sort + * occurred. Since this is a fairly generic exception, often a subclass + * of IOException will actually be thrown in order to provide a more + * detailed indication of what happened. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class IOException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 7818375828146090155L; + + /** + * Create an exception without a descriptive error message. + */ + public IOException() + { + } + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + public IOException(String message) + { + super(message); + } +} // class IOException diff --git a/libjava/classpath/java/io/InputStream.java b/libjava/classpath/java/io/InputStream.java new file mode 100644 index 0000000..86d1cd7 --- /dev/null +++ b/libjava/classpath/java/io/InputStream.java @@ -0,0 +1,272 @@ +/* InputStream.java -- Base class for input + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/** + * This abstract class forms the base of the hierarchy of classes that read + * input as a stream of bytes. It provides a common set of methods for + * reading bytes from streams. Subclasses implement and extend these + * methods to read bytes from a particular input source such as a file + * or network connection. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public abstract class InputStream +{ + /** + * Default, no-arg, public constructor + */ + public InputStream() + { + } + + /** + * This method returns the number of bytes that can be read from this + * stream before a read can block. A return of 0 indicates that blocking + * might (or might not) occur on the very next read attempt. + *

    + * This method always returns 0 in this class + * + * @return The number of bytes that can be read before blocking could occur + * + * @exception IOException If an error occurs + */ + public int available() throws IOException + { + return 0; + } + + /** + * This method closes the stream. Any futher attempts to read from the + * stream may generate an IOException + *

    + * This method does nothing in this class, but subclasses may override + * this method in order to provide additional functionality. + * + * @exception IOException If an error occurs, which can only happen + * in a subclass + */ + public void close() throws IOException + { + // Do nothing + } + + /** + * This method marks a position in the input to which the stream can + * be "reset" by calling the reset() method. The + * parameter @code{readlimit} is the number of bytes that can be read + * from the stream after setting the mark before the mark becomes + * invalid. For example, if mark() is called with a + * read limit of 10, then when 11 bytes of data are read from the + * stream before the reset() method is called, then the + * mark is invalid and the stream object instance is not required to + * remember the mark. + *

    + * This method does nothing in this class, but subclasses may override it + * to provide mark/reset functionality. + * + * @param readLimit The number of bytes that can be read before the + * mark becomes invalid + */ + public void mark(int readLimit) + { + // Do nothing + } + + /** + * This method returns a boolean that indicates whether the mark/reset + * methods are supported in this class. Those methods can be used to + * remember a specific point in the stream and reset the stream to that + * point. + *

    + * This method always returns false in this class, but + * subclasses can override this method to return true + * if they support mark/reset functionality. + * + * @return true if mark/reset functionality is + * supported, false otherwise + */ + public boolean markSupported() + { + return false; + } + + /** + * This method reads an unsigned byte from the input stream and returns it + * as an int in the range of 0-255. This method also will return -1 if + * the end of the stream has been reached. + *

    + * This method will block until the byte can be read. + * + * @return The byte read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public abstract int read() throws IOException; + + /** + * This method reads bytes from a stream and stores them into a caller + * supplied buffer. This method attempts to completely fill the buffer, + * but can return before doing so. The actual number of bytes read is + * returned as an int. A -1 is returned to indicate the end of the stream. + *

    + * This method will block until some data can be read. + *

    + * This method operates by calling an overloaded read method like so: + * read(b, 0, b.length) + * + * @param b The buffer into which the bytes read will be stored. + * + * @return The number of bytes read or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public int read(byte[] b) throws IOException + { + return read(b, 0, b.length); + } + + /** + * This method read bytes from a stream and stores them into a + * caller supplied buffer. It starts storing the data at index + * off into the buffer and attempts to read + * len bytes. This method can return before reading the + * number of bytes requested. The actual number of bytes read is + * returned as an int. A -1 is returned to indicate the end of the + * stream. + *

    + * This method will block until some data can be read. + *

    + * This method operates by calling the single byte read() method + * in a loop until the desired number of bytes are read. The read loop + * stops short if the end of the stream is encountered or if an IOException + * is encountered on any read operation except the first. If the first + * attempt to read a bytes fails, the IOException is allowed to propagate + * upward. And subsequent IOException is caught and treated identically + * to an end of stream condition. Subclasses can (and should if possible) + * override this method to provide a more efficient implementation. + * + * @param b The array into which the bytes read should be stored + * @param off The offset into the array to start storing bytes + * @param len The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public int read(byte[] b, int off, int len) throws IOException + { + if (off < 0 || len < 0 || off + len > b.length) + throw new IndexOutOfBoundsException(); + if (b.length == 0) + return 0; + + int i, ch; + + for (i = 0; i < len; ++i) + try + { + if ((ch = read()) < 0) + return i == 0 ? -1 : i; // EOF + b[off + i] = (byte) ch; + } + catch (IOException ex) + { + // Only reading the first byte should cause an IOException. + if (i == 0) + throw ex; + return i; + } + + return i; + } + + /** + * This method resets a stream to the point where the + * mark() method was called. Any bytes that were read + * after the mark point was set will be re-read during subsequent + * reads. + *

    + * This method always throws an IOException in this class, but subclasses + * can override this method if they provide mark/reset functionality. + * + * @exception IOException Always thrown for this class + */ + public void reset() throws IOException + { + throw new IOException("mark/reset not supported"); + } + + /** + * This method skips the specified number of bytes in the stream. It + * returns the actual number of bytes skipped, which may be less than the + * requested amount. + *

    + * This method reads and discards bytes into a byte array until the + * specified number of bytes were skipped or until either the end of stream + * is reached or a read attempt returns a short count. Subclasses can + * override this metho to provide a more efficient implementation where + * one exists. + * + * @param n The requested number of bytes to skip + * + * @return The actual number of bytes skipped. + * + * @exception IOException If an error occurs + */ + public long skip(long n) throws IOException + { + // Throw away n bytes by reading them into a temp byte[]. + // Limit the temp array to 2Kb so we don't grab too much memory. + final int buflen = n > 2048 ? 2048 : (int) n; + byte[] tmpbuf = new byte[buflen]; + final long origN = n; + + while (n > 0L) + { + int numread = read(tmpbuf, 0, n > buflen ? buflen : (int) n); + if (numread <= 0) + break; + n -= numread; + } + + return origN - n; + } +} diff --git a/libjava/classpath/java/io/InputStreamReader.java b/libjava/classpath/java/io/InputStreamReader.java new file mode 100644 index 0000000..315af83 --- /dev/null +++ b/libjava/classpath/java/io/InputStreamReader.java @@ -0,0 +1,438 @@ +/* InputStreamReader.java -- Reader than transforms bytes to chars + Copyright (C) 1998, 1999, 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 java.io; + +import java.nio.charset.UnsupportedCharsetException; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.CharBuffer; +import java.nio.ByteBuffer; +import gnu.java.nio.charset.EncodingHelper; + +/** + * This class reads characters from a byte input stream. The characters + * read are converted from bytes in the underlying stream by a + * decoding layer. The decoding layer transforms bytes to chars according + * to an encoding standard. There are many available encodings to choose + * from. The desired encoding can either be specified by name, or if no + * encoding is selected, the system default encoding will be used. The + * system default encoding name is determined from the system property + * file.encoding. The only encodings that are guaranteed to + * be availalbe are "8859_1" (the Latin-1 character set) and "UTF8". + * Unforunately, Java does not provide a mechanism for listing the + * ecodings that are supported in a given implementation. + *

    + * Here is a list of standard encoding names that may be available: + *

    + *

      + *
    • 8859_1 (ISO-8859-1/Latin-1)
    • + *
    • 8859_2 (ISO-8859-2/Latin-2)
    • + *
    • 8859_3 (ISO-8859-3/Latin-3)
    • + *
    • 8859_4 (ISO-8859-4/Latin-4)
    • + *
    • 8859_5 (ISO-8859-5/Latin-5)
    • + *
    • 8859_6 (ISO-8859-6/Latin-6)
    • + *
    • 8859_7 (ISO-8859-7/Latin-7)
    • + *
    • 8859_8 (ISO-8859-8/Latin-8)
    • + *
    • 8859_9 (ISO-8859-9/Latin-9)
    • + *
    • ASCII (7-bit ASCII)
    • + *
    • UTF8 (UCS Transformation Format-8)
    • + *
    • More later
    • + *
    + *

    + * It is recommended that applications do not use + * InputStreamReader's + * directly. Rather, for efficiency purposes, an object of this class + * should be wrapped by a BufferedReader. + *

    + * Due to a deficiency the Java class library design, there is no standard + * way for an application to install its own byte-character encoding. + * + * @see BufferedReader + * @see InputStream + * + * @author Robert Schuster + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + * @date April 22, 1998. + */ +public class InputStreamReader extends Reader +{ + /** + * The input stream. + */ + private InputStream in; + + /** + * The charset decoder. + */ + private CharsetDecoder decoder; + + /** + * End of stream reached. + */ + private boolean isDone = false; + + /** + * Need this. + */ + private float maxBytesPerChar; + + /** + * Buffer holding surplus loaded bytes (if any) + */ + private ByteBuffer byteBuffer; + + /** + * java.io canonical name of the encoding. + */ + private String encoding; + + /** + * We might decode to a 2-char UTF-16 surrogate, which won't fit in the + * output buffer. In this case we need to save the surrogate char. + */ + private char savedSurrogate; + private boolean hasSavedSurrogate = false; + + /** + * This method initializes a new instance of InputStreamReader + * to read from the specified stream using the default encoding. + * + * @param in The InputStream to read from + */ + public InputStreamReader(InputStream in) + { + if (in == null) + throw new NullPointerException(); + this.in = in; + try + { + encoding = System.getProperty("file.encoding"); + // Don't use NIO if avoidable + if(EncodingHelper.isISOLatin1(encoding)) + { + encoding = "ISO8859_1"; + maxBytesPerChar = 1f; + decoder = null; + return; + } + Charset cs = EncodingHelper.getCharset(encoding); + decoder = cs.newDecoder(); + encoding = EncodingHelper.getOldCanonical(cs.name()); + try { + maxBytesPerChar = cs.newEncoder().maxBytesPerChar(); + } catch(UnsupportedOperationException _){ + maxBytesPerChar = 1f; + } + decoder.onMalformedInput(CodingErrorAction.REPLACE); + decoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + decoder.reset(); + } catch(RuntimeException e) { + encoding = "ISO8859_1"; + maxBytesPerChar = 1f; + decoder = null; + } catch(UnsupportedEncodingException e) { + encoding = "ISO8859_1"; + maxBytesPerChar = 1f; + decoder = null; + } + } + + /** + * This method initializes a new instance of InputStreamReader + * to read from the specified stream using a caller supplied character + * encoding scheme. Note that due to a deficiency in the Java language + * design, there is no way to determine which encodings are supported. + * + * @param in The InputStream to read from + * @param encoding_name The name of the encoding scheme to use + * + * @exception UnsupportedEncodingException If the encoding scheme + * requested is not available. + */ + public InputStreamReader(InputStream in, String encoding_name) + throws UnsupportedEncodingException + { + if (in == null + || encoding_name == null) + throw new NullPointerException(); + + this.in = in; + // Don't use NIO if avoidable + if(EncodingHelper.isISOLatin1(encoding_name)) + { + encoding = "ISO8859_1"; + maxBytesPerChar = 1f; + decoder = null; + return; + } + try { + Charset cs = EncodingHelper.getCharset(encoding_name); + try { + maxBytesPerChar = cs.newEncoder().maxBytesPerChar(); + } catch(UnsupportedOperationException _){ + maxBytesPerChar = 1f; + } + + decoder = cs.newDecoder(); + decoder.onMalformedInput(CodingErrorAction.REPLACE); + decoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + decoder.reset(); + + // The encoding should be the old name, if such exists. + encoding = EncodingHelper.getOldCanonical(cs.name()); + } catch(RuntimeException e) { + encoding = "ISO8859_1"; + maxBytesPerChar = 1f; + decoder = null; + } + } + + /** + * Creates an InputStreamReader that uses a decoder of the given + * charset to decode the bytes in the InputStream into + * characters. + */ + public InputStreamReader(InputStream in, Charset charset) { + this.in = in; + decoder = charset.newDecoder(); + + decoder.onMalformedInput(CodingErrorAction.REPLACE); + decoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + decoder.reset(); + encoding = EncodingHelper.getOldCanonical(charset.name()); + } + + /** + * Creates an InputStreamReader that uses the given charset decoder + * to decode the bytes in the InputStream into characters. + */ + public InputStreamReader(InputStream in, CharsetDecoder decoder) { + this.in = in; + this.decoder = decoder; + + try { + maxBytesPerChar = decoder.charset().newEncoder().maxBytesPerChar(); + } catch(UnsupportedOperationException _){ + maxBytesPerChar = 1f; + } + + decoder.onMalformedInput(CodingErrorAction.REPLACE); + decoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + decoder.reset(); + encoding = EncodingHelper.getOldCanonical(decoder.charset().name()); + } + + /** + * This method closes this stream, as well as the underlying + * InputStream. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + synchronized (lock) + { + // Makes sure all intermediate data is released by the decoder. + if (decoder != null) + decoder.reset(); + if (in != null) + in.close(); + in = null; + isDone = true; + decoder = null; + } + } + + /** + * This method returns the name of the encoding that is currently in use + * by this object. If the stream has been closed, this method is allowed + * to return null. + * + * @return The current encoding name + */ + public String getEncoding() + { + return in != null ? encoding : null; + } + + /** + * This method checks to see if the stream is ready to be read. It + * will return true if is, or false if it is not. + * If the stream is not ready to be read, it could (although is not required + * to) block on the next read attempt. + * + * @return true if the stream is ready to be read, + * false otherwise + * + * @exception IOException If an error occurs + */ + public boolean ready() throws IOException + { + if (in == null) + throw new IOException("Reader has been closed"); + + return in.available() != 0; + } + + /** + * This method reads up to length characters from the stream into + * the specified array starting at index offset into the + * array. + * + * @param buf The character array to recieve the data read + * @param offset The offset into the array to start storing characters + * @param length The requested number of characters to read. + * + * @return The actual number of characters read, or -1 if end of stream. + * + * @exception IOException If an error occurs + */ + public int read(char[] buf, int offset, int length) throws IOException + { + if (in == null) + throw new IOException("Reader has been closed"); + if (isDone) + return -1; + if(decoder != null){ + int totalBytes = (int)((double)length * maxBytesPerChar); + byte[] bytes = new byte[totalBytes]; + + int remaining = 0; + if(byteBuffer != null) + { + remaining = byteBuffer.remaining(); + byteBuffer.get(bytes, 0, remaining); + } + int read; + if(totalBytes - remaining > 0) + { + read = in.read(bytes, remaining, totalBytes - remaining); + if(read == -1){ + read = remaining; + isDone = true; + } else + read += remaining; + } else + read = remaining; + byteBuffer = ByteBuffer.wrap(bytes, 0, read); + CharBuffer cb = CharBuffer.wrap(buf, offset, length); + int startPos = cb.position(); + + if(hasSavedSurrogate){ + hasSavedSurrogate = false; + cb.put(savedSurrogate); + read++; + } + + CoderResult cr = decoder.decode(byteBuffer, cb, isDone); + decoder.reset(); + // 1 char remains which is the first half of a surrogate pair. + if(cr.isOverflow() && cb.hasRemaining()){ + CharBuffer overflowbuf = CharBuffer.allocate(2); + cr = decoder.decode(byteBuffer, overflowbuf, isDone); + overflowbuf.flip(); + if(overflowbuf.hasRemaining()) + { + cb.put(overflowbuf.get()); + savedSurrogate = overflowbuf.get(); + hasSavedSurrogate = true; + isDone = false; + } + } + + if(byteBuffer.hasRemaining()) { + byteBuffer.compact(); + byteBuffer.flip(); + isDone = false; + } else + byteBuffer = null; + + read = cb.position() - startPos; + return (read <= 0) ? -1 : read; + } else { + byte[] bytes = new byte[length]; + int read = in.read(bytes); + for(int i=0;i + * This method will block until the char can be read. + * + * @return The char read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + char[] buf = new char[1]; + int count = read(buf, 0, 1); + return count > 0 ? buf[0] : -1; + } + + /** + * Skips the specified number of chars in the stream. It + * returns the actual number of chars skipped, which may be less than the + * requested amount. + * + * @param count The requested number of chars to skip + * + * @return The actual number of chars skipped. + * + * @exception IOException If an error occurs + */ + public long skip(long count) throws IOException + { + if (in == null) + throw new IOException("Reader has been closed"); + + return super.skip(count); + } +} diff --git a/libjava/classpath/java/io/InterruptedIOException.java b/libjava/classpath/java/io/InterruptedIOException.java new file mode 100644 index 0000000..96ec836 --- /dev/null +++ b/libjava/classpath/java/io/InterruptedIOException.java @@ -0,0 +1,94 @@ +/* InterruptedIOException.java -- an I/O operation was interrupted + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * This exception is thrown when a in process I/O operation is interrupted + * for some reason. The field bytesTransferred will contain the number of + * bytes that were read/written prior to the interruption. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @see Thread#interrupt() + * @status updated to 1.4 + */ +public class InterruptedIOException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 4020568460727500567L; + + /** + * The number of bytes read/written prior to the interruption. + * + * @serial count of bytes successfully transferred + */ + public int bytesTransferred; + + /** + * Create an extends without a descriptive error message. + */ + public InterruptedIOException() + { + } + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + public InterruptedIOException(String message) + { + super(message); + } + + /** + * Create an exception with a descriptive error message and count of + * bytes transferred. + * + * @param message the descriptive error message + * @param bytesTransferred number of bytes tranferred before interruption + */ + InterruptedIOException(String message, int bytesTransferred) + { + super(message); + this.bytesTransferred = bytesTransferred; + } +} // class InterruptedIOException diff --git a/libjava/classpath/java/io/InvalidClassException.java b/libjava/classpath/java/io/InvalidClassException.java new file mode 100644 index 0000000..c71b0c6 --- /dev/null +++ b/libjava/classpath/java/io/InvalidClassException.java @@ -0,0 +1,111 @@ +/* InvalidClassException.java -- deserializing a class failed + 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 java.io; + +/** + * This exception is thrown when there is some sort of problem with a + * class during a serialization operation. This could be:

      + *
    • the serial version of the class doesn't match
    • + *
    • the class contains unknown datatypes
    • + *
    • the class does not have an accessible no-arg constructor
    • + *
    . + * + *

    The field classname will contain the name of the + * class that caused the problem if known. The getMessage() method + * for this exception will always include the name of that class + * if known. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class InvalidClassException extends ObjectStreamException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -4333316296251054416L; + + /** + * The name of the class which encountered the error. + * + * @serial the classname causing the error + */ + public String classname; + + /** + * Create an exception with a descriptive error message, but a null + * classname. + * + * @param message the descriptive error message + */ + public InvalidClassException(String message) + { + super(message); + } + + /** + * Create an exception with a descriptive error message, and the name of + * the class that caused the problem. + * + * @param classname the name of the faulty class + * @param message the descriptive error message + */ + public InvalidClassException(String classname, String message) + { + super(message); + this.classname = classname; + } + + /** + * Returns the descriptive error message for this exception. It will + * include the class name that caused the problem if known, in the format: + * [classname][; ][super.getMessage()]. + * + * @return A descriptive error message, may be null + */ + public String getMessage() + { + String msg = super.getMessage(); + if (msg == null) + return classname; + return (classname == null ? "" : classname + "; ") + msg; + } +} + diff --git a/libjava/classpath/java/io/InvalidObjectException.java b/libjava/classpath/java/io/InvalidObjectException.java new file mode 100644 index 0000000..deee876 --- /dev/null +++ b/libjava/classpath/java/io/InvalidObjectException.java @@ -0,0 +1,66 @@ +/* InvalidObjectException.java -- deserialization failed verification + 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 java.io; + +/** + * This exception is thrown when an object fails a validation test + * during serialization. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class InvalidObjectException extends ObjectStreamException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 3233174318281839583L; + + /** + * Create an exception with a descriptive error message String. This should + * be the cause of the verification failure. + * + * @param message the descriptive error message + */ + public InvalidObjectException(String message) + { + super(message); + } +} // class InvalidObjectException diff --git a/libjava/classpath/java/io/LineNumberInputStream.java b/libjava/classpath/java/io/LineNumberInputStream.java new file mode 100644 index 0000000..da43097 --- /dev/null +++ b/libjava/classpath/java/io/LineNumberInputStream.java @@ -0,0 +1,315 @@ +/* LineNumberInputStream.java -- An input stream which counts line numbers + Copyright (C) 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 java.io; + +/** + * This class functions like a standard InputStream + * except that it counts line numbers, and canonicalizes newline + * characters. As data is read, whenever the byte sequences "\r", + * "\n", or "\r\n" are encountered, the running line count is + * incremeted by one. Additionally, the whatever line termination + * sequence was encountered will be converted to a "\n" byte. Note + * that this class numbers lines from 0. When the first line + * terminator is encountered, the line number is incremented to 1, and + * so on. + *

    + * This class counts only line termination characters. If the last line + * read from the stream does not end in a line termination sequence, it + * will not be counted as a line. + *

    + * Note that since this class operates as a filter on an underlying + * stream, it has the same mark/reset functionality as the underlying + * stream. The mark() and reset() methods + * in this class handle line numbers correctly. Calling + * reset() resets the line number to the point at which + * mark() was called if the subordinate stream supports + * that functionality. + *

    + * @deprecated This class is deprecated in favor if + * LineNumberReader because it operates on ASCII bytes + * instead of an encoded character stream. This class is for backward + * compatibility only and should not be used in new applications. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class LineNumberInputStream extends FilterInputStream +{ + /** The current line number. */ + private int lineNumber = 0; + + /** The line number when the stream was marked. */ + private int markLineNumber = 0; + + /** Flag to indicate a '\r' was just read so that an immediately + * subsequent '\n' can be ignored. */ + private boolean justReadReturnChar = false; + + /** + * Create a new LineNumberInputStream that reads from the + * specified subordinate InputStream + * + * @param in The subordinate InputStream to read from + */ + public LineNumberInputStream(InputStream in) + { + super(in); + } + + /** + * This method returns the number of bytes that can be read from the + * stream before the stream can block. This method is tricky + * because the subordinate InputStream might return + * only "\r\n" characters, which are replaced by a single "\n" + * character by the read() method of this class. So + * this method can only guarantee that in.available() / + * 2 bytes can actually be read before blocking. In + * practice, considerably more bytes might be read before blocking + *

    + * Note that the stream may not block if additional bytes beyond the count + * returned by this method are read. + * + * @return The number of bytes that can be read before blocking could occur + * + * @exception IOException If an error occurs + */ + public int available() throws IOException + { + // We can only guarantee half the characters that might be available + // without blocking because "\r\n" is treated as a single character. + return in.available() / 2; + } + + /** + * This method returns the current line number + * + * @return The current line number + */ + public int getLineNumber() + { + return lineNumber; + } + + /** + * This method marks a position in the input to which the stream can + * be "reset" byte calling the reset() method. The + * parameter readlimit is the number of bytes that can + * be read from the stream after setting the mark before the mark + * becomes invalid. For example, if mark() is called + * with a read limit of 10, then when 11 bytes of data are read from + * the stream before the reset() method is called, then + * the mark is invalid and the stream object instance is not + * required to remember the mark. + *

    + * In this class, this method will remember the current line number + * as well as the current position in the stream. When the + * reset() method is called, the line number will be + * restored to the saved line number in addition to the stream + * position. + *

    + * This method only works if the subordinate stream supports mark/reset + * functionality. + * + * @param readlimit The number of bytes that can be read before the + * mark becomes invalid + */ + public void mark(int readlimit) + { + in.mark(readlimit); + markLineNumber = lineNumber; + } + + /** + * This method reads an unsigned byte from the input stream and returns it + * as an int in the range of 0-255. This method will return -1 if the + * end of the stream has been reached. + *

    + * Note that if a line termination sequence is encountered (ie, "\r", + * "\n", or "\r\n") then that line termination sequence is converted to + * a single "\n" value which is returned from this method. This means + * that it is possible this method reads two bytes from the subordinate + * stream instead of just one. + *

    + * Note that this method will block until a byte of data is available + * to be read. + * + * @return The byte read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + // Treat "\r\n" as a single character. A '\r' may have been read by + // a previous call to read so we keep an internal flag to avoid having + // to read ahead. + + int ch = in.read(); + + if (ch == '\n') + if (justReadReturnChar) + { + ch = in.read(); + justReadReturnChar = false; + } + else + lineNumber++; + else if (ch == '\r') + { + ch = '\n'; + justReadReturnChar = true; + lineNumber++; + } + else + justReadReturnChar = false; + + return ch; + } + + /** + * This method reads bytes from a stream and stores them into a caller + * supplied buffer. It starts storing data at index offset into + * the buffer and attemps to read len bytes. This method can + * return before reading the number of bytes requested. The actual number + * of bytes read is returned as an int. A -1 is returned to indicated the + * end of the stream. + *

    + * This method will block until some data can be read. + *

    + * Note that if a line termination sequence is encountered (ie, "\r", + * "\n", or "\r\n") then that line termination sequence is converted to + * a single "\n" value which is stored in the buffer. Only a single + * byte is counted towards the number of bytes read in this case. + * + * @param b The array into which the bytes read should be stored + * @param off The offset into the array to start storing bytes + * @param len The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of stream + * + * @exception IOException If an error occurs. + */ + public int read(byte[] b, int off, int len) throws IOException + { + if (off < 0 || len < 0 || off + len > b.length) + throw new ArrayIndexOutOfBoundsException(); + + // This case always succeeds. + if (len == 0) + return 0; + + // The simplest, though not necessarily the most time efficient thing + // to do is simply call read(void) len times. Since this is a deprecated + // class, that should be ok. + final int origOff = off; + while (len-- > 0) + { + int ch = read(); + if (ch < 0) + break; + + b[off++] = (byte) ch; + } + + // This is safe since we already know that some bytes were + // actually requested. + return off == origOff ? -1 : off - origOff; + } + + /** + * This method resets a stream to the point where the + * mark() method was called. Any bytes that were read + * after the mark point was set will be re-read during subsequent + * reads. + *

    + * In this class, this method will also restore the line number that was + * current when the mark() method was called. + *

    + * This method only works if the subordinate stream supports mark/reset + * functionality. + * + * @exception IOException If an error occurs + */ + public void reset() throws IOException + { + in.reset(); + lineNumber = markLineNumber; + justReadReturnChar = false; + } + + /** + * This method sets the current line number to the specified value. + * + * @param lineNumber The new line number + */ + public void setLineNumber(int lineNumber) + { + this.lineNumber = lineNumber; + } + + /** + * This method skips up to the requested number of bytes in the + * input stream. The actual number of bytes skipped is returned. If the + * desired number of bytes to skip is negative, no bytes are skipped. + * + * @param n requested number of bytes to skip. + * + * @return The actual number of bytes skipped. + * + * @exception IOException If an error occurs. + */ + public long skip(long n) throws IOException + { + if (n <= 0) + return 0L; + + final long origN = n; + + do + { + int ch = read(); + if (ch < 0) + break; + if (ch == '\n' || ch == '\r') + lineNumber++; + } + while (--n > 0); + + return origN - n; + } +} diff --git a/libjava/classpath/java/io/LineNumberReader.java b/libjava/classpath/java/io/LineNumberReader.java new file mode 100644 index 0000000..ea418a5 --- /dev/null +++ b/libjava/classpath/java/io/LineNumberReader.java @@ -0,0 +1,417 @@ +/* LineNumberReader.java -- A character input stream which counts line numbers + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +/** + * This class functions like a standard Reader except that it + * counts line numbers, and canonicalizes newline characters. As data + * is read, whenever the char sequences "\r", "\n", or "\r\n" are encountered, + * the running line count is incremeted by one. Additionally, the whatever + * line termination sequence was encountered will be converted to a "\n" + * char. Note that this class numbers lines from 0. When the first + * line terminator is encountered, the line number is incremented to 1, and + * so on. Also note that actual "\r" and "\n" characters are looked for. + * The system dependent line separator sequence is ignored. + *

    + * This class counts only line termination characters. If the last line + * read from the stream does not end in a line termination sequence, it + * will not be counted as a line. + * + * @author Per Bothner (bothner@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Guilhem Lavaux (guilhem@kaffe.org) + * @date December 28, 2003. + */ +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + * + * This implementation has the feature that if '\r' is read, it + * does not look for a '\n', but immediately returns '\n'. + * On the next read(), if a '\n' is read, it is skipped. + * This has the advantage that we do not read (and hang) unnecessarily. + * + * This implementation is also minimal in the number of fields it uses. + */ +public class LineNumberReader extends BufferedReader +{ + /** The current line number. */ + private int lineNumber; + /** Whether we already found a new line in the former call. */ + private boolean matchedNewLine; + /** The saved line number when calling mark() */ + private int savedLineNumber; + + /** + * Create a new LineNumberReader that reads from the + * specified subordinate Reader. A default 8K char sized + * buffer will be used for reads. + * + * @param in The subordinate Reader to read from + */ + public LineNumberReader(Reader in) + { + super(in, DEFAULT_BUFFER_SIZE); + } + + /** + * This method initializes a new LineNumberReader to read + * from the specified subordinate Reader using the specified + * read buffer size. + * + * @param in The subordinate Reader to read from + * @param size The buffer size to use for reading + */ + public LineNumberReader(Reader in, int size) + { + super(in, size); + } + + /** + * This method returns the current line number + * + * @return The current line number + */ + public int getLineNumber() + { + return lineNumber; + } + + /** + * This method sets the current line number to the specified value. + * + * @param line_number The new line number + */ + public void setLineNumber(int lineNumber) + { + this.lineNumber = lineNumber; + } + + /** + * This method marks a position in the input to which the stream can be + * "reset" char calling the reset() method. The parameter + * readlimit is the number of chars that can be read from the + * stream after setting the mark before the mark becomes invalid. For + * example, if mark() is called with a read limit of 10, + * then when + * 11 chars of data are read from the stream before the reset() + * method is called, then the mark is invalid and the stream object + * instance is not required to remember the mark. + *

    + * In this class, this method will remember the current line number as well + * as the current position in the stream. When the reset() + * method + * is called, the line number will be restored to the saved line number in + * addition to the stream position. + * + * @param readlimit The number of chars that can be read before the + * mark becomes invalid + * + * @exception IOException If an error occurs + */ + public void mark(int readLimit) throws IOException + { + if (readLimit < 0) + throw new IllegalArgumentException("Read-ahead limit is negative"); + + synchronized (lock) + { + // This is basically the same as BufferedReader.mark. + // However, if the previous character was a '\r', we need to + // save that 'r', in case the next character is a '\n'. + if (pos + readLimit > limit) + { + int saveCR = matchedNewLine ? 1 : 0; + char[] old_buffer = buffer; + if (readLimit > limit) + buffer = new char[saveCR + readLimit]; + int copy_start = pos - saveCR; + savedLineNumber = lineNumber; + limit -= copy_start; + System.arraycopy(old_buffer, copy_start, buffer, 0, limit); + pos = saveCR; + } + markPos = pos; + } + } + + /** + * This method resets a stream to the point where the mark() + * method + * was called. Any chars that were read after the mark point was set will + * be re-read during subsequent reads. + *

    + * In this class, this method will also restore the line number that was + * current when the mark() method was called. + * + * @exception IOException If an error occurs + */ + public void reset() throws IOException + { + synchronized (lock) + { + if (markPos < 0) + throw new IOException("mark never set or invalidated"); + lineNumber = savedLineNumber; + pos = markPos; + matchedNewLine = (markPos > 0 && buffer[markPos-1] == '\r'); + } + } + + /** + * This private method fills the input buffer whatever pos is. + * Consequently pos should be checked before calling this method. + * + * @return the number of bytes actually read from the input stream or + * -1 if end of stream. + * @exception IOException If an error occurs. + */ + private int fill() throws IOException + { + if (markPos >= 0 && limit == buffer.length) + markPos = -1; + if (markPos < 0) + pos = limit = 0; + int count = in.read(buffer, limit, buffer.length - limit); + if (count <= 0) + return -1; + limit += count; + + return count; + } + + /** + * This method reads an unsigned char from the input stream and returns it + * as an int in the range of 0-65535. This method will return -1 if the + * end of the stream has been reached. + *

    + * Note that if a line termination sequence is encountered (ie, "\r", + * "\n", or "\r\n") then that line termination sequence is converted to + * a single "\n" value which is returned from this method. This means + * that it is possible this method reads two chars from the subordinate + * stream instead of just one. + *

    + * Note that this method will block until a char of data is available + * to be read. + * + * @return The char read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + synchronized (lock) + { + skipRedundantLF(); + if (pos >= limit && fill() < 0) + return -1; + char ch = buffer[pos++]; + + if ((matchedNewLine = (ch == '\r')) || ch == '\n') + { + lineNumber++; + return '\n'; + } + matchedNewLine = false; + return (int) ch; + } + } + + /** + * This method reads chars from a stream and stores them into a caller + * supplied buffer. It starts storing data at index offset into + * the buffer and attemps to read len chars. This method can + * return before reading the number of chars requested. The actual number + * of chars read is returned as an int. A -1 is returned to indicated the + * end of the stream. + *

    + * This method will block until some data can be read. + *

    + * Note that if a line termination sequence is encountered (ie, "\r", + * "\n", or "\r\n") then that line termination sequence is converted to + * a single "\n" value which is stored in the buffer. Only a single + * char is counted towards the number of chars read in this case. + * + * @param buf The array into which the chars read should be stored + * @param offset The offset into the array to start storing chars + * @param len The requested number of chars to read + * + * @return The actual number of chars read, or -1 if end of stream + * + * @exception IOException If an error occurs. + * @exception NullPointerException If buf is null (in any case). + * @exception IndexOutOfBoundsException If buffer parameters (offset and + * count) lies outside of the buffer capacity. + */ + public int read(char[] buf, int offset, int count) throws IOException + { + if (buf == null) + throw new NullPointerException(); + + if (offset + count > buf.length || offset < 0) + throw new IndexOutOfBoundsException(); + + if (count <= 0) + { + if (count < 0) + throw new IndexOutOfBoundsException(); + return 0; + } + + synchronized (lock) + { + if (pos >= limit && fill() < 0) + return -1; + + int start_offset = offset; + boolean matched = matchedNewLine; + + while (count-- > 0 && pos < limit) + { + char ch = buffer[pos++]; + if (ch == '\r') + { + lineNumber++; + matched = true; + } + else if (ch == '\n' && !matched) + lineNumber++; + else + matched = false; + + buf[offset++] = ch; + } + + matchedNewLine = matched; + return offset - start_offset; + } + } + + private void skipRedundantLF() throws IOException + { + if (pos > 0 && matchedNewLine) + { + if (pos < limit) + { // fast case + if (buffer[pos] == '\n') + pos++; + } + else + { // check whether the next buffer begins with '\n'. + // in that case kill the '\n'. + if (fill() <= 0) + return; + if (buffer[pos] == '\n') + pos++; + } + matchedNewLine = true; + } + } + + /** + * This method reads a line of text from the input stream and returns + * it as a String. A line is considered to be terminated + * by a "\r", "\n", or "\r\n" sequence, not by the system dependent line + * separator. + * + * @return The line read as a String or null + * if end of stream. + * + * @exception IOException If an error occurs + */ + public String readLine() throws IOException + { + // BufferedReader.readLine already does this. Shouldn't need to keep + // track of newlines (since the read method deals with this for us). + // But if the buffer is large, we may not call the read method at all + // and super.readLine can't increment lineNumber itself. + // Though it may seem kludgy, the safest thing to do is to save off + // lineNumber and increment it explicitly when we're done (iff we + // ended with a '\n' or '\r' as opposed to EOF). + // + // Also, we need to undo the special casing done by BufferedReader.readLine + // when a '\r' is the last char in the buffer. That situation is marked + // by 'pos > limit'. + int tmpLineNumber = lineNumber; + skipRedundantLF(); + String str = super.readLine(); + if (pos > limit) + --pos; + + // The only case where you mustn't increment the line number is you are + // at the EOS. + if (str != null) + lineNumber = tmpLineNumber + 1; + + return str; + } + + /** + * This method skips over characters in the stream. This method will + * skip the specified number of characters if possible, but is not required + * to skip them all. The actual number of characters skipped is returned. + * This method returns 0 if the specified number of chars is less than 1. + * + * @param count The specified number of chars to skip. + * + * @return The actual number of chars skipped. + * + * @exception IOException If an error occurs + */ + public long skip (long count) throws IOException + { + if (count < 0) + throw new IllegalArgumentException("skip() value is negative"); + if (count == 0) + return 0; + + int skipped; + char[] buf = new char[1]; + + for (skipped = 0; skipped < count; skipped++) + { + int ch = read(buf, 0, 1); + + if (ch < 0) + break; + } + + return skipped; + } +} + diff --git a/libjava/classpath/java/io/NotActiveException.java b/libjava/classpath/java/io/NotActiveException.java new file mode 100644 index 0000000..949ba8e --- /dev/null +++ b/libjava/classpath/java/io/NotActiveException.java @@ -0,0 +1,72 @@ +/* NotActiveException.java -- thrown when serialization is not active + 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 java.io; + +/** + * This exception is thrown when a problem occurs due to the fact that + * serialization is not active. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class NotActiveException extends ObjectStreamException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -3893467273049808895L; + + /** + * Create an exception without a descriptive error message. + */ + public NotActiveException() + { + } + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + public NotActiveException(String message) + { + super(message); + } +} // class NotActiveException diff --git a/libjava/classpath/java/io/NotSerializableException.java b/libjava/classpath/java/io/NotSerializableException.java new file mode 100644 index 0000000..d49c939 --- /dev/null +++ b/libjava/classpath/java/io/NotSerializableException.java @@ -0,0 +1,74 @@ +/* NotSerializableException.java -- a Serializable class that isn't + 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 java.io; + +/** + * This exception is thrown when a class implements Serializable because + * of a superclass, but should not be serialized. The descriptive message + * will consist of the name of the class in question. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class NotSerializableException extends ObjectStreamException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 2906642554793891381L; + + /** + * Create an exception without a descriptive error message. + */ + public NotSerializableException() + { + } + + /** + * Create an exception with a descriptive error message, which should + * be the name of the class. + * + * @param message the descriptive error message + */ + public NotSerializableException(String message) + { + super(message); + } +} // class NotSerializableException diff --git a/libjava/classpath/java/io/ObjectInput.java b/libjava/classpath/java/io/ObjectInput.java new file mode 100644 index 0000000..175b60f --- /dev/null +++ b/libjava/classpath/java/io/ObjectInput.java @@ -0,0 +1,140 @@ +/* ObjectInput.java -- Read object data from a stream + 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 java.io; + +/** + * This interface extends the DataInput interface to provide a + * facility to read objects as well as primitive types from a stream. It + * also has methods that allow input to be done in a manner similar to + * InputStream + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * + * @see DataInput + */ +public interface ObjectInput extends DataInput +{ + /** + * This method returns the number of bytes that can be read without + * blocking. + * + * @return The number of bytes available before blocking + * + * @exception IOException If an error occurs + */ + int available() throws IOException; + + /** + * This method reading a byte of data from a stream. It returns that byte + * as an int. This method blocks if no data is available + * to be read. + * + * @return The byte of data read + * + * @exception IOException If an error occurs + */ + int read() throws IOException; + + /** + * This method reads raw bytes and stores them them a byte array buffer. + * Note that this method will block if no data is available. However, + * it will not necessarily block until it fills the entire buffer. That is, + * a "short count" is possible. + * + * @param buf The byte array to receive the data read + * + * @return The actual number of bytes read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + int read(byte[] buf) throws IOException; + + /** + * This method reads raw bytes and stores them in a byte array buffer + * buf starting at position offset into the + * buffer. A + * maximum of len bytes will be read. Note that this method + * blocks if no data is available, but will not necessarily block until + * it can read len bytes of data. That is, a "short count" is + * possible. + * + * @param buf The byte array to receive the data read + * @param offset The offset into buf to start storing data + * @param len The maximum number of bytes to read + * + * @return The actual number of bytes read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + int read(byte[] buf, int offset, int len) throws IOException; + + /** + * Reads an object instance and returns it. If the class for the object + * being read cannot be found, then a ClassNotFoundException + * will be thrown. + * + * @return The object instance that was read + * + * @exception ClassNotFoundException If a class for the object cannot be + * found + * @exception IOException If any other error occurs + */ + Object readObject() + throws ClassNotFoundException, IOException; + + /** + * This method causes the specified number of bytes to be read and + * discarded. It is possible that fewer than the requested number of bytes + * will actually be skipped. + * + * @param numBytes The number of bytes to skip + * + * @return The actual number of bytes skipped + * + * @exception IOException If an error occurs + */ + long skip(long numBytes) throws IOException; + + /** + * This method closes the input source + * + * @exception IOException If an error occurs + */ + void close() throws IOException; +} diff --git a/libjava/classpath/java/io/ObjectInputStream.java b/libjava/classpath/java/io/ObjectInputStream.java new file mode 100644 index 0000000..05776a7 --- /dev/null +++ b/libjava/classpath/java/io/ObjectInputStream.java @@ -0,0 +1,1956 @@ +/* ObjectInputStream.java -- Class used to read serialized objects + Copyright (C) 1998, 1999, 2000, 2001, 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 java.io; + +import gnu.classpath.Configuration; +import gnu.java.io.ObjectIdentityWrapper; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.Vector; + +public class ObjectInputStream extends InputStream + implements ObjectInput, ObjectStreamConstants +{ + /** + * Creates a new ObjectInputStream that will do all of + * its reading from in. This method also checks + * the stream by reading the header information (stream magic number + * and stream version). + * + * @exception IOException Reading stream header from underlying + * stream cannot be completed. + * + * @exception StreamCorruptedException An invalid stream magic + * number or stream version was read from the stream. + * + * @see #readStreamHeader() + */ + public ObjectInputStream(InputStream in) + throws IOException, StreamCorruptedException + { + if (DEBUG) + { + String val = System.getProperty("gcj.dumpobjects"); + if (dump == false && val != null && !val.equals("")) + { + dump = true; + System.out.println ("Serialization debugging enabled"); + } + else if (dump == true && (val == null || val.equals(""))) + { + dump = false; + System.out.println ("Serialization debugging disabled"); + } + } + + this.resolveEnabled = false; + this.isDeserializing = false; + this.blockDataPosition = 0; + this.blockDataBytes = 0; + this.blockData = new byte[BUFFER_SIZE]; + this.blockDataInput = new DataInputStream(this); + this.realInputStream = new DataInputStream(in); + this.nextOID = baseWireHandle; + this.objectLookupTable = new Hashtable(); + this.validators = new Vector(); + this.classLookupTable = new Hashtable(); + setBlockDataMode(true); + readStreamHeader(); + } + + + /** + * Returns the next deserialized object read from the underlying stream. + * + * This method can be overriden by a class by implementing + * private void readObject (ObjectInputStream). + * + * If an exception is thrown from this method, the stream is left in + * an undefined state. + * + * @exception ClassNotFoundException The class that an object being + * read in belongs to cannot be found. + * + * @exception IOException Exception from underlying + * InputStream. + */ + public final Object readObject() throws ClassNotFoundException, IOException + { + if (this.useSubclassMethod) + return readObjectOverride(); + + boolean was_deserializing; + + Object ret_val; + was_deserializing = this.isDeserializing; + + boolean is_consumed = false; + boolean old_mode = setBlockDataMode(false); + + this.isDeserializing = true; + + byte marker = this.realInputStream.readByte(); + + depth += 2; + + if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " "); + + try + { + switch (marker) + { + case TC_ENDBLOCKDATA: + { + ret_val = null; + is_consumed = true; + break; + } + + case TC_BLOCKDATA: + case TC_BLOCKDATALONG: + { + if (marker == TC_BLOCKDATALONG) + { if(dump) dumpElementln("BLOCKDATALONG"); } + else + { if(dump) dumpElementln("BLOCKDATA"); } + readNextBlock(marker); + throw new StreamCorruptedException("Unexpected blockData"); + } + + case TC_NULL: + { + if(dump) dumpElementln("NULL"); + ret_val = null; + break; + } + + case TC_REFERENCE: + { + if(dump) dumpElement("REFERENCE "); + Integer oid = new Integer(this.realInputStream.readInt()); + if(dump) dumpElementln(Integer.toHexString(oid.intValue())); + ret_val = ((ObjectIdentityWrapper) + this.objectLookupTable.get(oid)).object; + break; + } + + case TC_CLASS: + { + if(dump) dumpElementln("CLASS"); + ObjectStreamClass osc = (ObjectStreamClass)readObject(); + Class clazz = osc.forClass(); + assignNewHandle(clazz); + ret_val = clazz; + break; + } + + case TC_PROXYCLASSDESC: + { + if(dump) dumpElementln("PROXYCLASS"); + int n_intf = this.realInputStream.readInt(); + String[] intfs = new String[n_intf]; + for (int i = 0; i < n_intf; i++) + { + intfs[i] = this.realInputStream.readUTF(); + System.out.println(intfs[i]); + } + + boolean oldmode = setBlockDataMode(true); + Class cl = resolveProxyClass(intfs); + setBlockDataMode(oldmode); + + ObjectStreamClass osc = lookupClass(cl); + assignNewHandle(osc); + + if (!is_consumed) + { + byte b = this.realInputStream.readByte(); + if (b != TC_ENDBLOCKDATA) + throw new IOException("Data annotated to class was not consumed." + b); + } + else + is_consumed = false; + ObjectStreamClass superosc = (ObjectStreamClass)readObject(); + osc.setSuperclass(superosc); + ret_val = osc; + break; + } + + case TC_CLASSDESC: + { + ObjectStreamClass osc = readClassDescriptor(); + + if (!is_consumed) + { + byte b = this.realInputStream.readByte(); + if (b != TC_ENDBLOCKDATA) + throw new IOException("Data annotated to class was not consumed." + b); + } + else + is_consumed = false; + + osc.setSuperclass ((ObjectStreamClass)readObject()); + ret_val = osc; + break; + } + + case TC_STRING: + case TC_LONGSTRING: + { + if(dump) dumpElement("STRING="); + String s = this.realInputStream.readUTF(); + if(dump) dumpElementln(s); + ret_val = processResolution(null, s, assignNewHandle(s)); + break; + } + + case TC_ARRAY: + { + if(dump) dumpElementln("ARRAY"); + ObjectStreamClass osc = (ObjectStreamClass)readObject(); + Class componentType = osc.forClass().getComponentType(); + if(dump) dumpElement("ARRAY LENGTH="); + int length = this.realInputStream.readInt(); + if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType); + Object array = Array.newInstance(componentType, length); + int handle = assignNewHandle(array); + readArrayElements(array, componentType); + if(dump) + for (int i = 0, len = Array.getLength(array); i < len; i++) + dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); + ret_val = processResolution(null, array, handle); + break; + } + + case TC_OBJECT: + { + if(dump) dumpElementln("OBJECT"); + ObjectStreamClass osc = (ObjectStreamClass)readObject(); + Class clazz = osc.forClass(); + + if (!osc.realClassIsSerializable) + throw new NotSerializableException + (clazz + " is not Serializable, and thus cannot be deserialized."); + + if (osc.realClassIsExternalizable) + { + Externalizable obj = osc.newInstance(); + + int handle = assignNewHandle(obj); + + boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0); + + boolean oldmode = this.readDataFromBlock; + if (read_from_blocks) + setBlockDataMode(true); + + obj.readExternal(this); + + if (read_from_blocks) + { + setBlockDataMode(oldmode); + if (!oldmode) + if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) + throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method."); + } + + ret_val = processResolution(osc, obj, handle); + break; + } // end if (osc.realClassIsExternalizable) + + Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor); + + int handle = assignNewHandle(obj); + Object prevObject = this.currentObject; + ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass; + + this.currentObject = obj; + ObjectStreamClass[] hierarchy = + inputGetObjectStreamClasses(clazz); + + for (int i = 0; i < hierarchy.length; i++) + { + this.currentObjectStreamClass = hierarchy[i]; + + if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ()); + + // XXX: should initialize fields in classes in the hierarchy + // that aren't in the stream + // should skip over classes in the stream that aren't in the + // real classes hierarchy + + Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod; + if (readObjectMethod != null) + { + fieldsAlreadyRead = false; + boolean oldmode = setBlockDataMode(true); + callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj); + setBlockDataMode(oldmode); + } + else + { + readFields(obj, currentObjectStreamClass); + } + + if (this.currentObjectStreamClass.hasWriteMethod()) + { + if(dump) dumpElement("ENDBLOCKDATA? "); + try + { + // FIXME: XXX: This try block is to + // catch EOF which is thrown for some + // objects. That indicates a bug in + // the logic. + + if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) + throw new IOException + ("No end of block data seen for class with readObject (ObjectInputStream) method."); + if(dump) dumpElementln("yes"); + } +// catch (EOFException e) +// { +// if(dump) dumpElementln("no, got EOFException"); +// } + catch (IOException e) + { + if(dump) dumpElementln("no, got IOException"); + } + } + } + + this.currentObject = prevObject; + this.currentObjectStreamClass = prevObjectStreamClass; + ret_val = processResolution(osc, obj, handle); + + break; + } + + case TC_RESET: + if(dump) dumpElementln("RESET"); + clearHandles(); + ret_val = readObject(); + break; + + case TC_EXCEPTION: + { + if(dump) dumpElement("EXCEPTION="); + Exception e = (Exception)readObject(); + if(dump) dumpElementln(e.toString()); + clearHandles(); + throw new WriteAbortedException("Exception thrown during writing of stream", e); + } + + default: + throw new IOException("Unknown marker on stream: " + marker); + } + } + finally + { + setBlockDataMode(old_mode); + + this.isDeserializing = was_deserializing; + + depth -= 2; + + if (! was_deserializing) + { + if (validators.size() > 0) + invokeValidators(); + } + } + + return ret_val; + } + + /** + * This method makes a partial check of types for the fields + * contained given in arguments. It checks primitive types of + * fields1 against non primitive types of fields2. This method + * assumes the two lists has already been sorted according to + * the Java specification. + * + * @param name Name of the class owning the given fields. + * @param fields1 First list to check. + * @param fields2 Second list to check. + * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present + * in the non primitive part in fields2. + */ + private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2) + throws InvalidClassException + { + int nonPrimitive = 0; + + for (nonPrimitive = 0; + nonPrimitive < fields1.length + && fields1[nonPrimitive].isPrimitive(); nonPrimitive++) + { + } + + if (nonPrimitive == fields1.length) + return; + + int i = 0; + ObjectStreamField f1; + ObjectStreamField f2; + + while (i < fields2.length + && nonPrimitive < fields1.length) + { + f1 = fields1[nonPrimitive]; + f2 = fields2[i]; + + if (!f2.isPrimitive()) + break; + + int compVal = f1.getName().compareTo (f2.getName()); + + if (compVal < 0) + { + nonPrimitive++; + } + else if (compVal > 0) + { + i++; + } + else + { + throw new InvalidClassException + ("invalid field type for " + f2.getName() + + " in class " + name); + } + } + } + + /** + * This method reads a class descriptor from the real input stream + * and use these data to create a new instance of ObjectStreamClass. + * Fields are sorted and ordered for the real read which occurs for + * each instance of the described class. Be aware that if you call that + * method you must ensure that the stream is synchronized, in the other + * case it may be completely desynchronized. + * + * @return A new instance of ObjectStreamClass containing the freshly + * created descriptor. + * @throws ClassNotFoundException if the required class to build the + * descriptor has not been found in the system. + * @throws IOException An input/output error occured. + * @throws InvalidClassException If there was a compatibility problem + * between the class present in the system and the serialized class. + */ + protected ObjectStreamClass readClassDescriptor() + throws ClassNotFoundException, IOException + { + if(dump) dumpElement("CLASSDESC NAME="); + String name = this.realInputStream.readUTF(); + if(dump) dumpElement(name + "; UID="); + long uid = this.realInputStream.readLong (); + if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS="); + byte flags = this.realInputStream.readByte (); + if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT="); + short field_count = this.realInputStream.readShort(); + if(dump) dumpElementln(Short.toString(field_count)); + ObjectStreamField[] fields = new ObjectStreamField[field_count]; + ObjectStreamClass osc = new ObjectStreamClass(name, uid, + flags, fields); + assignNewHandle(osc); + + if (callersClassLoader == null) + callersClassLoader = currentLoader(); + + for (int i = 0; i < field_count; i++) + { + if(dump) dumpElement(" TYPE CODE="); + char type_code = (char)this.realInputStream.readByte(); + if(dump) dumpElement(type_code + "; FIELD NAME="); + String field_name = this.realInputStream.readUTF(); + if(dump) dumpElementln(field_name); + String class_name; + + // If the type code is an array or an object we must + // decode a String here. In the other case we convert + // the type code and pass it to ObjectStreamField. + // Type codes are decoded by gnu.java.lang.reflect.TypeSignature. + if (type_code == 'L' || type_code == '[') + class_name = (String)readObject(); + else + class_name = String.valueOf(type_code); + + fields[i] = + new ObjectStreamField(field_name, class_name, callersClassLoader); + } + + /* Now that fields have been read we may resolve the class + * (and read annotation if needed). */ + Class clazz; + try + { + clazz = resolveClass(osc); + } + catch (ClassNotFoundException cnfe) + { + // Maybe it was an primitive class? + if (name.equals("void")) + clazz = Void.TYPE; + else if (name.equals("boolean")) + clazz = Boolean.TYPE; + else if (name.equals("byte")) + clazz = Byte.TYPE; + else if (name.equals("short")) + clazz = Short.TYPE; + else if (name.equals("char")) + clazz = Character.TYPE; + else if (name.equals("int")) + clazz = Integer.TYPE; + else if (name.equals("long")) + clazz = Long.TYPE; + else if (name.equals("float")) + clazz = Float.TYPE; + else if (name.equals("double")) + clazz = Double.TYPE; + else + throw cnfe; + } + + boolean oldmode = setBlockDataMode(true); + osc.setClass(clazz, lookupClass(clazz.getSuperclass())); + classLookupTable.put(clazz, osc); + setBlockDataMode(oldmode); + + // find the first non-serializable, non-abstract + // class in clazz's inheritance hierarchy + Class first_nonserial = clazz.getSuperclass(); + // Maybe it is a primitive class, those don't have a super class, + // or Object itself. Otherwise we can keep getting the superclass + // till we hit the Object class, or some other non-serializable class. + + if (first_nonserial == null) + first_nonserial = clazz; + else + while (Serializable.class.isAssignableFrom(first_nonserial) + || Modifier.isAbstract(first_nonserial.getModifiers())) + first_nonserial = first_nonserial.getSuperclass(); + + final Class local_constructor_class = first_nonserial; + + osc.firstNonSerializableParentConstructor = + (Constructor)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + try + { + Constructor c = local_constructor_class. + getDeclaredConstructor(new Class[0]); + if (Modifier.isPrivate(c.getModifiers())) + return null; + return c; + } + catch (NoSuchMethodException e) + { + // error will be reported later, in newObject() + return null; + } + } + }); + + osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz); + osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz); + + ObjectStreamField[] stream_fields = osc.fields; + ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields; + ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)]; + + int stream_idx = 0; + int real_idx = 0; + int map_idx = 0; + + /* + * Check that there is no type inconsistencies between the lists. + * A special checking must be done for the two groups: primitive types and + * not primitive types. + */ + checkTypeConsistency(name, real_fields, stream_fields); + checkTypeConsistency(name, stream_fields, real_fields); + + + while (stream_idx < stream_fields.length + || real_idx < real_fields.length) + { + ObjectStreamField stream_field = null; + ObjectStreamField real_field = null; + + if (stream_idx == stream_fields.length) + { + real_field = real_fields[real_idx++]; + } + else if (real_idx == real_fields.length) + { + stream_field = stream_fields[stream_idx++]; + } + else + { + int comp_val = + real_fields[real_idx].compareTo (stream_fields[stream_idx]); + + if (comp_val < 0) + { + real_field = real_fields[real_idx++]; + } + else if (comp_val > 0) + { + stream_field = stream_fields[stream_idx++]; + } + else + { + stream_field = stream_fields[stream_idx++]; + real_field = real_fields[real_idx++]; + if (stream_field.getType() != real_field.getType()) + throw new InvalidClassException + ("invalid field type for " + real_field.getName() + + " in class " + name); + } + } + + /* If some of stream_fields does not correspond to any of real_fields, + * or the opposite, then fieldmapping will go short. + */ + if (map_idx == fieldmapping.length) + { + ObjectStreamField[] newfieldmapping = + new ObjectStreamField[fieldmapping.length + 2]; + System.arraycopy(fieldmapping, 0, + newfieldmapping, 0, fieldmapping.length); + fieldmapping = newfieldmapping; + } + fieldmapping[map_idx++] = stream_field; + fieldmapping[map_idx++] = real_field; + } + osc.fieldMapping = fieldmapping; + + return osc; + } + + /** + * Reads the current objects non-transient, non-static fields from + * the current class from the underlying output stream. + * + * This method is intended to be called from within a object's + * private void readObject (ObjectInputStream) + * method. + * + * @exception ClassNotFoundException The class that an object being + * read in belongs to cannot be found. + * + * @exception NotActiveException This method was called from a + * context other than from the current object's and current class's + * private void readObject (ObjectInputStream) + * method. + * + * @exception IOException Exception from underlying + * OutputStream. + */ + public void defaultReadObject() + throws ClassNotFoundException, IOException, NotActiveException + { + if (this.currentObject == null || this.currentObjectStreamClass == null) + throw new NotActiveException("defaultReadObject called by non-active" + + " class and/or object"); + + if (fieldsAlreadyRead) + throw new NotActiveException("defaultReadObject called but fields " + + "already read from stream (by " + + "defaultReadObject or readFields)"); + + boolean oldmode = setBlockDataMode(false); + readFields(this.currentObject, this.currentObjectStreamClass); + setBlockDataMode(oldmode); + + fieldsAlreadyRead = true; + } + + + /** + * Registers a ObjectInputValidation to be carried out + * on the object graph currently being deserialized before it is + * returned to the original caller of readObject (). + * The order of validation for multiple + * ObjectInputValidations can be controled using + * priority. Validators with higher priorities are + * called first. + * + * @see java.io.ObjectInputValidation + * + * @exception InvalidObjectException validator is + * null + * + * @exception NotActiveException an attempt was made to add a + * validator outside of the readObject method of the + * object currently being deserialized + */ + public void registerValidation(ObjectInputValidation validator, + int priority) + throws InvalidObjectException, NotActiveException + { + if (this.currentObject == null || this.currentObjectStreamClass == null) + throw new NotActiveException("registerValidation called by non-active " + + "class and/or object"); + + if (validator == null) + throw new InvalidObjectException("attempt to add a null " + + "ObjectInputValidation object"); + + this.validators.addElement(new ValidatorAndPriority (validator, + priority)); + } + + + /** + * Called when a class is being deserialized. This is a hook to + * allow subclasses to read in information written by the + * annotateClass (Class) method of an + * ObjectOutputStream. + * + * This implementation looks up the active call stack for a + * ClassLoader; if a ClassLoader is found, + * it is used to load the class associated with osc, + * otherwise, the default system ClassLoader is used. + * + * @exception IOException Exception from underlying + * OutputStream. + * + * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class) + */ + protected Class resolveClass(ObjectStreamClass osc) + throws ClassNotFoundException, IOException + { + if (callersClassLoader == null) + { + callersClassLoader = currentLoader (); + if (DEBUG && dump) + { + dumpElementln ("CallersClassLoader = " + callersClassLoader); + } + } + + return Class.forName(osc.getName(), true, callersClassLoader); + } + + /** + * Returns the most recent user defined ClassLoader on the execution stack + * or null if none is found. + */ + private ClassLoader currentLoader() + { + return VMObjectInputStream.currentClassLoader(); + } + + /** + * Lookup a class stored in the local hashtable. If it is not + * use the global lookup function in ObjectStreamClass to build + * the ObjectStreamClass. This method is requested according to + * the behaviour detected in the JDK by Kaffe's team. + * + * @param clazz Class to lookup in the hash table or for which + * we must build a descriptor. + * @return A valid instance of ObjectStreamClass corresponding + * to the specified class. + */ + private ObjectStreamClass lookupClass(Class clazz) + { + if (clazz == null) + return null; + + ObjectStreamClass oclazz; + oclazz = (ObjectStreamClass)classLookupTable.get(clazz); + if (oclazz == null) + return ObjectStreamClass.lookup(clazz); + else + return oclazz; + } + + /** + * Reconstruct class hierarchy the same way + * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does + * but using lookupClass instead of ObjectStreamClass.lookup. This + * dup is necessary localize the lookup table. Hopefully some future + * rewritings will be able to prevent this. + * + * @param clazz This is the class for which we want the hierarchy. + * + * @return An array of valid {@link java.io.ObjectStreamClass} instances which + * represent the class hierarchy for clazz. + */ + private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz) + { + ObjectStreamClass osc = lookupClass(clazz); + + if (osc == null) + return new ObjectStreamClass[0]; + else + { + Vector oscs = new Vector(); + + while (osc != null) + { + oscs.addElement(osc); + osc = osc.getSuper(); + } + + int count = oscs.size(); + ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count]; + + for (int i = count - 1; i >= 0; i--) + sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i); + + return sorted_oscs; + } + } + + /** + * Allows subclasses to resolve objects that are read from the + * stream with other objects to be returned in their place. This + * method is called the first time each object is encountered. + * + * This method must be enabled before it will be called in the + * serialization process. + * + * @exception IOException Exception from underlying + * OutputStream. + * + * @see #enableResolveObject(boolean) + */ + protected Object resolveObject(Object obj) throws IOException + { + return obj; + } + + + protected Class resolveProxyClass(String[] intfs) + throws IOException, ClassNotFoundException + { + ClassLoader cl = currentLoader(); + + Class[] clss = new Class[intfs.length]; + if(cl == null) + { + for (int i = 0; i < intfs.length; i++) + clss[i] = Class.forName(intfs[i]); + cl = ClassLoader.getSystemClassLoader(); + } + else + for (int i = 0; i < intfs.length; i++) + clss[i] = cl.loadClass(intfs[i]); + try + { + return Proxy.getProxyClass(cl, clss); + } + catch (IllegalArgumentException e) + { + throw new ClassNotFoundException(null, e); + } + } + + /** + * If enable is true and this object is + * trusted, then resolveObject (Object) will be called + * in subsequent calls to readObject (Object). + * Otherwise, resolveObject (Object) will not be called. + * + * @exception SecurityException This class is not trusted. + */ + protected boolean enableResolveObject (boolean enable) + throws SecurityException + { + if (enable) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new SerializablePermission("enableSubstitution")); + } + + boolean old_val = this.resolveEnabled; + this.resolveEnabled = enable; + return old_val; + } + + /** + * Reads stream magic and stream version information from the + * underlying stream. + * + * @exception IOException Exception from underlying stream. + * + * @exception StreamCorruptedException An invalid stream magic + * number or stream version was read from the stream. + */ + protected void readStreamHeader() + throws IOException, StreamCorruptedException + { + if(dump) dumpElement("STREAM MAGIC "); + if (this.realInputStream.readShort() != STREAM_MAGIC) + throw new StreamCorruptedException("Invalid stream magic number"); + + if(dump) dumpElementln("STREAM VERSION "); + if (this.realInputStream.readShort() != STREAM_VERSION) + throw new StreamCorruptedException("Invalid stream version number"); + } + + public int read() throws IOException + { + if (this.readDataFromBlock) + { + if (this.blockDataPosition >= this.blockDataBytes) + readNextBlock(); + return (this.blockData[this.blockDataPosition++] & 0xff); + } + else + return this.realInputStream.read(); + } + + public int read(byte[] data, int offset, int length) throws IOException + { + if (this.readDataFromBlock) + { + if (this.blockDataPosition + length > this.blockDataBytes) + { + int remain = this.blockDataBytes - this.blockDataPosition; + if (remain != 0) + { + System.arraycopy(this.blockData, this.blockDataPosition, + data, offset, remain); + offset += remain; + length -= remain; + } + readNextBlock (); + } + + System.arraycopy(this.blockData, this.blockDataPosition, + data, offset, length); + this.blockDataPosition += length; + + return length; + } + else + return this.realInputStream.read(data, offset, length); + } + + public int available() throws IOException + { + if (this.readDataFromBlock) + { + if (this.blockDataPosition >= this.blockDataBytes) + readNextBlock (); + + return this.blockDataBytes - this.blockDataPosition; + } + else + return this.realInputStream.available(); + } + + public void close() throws IOException + { + this.realInputStream.close(); + } + + public boolean readBoolean() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode (true); + boolean value = this.dataInputStream.readBoolean (); + if (switchmode) + setBlockDataMode (oldmode); + return value; + } + + public byte readByte() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + byte value = this.dataInputStream.readByte(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public int readUnsignedByte() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + int value = this.dataInputStream.readUnsignedByte(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public short readShort() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + short value = this.dataInputStream.readShort(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public int readUnsignedShort() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + int value = this.dataInputStream.readUnsignedShort(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public char readChar() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + char value = this.dataInputStream.readChar(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public int readInt() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + int value = this.dataInputStream.readInt(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public long readLong() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + long value = this.dataInputStream.readLong(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public float readFloat() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + float value = this.dataInputStream.readFloat(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public double readDouble() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + double value = this.dataInputStream.readDouble(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public void readFully(byte data[]) throws IOException + { + this.dataInputStream.readFully(data); + } + + public void readFully(byte data[], int offset, int size) + throws IOException + { + this.dataInputStream.readFully(data, offset, size); + } + + public int skipBytes(int len) throws IOException + { + return this.dataInputStream.skipBytes(len); + } + + /** + * @deprecated + * @see java.io.DataInputStream#readLine () + */ + public String readLine() throws IOException + { + return this.dataInputStream.readLine(); + } + + public String readUTF() throws IOException + { + return this.dataInputStream.readUTF(); + } + + /** + * This class allows a class to specify exactly which fields should + * be read, and what values should be read for these fields. + * + * XXX: finish up comments + */ + public abstract static class GetField + { + public abstract ObjectStreamClass getObjectStreamClass(); + + public abstract boolean defaulted(String name) + throws IOException, IllegalArgumentException; + + public abstract boolean get(String name, boolean defvalue) + throws IOException, IllegalArgumentException; + + public abstract char get(String name, char defvalue) + throws IOException, IllegalArgumentException; + + public abstract byte get(String name, byte defvalue) + throws IOException, IllegalArgumentException; + + public abstract short get(String name, short defvalue) + throws IOException, IllegalArgumentException; + + public abstract int get(String name, int defvalue) + throws IOException, IllegalArgumentException; + + public abstract long get(String name, long defvalue) + throws IOException, IllegalArgumentException; + + public abstract float get(String name, float defvalue) + throws IOException, IllegalArgumentException; + + public abstract double get(String name, double defvalue) + throws IOException, IllegalArgumentException; + + public abstract Object get(String name, Object defvalue) + throws IOException, IllegalArgumentException; + } + + /** + * This method should be called by a method called 'readObject' in the + * deserializing class (if present). It cannot (and should not)be called + * outside of it. Its goal is to read all fields in the real input stream + * and keep them accessible through the {@link #GetField} class. Calling + * this method will not alter the deserializing object. + * + * @return A valid freshly created 'GetField' instance to get access to + * the deserialized stream. + * @throws IOException An input/output exception occured. + * @throws ClassNotFoundException + * @throws NotActiveException + */ + public GetField readFields() + throws IOException, ClassNotFoundException, NotActiveException + { + if (this.currentObject == null || this.currentObjectStreamClass == null) + throw new NotActiveException("readFields called by non-active class and/or object"); + + if (prereadFields != null) + return prereadFields; + + if (fieldsAlreadyRead) + throw new NotActiveException("readFields called but fields already read from" + + " stream (by defaultReadObject or readFields)"); + + final ObjectStreamClass clazz = this.currentObjectStreamClass; + final byte[] prim_field_data = new byte[clazz.primFieldSize]; + final Object[] objs = new Object[clazz.objectFieldCount]; + + // Apparently Block data is not used with GetField as per + // empirical evidence against JDK 1.2. Also see Mauve test + // java.io.ObjectInputOutput.Test.GetPutField. + boolean oldmode = setBlockDataMode(false); + readFully(prim_field_data); + for (int i = 0; i < objs.length; ++ i) + objs[i] = readObject(); + setBlockDataMode(oldmode); + + prereadFields = new GetField() + { + public ObjectStreamClass getObjectStreamClass() + { + return clazz; + } + + public boolean defaulted(String name) + throws IOException, IllegalArgumentException + { + ObjectStreamField f = clazz.getField(name); + + /* First if we have a serialized field use the descriptor */ + if (f != null) + { + /* It is in serialPersistentFields but setClass tells us + * it should not be set. This value is defaulted. + */ + if (f.isPersistent() && !f.isToSet()) + return true; + + return false; + } + + /* This is not a serialized field. There should be + * a default value only if the field really exists. + */ + try + { + return (clazz.forClass().getDeclaredField (name) != null); + } + catch (NoSuchFieldException e) + { + throw new IllegalArgumentException(e.getMessage()); + } + } + + public boolean get(String name, boolean defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Boolean.TYPE); + + if (field == null) + return defvalue; + + return prim_field_data[field.getOffset()] == 0 ? false : true; + } + + public char get(String name, char defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Character.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return (char)(((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF)); + } + + public byte get(String name, byte defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Byte.TYPE); + + if (field == null) + return defvalue; + + return prim_field_data[field.getOffset()]; + } + + public short get(String name, short defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Short.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return (short)(((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF)); + } + + public int get(String name, int defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Integer.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return ((prim_field_data[off++] & 0xFF) << 24) + | ((prim_field_data[off++] & 0xFF) << 16) + | ((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF); + } + + public long get(String name, long defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Long.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return (long)(((prim_field_data[off++] & 0xFFL) << 56) + | ((prim_field_data[off++] & 0xFFL) << 48) + | ((prim_field_data[off++] & 0xFFL) << 40) + | ((prim_field_data[off++] & 0xFFL) << 32) + | ((prim_field_data[off++] & 0xFF) << 24) + | ((prim_field_data[off++] & 0xFF) << 16) + | ((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF)); + } + + public float get(String name, float defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Float.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24) + | ((prim_field_data[off++] & 0xFF) << 16) + | ((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF)); + } + + public double get(String name, double defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Double.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return Double.longBitsToDouble + ( (long) (((prim_field_data[off++] & 0xFFL) << 56) + | ((prim_field_data[off++] & 0xFFL) << 48) + | ((prim_field_data[off++] & 0xFFL) << 40) + | ((prim_field_data[off++] & 0xFFL) << 32) + | ((prim_field_data[off++] & 0xFF) << 24) + | ((prim_field_data[off++] & 0xFF) << 16) + | ((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF))); + } + + public Object get(String name, Object defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = + getField(name, defvalue == null ? null : defvalue.getClass ()); + + if (field == null) + return defvalue; + + return objs[field.getOffset()]; + } + + private ObjectStreamField getField(String name, Class type) + throws IllegalArgumentException + { + ObjectStreamField field = clazz.getField(name); + boolean illegal = false; + + try + { + try + { + Class field_type = field.getType(); + + if (type == field_type || + (type == null && !field_type.isPrimitive())) + { + /* See defaulted */ + return field; + } + + illegal = true; + throw new IllegalArgumentException + ("Field requested is of type " + + field_type.getName() + + ", but requested type was " + + (type == null ? "Object" : type.getName())); + } + catch (NullPointerException _) + { + /* Here we catch NullPointerException, because it may + only come from the call 'field.getType()'. If field + is null, we have to return null and classpath ethic + say we must try to avoid 'if (xxx == null)'. + */ + } + catch (IllegalArgumentException e) + { + throw e; + } + + return null; + } + finally + { + /* If this is an unassigned field we should return + * the default value. + */ + if (!illegal && field != null && !field.isToSet() && field.isPersistent()) + return null; + + /* We do not want to modify transient fields. They should + * be left to 0. + */ + try + { + Field f = clazz.forClass().getDeclaredField(name); + if (Modifier.isTransient(f.getModifiers())) + throw new IllegalArgumentException + ("no such field (non transient) " + name); + if (field == null && f.getType() != type) + throw new IllegalArgumentException + ("Invalid requested type for field " + name); + } + catch (NoSuchFieldException e) + { + if (field == null) + throw new IllegalArgumentException(e.getMessage()); + } + + } + } + }; + + fieldsAlreadyRead = true; + return prereadFields; + } + + /** + * Protected constructor that allows subclasses to override + * deserialization. This constructor should be called by subclasses + * that wish to override readObject (Object). This + * method does a security check NOTE: currently not + * implemented, then sets a flag that informs + * readObject (Object) to call the subclasses + * readObjectOverride (Object) method. + * + * @see #readObjectOverride() + */ + protected ObjectInputStream() + throws IOException, SecurityException + { + SecurityManager sec_man = System.getSecurityManager(); + if (sec_man != null) + sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); + this.useSubclassMethod = true; + } + + /** + * This method allows subclasses to override the default + * de serialization mechanism provided by + * ObjectInputStream. To make this method be used for + * writing objects, subclasses must invoke the 0-argument + * constructor on this class from their constructor. + * + * @see #ObjectInputStream() + */ + protected Object readObjectOverride() + throws ClassNotFoundException, IOException, OptionalDataException + { + throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride"); + } + + /** + * Assigns the next available handle to obj. + * + * @param obj The object for which we want a new handle. + * @return A valid handle for the specified object. + */ + private int assignNewHandle(Object obj) + { + this.objectLookupTable.put(new Integer(this.nextOID), + new ObjectIdentityWrapper(obj)); + return this.nextOID++; + } + + private Object processResolution(ObjectStreamClass osc, Object obj, int handle) + throws IOException + { + if (osc != null && obj instanceof Serializable) + { + try + { + Method m = osc.readResolveMethod; + if(m != null) + { + obj = m.invoke(obj, new Object[] {}); + } + } + catch (IllegalAccessException ignore) + { + } + catch (InvocationTargetException ignore) + { + } + } + + if (this.resolveEnabled) + obj = resolveObject(obj); + + this.objectLookupTable.put(new Integer(handle), + new ObjectIdentityWrapper(obj)); + + return obj; + } + + private void clearHandles() + { + this.objectLookupTable.clear(); + this.nextOID = baseWireHandle; + } + + private void readNextBlock() throws IOException + { + readNextBlock(this.realInputStream.readByte()); + } + + private void readNextBlock(byte marker) throws IOException + { + if (marker == TC_BLOCKDATA) + { + if(dump) dumpElement("BLOCK DATA SIZE="); + this.blockDataBytes = this.realInputStream.readUnsignedByte(); + if(dump) dumpElementln (Integer.toString(this.blockDataBytes)); + } + else if (marker == TC_BLOCKDATALONG) + { + if(dump) dumpElement("BLOCK DATA LONG SIZE="); + this.blockDataBytes = this.realInputStream.readInt(); + if(dump) dumpElementln (Integer.toString(this.blockDataBytes)); + } + else + { + throw new EOFException("Attempt to read primitive data, but no data block is active."); + } + + if (this.blockData.length < this.blockDataBytes) + this.blockData = new byte[this.blockDataBytes]; + + this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes); + this.blockDataPosition = 0; + } + + private void readArrayElements (Object array, Class clazz) + throws ClassNotFoundException, IOException + { + if (clazz.isPrimitive()) + { + if (clazz == Boolean.TYPE) + { + boolean[] cast_array = (boolean[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readBoolean(); + return; + } + if (clazz == Byte.TYPE) + { + byte[] cast_array = (byte[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readByte(); + return; + } + if (clazz == Character.TYPE) + { + char[] cast_array = (char[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readChar(); + return; + } + if (clazz == Double.TYPE) + { + double[] cast_array = (double[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readDouble(); + return; + } + if (clazz == Float.TYPE) + { + float[] cast_array = (float[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readFloat(); + return; + } + if (clazz == Integer.TYPE) + { + int[] cast_array = (int[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readInt(); + return; + } + if (clazz == Long.TYPE) + { + long[] cast_array = (long[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readLong(); + return; + } + if (clazz == Short.TYPE) + { + short[] cast_array = (short[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readShort(); + return; + } + } + else + { + Object[] cast_array = (Object[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = readObject(); + } + } + + private void readFields (Object obj, ObjectStreamClass stream_osc) + throws ClassNotFoundException, IOException + { + ObjectStreamField[] fields = stream_osc.fieldMapping; + + for (int i = 0; i < fields.length; i += 2) + { + ObjectStreamField stream_field = fields[i]; + ObjectStreamField real_field = fields[i + 1]; + boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet()); + boolean set_value = (real_field != null && real_field.isToSet()); + String field_name; + char type; + + if (stream_field != null) + { + field_name = stream_field.getName(); + type = stream_field.getTypeCode(); + } + else + { + field_name = real_field.getName(); + type = real_field.getTypeCode(); + } + + switch(type) + { + case 'Z': + { + boolean value = + read_value ? this.realInputStream.readBoolean() : false; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setBooleanField(obj, value); + break; + } + case 'B': + { + byte value = + read_value ? this.realInputStream.readByte() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setByteField(obj, value); + break; + } + case 'C': + { + char value = + read_value ? this.realInputStream.readChar(): 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setCharField(obj, value); + break; + } + case 'D': + { + double value = + read_value ? this.realInputStream.readDouble() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setDoubleField(obj, value); + break; + } + case 'F': + { + float value = + read_value ? this.realInputStream.readFloat() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setFloatField(obj, value); + break; + } + case 'I': + { + int value = + read_value ? this.realInputStream.readInt() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setIntField(obj, value); + break; + } + case 'J': + { + long value = + read_value ? this.realInputStream.readLong() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setLongField(obj, value); + break; + } + case 'S': + { + short value = + read_value ? this.realInputStream.readShort() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setShortField(obj, value); + break; + } + case 'L': + case '[': + { + Object value = + read_value ? readObject() : null; + if (set_value) + real_field.setObjectField(obj, value); + break; + } + default: + throw new InternalError("Invalid type code: " + type); + } + } + } + + // Toggles writing primitive data to block-data buffer. + private boolean setBlockDataMode (boolean on) + { + boolean oldmode = this.readDataFromBlock; + this.readDataFromBlock = on; + + if (on) + this.dataInputStream = this.blockDataInput; + else + this.dataInputStream = this.realInputStream; + return oldmode; + } + + // returns a new instance of REAL_CLASS that has been constructed + // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS) + private Object newObject (Class real_class, Constructor constructor) + throws ClassNotFoundException, IOException + { + if (constructor == null) + throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName()); + try + { + return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor); + } + catch (InstantiationException e) + { + throw new ClassNotFoundException + ("Instance of " + real_class + " could not be created"); + } + } + + // runs all registered ObjectInputValidations in prioritized order + // on OBJ + private void invokeValidators() throws InvalidObjectException + { + Object[] validators = new Object[this.validators.size()]; + this.validators.copyInto (validators); + Arrays.sort (validators); + + try + { + for (int i=0; i < validators.length; i++) + ((ObjectInputValidation)validators[i]).validateObject(); + } + finally + { + this.validators.removeAllElements(); + } + } + + private void callReadMethod (Method readObject, Class klass, Object obj) + throws ClassNotFoundException, IOException + { + try + { + readObject.invoke(obj, new Object[] { this }); + } + catch (InvocationTargetException x) + { + /* Rethrow if possible. */ + Throwable exception = x.getTargetException(); + if (exception instanceof RuntimeException) + throw (RuntimeException) exception; + if (exception instanceof IOException) + throw (IOException) exception; + if (exception instanceof ClassNotFoundException) + throw (ClassNotFoundException) exception; + + throw new IOException("Exception thrown from readObject() on " + + klass + ": " + exception.getClass().getName()); + } + catch (Exception x) + { + throw new IOException("Failure invoking readObject() on " + + klass + ": " + x.getClass().getName()); + } + + // Invalidate fields which has been read through readFields. + prereadFields = null; + } + + private static final int BUFFER_SIZE = 1024; + + private DataInputStream realInputStream; + private DataInputStream dataInputStream; + private DataInputStream blockDataInput; + private int blockDataPosition; + private int blockDataBytes; + private byte[] blockData; + private boolean useSubclassMethod; + private int nextOID; + private boolean resolveEnabled; + private Hashtable objectLookupTable; + private Object currentObject; + private ObjectStreamClass currentObjectStreamClass; + private boolean readDataFromBlock; + private boolean isDeserializing; + private boolean fieldsAlreadyRead; + private Vector validators; + private Hashtable classLookupTable; + private GetField prereadFields; + + private ClassLoader callersClassLoader; + private static boolean dump; + + // The nesting depth for debugging output + private int depth = 0; + + private static final boolean DEBUG = false; + + private void dumpElement (String msg) + { + System.out.print(msg); + } + + private void dumpElementln (String msg) + { + System.out.println(msg); + for (int i = 0; i < depth; i++) + System.out.print (" "); + System.out.print (Thread.currentThread() + ": "); + } + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary ("javaio"); + } + } + + // used to keep a prioritized list of object validators + private static final class ValidatorAndPriority implements Comparable + { + int priority; + ObjectInputValidation validator; + + ValidatorAndPriority (ObjectInputValidation validator, int priority) + { + this.priority = priority; + this.validator = validator; + } + + public int compareTo (Object o) + { + ValidatorAndPriority vap = (ValidatorAndPriority)o; + return this.priority - vap.priority; + } + } +} + diff --git a/libjava/classpath/java/io/ObjectInputValidation.java b/libjava/classpath/java/io/ObjectInputValidation.java new file mode 100644 index 0000000..4fdb841 --- /dev/null +++ b/libjava/classpath/java/io/ObjectInputValidation.java @@ -0,0 +1,67 @@ +/* ObjectInputValidation.java -- Validate an object + 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 java.io; + +/** + * This class allows an object to validate that it is valid after + * deserialization has run completely for it and all dependent objects. + * This allows an object to determine if it is invalid even if all + * state data was correctly deserialized from the stream. It can also + * be used to perform re-initialization type activities on an object + * after it has been completely deserialized. + * + * Since this method functions as a type of callback, it must be + * registered through ObjectInputStream.registerValidation + * in order to be invoked. This is typically done in the + * readObject method. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * + * @see ObjectInputStream#registerValidation + */ +public interface ObjectInputValidation +{ + /** + * This method is called to validate an object after serialization + * is complete. If the object is invalid an exception is thrown. + * + * @exception InvalidObjectException If the object is invalid + */ + void validateObject() throws InvalidObjectException; +} diff --git a/libjava/classpath/java/io/ObjectOutput.java b/libjava/classpath/java/io/ObjectOutput.java new file mode 100644 index 0000000..d35a09c --- /dev/null +++ b/libjava/classpath/java/io/ObjectOutput.java @@ -0,0 +1,111 @@ +/* ObjectOutput.java -- Interface for writing objects to a stream + 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 java.io; + +/** + * This interface extends DataOutput to provide the additional + * facility of writing object instances to a stream. It also adds some + * additional methods to make the interface more + * OutputStream like. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * + * @see DataOutput + */ +public interface ObjectOutput extends DataOutput +{ + /** + * This method writes the specified byte to the output stream. + * + * @param b The byte to write. + * + * @exception IOException If an error occurs. + */ + void write(int b) throws IOException; + + /** + * This method writes all the bytes in the specified byte array to the + * output stream. + * + * @param buf The array of bytes to write. + * + * @exception IOException If an error occurs. + */ + void write(byte[] buf) throws IOException; + + /** + * This method writes len bytes from the specified array + * starting at index offset into that array. + * + * @param buf The byte array to write from. + * @param offset The index into the byte array to start writing from. + * @param len The number of bytes to write. + * + * @exception IOException If an error occurs. + */ + void write(byte[] buf, int offset, int len) + throws IOException; + + /** + * This method writes a object instance to a stream. The format of the + * data written is determined by the actual implementation of this method + * + * @param obj The object to write + * + * @exception IOException If an error occurs + */ + void writeObject(Object obj) throws IOException; + + /** + * This method causes any buffered data to be flushed out to the underlying + * stream + * + * @exception IOException If an error occurs + */ + void flush() throws IOException; + + /** + * This method closes the underlying stream. + * + * @exception IOException If an error occurs + */ + void close() throws IOException; + +} // interface ObjectOutput + diff --git a/libjava/classpath/java/io/ObjectOutputStream.java b/libjava/classpath/java/io/ObjectOutputStream.java new file mode 100644 index 0000000..5e754c5 --- /dev/null +++ b/libjava/classpath/java/io/ObjectOutputStream.java @@ -0,0 +1,1578 @@ +/* ObjectOutputStream.java -- Class used to write serialized objects + 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 java.io; + +import gnu.classpath.Configuration; +import gnu.java.io.ObjectIdentityWrapper; +import gnu.java.lang.reflect.TypeSignature; +import gnu.java.security.action.SetAccessibleAction; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.util.Hashtable; + +/** + * An ObjectOutputStream can be used to write objects + * as well as primitive data in a platform-independent manner to an + * OutputStream. + * + * The data produced by an ObjectOutputStream can be read + * and reconstituted by an ObjectInputStream. + * + * writeObject (Object) is used to write Objects, the + * write<type> methods are used to write primitive + * data (as in DataOutputStream). Strings can be written + * as objects or as primitive data. + * + * Not all objects can be written out using an + * ObjectOutputStream. Only those objects that are an + * instance of java.io.Serializable can be written. + * + * Using default serialization, information about the class of an + * object is written, all of the non-transient, non-static fields of + * the object are written, if any of these fields are objects, they are + * written out in the same manner. + * + * An object is only written out the first time it is encountered. If + * the object is encountered later, a reference to it is written to + * the underlying stream. Thus writing circular object graphs + * does not present a problem, nor are relationships between objects + * in a graph lost. + * + * Example usage: + *

    + * Hashtable map = new Hashtable ();
    + * map.put ("one", new Integer (1));
    + * map.put ("two", new Integer (2));
    + *
    + * ObjectOutputStream oos =
    + * new ObjectOutputStream (new FileOutputStream ("numbers"));
    + * oos.writeObject (map);
    + * oos.close ();
    + *
    + * ObjectInputStream ois =
    + * new ObjectInputStream (new FileInputStream ("numbers"));
    + * Hashtable newmap = (Hashtable)ois.readObject ();
    + *
    + * System.out.println (newmap);
    + * 
    + * + * The default serialization can be overriden in two ways. + * + * By defining a method private void + * writeObject (ObjectOutputStream), a class can dictate exactly + * how information about itself is written. + * defaultWriteObject () may be called from this method to + * carry out default serialization. This method is not + * responsible for dealing with fields of super-classes or subclasses. + * + * By implementing java.io.Externalizable. This gives + * the class complete control over the way it is written to the + * stream. If this approach is used the burden of writing superclass + * and subclass data is transfered to the class implementing + * java.io.Externalizable. + * + * @see java.io.DataOutputStream + * @see java.io.Externalizable + * @see java.io.ObjectInputStream + * @see java.io.Serializable + */ +public class ObjectOutputStream extends OutputStream + implements ObjectOutput, ObjectStreamConstants +{ + /** + * Creates a new ObjectOutputStream that will do all of + * its writing onto out. This method also initializes + * the stream by writing the header information (stream magic number + * and stream version). + * + * @exception IOException Writing stream header to underlying + * stream cannot be completed. + * + * @see #writeStreamHeader() + */ + public ObjectOutputStream (OutputStream out) throws IOException + { + realOutput = new DataOutputStream(out); + blockData = new byte[ BUFFER_SIZE ]; + blockDataCount = 0; + blockDataOutput = new DataOutputStream(this); + setBlockDataMode(true); + replacementEnabled = false; + isSerializing = false; + nextOID = baseWireHandle; + OIDLookupTable = new Hashtable(); + protocolVersion = defaultProtocolVersion; + useSubclassMethod = false; + writeStreamHeader(); + + if (DEBUG) + { + String val = System.getProperty("gcj.dumpobjects"); + if (val != null && !val.equals("")) + dump = true; + } + } + + /** + * Writes a representation of obj to the underlying + * output stream by writing out information about its class, then + * writing out each of the objects non-transient, non-static + * fields. If any of these fields are other objects, + * they are written out in the same manner. + * + * This method can be overriden by a class by implementing + * private void writeObject (ObjectOutputStream). + * + * If an exception is thrown from this method, the stream is left in + * an undefined state. + * + * @exception NotSerializableException An attempt was made to + * serialize an Object that is not serializable. + * + * @exception InvalidClassException Somebody tried to serialize + * an object which is wrongly formatted. + * + * @exception IOException Exception from underlying + * OutputStream. + */ + public final void writeObject(Object obj) throws IOException + { + if (useSubclassMethod) + { + if (dump) + dumpElementln ("WRITE OVERRIDE: " + obj); + + writeObjectOverride(obj); + return; + } + + if (dump) + dumpElementln ("WRITE: " + obj); + + depth += 2; + + boolean was_serializing = isSerializing; + boolean old_mode = setBlockDataMode(false); + try + { + isSerializing = true; + boolean replaceDone = false; + Object replacedObject = null; + + while (true) + { + if (obj == null) + { + realOutput.writeByte(TC_NULL); + break; + } + + Integer handle = findHandle(obj); + if (handle != null) + { + realOutput.writeByte(TC_REFERENCE); + realOutput.writeInt(handle.intValue()); + break; + } + + if (obj instanceof Class) + { + Class cl = (Class)obj; + ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl); + realOutput.writeByte(TC_CLASS); + if (!osc.isProxyClass) + { + writeObject (osc); + } + else + { + realOutput.writeByte(TC_PROXYCLASSDESC); + Class[] intfs = cl.getInterfaces(); + realOutput.writeInt(intfs.length); + for (int i = 0; i < intfs.length; i++) + realOutput.writeUTF(intfs[i].getName()); + + boolean oldmode = setBlockDataMode(true); + annotateProxyClass(cl); + setBlockDataMode(oldmode); + realOutput.writeByte(TC_ENDBLOCKDATA); + + writeObject(osc.getSuper()); + } + assignNewHandle(obj); + break; + } + + if (obj instanceof ObjectStreamClass) + { + writeClassDescriptor((ObjectStreamClass) obj); + break; + } + + Class clazz = obj.getClass(); + ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz); + if (osc == null) + throw new NotSerializableException(clazz.getName()); + + if ((replacementEnabled || obj instanceof Serializable) + && ! replaceDone) + { + replacedObject = obj; + + if (obj instanceof Serializable) + { + try + { + Method m = osc.writeReplaceMethod; + if (m != null) + obj = m.invoke(obj, new Object[0]); + } + catch (IllegalAccessException ignore) + { + } + catch (InvocationTargetException ignore) + { + } + } + + if (replacementEnabled) + obj = replaceObject(obj); + + replaceDone = true; + continue; + } + + if (obj instanceof String) + { + realOutput.writeByte(TC_STRING); + assignNewHandle(obj); + realOutput.writeUTF((String)obj); + break; + } + + if (clazz.isArray ()) + { + realOutput.writeByte(TC_ARRAY); + writeObject(osc); + assignNewHandle(obj); + writeArraySizeAndElements(obj, clazz.getComponentType()); + break; + } + + realOutput.writeByte(TC_OBJECT); + writeObject(osc); + + if (replaceDone) + assignNewHandle(replacedObject); + else + assignNewHandle(obj); + + if (obj instanceof Externalizable) + { + if (protocolVersion == PROTOCOL_VERSION_2) + setBlockDataMode(true); + + ((Externalizable)obj).writeExternal(this); + + if (protocolVersion == PROTOCOL_VERSION_2) + { + setBlockDataMode(false); + realOutput.writeByte(TC_ENDBLOCKDATA); + } + + break; + } + + if (obj instanceof Serializable) + { + Object prevObject = this.currentObject; + ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass; + currentObject = obj; + ObjectStreamClass[] hierarchy = + ObjectStreamClass.getObjectStreamClasses(clazz); + + for (int i = 0; i < hierarchy.length; i++) + { + currentObjectStreamClass = hierarchy[i]; + + fieldsAlreadyWritten = false; + if (currentObjectStreamClass.hasWriteMethod()) + { + if (dump) + dumpElementln ("WRITE METHOD CALLED FOR: " + obj); + setBlockDataMode(true); + callWriteMethod(obj, currentObjectStreamClass); + setBlockDataMode(false); + realOutput.writeByte(TC_ENDBLOCKDATA); + if (dump) + dumpElementln ("WRITE ENDBLOCKDATA FOR: " + obj); + } + else + { + if (dump) + dumpElementln ("WRITE FIELDS CALLED FOR: " + obj); + writeFields(obj, currentObjectStreamClass); + } + } + + this.currentObject = prevObject; + this.currentObjectStreamClass = prevObjectStreamClass; + currentPutField = null; + break; + } + + throw new NotSerializableException(clazz.getName ()); + } // end pseudo-loop + } + catch (ObjectStreamException ose) + { + // Rethrow these are fatal. + throw ose; + } + catch (IOException e) + { + realOutput.writeByte(TC_EXCEPTION); + reset(true); + + setBlockDataMode(false); + try + { + if (DEBUG) + { + e.printStackTrace(System.out); + } + writeObject(e); + } + catch (IOException ioe) + { + StreamCorruptedException ex = + new StreamCorruptedException + (ioe + " thrown while exception was being written to stream."); + if (DEBUG) + { + ex.printStackTrace(System.out); + } + throw ex; + } + + reset (true); + + } + finally + { + isSerializing = was_serializing; + setBlockDataMode(old_mode); + depth -= 2; + + if (dump) + dumpElementln ("END: " + obj); + } + } + + protected void writeClassDescriptor(ObjectStreamClass osc) throws IOException + { + realOutput.writeByte(TC_CLASSDESC); + realOutput.writeUTF(osc.getName()); + realOutput.writeLong(osc.getSerialVersionUID()); + assignNewHandle(osc); + + int flags = osc.getFlags(); + + if (protocolVersion == PROTOCOL_VERSION_2 + && osc.isExternalizable()) + flags |= SC_BLOCK_DATA; + + realOutput.writeByte(flags); + + ObjectStreamField[] fields = osc.fields; + realOutput.writeShort(fields.length); + + ObjectStreamField field; + for (int i = 0; i < fields.length; i++) + { + field = fields[i]; + realOutput.writeByte(field.getTypeCode ()); + realOutput.writeUTF(field.getName ()); + + if (! field.isPrimitive()) + writeObject(field.getTypeString()); + } + + boolean oldmode = setBlockDataMode(true); + annotateClass(osc.forClass()); + setBlockDataMode(oldmode); + realOutput.writeByte(TC_ENDBLOCKDATA); + + if (osc.isSerializable() || osc.isExternalizable()) + writeObject(osc.getSuper()); + else + writeObject(null); + } + + /** + * Writes the current objects non-transient, non-static fields from + * the current class to the underlying output stream. + * + * This method is intended to be called from within a object's + * private void writeObject (ObjectOutputStream) + * method. + * + * @exception NotActiveException This method was called from a + * context other than from the current object's and current class's + * private void writeObject (ObjectOutputStream) + * method. + * + * @exception IOException Exception from underlying + * OutputStream. + */ + public void defaultWriteObject() + throws IOException, NotActiveException + { + markFieldsWritten(); + writeFields(currentObject, currentObjectStreamClass); + } + + + private void markFieldsWritten() throws IOException + { + if (currentObject == null || currentObjectStreamClass == null) + throw new NotActiveException + ("defaultWriteObject called by non-active class and/or object"); + + if (fieldsAlreadyWritten) + throw new IOException + ("Only one of writeFields and defaultWriteObject may be called, and it may only be called once"); + + fieldsAlreadyWritten = true; + } + + /** + * Resets stream to state equivalent to the state just after it was + * constructed. + * + * Causes all objects previously written to the stream to be + * forgotten. A notification of this reset is also written to the + * underlying stream. + * + * @exception IOException Exception from underlying + * OutputStream or reset called while serialization is + * in progress. + */ + public void reset() throws IOException + { + reset(false); + } + + + private void reset(boolean internal) throws IOException + { + if (!internal) + { + if (isSerializing) + throw new IOException("Reset called while serialization in progress"); + + realOutput.writeByte(TC_RESET); + } + + clearHandles(); + } + + + /** + * Informs this ObjectOutputStream to write data + * according to the specified protocol. There are currently two + * different protocols, specified by PROTOCOL_VERSION_1 + * and PROTOCOL_VERSION_2. This implementation writes + * data using PROTOCOL_VERSION_2 by default, as is done + * by the JDK 1.2. + * + * A non-portable method, setDefaultProtocolVersion (int + * version) is provided to change the default protocol + * version. + * + * For an explination of the differences beween the two protocols + * see XXX: the Java ObjectSerialization Specification. + * + * @exception IOException if version is not a valid + * protocol + * + * @see #setDefaultProtocolVersion(int) + */ + public void useProtocolVersion(int version) throws IOException + { + if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2) + throw new IOException("Invalid protocol version requested."); + + protocolVersion = version; + } + + + /** + * GNU $classpath specific + * + * Changes the default stream protocol used by all + * ObjectOutputStreams. There are currently two + * different protocols, specified by PROTOCOL_VERSION_1 + * and PROTOCOL_VERSION_2. The default default is + * PROTOCOL_VERSION_1. + * + * @exception IOException if version is not a valid + * protocol + * + * @see #useProtocolVersion(int) + */ + public static void setDefaultProtocolVersion(int version) + throws IOException + { + if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2) + throw new IOException("Invalid protocol version requested."); + + defaultProtocolVersion = version; + } + + + /** + * An empty hook that allows subclasses to write extra information + * about classes to the stream. This method is called the first + * time each class is seen, and after all of the standard + * information about the class has been written. + * + * @exception IOException Exception from underlying + * OutputStream. + * + * @see ObjectInputStream#resolveClass(java.io.ObjectStreamClass) + */ + protected void annotateClass(Class cl) throws IOException + { + } + + protected void annotateProxyClass(Class cl) throws IOException + { + } + + /** + * Allows subclasses to replace objects that are written to the + * stream with other objects to be written in their place. This + * method is called the first time each object is encountered + * (modulo reseting of the stream). + * + * This method must be enabled before it will be called in the + * serialization process. + * + * @exception IOException Exception from underlying + * OutputStream. + * + * @see #enableReplaceObject(boolean) + */ + protected Object replaceObject(Object obj) throws IOException + { + return obj; + } + + + /** + * If enable is true and this object is + * trusted, then replaceObject (Object) will be called + * in subsequent calls to writeObject (Object). + * Otherwise, replaceObject (Object) will not be called. + * + * @exception SecurityException This class is not trusted. + */ + protected boolean enableReplaceObject(boolean enable) + throws SecurityException + { + if (enable) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new SerializablePermission("enableSubstitution")); + } + + boolean old_val = replacementEnabled; + replacementEnabled = enable; + return old_val; + } + + + /** + * Writes stream magic and stream version information to the + * underlying stream. + * + * @exception IOException Exception from underlying + * OutputStream. + */ + protected void writeStreamHeader() throws IOException + { + realOutput.writeShort(STREAM_MAGIC); + realOutput.writeShort(STREAM_VERSION); + } + + /** + * Protected constructor that allows subclasses to override + * serialization. This constructor should be called by subclasses + * that wish to override writeObject (Object). This + * method does a security check NOTE: currently not + * implemented, then sets a flag that informs + * writeObject (Object) to call the subclasses + * writeObjectOverride (Object) method. + * + * @see #writeObjectOverride(Object) + */ + protected ObjectOutputStream() throws IOException, SecurityException + { + SecurityManager sec_man = System.getSecurityManager (); + if (sec_man != null) + sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); + useSubclassMethod = true; + } + + + /** + * This method allows subclasses to override the default + * serialization mechanism provided by + * ObjectOutputStream. To make this method be used for + * writing objects, subclasses must invoke the 0-argument + * constructor on this class from there constructor. + * + * @see #ObjectOutputStream() + * + * @exception NotActiveException Subclass has arranged for this + * method to be called, but did not implement this method. + */ + protected void writeObjectOverride(Object obj) throws NotActiveException, + IOException + { + throw new NotActiveException + ("Subclass of ObjectOutputStream must implement writeObjectOverride"); + } + + + /** + * @see DataOutputStream#write(int) + */ + public void write (int data) throws IOException + { + if (writeDataAsBlocks) + { + if (blockDataCount == BUFFER_SIZE) + drain(); + + blockData[ blockDataCount++ ] = (byte)data; + } + else + realOutput.write(data); + } + + + /** + * @see DataOutputStream#write(byte[]) + */ + public void write(byte[] b) throws IOException + { + write(b, 0, b.length); + } + + + /** + * @see DataOutputStream#write(byte[],int,int) + */ + public void write(byte[] b, int off, int len) throws IOException + { + if (writeDataAsBlocks) + { + if (len < 0) + throw new IndexOutOfBoundsException(); + + if (blockDataCount + len < BUFFER_SIZE) + { + System.arraycopy(b, off, blockData, blockDataCount, len); + blockDataCount += len; + } + else + { + drain(); + writeBlockDataHeader(len); + realOutput.write(b, off, len); + } + } + else + realOutput.write(b, off, len); + } + + + /** + * @see DataOutputStream#flush() + */ + public void flush () throws IOException + { + drain(); + realOutput.flush(); + } + + + /** + * Causes the block-data buffer to be written to the underlying + * stream, but does not flush underlying stream. + * + * @exception IOException Exception from underlying + * OutputStream. + */ + protected void drain() throws IOException + { + if (blockDataCount == 0) + return; + + if (writeDataAsBlocks) + writeBlockDataHeader(blockDataCount); + realOutput.write(blockData, 0, blockDataCount); + blockDataCount = 0; + } + + + /** + * @see java.io.DataOutputStream#close () + */ + public void close() throws IOException + { + flush(); + realOutput.close(); + } + + + /** + * @see java.io.DataOutputStream#writeBoolean (boolean) + */ + public void writeBoolean(boolean data) throws IOException + { + blockDataOutput.writeBoolean(data); + } + + + /** + * @see java.io.DataOutputStream#writeByte (int) + */ + public void writeByte(int data) throws IOException + { + blockDataOutput.writeByte(data); + } + + + /** + * @see java.io.DataOutputStream#writeShort (int) + */ + public void writeShort (int data) throws IOException + { + blockDataOutput.writeShort(data); + } + + + /** + * @see java.io.DataOutputStream#writeChar (int) + */ + public void writeChar(int data) throws IOException + { + blockDataOutput.writeChar(data); + } + + + /** + * @see java.io.DataOutputStream#writeInt (int) + */ + public void writeInt(int data) throws IOException + { + blockDataOutput.writeInt(data); + } + + + /** + * @see java.io.DataOutputStream#writeLong (long) + */ + public void writeLong(long data) throws IOException + { + blockDataOutput.writeLong(data); + } + + + /** + * @see java.io.DataOutputStream#writeFloat (float) + */ + public void writeFloat(float data) throws IOException + { + blockDataOutput.writeFloat(data); + } + + + /** + * @see java.io.DataOutputStream#writeDouble (double) + */ + public void writeDouble(double data) throws IOException + { + blockDataOutput.writeDouble(data); + } + + + /** + * @see java.io.DataOutputStream#writeBytes (java.lang.String) + */ + public void writeBytes(String data) throws IOException + { + blockDataOutput.writeBytes(data); + } + + + /** + * @see java.io.DataOutputStream#writeChars (java.lang.String) + */ + public void writeChars(String data) throws IOException + { + dataOutput.writeChars(data); + } + + + /** + * @see java.io.DataOutputStream#writeUTF (java.lang.String) + */ + public void writeUTF(String data) throws IOException + { + dataOutput.writeUTF(data); + } + + + /** + * This class allows a class to specify exactly which fields should + * be written, and what values should be written for these fields. + * + * XXX: finish up comments + */ + public abstract static class PutField + { + public abstract void put (String name, boolean value); + public abstract void put (String name, byte value); + public abstract void put (String name, char value); + public abstract void put (String name, double value); + public abstract void put (String name, float value); + public abstract void put (String name, int value); + public abstract void put (String name, long value); + public abstract void put (String name, short value); + public abstract void put (String name, Object value); + + /** + * @deprecated + */ + public abstract void write (ObjectOutput out) throws IOException; + } + + public PutField putFields() throws IOException + { + if (currentPutField != null) + return currentPutField; + + currentPutField = new PutField() + { + private byte[] prim_field_data + = new byte[currentObjectStreamClass.primFieldSize]; + private Object[] objs + = new Object[currentObjectStreamClass.objectFieldCount]; + + private ObjectStreamField getField (String name) + { + ObjectStreamField field + = currentObjectStreamClass.getField(name); + + if (field == null) + throw new IllegalArgumentException("no such serializable field " + name); + + return field; + } + + public void put(String name, boolean value) + { + ObjectStreamField field = getField(name); + + checkType(field, 'Z'); + prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0); + } + + public void put(String name, byte value) + { + ObjectStreamField field = getField(name); + + checkType(field, 'B'); + prim_field_data[field.getOffset()] = value; + } + + public void put(String name, char value) + { + ObjectStreamField field = getField(name); + + checkType(field, 'C'); + int off = field.getOffset(); + prim_field_data[off++] = (byte)(value >>> 8); + prim_field_data[off] = (byte)value; + } + + public void put(String name, double value) + { + ObjectStreamField field = getField (name); + + checkType(field, 'D'); + int off = field.getOffset(); + long l_value = Double.doubleToLongBits (value); + prim_field_data[off++] = (byte)(l_value >>> 52); + prim_field_data[off++] = (byte)(l_value >>> 48); + prim_field_data[off++] = (byte)(l_value >>> 40); + prim_field_data[off++] = (byte)(l_value >>> 32); + prim_field_data[off++] = (byte)(l_value >>> 24); + prim_field_data[off++] = (byte)(l_value >>> 16); + prim_field_data[off++] = (byte)(l_value >>> 8); + prim_field_data[off] = (byte)l_value; + } + + public void put(String name, float value) + { + ObjectStreamField field = getField(name); + + checkType(field, 'F'); + int off = field.getOffset(); + int i_value = Float.floatToIntBits(value); + prim_field_data[off++] = (byte)(i_value >>> 24); + prim_field_data[off++] = (byte)(i_value >>> 16); + prim_field_data[off++] = (byte)(i_value >>> 8); + prim_field_data[off] = (byte)i_value; + } + + public void put(String name, int value) + { + ObjectStreamField field = getField(name); + checkType(field, 'I'); + int off = field.getOffset(); + prim_field_data[off++] = (byte)(value >>> 24); + prim_field_data[off++] = (byte)(value >>> 16); + prim_field_data[off++] = (byte)(value >>> 8); + prim_field_data[off] = (byte)value; + } + + public void put(String name, long value) + { + ObjectStreamField field = getField(name); + checkType(field, 'J'); + int off = field.getOffset(); + prim_field_data[off++] = (byte)(value >>> 52); + prim_field_data[off++] = (byte)(value >>> 48); + prim_field_data[off++] = (byte)(value >>> 40); + prim_field_data[off++] = (byte)(value >>> 32); + prim_field_data[off++] = (byte)(value >>> 24); + prim_field_data[off++] = (byte)(value >>> 16); + prim_field_data[off++] = (byte)(value >>> 8); + prim_field_data[off] = (byte)value; + } + + public void put(String name, short value) + { + ObjectStreamField field = getField(name); + checkType(field, 'S'); + int off = field.getOffset(); + prim_field_data[off++] = (byte)(value >>> 8); + prim_field_data[off] = (byte)value; + } + + public void put(String name, Object value) + { + ObjectStreamField field = getField(name); + + if (value != null && + ! field.getType().isAssignableFrom(value.getClass ())) + throw new IllegalArgumentException("Class " + value.getClass() + + " cannot be cast to " + field.getType()); + objs[field.getOffset()] = value; + } + + public void write(ObjectOutput out) throws IOException + { + // Apparently Block data is not used with PutField as per + // empirical evidence against JDK 1.2. Also see Mauve test + // java.io.ObjectInputOutput.Test.GetPutField. + boolean oldmode = setBlockDataMode(false); + out.write(prim_field_data); + for (int i = 0; i < objs.length; ++ i) + out.writeObject(objs[i]); + setBlockDataMode(oldmode); + } + + private void checkType(ObjectStreamField field, char type) + throws IllegalArgumentException + { + if (TypeSignature.getEncodingOfClass(field.getType()).charAt(0) + != type) + throw new IllegalArgumentException(); + } + }; + // end PutFieldImpl + + return currentPutField; + } + + + public void writeFields() throws IOException + { + if (currentPutField == null) + throw new NotActiveException("writeFields can only be called after putFields has been called"); + + markFieldsWritten(); + currentPutField.write(this); + } + + + // write out the block-data buffer, picking the correct header + // depending on the size of the buffer + private void writeBlockDataHeader(int size) throws IOException + { + if (size < 256) + { + realOutput.writeByte(TC_BLOCKDATA); + realOutput.write(size); + } + else + { + realOutput.writeByte(TC_BLOCKDATALONG); + realOutput.writeInt(size); + } + } + + + // lookup the handle for OBJ, return null if OBJ doesn't have a + // handle yet + private Integer findHandle(Object obj) + { + return (Integer)OIDLookupTable.get(new ObjectIdentityWrapper(obj)); + } + + + // assigns the next availible handle to OBJ + private int assignNewHandle(Object obj) + { + OIDLookupTable.put(new ObjectIdentityWrapper(obj), + new Integer(nextOID)); + return nextOID++; + } + + + // resets mapping from objects to handles + private void clearHandles() + { + nextOID = baseWireHandle; + OIDLookupTable.clear(); + } + + + // write out array size followed by each element of the array + private void writeArraySizeAndElements(Object array, Class clazz) + throws IOException + { + int length = Array.getLength(array); + + if (clazz.isPrimitive()) + { + if (clazz == Boolean.TYPE) + { + boolean[] cast_array = (boolean[])array; + realOutput.writeInt (length); + for (int i = 0; i < length; i++) + realOutput.writeBoolean(cast_array[i]); + return; + } + if (clazz == Byte.TYPE) + { + byte[] cast_array = (byte[])array; + realOutput.writeInt(length); + realOutput.write(cast_array, 0, length); + return; + } + if (clazz == Character.TYPE) + { + char[] cast_array = (char[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + realOutput.writeChar(cast_array[i]); + return; + } + if (clazz == Double.TYPE) + { + double[] cast_array = (double[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + realOutput.writeDouble(cast_array[i]); + return; + } + if (clazz == Float.TYPE) + { + float[] cast_array = (float[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + realOutput.writeFloat(cast_array[i]); + return; + } + if (clazz == Integer.TYPE) + { + int[] cast_array = (int[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + realOutput.writeInt(cast_array[i]); + return; + } + if (clazz == Long.TYPE) + { + long[] cast_array = (long[])array; + realOutput.writeInt (length); + for (int i = 0; i < length; i++) + realOutput.writeLong(cast_array[i]); + return; + } + if (clazz == Short.TYPE) + { + short[] cast_array = (short[])array; + realOutput.writeInt (length); + for (int i = 0; i < length; i++) + realOutput.writeShort(cast_array[i]); + return; + } + } + else + { + Object[] cast_array = (Object[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + writeObject(cast_array[i]); + } + } + + + // writes out FIELDS of OBJECT for the specified ObjectStreamClass. + // FIELDS are already in canonical order. + private void writeFields(Object obj, ObjectStreamClass osc) + throws IOException + { + ObjectStreamField[] fields = osc.fields; + boolean oldmode = setBlockDataMode(false); + String field_name; + Class type; + + for (int i = 0; i < fields.length; i++) + { + field_name = fields[i].getName(); + type = fields[i].getType(); + + if (dump) + dumpElementln ("WRITE FIELD: " + field_name + " type=" + type); + + if (type == Boolean.TYPE) + realOutput.writeBoolean(getBooleanField(obj, osc.forClass(), field_name)); + else if (type == Byte.TYPE) + realOutput.writeByte(getByteField(obj, osc.forClass(), field_name)); + else if (type == Character.TYPE) + realOutput.writeChar(getCharField(obj, osc.forClass(), field_name)); + else if (type == Double.TYPE) + realOutput.writeDouble(getDoubleField(obj, osc.forClass(), field_name)); + else if (type == Float.TYPE) + realOutput.writeFloat(getFloatField(obj, osc.forClass(), field_name)); + else if (type == Integer.TYPE) + realOutput.writeInt(getIntField(obj, osc.forClass(), field_name)); + else if (type == Long.TYPE) + realOutput.writeLong(getLongField(obj, osc.forClass(), field_name)); + else if (type == Short.TYPE) + realOutput.writeShort(getShortField(obj, osc.forClass(), field_name)); + else + writeObject(getObjectField(obj, osc.forClass(), field_name, + fields[i].getTypeString ())); + } + setBlockDataMode(oldmode); + } + + + // Toggles writing primitive data to block-data buffer. + // Package-private to avoid a trampoline constructor. + boolean setBlockDataMode(boolean on) throws IOException + { + if (on == writeDataAsBlocks) + return on; + + drain(); + boolean oldmode = writeDataAsBlocks; + writeDataAsBlocks = on; + + if (on) + dataOutput = blockDataOutput; + else + dataOutput = realOutput; + + return oldmode; + } + + + private void callWriteMethod(Object obj, ObjectStreamClass osc) + throws IOException + { + currentPutField = null; + try + { + Object args[] = {this}; + osc.writeObjectMethod.invoke(obj, args); + } + catch (InvocationTargetException x) + { + /* Rethrow if possible. */ + Throwable exception = x.getTargetException(); + if (exception instanceof RuntimeException) + throw (RuntimeException) exception; + if (exception instanceof IOException) + throw (IOException) exception; + + IOException ioe + = new IOException("Exception thrown from writeObject() on " + + osc.forClass().getName() + ": " + + exception.getClass().getName()); + ioe.initCause(exception); + throw ioe; + } + catch (Exception x) + { + IOException ioe + = new IOException("Failure invoking writeObject() on " + + osc.forClass().getName() + ": " + + x.getClass().getName()); + ioe.initCause(x); + throw ioe; + } + } + + private boolean getBooleanField(Object obj, Class klass, String field_name) + throws IOException + { + try + { + Field f = getField(klass, field_name); + boolean b = f.getBoolean(obj); + return b; + } + catch (IllegalArgumentException _) + { + throw new InvalidClassException + ("invalid requested type for field " + field_name + " in class " + klass.getName()); + } + catch (IOException e) + { + throw e; + } + catch (Exception _) + { + throw new IOException("Unexpected exception " + _); + } + } + + private byte getByteField (Object obj, Class klass, String field_name) + throws IOException + { + try + { + Field f = getField (klass, field_name); + byte b = f.getByte (obj); + return b; + } + catch (IllegalArgumentException _) + { + throw new InvalidClassException + ("invalid requested type for field " + field_name + " in class " + klass.getName()); + } + catch (IOException e) + { + throw e; + } + catch (Exception _) + { + throw new IOException("Unexpected exception " + _); + } + } + + private char getCharField (Object obj, Class klass, String field_name) + throws IOException + { + try + { + Field f = getField (klass, field_name); + char b = f.getChar (obj); + return b; + } + catch (IllegalArgumentException _) + { + throw new InvalidClassException + ("invalid requested type for field " + field_name + " in class " + klass.getName()); + } + catch (IOException e) + { + throw e; + } + catch (Exception _) + { + throw new IOException("Unexpected exception " + _); + } + } + + private double getDoubleField (Object obj, Class klass, String field_name) + throws IOException + { + try + { + Field f = getField (klass, field_name); + double b = f.getDouble (obj); + return b; + } + catch (IllegalArgumentException _) + { + throw new InvalidClassException + ("invalid requested type for field " + field_name + " in class " + klass.getName()); + } + catch (IOException e) + { + throw e; + } + catch (Exception _) + { + throw new IOException("Unexpected exception " + _); + } + } + + private float getFloatField (Object obj, Class klass, String field_name) + throws IOException + { + try + { + Field f = getField (klass, field_name); + float b = f.getFloat (obj); + return b; + } + catch (IllegalArgumentException _) + { + throw new InvalidClassException + ("invalid requested type for field " + field_name + " in class " + klass.getName()); + } + catch (IOException e) + { + throw e; + } + catch (Exception _) + { + throw new IOException("Unexpected exception " + _); + } + } + + private int getIntField (Object obj, Class klass, String field_name) + throws IOException + { + try + { + Field f = getField (klass, field_name); + int b = f.getInt (obj); + return b; + } + catch (IllegalArgumentException _) + { + throw new InvalidClassException + ("invalid requested type for field " + field_name + " in class " + klass.getName()); + } + catch (IOException e) + { + throw e; + } + catch (Exception _) + { + throw new IOException("Unexpected exception " + _); + } + } + + private long getLongField (Object obj, Class klass, String field_name) + throws IOException + { + try + { + Field f = getField (klass, field_name); + long b = f.getLong (obj); + return b; + } + catch (IllegalArgumentException _) + { + throw new InvalidClassException + ("invalid requested type for field " + field_name + " in class " + klass.getName()); + } + catch (IOException e) + { + throw e; + } + catch (Exception _) + { + throw new IOException("Unexpected exception " + _); + } + } + + private short getShortField (Object obj, Class klass, String field_name) + throws IOException + { + try + { + Field f = getField (klass, field_name); + short b = f.getShort (obj); + return b; + } + catch (IllegalArgumentException _) + { + throw new InvalidClassException + ("invalid requested type for field " + field_name + " in class " + klass.getName()); + } + catch (IOException e) + { + throw e; + } + catch (Exception _) + { + throw new IOException("Unexpected exception " + _); + } + } + + private Object getObjectField (Object obj, Class klass, String field_name, + String type_code) throws IOException + { + try + { + Field f = getField (klass, field_name); + ObjectStreamField of = new ObjectStreamField(f.getName(), f.getType()); + + /* if of is primitive something went wrong + * in the check for primitive classes in writeFields. + */ + if (of.isPrimitive()) + throw new InvalidClassException + ("invalid type code for " + field_name + " in class " + klass.getName() + " : object stream field is primitive"); + + if (!of.getTypeString().equals(type_code)) + throw new InvalidClassException + ("invalid type code for " + field_name + " in class " + klass.getName() + " : object stream field " + of + " has type string " + of.getTypeString() + " instead of " + type_code); + + Object o = f.get (obj); + // FIXME: We should check the type_code here + return o; + } + catch (IOException e) + { + throw e; + } + catch (Exception e) + { + throw new IOException (); + } + } + + private Field getField (Class klass, String name) + throws java.io.InvalidClassException + { + try + { + final Field f = klass.getDeclaredField(name); + setAccessible.setMember(f); + AccessController.doPrivileged(setAccessible); + return f; + } + catch (java.lang.NoSuchFieldException e) + { + throw new InvalidClassException + ("no field called " + name + " in class " + klass.getName()); + } + } + + private void dumpElementln (String msg) + { + for (int i = 0; i < depth; i++) + System.out.print (" "); + System.out.print (Thread.currentThread() + ": "); + System.out.println(msg); + } + + // this value comes from 1.2 spec, but is used in 1.1 as well + private static final int BUFFER_SIZE = 1024; + + private static int defaultProtocolVersion = PROTOCOL_VERSION_2; + + private DataOutputStream dataOutput; + private boolean writeDataAsBlocks; + private DataOutputStream realOutput; + private DataOutputStream blockDataOutput; + private byte[] blockData; + private int blockDataCount; + private Object currentObject; + // Package-private to avoid a trampoline. + ObjectStreamClass currentObjectStreamClass; + private PutField currentPutField; + private boolean fieldsAlreadyWritten; + private boolean replacementEnabled; + private boolean isSerializing; + private int nextOID; + private Hashtable OIDLookupTable; + private int protocolVersion; + private boolean useSubclassMethod; + private SetAccessibleAction setAccessible = new SetAccessibleAction(); + + // The nesting depth for debugging output + private int depth = 0; + + // Set if we're generating debugging dumps + private boolean dump = false; + + private static final boolean DEBUG = false; + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javaio"); + } + } +} diff --git a/libjava/classpath/java/io/ObjectStreamClass.java b/libjava/classpath/java/io/ObjectStreamClass.java new file mode 100644 index 0000000..b7bd127 --- /dev/null +++ b/libjava/classpath/java/io/ObjectStreamClass.java @@ -0,0 +1,976 @@ +/* ObjectStreamClass.java -- Class used to write class information + about serialized objects. + Copyright (C) 1998, 1999, 2000, 2001, 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 java.io; + +import gnu.java.io.NullOutputStream; +import gnu.java.lang.reflect.TypeSignature; +import gnu.java.security.action.SetAccessibleAction; +import gnu.java.security.provider.Gnu; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.security.AccessController; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedAction; +import java.security.Security; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Hashtable; +import java.util.Vector; + +public class ObjectStreamClass implements Serializable +{ + /** + * Returns the ObjectStreamClass for cl. + * If cl is null, or is not Serializable, + * null is returned. ObjectStreamClass's are memorized; + * later calls to this method with the same class will return the + * same ObjectStreamClass object and no recalculation + * will be done. + * + * @see java.io.Serializable + */ + public static ObjectStreamClass lookup(Class cl) + { + if (cl == null) + return null; + if (! (Serializable.class).isAssignableFrom(cl)) + return null; + + return lookupForClassObject(cl); + } + + /** + * This lookup for internal use by ObjectOutputStream. Suppose + * we have a java.lang.Class object C for class A, though A is not + * serializable, but it's okay to serialize C. + */ + static ObjectStreamClass lookupForClassObject(Class cl) + { + if (cl == null) + return null; + + ObjectStreamClass osc = (ObjectStreamClass) classLookupTable.get(cl); + + if (osc != null) + return osc; + else + { + osc = new ObjectStreamClass(cl); + classLookupTable.put(cl, osc); + return osc; + } + } + + /** + * Returns the name of the class that this + * ObjectStreamClass represents. + * + * @return the name of the class. + */ + public String getName() + { + return name; + } + + /** + * Returns the class that this ObjectStreamClass + * represents. Null could be returned if this + * ObjectStreamClass was read from an + * ObjectInputStream and the class it represents cannot + * be found or loaded. + * + * @see java.io.ObjectInputStream + */ + public Class forClass() + { + return clazz; + } + + /** + * Returns the serial version stream-unique identifier for the class + * represented by this ObjectStreamClass. This SUID is + * either defined by the class as static final long + * serialVersionUID or is calculated as specified in + * Javasoft's "Object Serialization Specification" XXX: add reference + * + * @return the serial version UID. + */ + public long getSerialVersionUID() + { + return uid; + } + + /** + * Returns the serializable (non-static and non-transient) Fields + * of the class represented by this ObjectStreamClass. The Fields + * are sorted by name. + * + * @return the fields. + */ + public ObjectStreamField[] getFields() + { + ObjectStreamField[] copy = new ObjectStreamField[ fields.length ]; + System.arraycopy(fields, 0, copy, 0, fields.length); + return copy; + } + + // XXX doc + // Can't do binary search since fields is sorted by name and + // primitiveness. + public ObjectStreamField getField (String name) + { + for (int i = 0; i < fields.length; i++) + if (fields[i].getName().equals(name)) + return fields[i]; + return null; + } + + /** + * Returns a textual representation of this + * ObjectStreamClass object including the name of the + * class it represents as well as that class's serial version + * stream-unique identifier. + * + * @see #getSerialVersionUID() + * @see #getName() + */ + public String toString() + { + return "java.io.ObjectStreamClass< " + name + ", " + uid + " >"; + } + + // Returns true iff the class that this ObjectStreamClass represents + // has the following method: + // + // private void writeObject (ObjectOutputStream) + // + // This method is used by the class to override default + // serialization behavior. + boolean hasWriteMethod() + { + return (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0; + } + + // Returns true iff the class that this ObjectStreamClass represents + // implements Serializable but does *not* implement Externalizable. + boolean isSerializable() + { + return (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0; + } + + + // Returns true iff the class that this ObjectStreamClass represents + // implements Externalizable. + boolean isExternalizable() + { + return (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0; + } + + + // Returns the ObjectStreamClass that represents the + // class that is the superclass of the class this + // ObjectStreamClass represents. If the superclass is + // not Serializable, null is returned. + ObjectStreamClass getSuper() + { + return superClass; + } + + + // returns an array of ObjectStreamClasses that represent the super + // classes of CLAZZ and CLAZZ itself in order from most super to + // CLAZZ. ObjectStreamClass[0] is the highest superclass of CLAZZ + // that is serializable. + static ObjectStreamClass[] getObjectStreamClasses(Class clazz) + { + ObjectStreamClass osc = ObjectStreamClass.lookup(clazz); + + if (osc == null) + return new ObjectStreamClass[0]; + else + { + Vector oscs = new Vector(); + + while (osc != null) + { + oscs.addElement (osc); + osc = osc.getSuper(); + } + + int count = oscs.size(); + ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[ count ]; + + for (int i = count - 1; i >= 0; i--) + sorted_oscs[ count - i - 1 ] = (ObjectStreamClass) oscs.elementAt(i); + + return sorted_oscs; + } + } + + + // Returns an integer that consists of bit-flags that indicate + // properties of the class represented by this ObjectStreamClass. + // The bit-flags that could be present are those defined in + // ObjectStreamConstants that begin with `SC_' + int getFlags() + { + return flags; + } + + + ObjectStreamClass(String name, long uid, byte flags, + ObjectStreamField[] fields) + { + this.name = name; + this.uid = uid; + this.flags = flags; + this.fields = fields; + } + + /** + * This method builds the internal description corresponding to a Java Class. + * As the constructor only assign a name to the current ObjectStreamClass instance, + * that method sets the serial UID, chose the fields which will be serialized, + * and compute the position of the fields in the serialized stream. + * + * @param cl The Java class which is used as a reference for building the descriptor. + * @param superClass The descriptor of the super class for this class descriptor. + * @throws InvalidClassException if an incompatibility between computed UID and + * already set UID is found. + */ + void setClass(Class cl, ObjectStreamClass superClass) throws InvalidClassException + { + this.clazz = cl; + + cacheMethods(); + + long class_uid = getClassUID(cl); + if (uid == 0) + uid = class_uid; + else + { + // Check that the actual UID of the resolved class matches the UID from + // the stream. + if (uid != class_uid) + { + String msg = cl + + ": Local class not compatible: stream serialVersionUID=" + + uid + ", local serialVersionUID=" + class_uid; + throw new InvalidClassException (msg); + } + } + + isProxyClass = clazz != null && Proxy.isProxyClass(clazz); + this.superClass = superClass; + calculateOffsets(); + + try + { + ObjectStreamField[] exportedFields = getSerialPersistentFields (clazz); + + if (exportedFields == null) + return; + + ObjectStreamField[] newFieldList = new ObjectStreamField[exportedFields.length + fields.length]; + int i, j, k; + + /* We now check the import fields against the exported fields. + * There should not be contradiction (e.g. int x and String x) + * but extra virtual fields can be added to the class. + */ + + Arrays.sort(exportedFields); + + i = 0; j = 0; k = 0; + while (i < fields.length && j < exportedFields.length) + { + int comp = fields[i].compareTo(exportedFields[j]); + + if (comp < 0) + { + newFieldList[k] = fields[i]; + fields[i].setPersistent(false); + fields[i].setToSet(false); + i++; + } + else if (comp > 0) + { + /* field not found in imported fields. We add it + * in the list of supported fields. + */ + newFieldList[k] = exportedFields[j]; + newFieldList[k].setPersistent(true); + newFieldList[k].setToSet(false); + try + { + newFieldList[k].lookupField(clazz); + newFieldList[k].checkFieldType(); + } + catch (NoSuchFieldException _) + { + } + j++; + } + else + { + try + { + exportedFields[j].lookupField(clazz); + exportedFields[j].checkFieldType(); + } + catch (NoSuchFieldException _) + { + } + + if (!fields[i].getType().equals(exportedFields[j].getType())) + throw new InvalidClassException + ("serialPersistentFields must be compatible with" + + " imported fields (about " + fields[i].getName() + ")"); + newFieldList[k] = fields[i]; + fields[i].setPersistent(true); + i++; + j++; + } + k++; + } + + if (i < fields.length) + for (;i"); + data_out.writeInt(Modifier.STATIC); + data_out.writeUTF("()V"); + } + + Constructor constructor; + Constructor[] constructors = cl.getDeclaredConstructors(); + Arrays.sort (constructors, memberComparator); + for (int i = 0; i < constructors.length; i++) + { + constructor = constructors[i]; + modifiers = constructor.getModifiers(); + if (Modifier.isPrivate(modifiers)) + continue; + + data_out.writeUTF(""); + data_out.writeInt(modifiers); + + // the replacement of '/' with '.' was needed to make computed + // SUID's agree with those computed by JDK + data_out.writeUTF + (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.')); + } + + Method method; + Method[] methods = cl.getDeclaredMethods(); + Arrays.sort(methods, memberComparator); + for (int i = 0; i < methods.length; i++) + { + method = methods[i]; + modifiers = method.getModifiers(); + if (Modifier.isPrivate(modifiers)) + continue; + + data_out.writeUTF(method.getName()); + data_out.writeInt(modifiers); + + // the replacement of '/' with '.' was needed to make computed + // SUID's agree with those computed by JDK + data_out.writeUTF + (TypeSignature.getEncodingOfMethod(method).replace('/', '.')); + } + + data_out.close(); + 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 (NoSuchAlgorithmException e) + { + throw new RuntimeException + ("The SHA algorithm was not found to use in computing the Serial Version UID for class " + + cl.getName(), e); + } + catch (IOException ioe) + { + throw new RuntimeException(ioe); + } + } + + /** + * Returns the value of CLAZZ's private static final field named + * `serialPersistentFields'. It performs some sanity checks before + * returning the real array. Besides, the returned array is a clean + * copy of the original. So it can be modified. + * + * @param clazz Class to retrieve 'serialPersistentFields' from. + * @return The content of 'serialPersistentFields'. + */ + private ObjectStreamField[] getSerialPersistentFields(Class clazz) + throws NoSuchFieldException, IllegalAccessException + { + ObjectStreamField[] fieldsArray = null; + ObjectStreamField[] o; + + // Use getDeclaredField rather than getField for the same reason + // as above in getDefinedSUID. + Field f = clazz.getDeclaredField("serialPersistentFields"); + f.setAccessible(true); + + int modifiers = f.getModifiers(); + if (!(Modifier.isStatic(modifiers) && + Modifier.isFinal(modifiers) && + Modifier.isPrivate(modifiers))) + return null; + + o = (ObjectStreamField[]) f.get(null); + + if (o == null) + return null; + + fieldsArray = new ObjectStreamField[ o.length ]; + System.arraycopy(o, 0, fieldsArray, 0, o.length); + + return fieldsArray; + } + + /** + * Returns a new instance of the Class this ObjectStreamClass corresponds + * to. + * Note that this should only be used for Externalizable classes. + * + * @return A new instance. + */ + Externalizable newInstance() throws InvalidClassException + { + synchronized(this) + { + if (constructor == null) + { + try + { + final Constructor c = clazz.getConstructor(new Class[0]); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + c.setAccessible(true); + return null; + } + }); + + constructor = c; + } + catch(NoSuchMethodException x) + { + throw new InvalidClassException(clazz.getName(), + "No public zero-argument constructor"); + } + } + } + + try + { + return (Externalizable)constructor.newInstance(null); + } + catch(Exception x) + { + throw (InvalidClassException) + new InvalidClassException(clazz.getName(), + "Unable to instantiate").initCause(x); + } + } + + public static final ObjectStreamField[] NO_FIELDS = {}; + + private static Hashtable classLookupTable = new Hashtable(); + private static final NullOutputStream nullOutputStream = new NullOutputStream(); + private static final Comparator interfaceComparator = new InterfaceComparator(); + private static final Comparator memberComparator = new MemberComparator(); + private static final + Class[] writeMethodArgTypes = { java.io.ObjectOutputStream.class }; + + private ObjectStreamClass superClass; + private Class clazz; + private String name; + private long uid; + private byte flags; + + // this field is package protected so that ObjectInputStream and + // ObjectOutputStream can access it directly + ObjectStreamField[] fields; + + // these are accessed by ObjectIn/OutputStream + int primFieldSize = -1; // -1 if not yet calculated + int objectFieldCount; + + Method readObjectMethod; + Method readResolveMethod; + Method writeReplaceMethod; + Method writeObjectMethod; + boolean realClassIsSerializable; + boolean realClassIsExternalizable; + ObjectStreamField[] fieldMapping; + Constructor firstNonSerializableParentConstructor; + private Constructor constructor; // default constructor for Externalizable + + boolean isProxyClass = false; + + // This is probably not necessary because this class is special cased already + // but it will avoid showing up as a discrepancy when comparing SUIDs. + private static final long serialVersionUID = -6120832682080437368L; + + + // interfaces are compared only by name + private static final class InterfaceComparator implements Comparator + { + public int compare(Object o1, Object o2) + { + return ((Class) o1).getName().compareTo(((Class) o2).getName()); + } + } + + + // Members (Methods and Constructors) are compared first by name, + // conflicts are resolved by comparing type signatures + private static final class MemberComparator implements Comparator + { + public int compare(Object o1, Object o2) + { + Member m1 = (Member) o1; + Member m2 = (Member) o2; + + int comp = m1.getName().compareTo(m2.getName()); + + if (comp == 0) + return TypeSignature.getEncodingOfMember(m1). + compareTo(TypeSignature.getEncodingOfMember(m2)); + else + return comp; + } + } +} diff --git a/libjava/classpath/java/io/ObjectStreamConstants.java b/libjava/classpath/java/io/ObjectStreamConstants.java new file mode 100644 index 0000000..f1a4af7 --- /dev/null +++ b/libjava/classpath/java/io/ObjectStreamConstants.java @@ -0,0 +1,89 @@ +/* ObjectStreamConstants.java -- Interface containing constant values + used in reading and writing serialized objects + 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 java.io; + +/** + * This interface contains constants that are used in object + * serialization. This interface is used by ObjectOutputStream, + * ObjectInputStream, and ObjectStreamClass. + * The values for these constants are specified by the Java library + * specification. + */ +public interface ObjectStreamConstants +{ + // FIXME: Javadoc comment these values. + int PROTOCOL_VERSION_1 = 1; + int PROTOCOL_VERSION_2 = 2; + + short STREAM_MAGIC = (short)0xaced; + short STREAM_VERSION = 5; + + byte TC_NULL = (byte)112; //0x70 + byte TC_REFERENCE = (byte)113; //0x71 + byte TC_CLASSDESC = (byte)114; //0x72 + byte TC_OBJECT = (byte)115; //0x73 + byte TC_STRING = (byte)116; //0x74 + byte TC_ARRAY = (byte)117; //0x75 + byte TC_CLASS = (byte)118; //0x76 + byte TC_BLOCKDATA = (byte)119; //0x77 + byte TC_ENDBLOCKDATA = (byte)120; //0x78 + byte TC_RESET = (byte)121; //0x79 + byte TC_BLOCKDATALONG = (byte)122; //0x7A + byte TC_EXCEPTION = (byte)123; //0x7B + byte TC_LONGSTRING = (byte)124; //0x7C + byte TC_PROXYCLASSDESC = (byte)125; //0x7D + + byte TC_BASE = TC_NULL; + byte TC_MAX = TC_PROXYCLASSDESC; + + int baseWireHandle = 0x7e0000; + + byte SC_WRITE_METHOD = 0x01; + byte SC_SERIALIZABLE = 0x02; + byte SC_EXTERNALIZABLE = 0x04; + byte SC_BLOCK_DATA = 0x08; + + SerializablePermission SUBSTITUTION_PERMISSION + = new SerializablePermission("enableSubstitution"); + + SerializablePermission SUBCLASS_IMPLEMENTATION_PERMISSION + = new SerializablePermission("enableSubclassImplementation"); +} + diff --git a/libjava/classpath/java/io/ObjectStreamException.java b/libjava/classpath/java/io/ObjectStreamException.java new file mode 100644 index 0000000..61d4dd0 --- /dev/null +++ b/libjava/classpath/java/io/ObjectStreamException.java @@ -0,0 +1,74 @@ +/* ObjectStreamException.java -- Superclass of all serialization exceptions + Copyright (C) 1998, 2000, 2001, 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 java.io; + +/** + * This exception is thrown when a problem occurs during serialization. + * There are more specific subclasses that give more fine grained + * indications of the precise failure. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class ObjectStreamException extends IOException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 7260898174833392607L; + + /** + * Create an exception without a descriptive error message. + */ + protected ObjectStreamException() + { + } + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + protected ObjectStreamException(String message) + { + super(message); + } +} // class ObjectStreamException diff --git a/libjava/classpath/java/io/ObjectStreamField.java b/libjava/classpath/java/io/ObjectStreamField.java new file mode 100644 index 0000000..611457b --- /dev/null +++ b/libjava/classpath/java/io/ObjectStreamField.java @@ -0,0 +1,412 @@ +/* ObjectStreamField.java -- Class used to store name and class of fields + Copyright (C) 1998, 1999, 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 java.io; + +import gnu.java.lang.reflect.TypeSignature; + +import java.lang.reflect.Field; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * This class intends to describe the field of a class for the serialization + * subsystem. Serializable fields in a serializable class can be explicitly + * exported using an array of ObjectStreamFields. + */ +public class ObjectStreamField implements Comparable +{ + private String name; + private Class type; + private String typename; + private int offset = -1; // XXX make sure this is correct + private boolean unshared; + private boolean persistent = false; + private boolean toset = true; + private Field field; + + ObjectStreamField (Field field) + { + this (field.getName(), field.getType()); + this.field = field; + } + + /** + * This constructor creates an ObjectStreamField instance + * which represents a field named name and is + * of the type type. + * + * @param name Name of the field to export. + * @param type Type of the field in the concerned class. + */ + public ObjectStreamField (String name, Class type) + { + this (name, type, false); + } + + /** + * This constructor creates an ObjectStreamField instance + * which represents a field named name and is + * of the type type. + * + * @param name Name of the field to export. + * @param type Type of the field in the concerned class. + * @param unshared true if field will be unshared, false otherwise. + */ + public ObjectStreamField (String name, Class type, boolean unshared) + { + if (name == null) + throw new NullPointerException(); + + this.name = name; + this.type = type; + this.typename = TypeSignature.getEncodingOfClass(type); + this.unshared = unshared; + } + + /** + * There are many cases you can not get java.lang.Class from typename + * if your context class loader cannot load it, then use typename to + * construct the field. + * + * @param name Name of the field to export. + * @param typename The coded name of the type for this field. + */ + ObjectStreamField (String name, String typename) + { + this.name = name; + this.typename = typename; + try + { + type = TypeSignature.getClassForEncoding(typename); + } + catch(ClassNotFoundException e) + { + } + } + + /** + * There are many cases you can not get java.lang.Class from typename + * if your context class loader cann not load it, then use typename to + * construct the field. + * + * @param name Name of the field to export. + * @param typename The coded name of the type for this field. + * @param loader The class loader to use to resolve class names. + */ + ObjectStreamField (String name, String typename, ClassLoader loader) + { + this.name = name; + this.typename = typename; + try + { + type = TypeSignature.getClassForEncoding(typename, true, loader); + } + catch(ClassNotFoundException e) + { + } + } + + /** + * This method returns the name of the field represented by the + * ObjectStreamField instance. + * + * @return A string containing the name of the field. + */ + public String getName () + { + return name; + } + + /** + * This method returns the class representing the type of the + * field which is represented by this instance of ObjectStreamField. + * + * @return A class representing the type of the field. + */ + public Class getType () + { + return type; + } + + /** + * This method returns the char encoded type of the field which + * is represented by this instance of ObjectStreamField. + * + * @return A char representing the type of the field. + */ + public char getTypeCode () + { + return typename.charAt (0); + } + + /** + * This method returns a more explicit type name than + * {@link #getTypeCode()} in the case the type is a real + * class (and not a primitive). + * + * @return The name of the type (class name) if it is not a + * primitive, in the other case null is returned. + */ + public String getTypeString () + { + // use intern() + if (isPrimitive()) + return null; + return typename.intern(); + } + + /** + * This method returns the current offset of the field in + * the serialization stream relatively to the other fields. + * The offset is expressed in bytes. + * + * @return The offset of the field in bytes. + * @see #setOffset(int) + */ + public int getOffset () + { + return offset; + } + + /** + * This method sets the current offset of the field. + * + * @param off The offset of the field in bytes. + * @see getOffset() + */ + protected void setOffset (int off) + { + offset = off; + } + + /** + * This method returns whether the field represented by this object is + * unshared or not. + * + * @return Tells if this field is unshared or not. + */ + public boolean isUnshared () + { + return unshared; + } + + /** + * This method returns true if the type of the field + * represented by this instance is a primitive. + * + * @return true if the type is a primitive, false + * in the other case. + */ + public boolean isPrimitive () + { + return typename.length() == 1; + } + + /** + * Compares this object to the given object. + * + * @param obj the object to compare to. + * + * @return -1, 0 or 1. + */ + public int compareTo (Object obj) + { + ObjectStreamField f = (ObjectStreamField) obj; + boolean this_is_primitive = isPrimitive (); + boolean f_is_primitive = f.isPrimitive (); + + if (this_is_primitive && !f_is_primitive) + return -1; + + if (!this_is_primitive && f_is_primitive) + return 1; + + return getName ().compareTo (f.getName ()); + } + + /** + * This method is specific to classpath's implementation and so has the default + * access. It changes the state of this field to "persistent". It means that + * the field should not be changed when the stream is read (if it is not + * explicitly specified using serialPersistentFields). + * + * @param persistent True if the field is persistent, false in the + * other cases. + * @see #isPersistent() + */ + void setPersistent(boolean persistent) + { + this.persistent = persistent; + } + + /** + * This method returns true if the field is marked as persistent. + * + * @return True if persistent, false in the other cases. + * @see #setPersistent(boolean) + */ + boolean isPersistent() + { + return persistent; + } + + /** + * This method is specific to classpath's implementation and so + * has the default access. It changes the state of this field as + * to be set by ObjectInputStream. + * + * @param toset True if this field should be set, false in the other + * cases. + * @see #isToSet() + */ + void setToSet(boolean toset) + { + this.toset = toset; + } + + /** + * This method returns true if the field is marked as to be + * set. + * + * @return True if it is to be set, false in the other cases. + * @see #setToSet(boolean) + */ + boolean isToSet() + { + return toset; + } + + /** + * This method searches for its field reference in the specified class + * object. It requests privileges. If an error occurs the internal field + * reference is not modified. + * + * @throws NoSuchFieldException if the field name does not exist in this class. + * @throws SecurityException if there was an error requesting the privileges. + */ + void lookupField(Class clazz) throws NoSuchFieldException, SecurityException + { + final Field f = clazz.getDeclaredField(name); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + f.setAccessible(true); + return null; + } + }); + + this.field = f; + } + + /** + * This method check whether the field described by this + * instance of ObjectStreamField is compatible with the + * actual implementation of this field. + * + * @throws NullPointerException if this field does not exist + * in the real class. + * @throws InvalidClassException if the types are incompatible. + */ + void checkFieldType() throws InvalidClassException + { + Class ftype = field.getType(); + + if (!ftype.isAssignableFrom(type)) + throw new InvalidClassException + ("invalid field type for " + name + + " in class " + field.getDeclaringClass()); + } + + /** + * Returns a string representing this object. + * + * @return the string. + */ + public String toString () + { + return "ObjectStreamField< " + type + " " + name + " >"; + } + + final void setBooleanField(Object obj, boolean val) + { + VMObjectStreamClass.setBooleanNative(field, obj, val); + } + + final void setByteField(Object obj, byte val) + { + VMObjectStreamClass.setByteNative(field, obj, val); + } + + final void setCharField(Object obj, char val) + { + VMObjectStreamClass.setCharNative(field, obj, val); + } + + final void setShortField(Object obj, short val) + { + VMObjectStreamClass.setShortNative(field, obj, val); + } + + final void setIntField(Object obj, int val) + { + VMObjectStreamClass.setIntNative(field, obj, val); + } + + final void setLongField(Object obj, long val) + { + VMObjectStreamClass.setLongNative(field, obj, val); + } + + final void setFloatField(Object obj, float val) + { + VMObjectStreamClass.setFloatNative(field, obj, val); + } + + final void setDoubleField(Object obj, double val) + { + VMObjectStreamClass.setDoubleNative(field, obj, val); + } + + final void setObjectField(Object obj, Object val) + { + VMObjectStreamClass.setObjectNative(field, obj, val); + } +} diff --git a/libjava/classpath/java/io/OptionalDataException.java b/libjava/classpath/java/io/OptionalDataException.java new file mode 100644 index 0000000..8d8b1bd --- /dev/null +++ b/libjava/classpath/java/io/OptionalDataException.java @@ -0,0 +1,91 @@ +/* OptionalDataException.java -- indicates unexpected data in serialized stream + Copyright (C) 1998, 2000, 2001, 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 java.io; + +/** + * This exception is thrown when unexpected data appears in the input + * stream from which a serialized object is being read. There are two + * cases:
      + *
    • The next stream element is primitive data. eof will + * be false, and count is the number of bytes of primitive + * data available.
    • + *
    • The data consumable by readObject or readExternal has been exhausted. + * eof is true, and count is 0.
    • + *
    + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class OptionalDataException extends ObjectStreamException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -8011121865681257820L; + + /** + * Whether or not the end of the stream has been reached. + * + * @serial the end of the buffer was reached + */ + public boolean eof; + + /** + * The number of valid bytes that can be read. + * + * @serial the bytes of the buffer remaining + */ + public int length; + + /** + * Create a new OptionalDataException with an eof parameter indicating + * whether or not the end of stream is reached and the number of valid + * bytes that may be read. + * + * @param eof 'true' if end of stream reached, 'false' otherwise + * @param count The number of valid bytes to be read + */ + OptionalDataException(boolean eof, int count) + { + this.eof = eof; + this.length = count; + } +} // class OptionalDataException diff --git a/libjava/classpath/java/io/OutputStream.java b/libjava/classpath/java/io/OutputStream.java new file mode 100644 index 0000000..8608daa --- /dev/null +++ b/libjava/classpath/java/io/OutputStream.java @@ -0,0 +1,140 @@ +/* OutputStream.java -- Base class for byte output streams + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/** + * This abstract class forms the base of the hierarchy of classes that + * write output as a stream of bytes. It provides a common set of methods + * for writing bytes to stream. Subclasses implement and/or extend these + * methods to write bytes in a particular manner or to a particular + * destination such as a file on disk or network connection. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public abstract class OutputStream +{ + /** + * This is the default no-argument constructor for this class. This method + * does nothing in this class. + */ + public OutputStream () + { + } + + /** + * This method writes a single byte to the output stream. The byte written + * is the low eight bits of the int passed and a argument. + *

    + * Subclasses must provide an implementation of this abstract method + * + * @param b The byte to be written to the output stream, passed as + * the low eight bits of an int + * + * @exception IOException If an error occurs + */ + public abstract void write (int b) throws IOException; + + /** + * This method all the writes bytes from the passed array to the + * output stream. This method is equivalent to write(b, 0, + * buf.length) which is exactly how it is implemented in this + * class. + * + * @param b The array of bytes to write + * + * @exception IOException If an error occurs + */ + public void write (byte[] b) throws IOException, NullPointerException + { + write (b, 0, b.length); + } + + /** + * This method writes len bytes from the specified array + * b starting at index off into the array. + *

    + * This method in this class calls the single byte write() + * method in a loop until all bytes have been written. Subclasses should + * override this method if possible in order to provide a more efficent + * implementation. + * + * @param b The array of bytes to write from + * @param off The index into the array to start writing from + * @param len The number of bytes to write + * + * @exception IOException If an error occurs + */ + public void write (byte[] b, int off, int len) + throws IOException, NullPointerException, IndexOutOfBoundsException + { + if (off < 0 || len < 0 || off + len > b.length) + throw new ArrayIndexOutOfBoundsException (); + for (int i = 0; i < len; ++i) + write (b[off + i]); + } + + /** + * This method forces any data that may have been buffered to be written + * to the underlying output device. Please note that the host environment + * might perform its own buffering unbeknowst to Java. In that case, a + * write made (for example, to a disk drive) might be cached in OS + * buffers instead of actually being written to disk. + *

    + * This method in this class does nothing. + * + * @exception IOException If an error occurs + */ + public void flush () throws IOException + { + } + + /** + * This method closes the stream. Any internal or native resources + * associated with this stream are freed. Any subsequent attempt to + * access the stream might throw an exception. + *

    + * This method in this class does nothing. + * + * @exception IOException If an error occurs + */ + public void close () throws IOException + { + } +} diff --git a/libjava/classpath/java/io/OutputStreamWriter.java b/libjava/classpath/java/io/OutputStreamWriter.java new file mode 100644 index 0000000..ee229796 --- /dev/null +++ b/libjava/classpath/java/io/OutputStreamWriter.java @@ -0,0 +1,356 @@ +/* OutputStreamWriter.java -- Writer that converts chars to bytes + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +import gnu.java.nio.charset.EncodingHelper; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.MalformedInputException; +import java.nio.charset.UnsupportedCharsetException; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; + +/** + * This class writes characters to an output stream that is byte oriented + * It converts the chars that are written to bytes using an encoding layer, + * which is specific to a particular encoding standard. The desired + * encoding can either be specified by name, or if no encoding is specified, + * the system default encoding will be used. The system default encoding + * name is determined from the system property file.encoding. + * The only encodings that are guaranteed to be available are "8859_1" + * (the Latin-1 character set) and "UTF8". Unfortunately, Java does not + * provide a mechanism for listing the encodings that are supported in + * a given implementation. + *

    + * Here is a list of standard encoding names that may be available: + *

    + *

      + *
    • 8859_1 (ISO-8859-1/Latin-1) + *
    • 8859_2 (ISO-8859-2/Latin-2) + *
    • 8859_3 (ISO-8859-3/Latin-3) + *
    • 8859_4 (ISO-8859-4/Latin-4) + *
    • 8859_5 (ISO-8859-5/Latin-5) + *
    • 8859_6 (ISO-8859-6/Latin-6) + *
    • 8859_7 (ISO-8859-7/Latin-7) + *
    • 8859_8 (ISO-8859-8/Latin-8) + *
    • 8859_9 (ISO-8859-9/Latin-9) + *
    • ASCII (7-bit ASCII) + *
    • UTF8 (UCS Transformation Format-8) + *
    • More Later + *
    + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + * @date April 17, 1998. + */ +public class OutputStreamWriter extends Writer +{ + /** + * The output stream. + */ + private OutputStream out; + + /** + * The charset encoder. + */ + private CharsetEncoder encoder; + + /** + * java.io canonical name of the encoding. + */ + private String encodingName; + + /** + * Buffer output before character conversion as it has costly overhead. + */ + private CharBuffer outputBuffer; + private final static int BUFFER_SIZE = 1024; + + /** + * This method initializes a new instance of OutputStreamWriter + * to write to the specified stream using a caller supplied character + * encoding scheme. Note that due to a deficiency in the Java language + * design, there is no way to determine which encodings are supported. + * + * @param out The OutputStream to write to + * @param encoding_scheme The name of the encoding scheme to use for + * character to byte translation + * + * @exception UnsupportedEncodingException If the named encoding is + * not available. + */ + public OutputStreamWriter (OutputStream out, String encoding_scheme) + throws UnsupportedEncodingException + { + this.out = out; + try + { + // Don't use NIO if avoidable + if(EncodingHelper.isISOLatin1(encoding_scheme)) + { + encodingName = "ISO8859_1"; + encoder = null; + return; + } + + /* + * Workraround for encodings with a byte-order-mark. + * We only want to write it once per stream. + */ + try { + if(encoding_scheme.equalsIgnoreCase("UnicodeBig") || + encoding_scheme.equalsIgnoreCase("UTF-16") || + encoding_scheme.equalsIgnoreCase("UTF16")) + { + encoding_scheme = "UTF-16BE"; + out.write((byte)0xFE); + out.write((byte)0xFF); + } else if(encoding_scheme.equalsIgnoreCase("UnicodeLittle")){ + encoding_scheme = "UTF-16LE"; + out.write((byte)0xFF); + out.write((byte)0xFE); + } + } catch(IOException ioe){ + } + + outputBuffer = CharBuffer.allocate(BUFFER_SIZE); + + Charset cs = EncodingHelper.getCharset(encoding_scheme); + if(cs == null) + throw new UnsupportedEncodingException("Encoding "+encoding_scheme+ + " unknown"); + encoder = cs.newEncoder(); + encodingName = EncodingHelper.getOldCanonical(cs.name()); + + encoder.onMalformedInput(CodingErrorAction.REPLACE); + encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + } catch(RuntimeException e) { + // Default to ISO Latin-1, will happen if this is called, for instance, + // before the NIO provider is loadable. + encoder = null; + encodingName = "ISO8859_1"; + } + } + + /** + * This method initializes a new instance of OutputStreamWriter + * to write to the specified stream using the default encoding. + * + * @param out The OutputStream to write to + */ + public OutputStreamWriter (OutputStream out) + { + this.out = out; + outputBuffer = null; + try + { + String encoding = System.getProperty("file.encoding"); + Charset cs = Charset.forName(encoding); + encoder = cs.newEncoder(); + encodingName = EncodingHelper.getOldCanonical(cs.name()); + } catch(RuntimeException e) { + encoder = null; + encodingName = "ISO8859_1"; + } + if(encoder != null) + { + encoder.onMalformedInput(CodingErrorAction.REPLACE); + encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + outputBuffer = CharBuffer.allocate(BUFFER_SIZE); + } + } + + /** + * This method closes this stream, and the underlying + * OutputStream + * + * @exception IOException If an error occurs + */ + public void close () throws IOException + { + if(out == null) + return; + flush(); + out.close (); + out = null; + } + + /** + * This method returns the name of the character encoding scheme currently + * in use by this stream. If the stream has been closed, then this method + * may return null. + * + * @return The encoding scheme name + */ + public String getEncoding () + { + return out != null ? encodingName : null; + } + + /** + * This method flushes any buffered bytes to the underlying output sink. + * + * @exception IOException If an error occurs + */ + public void flush () throws IOException + { + if(out != null){ + if(outputBuffer != null){ + char[] buf = new char[outputBuffer.position()]; + if(buf.length > 0){ + outputBuffer.flip(); + outputBuffer.get(buf); + writeConvert(buf, 0, buf.length); + outputBuffer.clear(); + } + } + out.flush (); + } + } + + /** + * This method writes count characters from the specified + * array to the output stream starting at position offset + * into the array. + * + * @param buf The array of character to write from + * @param offset The offset into the array to start writing chars from + * @param count The number of chars to write. + * + * @exception IOException If an error occurs + */ + public void write (char[] buf, int offset, int count) throws IOException + { + if(out == null) + throw new IOException("Stream is closed."); + if(buf == null) + throw new IOException("Buffer is null."); + + if(outputBuffer != null) + { + if(count >= outputBuffer.remaining()) + { + int r = outputBuffer.remaining(); + outputBuffer.put(buf, offset, r); + writeConvert(outputBuffer.array(), 0, BUFFER_SIZE); + outputBuffer.clear(); + offset += r; + count -= r; + // if the remaining bytes is larger than the whole buffer, + // just don't buffer. + if(count >= outputBuffer.remaining()){ + writeConvert(buf, offset, count); + return; + } + } + outputBuffer.put(buf, offset, count); + } else writeConvert(buf, offset, count); + } + + /** + * Converts and writes characters. + */ + private void writeConvert (char[] buf, int offset, int count) + throws IOException + { + if(encoder == null) + { + byte[] b = new byte[count]; + for(int i=0;icount
    bytes from the specified + * String starting at position offset into the + * String. + * + * @param str The String to write chars from + * @param offset The position in the String to start + * writing chars from + * @param count The number of chars to write + * + * @exception IOException If an error occurs + */ + public void write (String str, int offset, int count) throws IOException + { + if(str == null) + throw new IOException("String is null."); + + write(str.toCharArray(), offset, count); + } + + /** + * This method writes a single character to the output stream. + * + * @param ch The char to write, passed as an int. + * + * @exception IOException If an error occurs + */ + public void write (int ch) throws IOException + { + write(new char[]{ (char)ch }, 0, 1); + } +} // class OutputStreamWriter + diff --git a/libjava/classpath/java/io/PipedInputStream.java b/libjava/classpath/java/io/PipedInputStream.java new file mode 100644 index 0000000..beb310b --- /dev/null +++ b/libjava/classpath/java/io/PipedInputStream.java @@ -0,0 +1,374 @@ +/* PipedInputStream.java -- Read portion of piped streams. + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +// NOTE: This implementation is very similar to that of PipedReader. If you +// fix a bug in here, chances are you should make a similar change to the +// PipedReader code. + +/** + * An input stream that reads its bytes from an output stream + * to which it is connected. + *

    + * Data is read and written to an internal buffer. It is highly recommended + * that the PipedInputStream and connected + * PipedOutputStream + * be part of different threads. If they are not, the read and write + * operations could deadlock their thread. + * + * @specnote The JDK implementation appears to have some undocumented + * functionality where it keeps track of what thread is writing + * to pipe and throws an IOException if that thread susequently + * dies. This behaviour seems dubious and unreliable - we don't + * implement it. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PipedInputStream extends InputStream +{ + /** PipedOutputStream to which this is connected. Null only if this + * InputStream hasn't been connected yet. */ + PipedOutputStream source; + + /** Set to true if close() has been called on this InputStream. */ + boolean closed; + + + /** + * The size of the internal buffer used for input/output. + */ + /* The "Constant Field Values" Javadoc of the Sun J2SE 1.4 + * specifies 1024. + */ + protected static final int PIPE_SIZE = 1024; + + + /** + * This is the internal circular buffer used for storing bytes written + * to the pipe and from which bytes are read by this stream + */ + protected byte[] buffer = new byte[PIPE_SIZE]; + + /** + * The index into buffer where the next byte from the connected + * PipedOutputStream will be written. If this variable is + * equal to out, then the buffer is full. If set to < 0, + * the buffer is empty. + */ + protected int in = -1; + + /** + * This index into the buffer where bytes will be read from. + */ + protected int out = 0; + + /** Buffer used to implement single-argument read/receive */ + private byte[] read_buf = new byte[1]; + + /** + * Creates a new PipedInputStream that is not connected to a + * PipedOutputStream. It must be connected before bytes can + * be read from this stream. + */ + public PipedInputStream() + { + } + + /** + * This constructor creates a new PipedInputStream and connects + * it to the passed in PipedOutputStream. The stream is then + * ready for reading. + * + * @param source The PipedOutputStream to connect this + * stream to + * + * @exception IOException If source is already connected. + */ + public PipedInputStream(PipedOutputStream source) throws IOException + { + connect(source); + } + + /** + * This method connects this stream to the passed in + * PipedOutputStream. + * This stream is then ready for reading. If this stream is already + * connected or has been previously closed, then an exception is thrown + * + * @param src The PipedOutputStream to connect this stream to + * + * @exception IOException If this PipedInputStream or source + * has been connected already. + */ + public void connect(PipedOutputStream source) throws IOException + { + // The JDK (1.3) does not appear to check for a previously closed + // connection here. + + if (this.source != null || source.sink != null) + throw new IOException ("Already connected"); + + source.sink = this; + this.source = source; + } + + /** + * This method receives a byte of input from the source PipedOutputStream. + * If the internal circular buffer is full, this method blocks. + * + * @param val The byte to write to this stream + * + * @exception IOException if error occurs + * @specnote Weird. This method must be some sort of accident. + */ + protected synchronized void receive(int val) throws IOException + { + read_buf[0] = (byte) (val & 0xff); + receive (read_buf, 0, 1); + } + + /** + * This method is used by the connected PipedOutputStream to + * write bytes into the buffer. + * + * @param buf The array containing bytes to write to this stream + * @param offset The offset into the array to start writing from + * @param len The number of bytes to write. + * + * @exception IOException If an error occurs + * @specnote This code should be in PipedOutputStream.write, but we + * put it here in order to support that bizarre recieve(int) + * method. + */ + synchronized void receive(byte[] buf, int offset, int len) + throws IOException + { + if (closed) + throw new IOException ("Pipe closed"); + + int bufpos = offset; + int copylen; + + while (len > 0) + { + try + { + while (in == out) + { + // The pipe is full. Wake up any readers and wait for them. + notifyAll(); + wait(); + // The pipe could have been closed while we were waiting. + if (closed) + throw new IOException ("Pipe closed"); + } + } + catch (InterruptedException ix) + { + throw new InterruptedIOException (); + } + + if (in < 0) // The pipe is empty. + in = 0; + + // Figure out how many bytes from buf can be copied without + // overrunning out or going past the length of the buffer. + if (in < out) + copylen = Math.min (len, out - in); + else + copylen = Math.min (len, buffer.length - in); + + // Copy bytes until the pipe is filled, wrapping if necessary. + System.arraycopy(buf, bufpos, buffer, in, copylen); + len -= copylen; + bufpos += copylen; + in += copylen; + if (in == buffer.length) + in = 0; + } + // Notify readers that new data is in the pipe. + notifyAll(); + } + + /** + * This method reads one byte from the stream. + * -1 is returned to indicated that no bytes can be read + * because the end of the stream was reached. If the stream is already + * closed, a -1 will again be returned to indicate the end of the stream. + * + *

    This method will block if no byte is available to be read.

    + * + * @return the value of the read byte value, or -1 of the end of the stream + * was reached + * + * @throws IOException if an error occured + */ + public int read() throws IOException + { + // Method operates by calling the multibyte overloaded read method + // Note that read_buf is an internal instance variable. I allocate it + // there to avoid constant reallocation overhead for applications that + // call this method in a loop at the cost of some unneeded overhead + // if this method is never called. + + int r = read(read_buf, 0, 1); + return r != -1 ? (read_buf[0] & 0xff) : -1; + } + + /** + * This method reads bytes from the stream into a caller supplied buffer. + * It starts storing bytes at position offset into the + * buffer and + * reads a maximum of len bytes. Note that this method + * can actually + * read fewer than len bytes. The actual number of bytes + * read is + * returned. A -1 is returned to indicated that no bytes can be read + * because the end of the stream was reached - ie close() was called on the + * connected PipedOutputStream. + *

    + * This method will block if no bytes are available to be read. + * + * @param buf The buffer into which bytes will be stored + * @param offset The index into the buffer at which to start writing. + * @param len The maximum number of bytes to read. + * + * @exception IOException If close() was called on this Piped + * InputStream. + */ + public synchronized int read(byte[] buf, int offset, int len) + throws IOException + { + if (source == null) + throw new IOException ("Not connected"); + if (closed) + throw new IOException ("Pipe closed"); + + // If the buffer is empty, wait until there is something in the pipe + // to read. + try + { + while (in < 0) + { + if (source.closed) + return -1; + wait(); + } + } + catch (InterruptedException ix) + { + throw new InterruptedIOException(); + } + + int total = 0; + int copylen; + + while (true) + { + // Figure out how many bytes from the pipe can be copied without + // overrunning in or going past the length of buf. + if (out < in) + copylen = Math.min (len, in - out); + else + copylen = Math.min (len, buffer.length - out); + + System.arraycopy (buffer, out, buf, offset, copylen); + offset += copylen; + len -= copylen; + out += copylen; + total += copylen; + + if (out == buffer.length) + out = 0; + + if (out == in) + { + // Pipe is now empty. + in = -1; + out = 0; + } + + // If output buffer is filled or the pipe is empty, we're done. + if (len == 0 || in == -1) + { + // Notify any waiting outputstream that there is now space + // to write. + notifyAll(); + return total; + } + } + } + + /** + * This method returns the number of bytes that can be read from this stream + * before blocking could occur. This is the number of bytes that are + * currently unread in the internal circular buffer. Note that once this + * many additional bytes are read, the stream may block on a subsequent + * read, but it not guaranteed to block. + * + * @return The number of bytes that can be read before blocking might occur + * + * @exception IOException If an error occurs + */ + public synchronized int available() throws IOException + { + // The JDK 1.3 implementation does not appear to check for the closed or + // unconnected stream conditions here. + + if (in < 0) + return 0; + else if (out < in) + return in - out; + else + return (buffer.length - out) + in; + } + + /** + * This methods closes the stream so that no more data can be read + * from it. + * + * @exception IOException If an error occurs + */ + public synchronized void close() throws IOException + { + closed = true; + // Wake any thread which may be in receive() waiting to write data. + notifyAll(); + } +} + diff --git a/libjava/classpath/java/io/PipedOutputStream.java b/libjava/classpath/java/io/PipedOutputStream.java new file mode 100644 index 0000000..8188105 --- /dev/null +++ b/libjava/classpath/java/io/PipedOutputStream.java @@ -0,0 +1,181 @@ +/* PipedOutputStream.java -- Write portion of piped streams. + Copyright (C) 1998, 2000, 2001, 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 java.io; + +// NOTE: This implementation is very similar to that of PipedWriter. If you +// fix a bug in here, chances are you should make a similar change to the +// PipedWriter code. + +/** + * This class writes its bytes to a PipedInputStream to + * which it is connected. + *

    + * It is highly recommended that a PipedOutputStream and its + * connected PipedInputStream be in different threads. If + * they are in the same thread, read and write operations could deadlock + * the thread. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PipedOutputStream extends OutputStream +{ + /** Target PipedInputStream to which this is connected. Null only if this + * OutputStream hasn't been connected yet. */ + PipedInputStream sink; + + /** Set to true if close() has been called on this OutputStream. */ + boolean closed; + + /** + * Create an unconnected PipedOutputStream. It must be connected + * to a PipedInputStream using the connect + * method prior to writing any data or an exception will be thrown. + */ + public PipedOutputStream() + { + } + + /** + * Create a new PipedOutputStream instance + * to write to the specified PipedInputStream. This stream + * is then ready for writing. + * + * @param sink The PipedInputStream to connect this stream to. + * + * @exception IOException If sink has already been connected + * to a different PipedOutputStream. + */ + public PipedOutputStream(PipedInputStream sink) throws IOException + { + sink.connect(this); + } + + /** + * Connects this object to the specified PipedInputStream + * object. This stream will then be ready for writing. + * + * @param sink The PipedInputStream to connect this stream to + * + * @exception IOException If the stream has not been connected or has + * been closed. + */ + public void connect(PipedInputStream sink) throws IOException + { + if (this.sink != null || sink.source != null) + throw new IOException ("Already connected"); + sink.connect(this); + } + + /** + * Write a single byte of date to the stream. Note that this method will + * block if the PipedInputStream to which this object is + * connected has a full buffer. + * + * @param b The byte of data to be written, passed as an int. + * + * @exception IOException If the stream has not been connected or has + * been closed. + */ + public void write(int b) throws IOException + { + if (sink == null) + throw new IOException ("Not connected"); + if (closed) + throw new IOException ("Pipe closed"); + + sink.receive (b); + } + + /** + * This method writes len bytes of data from the byte array + * buf starting at index offset in the array + * to the stream. Note that this method will block if the + * PipedInputStream to which this object is connected has + * a buffer that cannot hold all of the bytes to be written. + * + * @param buffer The array containing bytes to write to the stream. + * @param offset The index into the array to start writing bytes from. + * @param len The number of bytes to write. + * + * @exception IOException If the stream has not been connected or has + * been closed. + */ + public void write(byte[] buffer, int offset, int len) throws IOException + { + if (sink == null) + throw new IOException ("Not connected"); + if (closed) + throw new IOException ("Pipe closed"); + + sink.receive(buffer, offset, len); + } + + /** + * This method does nothing. + * + * @exception IOException If the stream is closed. + * @specnote You'd think that this method would block until the sink + * had read all available data. Thats not the case - this method + * appears to be a no-op? + */ + public void flush() throws IOException + { + } + + /** + * This method closes this stream so that no more data can be written + * to it. Any further attempts to write to this stream may throw an + * exception + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + // A close call on an unconnected PipedOutputStream has no effect. + if (sink != null) + { + closed = true; + // Notify any waiting readers that the stream is now closed. + synchronized (sink) + { + sink.notifyAll(); + } + } + } +} diff --git a/libjava/classpath/java/io/PipedReader.java b/libjava/classpath/java/io/PipedReader.java new file mode 100644 index 0000000..90fc10f --- /dev/null +++ b/libjava/classpath/java/io/PipedReader.java @@ -0,0 +1,361 @@ +/* PipedReader.java -- Read portion of piped character streams. + Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +// NOTE: This implementation is very similar to that of PipedInputStream. +// If you fix a bug in here, chances are you should make a similar change to +// the PipedInputStream code. + +/** + * An input stream that reads characters from a piped writer to which it is + * connected. + *

    + * Data is read and written to an internal buffer. It is highly recommended + * that the PipedReader and connected PipedWriter + * be part of different threads. If they are not, there is a possibility + * that the read and write operations could deadlock their thread. + * + * @specnote The JDK implementation appears to have some undocumented + * functionality where it keeps track of what thread is writing + * to pipe and throws an IOException if that thread susequently + * dies. This behaviour seems dubious and unreliable - we don't + * implement it. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PipedReader extends Reader +{ + /** PipedWriter to which this is connected. Null only if this + * Reader hasn't been connected yet. */ + PipedWriter source; + + /** Set to true if close() has been called on this Reader. */ + boolean closed; + + /** + * The size of the internal buffer used for input/output. + */ + static final int PIPE_SIZE = 2048; + + /** + * This is the internal circular buffer used for storing chars written + * to the pipe and from which chars are read by this stream + */ + char[] buffer = new char[PIPE_SIZE]; + + /** + * The index into buffer where the next char from the connected + * PipedWriter will be written. If this variable is + * equal to out, then the buffer is full. If set to < 0, + * the buffer is empty. + */ + int in = -1; + + /** + * This index into the buffer where chars will be read from. + */ + int out = 0; + + /** Buffer used to implement single-argument read/receive */ + char[] read_buf = new char[1]; + + /** + * Creates a new PipedReader that is not connected to a + * PipedWriter. It must be connected before chars can + * be read from this stream. + */ + public PipedReader() + { + } + + /** + * This constructor creates a new PipedReader and connects + * it to the passed in PipedWriter. The stream is then + * ready for reading. + * + * @param source The PipedWriter to connect this stream to + * + * @exception IOException If source is already connected. + */ + public PipedReader(PipedWriter source) throws IOException + { + connect(source); + } + + /** + * This method connects this stream to the passed in + * PipedWriter. + * This stream is then ready for reading. If this stream is already + * connected or has been previously closed, then an exception is thrown + * + * @param source The PipedWriter to connect this stream to + * + * @exception IOException If this PipedReader or source + * has been connected already. + */ + public void connect(PipedWriter source) throws IOException + { + // The JDK (1.3) does not appear to check for a previously closed + // connection here. + + if (this.source != null || source.sink != null) + throw new IOException ("Already connected"); + + source.sink = this; + this.source = source; + } + + /** + * This method is used by the connected PipedWriter to + * write chars into the buffer. + * + * @param buf The array containing chars to write to this stream + * @param offset The offset into the array to start writing from + * @param len The number of chars to write. + * + * @exception IOException If an error occurs + * @specnote This code should be in PipedWriter.write, but we + * put it here in order to support that bizarre recieve(int) + * method. + */ + void receive(char[] buf, int offset, int len) + throws IOException + { + synchronized (lock) + { + if (closed) + throw new IOException ("Pipe closed"); + + int bufpos = offset; + int copylen; + + while (len > 0) + { + try + { + while (in == out) + { + // The pipe is full. Wake up any readers and wait for them. + lock.notifyAll(); + lock.wait(); + // The pipe could have been closed while we were waiting. + if (closed) + throw new IOException ("Pipe closed"); + } + } + catch (InterruptedException ix) + { + throw new InterruptedIOException (); + } + + if (in < 0) // The pipe is empty. + in = 0; + + // Figure out how many chars from buf can be copied without + // overrunning out or going past the length of the buffer. + if (in < out) + copylen = Math.min (len, out - in); + else + copylen = Math.min (len, buffer.length - in); + + // Copy chars until the pipe is filled, wrapping if necessary. + System.arraycopy(buf, bufpos, buffer, in, copylen); + len -= copylen; + bufpos += copylen; + in += copylen; + if (in == buffer.length) + in = 0; + } + // Notify readers that new data is in the pipe. + lock.notifyAll(); + } + } + + /** + * This method reads chars from the stream into a caller supplied buffer. + * It starts storing chars at position offset into the + * buffer and + * reads a maximum of len chars. Note that this method + * can actually + * read fewer than len chars. The actual number of chars + * read is + * returned. A -1 is returned to indicated that no chars can be read + * because the end of the stream was reached. If the stream is already + * closed, a -1 will again be returned to indicate the end of the stream. + *

    + * This method will block if no char is available to be read. + */ + public int read() throws IOException + { + // Method operates by calling the multichar overloaded read method + // Note that read_buf is an internal instance variable. I allocate it + // there to avoid constant reallocation overhead for applications that + // call this method in a loop at the cost of some unneeded overhead + // if this method is never called. + + int r = read(read_buf, 0, 1); + return r != -1 ? read_buf[0] : -1; + } + + /** + * This method reads characters from the stream into a caller supplied + * buffer. It starts storing chars at position offset into + * the buffer and reads a maximum of len chars. Note that + * this method can actually read fewer than len chars. + * The actual number of chars read is + * returned. A -1 is returned to indicated that no chars can be read + * because the end of the stream was reached - ie close() was called on the + * connected PipedWriter. + *

    + * This method will block if no chars are available to be read. + * + * @param buf The buffer into which chars will be stored + * @param offset The index into the buffer at which to start writing. + * @param len The maximum number of chars to read. + * + * @exception IOException If close() was called on this Piped + * Reader. + */ + public int read(char[] buf, int offset, int len) + throws IOException + { + synchronized (lock) + { + if (source == null) + throw new IOException ("Not connected"); + if (closed) + throw new IOException ("Pipe closed"); + + // If the buffer is empty, wait until there is something in the pipe + // to read. + try + { + while (in < 0) + { + if (source.closed) + return -1; + lock.wait(); + } + } + catch (InterruptedException ix) + { + throw new InterruptedIOException(); + } + + int total = 0; + int copylen; + + while (true) + { + // Figure out how many chars from the pipe can be copied without + // overrunning in or going past the length of buf. + if (out < in) + copylen = Math.min (len, in - out); + else + copylen = Math.min (len, buffer.length - out); + + System.arraycopy (buffer, out, buf, offset, copylen); + offset += copylen; + len -= copylen; + out += copylen; + total += copylen; + + if (out == buffer.length) + out = 0; + + if (out == in) + { + // Pipe is now empty. + in = -1; + out = 0; + } + + // If output buffer is filled or the pipe is empty, we're done. + if (len == 0 || in == -1) + { + // Notify any waiting Writer that there is now space + // to write. + lock.notifyAll(); + return total; + } + } + } + } + + public boolean ready() throws IOException + { + // The JDK 1.3 implementation does not appear to check for the closed or + // unconnected stream conditions here. However, checking for a + // closed stream is explicitly required by the JDK 1.2 and 1.3 + // documentation (for Reader.close()), so we do it. + + synchronized (lock) + { + if (closed) + throw new IOException("Pipe closed"); + + if (in < 0) + return false; + + int count; + if (out < in) + count = in - out; + else + count = (buffer.length - out) - in; + + return (count > 0); + } + } + + /** + * This methods closes the stream so that no more data can be read + * from it. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + synchronized (lock) + { + closed = true; + // Wake any thread which may be in receive() waiting to write data. + lock.notifyAll(); + } + } +} + diff --git a/libjava/classpath/java/io/PipedWriter.java b/libjava/classpath/java/io/PipedWriter.java new file mode 100644 index 0000000..92786e5 --- /dev/null +++ b/libjava/classpath/java/io/PipedWriter.java @@ -0,0 +1,182 @@ +/* PipedWriter.java -- Write portion of piped character streams. + Copyright (C) 1998, 2000, 2001, 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 java.io; + +// NOTE: This implementation is very similar to that of PipedOutputStream. +// If you fix a bug in here, chances are you should make a similar change to +// the PipedOutputStream code. + +/** + * This class writes its chars to a PipedReader to + * which it is connected. + *

    + * It is highly recommended that a PipedWriter and its + * connected PipedReader be in different threads. If + * they are in the same thread, read and write operations could deadlock + * the thread. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PipedWriter extends Writer +{ + /** Target PipedReader to which this is connected. Null only if this + * Writer hasn't been connected yet. */ + PipedReader sink; + + /** Set to true if close() has been called on this Writer. */ + boolean closed; + + /** Buffer used to implement single-argument write */ + char[] read_buf = new char[1]; + + /** + * Create an unconnected PipedWriter. It must be connected + * to a PipedReader using the connect + * method prior to writing any data or an exception will be thrown. + */ + public PipedWriter() + { + } + + /** + * Create a new PipedWriter instance + * to write to the specified PipedReader. This stream + * is then ready for writing. + * + * @param sink The PipedReader to connect this stream to. + * + * @exception IOException If sink has already been connected + * to a different PipedWriter. + */ + public PipedWriter(PipedReader sink) throws IOException + { + sink.connect(this); + } + + /** + * Connects this object to the specified PipedReader + * object. This stream will then be ready for writing. + * + * @param sink The PipedReader to connect this stream to + * + * @exception IOException If the stream has not been connected or has + * been closed. + */ + public void connect(PipedReader sink) throws IOException + { + if (this.sink != null || sink.source != null) + throw new IOException ("Already connected"); + sink.connect(this); + } + + /** + * Write a single char of date to the stream. Note that this method will + * block if the PipedReader to which this object is + * connected has a full buffer. + * + * @param b The char of data to be written, passed as an int. + * + * @exception IOException If the stream has not been connected or has + * been closed. + */ + public void write(int b) throws IOException + { + read_buf[0] = (char) (b & 0xffff); + sink.receive (read_buf, 0, 1); + } + + /** + * This method writes len chars of data from the char array + * buf starting at index offset in the array + * to the stream. Note that this method will block if the + * PipedReader to which this object is connected has + * a buffer that cannot hold all of the chars to be written. + * + * @param buffer The array containing chars to write to the stream. + * @param offset The index into the array to start writing chars from. + * @param len The number of chars to write. + * + * @exception IOException If the stream has not been connected or has + * been closed. + */ + public void write(char[] buffer, int offset, int len) throws IOException + { + if (sink == null) + throw new IOException ("Not connected"); + if (closed) + throw new IOException ("Pipe closed"); + + sink.receive(buffer, offset, len); + } + + /** + * This method does nothing. + * + * @exception IOException If the stream is closed. + * @specnote You'd think that this method would block until the sink + * had read all available data. Thats not the case - this method + * appears to be a no-op? + */ + public void flush() throws IOException + { + if (closed) + throw new IOException ("Pipe closed"); + } + + /** + * This method closes this stream so that no more data can be written + * to it. Any further attempts to write to this stream may throw an + * exception + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + // A close call on an unconnected PipedWriter has no effect. + if (sink != null) + { + closed = true; + // Notify any waiting readers that the stream is now closed. + synchronized (sink) + { + sink.notifyAll(); + } + } + } +} diff --git a/libjava/classpath/java/io/PrintStream.java b/libjava/classpath/java/io/PrintStream.java new file mode 100644 index 0000000..8e50559 --- /dev/null +++ b/libjava/classpath/java/io/PrintStream.java @@ -0,0 +1,553 @@ +/* PrintStream.java -- OutputStream for printing output + Copyright (C) 1998, 1999, 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 java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Believed complete and correct to 1.3 + */ + +/** + * This class prints Java primitive values and object to a stream as + * text. None of the methods in this class throw an exception. However, + * errors can be detected by calling the checkError() method. + * Additionally, this stream can be designated as "autoflush" when + * created so that any writes are automatically flushed to the underlying + * output sink when the current line is terminated. + *

    + * This class converts char's into byte's using the system default encoding. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class PrintStream extends FilterOutputStream +{ + /* Notice the implementation is quite similar to OutputStreamWriter. + * This leads to some minor duplication, because neither inherits + * from the other, and we want to maximize performance. */ + + // Line separator string. + private static final char[] line_separator + = System.getProperty("line.separator").toCharArray(); + + /** + * Encoding name + */ + private String encoding; + + /** + * This boolean indicates whether or not an error has ever occurred + * on this stream. + */ + private boolean error_occurred = false; + + /** + * This is true if auto-flush is enabled, + * false otherwise + */ + private boolean auto_flush; + + /** + * This method intializes a new PrintStream object to write + * to the specified output sink. + * + * @param out The OutputStream to write to. + */ + public PrintStream (OutputStream out) + { + this (out, false); + } + + /** + * This method intializes a new PrintStream object to write + * to the specified output sink. This constructor also allows "auto-flush" + * functionality to be specified where the stream will be flushed after + * every print or println call, when the + * write methods with array arguments are called, or when a + * single new-line character is written. + *

    + * + * @param out The OutputStream to write to. + * @param auto_flush true to flush the stream after every + * line, false otherwise + */ + public PrintStream (OutputStream out, boolean auto_flush) + { + super (out); + + try { + this.encoding = System.getProperty("file.encoding"); + } catch (SecurityException e){ + this.encoding = "ISO8859_1"; + } catch (IllegalArgumentException e){ + this.encoding = "ISO8859_1"; + } catch (NullPointerException e){ + this.encoding = "ISO8859_1"; + } + this.auto_flush = auto_flush; + } + + /** + * This method intializes a new PrintStream object to write + * to the specified output sink. This constructor also allows "auto-flush" + * functionality to be specified where the stream will be flushed after + * every print or println call, when the + * write methods with array arguments are called, or when a + * single new-line character is written. + *

    + * + * @param out The OutputStream to write to. + * @param auto_flush true to flush the stream after every + * line, false otherwise + * @param encoding The name of the character encoding to use for this + * object. + */ + public PrintStream (OutputStream out, boolean auto_flush, String encoding) + throws UnsupportedEncodingException + { + super (out); + + new String(new byte[]{0}, encoding); // check if encoding is supported + this.encoding = encoding; + this.auto_flush = auto_flush; + } + + /** + * This method checks to see if an error has occurred on this stream. Note + * that once an error has occurred, this method will continue to report + * true forever for this stream. Before checking for an + * error condition, this method flushes the stream. + * + * @return true if an error has occurred, + * false otherwise + */ + public boolean checkError () + { + flush (); + return error_occurred; + } + + /** + * This method can be called by subclasses to indicate that an error + * has occurred and should be reported by checkError. + */ + protected void setError () + { + error_occurred = true; + } + + /** + * This method closes this stream and all underlying streams. + */ + public void close () + { + try + { + flush(); + out.close(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + } + } + + /** + * This method flushes any buffered bytes to the underlying stream and + * then flushes that stream as well. + */ + public void flush () + { + try + { + out.flush(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + } + } + + private synchronized void print (String str, boolean println) + { + try + { + writeChars(str, 0, str.length()); + if (println) + writeChars(line_separator, 0, line_separator.length); + if (auto_flush) + flush(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + } + } + + private synchronized void print (char[] chars, int pos, int len, + boolean println) + { + try + { + writeChars(chars, pos, len); + if (println) + writeChars(line_separator, 0, line_separator.length); + if (auto_flush) + flush(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + } + } + + private void writeChars(char[] buf, int offset, int count) + throws IOException + { + byte[] bytes = (new String(buf, offset, count)).getBytes(encoding); + out.write(bytes, 0, bytes.length); + } + + private void writeChars(String str, int offset, int count) + throws IOException + { + byte[] bytes = str.substring(offset, offset+count).getBytes(encoding); + out.write(bytes, 0, bytes.length); + } + + /** + * This methods prints a boolean value to the stream. true + * values are printed as "true" and false values are printed + * as "false". + * + * @param bool The boolean value to print + */ + public void print (boolean bool) + { + print(String.valueOf(bool), false); + } + + /** + * This method prints an integer to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param inum The int value to be printed + */ + public void print (int inum) + { + print(String.valueOf(inum), false); + } + + /** + * This method prints a long to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param lnum The long value to be printed + */ + public void print (long lnum) + { + print(String.valueOf(lnum), false); + } + + /** + * This method prints a float to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param fnum The float value to be printed + */ + public void print (float fnum) + { + print(String.valueOf(fnum), false); + } + + /** + * This method prints a double to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param dnum The double value to be printed + */ + public void print (double dnum) + { + print(String.valueOf(dnum), false); + } + + /** + * This method prints an Object to the stream. The actual + * value printed is determined by calling the String.valueOf() + * method. + * + * @param obj The Object to print. + */ + public void print (Object obj) + { + print(obj == null ? "null" : obj.toString(), false); + } + + /** + * This method prints a String to the stream. The actual + * value printed depends on the system default encoding. + * + * @param str The String to print. + */ + public void print (String str) + { + print(str == null ? "null" : str, false); + } + + /** + * This method prints a char to the stream. The actual value printed is + * determined by the character encoding in use. + * + * @param ch The char value to be printed + */ + public synchronized void print (char ch) + { + print(new char[]{ch}, 0, 1, false); + } + + /** + * This method prints an array of characters to the stream. The actual + * value printed depends on the system default encoding. + * + * @param charArray The array of characters to print. + */ + public void print (char[] charArray) + { + print(charArray, 0, charArray.length, false); + } + + /** + * This method prints a line separator sequence to the stream. The value + * printed is determined by the system property

    line.separator + * and is not necessarily the Unix '\n' newline character. + */ + public void println () + { + print(line_separator, 0, line_separator.length, false); + } + + /** + * This methods prints a boolean value to the stream. true + * values are printed as "true" and false values are printed + * as "false". + *

    + * This method prints a line termination sequence after printing the value. + * + * @param bool The boolean value to print + */ + public void println (boolean bool) + { + print(String.valueOf(bool), true); + } + + /** + * This method prints an integer to the stream. The value printed is + * determined using the String.valueOf() method. + *

    + * This method prints a line termination sequence after printing the value. + * + * @param inum The int value to be printed + */ + public void println (int inum) + { + print(String.valueOf(inum), true); + } + + /** + * This method prints a long to the stream. The value printed is + * determined using the String.valueOf() method. + *

    + * This method prints a line termination sequence after printing the value. + * + * @param lnum The long value to be printed + */ + public void println (long lnum) + { + print(String.valueOf(lnum), true); + } + + /** + * This method prints a float to the stream. The value printed is + * determined using the String.valueOf() method. + *

    + * This method prints a line termination sequence after printing the value. + * + * @param fnum The float value to be printed + */ + public void println (float fnum) + { + print(String.valueOf(fnum), true); + } + + /** + * This method prints a double to the stream. The value printed is + * determined using the String.valueOf() method. + *

    + * This method prints a line termination sequence after printing the value. + * + * @param dnum The double value to be printed + */ + public void println (double dnum) + { + print(String.valueOf(dnum), true); + } + + /** + * This method prints an Object to the stream. The actual + * value printed is determined by calling the String.valueOf() + * method. + *

    + * This method prints a line termination sequence after printing the value. + * + * @param obj The Object to print. + */ + public void println (Object obj) + { + print(obj == null ? "null" : obj.toString(), true); + } + + /** + * This method prints a String to the stream. The actual + * value printed depends on the system default encoding. + *

    + * This method prints a line termination sequence after printing the value. + * + * @param str The String to print. + */ + public void println (String str) + { + print (str == null ? "null" : str, true); + } + + /** + * This method prints a char to the stream. The actual value printed is + * determined by the character encoding in use. + *

    + * This method prints a line termination sequence after printing the value. + * + * @param ch The char value to be printed + */ + public synchronized void println (char ch) + { + print(new char[]{ch}, 0, 1, true); + } + + /** + * This method prints an array of characters to the stream. The actual + * value printed depends on the system default encoding. + *

    + * This method prints a line termination sequence after printing the value. + * + * @param charArray The array of characters to print. + */ + public void println (char[] charArray) + { + print(charArray, 0, charArray.length, true); + } + + /** + * This method writes a byte of data to the stream. If auto-flush is + * enabled, printing a newline character will cause the stream to be + * flushed after the character is written. + * + * @param oneByte The byte to be written + */ + public void write (int oneByte) + { + try + { + out.write (oneByte & 0xff); + + if (auto_flush && (oneByte == '\n')) + flush (); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread ().interrupt (); + } + catch (IOException e) + { + setError (); + } + } + + /** + * This method writes len bytes from the specified array + * starting at index offset into the array. + * + * @param buffer The array of bytes to write + * @param offset The index into the array to start writing from + * @param len The number of bytes to write + */ + public void write (byte[] buffer, int offset, int len) + { + try + { + out.write (buffer, offset, len); + + if (auto_flush) + flush (); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread ().interrupt (); + } + catch (IOException e) + { + setError (); + } + } +} // class PrintStream + diff --git a/libjava/classpath/java/io/PrintWriter.java b/libjava/classpath/java/io/PrintWriter.java new file mode 100644 index 0000000..5fd0b16 --- /dev/null +++ b/libjava/classpath/java/io/PrintWriter.java @@ -0,0 +1,571 @@ +/* PrintWriter.java -- prints primitive values and objects to a stream as text + Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + * However, should use native methods for conversion. + */ + +/** + * This class prints Java primitive values and objects to a stream as + * text. None of the methods in this class throw an exception. However, + * errors can be detected by calling the checkError() method. + * Additionally, this stream can be designated as "autoflush" when + * created so that any writes are automatically flushed to the underlying + * output sink whenever one of the println methods is + * called. (Note that this differs from the PrintStream + * class which also auto-flushes when it encounters a newline character + * in the chars written). + * + * @author Per Bothner (bothner@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @date April 17, 1998. + */ +public class PrintWriter extends Writer +{ + /** + * true if auto-flush is enabled, false otherwise + */ + private boolean autoflush; + + /** + * This boolean indicates whether or not an error has ever occurred + * on this stream. + */ + private boolean error; + + /** + * This is the underlying Writer we are sending output + * to + */ + protected Writer out; + + /** + * This method intializes a new PrintWriter object to write + * to the specified output sink. The form of the constructor does not + * enable auto-flush functionality. + * + * @param wr The Writer to write to. + */ + public PrintWriter(Writer wr) + { + super(wr.lock); + this.out = wr; + } + + /** + * This method intializes a new PrintWriter object to write + * to the specified output sink. This constructor also allows "auto-flush" + * functionality to be specified where the stream will be flushed after + * every line is terminated or newline character is written. + * + * @param wr The Writer to write to. + * @param autoflush true to flush the stream after every + * line, false otherwise + */ + public PrintWriter(Writer wr, boolean autoflush) + { + super(wr.lock); + this.out = wr; + this.autoflush = autoflush; + } + + /** + * This method initializes a new PrintWriter object to write + * to the specified OutputStream. Characters will be converted + * to chars using the system default encoding. Auto-flush functionality + * will not be enabled. + * + * @param out The OutputStream to write to + */ + public PrintWriter(OutputStream out) + { + super(); + this.out = new OutputStreamWriter(out); + this.lock = this.out; + } + + /** + * This method initializes a new PrintWriter object to write + * to the specified OutputStream. Characters will be converted + * to chars using the system default encoding. This form of the + * constructor allows auto-flush functionality to be enabled if desired + * + * @param out The OutputStream to write to + * @param autoflush true to flush the stream after every + * println call, false otherwise. + */ + public PrintWriter(OutputStream out, boolean autoflush) + { + this(out); + this.autoflush = autoflush; + } + + /** + * This method can be called by subclasses to indicate that an error + * has occurred and should be reported by checkError. + */ + protected void setError() + { + error = true; + } + + /** + * This method checks to see if an error has occurred on this stream. Note + * that once an error has occurred, this method will continue to report + * true forever for this stream. Before checking for an + * error condition, this method flushes the stream. + * + * @return true if an error has occurred, + * false otherwise + */ + public boolean checkError() + { + flush(); + return error; + } + + /** + * This method flushes any buffered chars to the underlying stream and + * then flushes that stream as well. + */ + public void flush() + { + try + { + out.flush(); + } + catch (IOException ex) + { + error = true; + } + } + + /** + * This method closes this stream and all underlying streams. + */ + public void close() + { + try + { + out.close(); + } + catch (IOException ex) + { + error = true; + } + } + + /** + * This method prints a String to the stream. The actual + * value printed depends on the system default encoding. + * + * @param str The String to print. + */ + public void print(String str) + { + write(str == null ? "null" : str); + } + + /** + * This method prints a char to the stream. The actual value printed is + * determined by the character encoding in use. + * + * @param ch The char value to be printed + */ + public void print(char ch) + { + write((int) ch); + } + + /** + * This method prints an array of characters to the stream. The actual + * value printed depends on the system default encoding. + * + * @param charArray The array of characters to print. + */ + public void print(char[] charArray) + { + write(charArray, 0, charArray.length); + } + + /** + * This methods prints a boolean value to the stream. true + * values are printed as "true" and false values are printed + * as "false". + * + * @param bool The boolean value to print + */ + public void print(boolean bool) + { + // We purposely call write() and not print() here. This preserves + // compatibility with JDK 1.2. + write (bool ? "true" : "false"); + } + + /** + * This method prints an integer to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param inum The int value to be printed + */ + public void print(int inum) + { + // We purposely call write() and not print() here. This preserves + // compatibility with JDK 1.2. + write(Integer.toString(inum)); + } + + /** + * This method prints a long to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param lnum The long value to be printed + */ + public void print(long lnum) + { + // We purposely call write() and not print() here. This preserves + // compatibility with JDK 1.2. + write(Long.toString(lnum)); + } + + /** + * This method prints a float to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param fnum The float value to be printed + */ + public void print(float fnum) + { + // We purposely call write() and not print() here. This preserves + // compatibility with JDK 1.2. + write(Float.toString(fnum)); + } + + /** + * This method prints a double to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param dnum The double value to be printed + */ + public void print(double dnum) + { + // We purposely call write() and not print() here. This preserves + // compatibility with JDK 1.2. + write(Double.toString(dnum)); + } + + /** + * This method prints an Object to the stream. The actual + * value printed is determined by calling the String.valueOf() + * method. + * + * @param obj The Object to print. + */ + public void print(Object obj) + { + // We purposely call write() and not print() here. This preserves + // compatibility with JDK 1.2. + write(obj == null ? "null" : obj.toString()); + } + + /** + * This is the system dependent line separator + */ + private static final char[] line_separator + = System.getProperty("line.separator").toCharArray(); + + /** + * This method prints a line separator sequence to the stream. The value + * printed is determined by the system property

    line.separator + * and is not necessarily the Unix '\n' newline character. + */ + public void println() + { + synchronized (lock) + { + try + { + write(line_separator, 0, line_separator.length); + if (autoflush) + out.flush(); + } + catch (IOException ex) + { + error = true; + } + } + } + + /** + * This methods prints a boolean value to the stream. true + * values are printed as "true" and false values are printed + * as "false". + * + * This method prints a line termination sequence after printing the value. + * + * @param bool The boolean value to print + */ + public void println(boolean bool) + { + synchronized (lock) + { + print(bool); + println(); + } + } + + /** + * This method prints an integer to the stream. The value printed is + * determined using the String.valueOf() method. + * + * This method prints a line termination sequence after printing the value. + * + * @param inum The int value to be printed + */ + public void println(int inum) + { + synchronized (lock) + { + print(inum); + println(); + } + } + + /** + * This method prints a long to the stream. The value printed is + * determined using the String.valueOf() method. + * + * This method prints a line termination sequence after printing the value. + * + * @param lnum The long value to be printed + */ + public void println(long lnum) + { + synchronized (lock) + { + print(lnum); + println(); + } + } + + /** + * This method prints a float to the stream. The value printed is + * determined using the String.valueOf() method. + * + * This method prints a line termination sequence after printing the value. + * + * @param fnum The float value to be printed + */ + public void println(float fnum) + { + synchronized (lock) + { + print(fnum); + println(); + } + } + + /** + * This method prints a double to the stream. The value printed is + * determined using the String.valueOf() method. + * + * This method prints a line termination sequence after printing the value. + * + * @param dnum The double value to be printed + */ + public void println(double dnum) + { + synchronized (lock) + { + print(dnum); + println(); + } + } + + /** + * This method prints an Object to the stream. The actual + * value printed is determined by calling the String.valueOf() + * method. + * + * This method prints a line termination sequence after printing the value. + * + * @param obj The Object to print. + */ + public void println(Object obj) + { + synchronized (lock) + { + print(obj); + println(); + } + } + + /** + * This method prints a String to the stream. The actual + * value printed depends on the system default encoding. + * + * This method prints a line termination sequence after printing the value. + * + * @param str The String to print. + */ + public void println(String str) + { + synchronized (lock) + { + print(str); + println(); + } + } + + /** + * This method prints a char to the stream. The actual value printed is + * determined by the character encoding in use. + * + * This method prints a line termination sequence after printing the value. + * + * @param ch The char value to be printed + */ + public void println(char ch) + { + synchronized (lock) + { + print(ch); + println(); + } + } + + /** + * This method prints an array of characters to the stream. The actual + * value printed depends on the system default encoding. + * + * This method prints a line termination sequence after printing the value. + * + * @param charArray The array of characters to print. + */ + public void println(char[] charArray) + { + synchronized (lock) + { + print(charArray); + println(); + } + } + + /** + * This method writes a single char to the stream. + * + * @param ch The char to be written, passed as a int + */ + public void write(int ch) + { + try + { + out.write(ch); + } + catch (IOException ex) + { + error = true; + } + } + + /** + * This method writes count chars from the specified array + * starting at index offset into the array. + * + * @param charArray The array of chars to write + * @param offset The index into the array to start writing from + * @param count The number of chars to write + */ + public void write(char[] charArray, int offset, int count) + { + try + { + out.write(charArray, offset, count); + } + catch (IOException ex) + { + error = true; + } + } + + /** + * This method writes count chars from the specified + * String to the output starting at character position + * offset into the String + * + * @param str The String to write chars from + * @param offset The offset into the String to start writing from + * @param count The number of chars to write. + */ + public void write(String str, int offset, int count) + { + try + { + out.write(str, offset, count); + } + catch (IOException ex) + { + error = true; + } + } + + /** + * This method write all the chars in the specified array to the output. + * + * @param charArray The array of characters to write + */ + public void write(char[] charArray) + { + write(charArray, 0, charArray.length); + } + + /** + * This method writes the contents of the specified String + * to the underlying stream. + * + * @param str The String to write + */ + public void write(String str) + { + write(str, 0, str.length()); + } +} + diff --git a/libjava/classpath/java/io/PushbackInputStream.java b/libjava/classpath/java/io/PushbackInputStream.java new file mode 100644 index 0000000..71cf244 --- /dev/null +++ b/libjava/classpath/java/io/PushbackInputStream.java @@ -0,0 +1,328 @@ +/* PushbackInputStream.java -- An input stream that can unread bytes + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * This subclass of FilterInputStream provides the ability to + * unread data from a stream. It maintains an internal buffer of unread + * data that is supplied to the next read operation. This is conceptually + * similar to mark/reset functionality, except that in this case the + * position to reset the stream to does not need to be known in advance. + *

    + * The default pushback buffer size one byte, but this can be overridden + * by the creator of the stream. + *

    + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class PushbackInputStream extends FilterInputStream +{ + /** + * This is the default buffer size + */ + private static final int DEFAULT_BUFFER_SIZE = 1; + + /** + * This is the buffer that is used to store the pushed back data + */ + protected byte[] buf; + + /** + * This is the position in the buffer from which the next byte will be + * read. Bytes are stored in reverse order in the buffer, starting from + * buf[buf.length - 1] to buf[0]. Thus when + * pos is 0 the buffer is full and buf.length when + * it is empty + */ + protected int pos; + + /** + * This method initializes a PushbackInputStream to + * read from the specified subordinate InputStream + * with a default pushback buffer size of 1. + * + * @param in The subordinate stream to read from + */ + public PushbackInputStream(InputStream in) + { + this(in, DEFAULT_BUFFER_SIZE); + } + + /** + * This method initializes a PushbackInputStream to + * read from the specified subordinate InputStream with + * the specified buffer size + * + * @param in The subordinate InputStream to read from + * @param size The pushback buffer size to use + */ + public PushbackInputStream(InputStream in, int size) + { + super(in); + if (size < 0) + throw new IllegalArgumentException(); + buf = new byte[size]; + pos = buf.length; + } + + /** + * This method returns the number of bytes that can be read from this + * stream before a read can block. A return of 0 indicates that blocking + * might (or might not) occur on the very next read attempt. + *

    + * This method will return the number of bytes available from the + * pushback buffer plus the number of bytes available from the + * underlying stream. + * + * @return The number of bytes that can be read before blocking could occur + * + * @exception IOException If an error occurs + */ + public int available() throws IOException + { + return (buf.length - pos) + super.available(); + } + + /** + * This method closes the stream and releases any associated resources. + * + * @exception IOException If an error occurs. + */ + public synchronized void close() throws IOException + { + buf = null; + super.close(); + } + + /** + * This method returns false to indicate that it does + * not support mark/reset functionality. + * + * @return This method returns false to indicate that + * this class does not support mark/reset functionality + */ + public boolean markSupported() + { + return false; + } + + /** + * This method always throws an IOException in this class because + * mark/reset functionality is not supported. + * + * @exception IOException Always thrown for this class + */ + public void reset() throws IOException + { + throw new IOException("Mark not supported in this class"); + } + + /** + * This method reads an unsigned byte from the input stream and returns it + * as an int in the range of 0-255. This method also will return -1 if + * the end of the stream has been reached. The byte returned will be read + * from the pushback buffer, unless the buffer is empty, in which case + * the byte will be read from the underlying stream. + *

    + * This method will block until the byte can be read. + * + * @return The byte read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public synchronized int read() throws IOException + { + if (pos < buf.length) + return ((int) buf[pos++]) & 0xFF; + + return super.read(); + } + + /** + * This method read bytes from a stream and stores them into a + * caller supplied buffer. It starts storing the data at index + * offset into the buffer and attempts to read + * len bytes. This method can return before reading the + * number of bytes requested. The actual number of bytes read is + * returned as an int. A -1 is returned to indicate the end of the + * stream. + *

    + * This method will block until some data can be read. + *

    + * This method first reads bytes from the pushback buffer in order to + * satisfy the read request. If the pushback buffer cannot provide all + * of the bytes requested, the remaining bytes are read from the + * underlying stream. + * + * @param b The array into which the bytes read should be stored + * @param off The offset into the array to start storing bytes + * @param len The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public synchronized int read(byte[] b, int off, int len) throws IOException + { + int numBytes = Math.min(buf.length - pos, len); + + if (numBytes > 0) + { + System.arraycopy (buf, pos, b, off, numBytes); + pos += numBytes; + len -= numBytes; + off += numBytes; + } + + if (len > 0) + { + len = super.read(b, off, len); + if (len == -1) //EOF + return numBytes > 0 ? numBytes : -1; + numBytes += len; + } + return numBytes; + } + + /** + * This method pushes a single byte of data into the pushback buffer. + * The byte pushed back is the one that will be returned as the first byte + * of the next read. + *

    + * If the pushback buffer is full, this method throws an exception. + *

    + * The argument to this method is an int. Only the low + * eight bits of this value are pushed back. + * + * @param b The byte to be pushed back, passed as an int + * + * @exception IOException If the pushback buffer is full. + */ + public synchronized void unread(int b) throws IOException + { + if (pos <= 0) + throw new IOException("Insufficient space in pushback buffer"); + + buf[--pos] = (byte) b; + } + + /** + * This method pushes all of the bytes in the passed byte array into + * the pushback bfer. These bytes are pushed in reverse order so that + * the next byte read from the stream after this operation will be + * b[0] followed by b[1], etc. + *

    + * If the pushback buffer cannot hold all of the requested bytes, an + * exception is thrown. + * + * @param b The byte array to be pushed back + * + * @exception IOException If the pushback buffer is full + */ + public synchronized void unread(byte[] b) throws IOException + { + unread(b, 0, b.length); + } + + /** + * This method pushed back bytes from the passed in array into the + * pushback buffer. The bytes from b[offset] to + * b[offset + len] are pushed in reverse order so that + * the next byte read from the stream after this operation will be + * b[offset] followed by b[offset + 1], + * etc. + *

    + * If the pushback buffer cannot hold all of the requested bytes, an + * exception is thrown. + * + * @param b The byte array to be pushed back + * @param off The index into the array where the bytes to be push start + * @param len The number of bytes to be pushed. + * + * @exception IOException If the pushback buffer is full + */ + public synchronized void unread(byte[] b, int off, int len) + throws IOException + { + if (pos < len) + throw new IOException("Insufficient space in pushback buffer"); + + // Note the order that these bytes are being added is the opposite + // of what would be done if they were added to the buffer one at a time. + // See the Java Class Libraries book p. 1390. + System.arraycopy(b, off, buf, pos - len, len); + + // Don't put this into the arraycopy above, an exception might be thrown + // and in that case we don't want to modify pos. + pos -= len; + } + + /** + * This method skips the specified number of bytes in the stream. It + * returns the actual number of bytes skipped, which may be less than the + * requested amount. + *

    + * This method first discards bytes from the buffer, then calls the + * skip method on the underlying InputStream to + * skip additional bytes if necessary. + * + * @param n The requested number of bytes to skip + * + * @return The actual number of bytes skipped. + * + * @exception IOException If an error occurs + * + * @since 1.2 + */ + public synchronized long skip(long n) throws IOException + { + final long origN = n; + + if (n > 0L) + { + int numread = (int) Math.min((long) (buf.length - pos), n); + pos += numread; + n -= numread; + if (n > 0) + n -= super.skip(n); + } + + return origN - n; + } +} diff --git a/libjava/classpath/java/io/PushbackReader.java b/libjava/classpath/java/io/PushbackReader.java new file mode 100644 index 0000000..04bccc7 --- /dev/null +++ b/libjava/classpath/java/io/PushbackReader.java @@ -0,0 +1,384 @@ +/* PushbackReader.java -- An character stream that can unread chars + Copyright (C) 1998, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/** + * This subclass of FilterReader provides the ability to + * unread data from a stream. It maintains an internal buffer of unread + * data that is supplied to the next read operation. This is conceptually + * similar to mark/reset functionality, except that in this case the + * position to reset the stream to does not need to be known in advance. + *

    + * The default pushback buffer size one char, but this can be overridden + * by the creator of the stream. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class PushbackReader extends FilterReader +{ + /** + * This is the default buffer size + */ + private static final int DEFAULT_BUFFER_SIZE = 1; + + /** + * This is the buffer that is used to store the pushed back data + */ + private char[] buf; + + /** + * This is the position in the buffer from which the next char will be + * read. Bytes are stored in reverse order in the buffer, starting from + * buf[buf.length - 1] to buf[0]. Thus when + * pos is 0 the buffer is full and buf.length when + * it is empty + */ + private int pos; + + /** + * This method initializes a PushbackReader to read from the + * specified subordinate Reader with a default pushback buffer + * size of 1. + * + * @param in The subordinate stream to read from + */ + public PushbackReader(Reader in) + { + this(in, DEFAULT_BUFFER_SIZE); + } + + /** + * This method initializes a PushbackReader to read from the + * specified subordinate Reader with the specified buffer + * size + * + * @param in The subordinate Reader to read from + * @param bufsize The pushback buffer size to use + */ + public PushbackReader(Reader in, int bufsize) + { + super(in); + + if (bufsize < 0) + throw new IllegalArgumentException("buffer size must be positive"); + + buf = new char[bufsize]; + pos = bufsize; + } + + /** + * This method closes the stream and frees any associated resources. + * + * @exception IOException If an error occurs. + */ + public void close() throws IOException + { + synchronized (lock) + { + buf = null; + super.close(); + } + } + + /** + * This method throws an exception when called since this class does + * not support mark/reset. + * + * @param read_limit Not used. + * + * @exception IOException Always thrown to indicate mark/reset not supported. + */ + public void mark(int read_limit) throws IOException + { + throw new IOException("mark not supported in this class"); + } + + /** + * This method returns false to indicate that it does not support + * mark/reset functionality. + * + * @return This method returns false to indicate that this + * class does not support mark/reset functionality + * + */ + public boolean markSupported() + { + return(false); + } + + /** + * This method always throws an IOException in this class because + * mark/reset functionality is not supported. + * + * @exception IOException Always thrown for this class + */ + public void reset() throws IOException + { + throw new IOException("reset not supported in this class"); + } + + /** + * This method determines whether or not this stream is ready to be read. + * If it returns false to indicate that the stream is not + * ready, any attempt to read from the stream could (but is not + * guaranteed to) block. + *

    + * This stream is ready to read if there are either chars waiting to be + * read in the pushback buffer or if the underlying stream is ready to + * be read. + * + * @return true if this stream is ready to be read, + * false otherwise + * + * @exception IOException If an error occurs + */ + public boolean ready() throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException ("stream closed"); + + if (((buf.length - pos) > 0) || super.ready()) + return(true); + else + return(false); + } + } + + // Don't delete this method just because the spec says it shouldn't be there! + // See the CVS log for details. + /** + * This method skips the specified number of chars in the stream. It + * returns the actual number of chars skipped, which may be less than the + * requested amount. + *

    + * This method first discards chars from the buffer, then calls the + * skip method on the underlying Reader to + * skip additional chars if necessary. + * + * @param num_chars The requested number of chars to skip + * + * @return The actual number of chars skipped. + * + * @exception IOException If an error occurs + */ + public long skip(long num_chars) throws IOException + { + synchronized (lock) + { + if (num_chars <= 0) + return(0); + + if ((buf.length - pos) >= num_chars) + { + pos += num_chars; + return(num_chars); + } + + int chars_discarded = buf.length - pos; + pos = buf.length; + + long chars_skipped = in.skip(num_chars - chars_discarded); + + return(chars_discarded + chars_skipped); + } + } + + /** + * This method reads an unsigned char from the input stream and returns it + * as an int in the range of 0-65535. This method also will return -1 if + * the end of the stream has been reached. The char returned will be read + * from the pushback buffer, unless the buffer is empty, in which case + * the char will be read from the underlying stream. + *

    + * This method will block until the char can be read. + * + * @return The char read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("stream closed"); + + if (pos == buf.length) + return(super.read()); + + ++pos; + return((buf[pos - 1] & 0xFFFF)); + } + } + + /** + * This method read chars from a stream and stores them into a caller + * supplied buffer. It starts storing the data at index offset + * into + * the buffer and attempts to read len chars. This method can + * return before reading the number of chars requested. The actual number + * of chars read is returned as an int. A -1 is returned to indicate the + * end of the stream. + *

    + * This method will block until some data can be read. + *

    + * This method first reads chars from the pushback buffer in order to + * satisfy the read request. If the pushback buffer cannot provide all + * of the chars requested, the remaining chars are read from the + * underlying stream. + * + * @param buffer The array into which the chars read should be stored + * @param offset The offset into the array to start storing chars + * @param length The requested number of chars to read + * + * @return The actual number of chars read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public synchronized int read(char[] buffer, int offset, int length) + throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("stream closed"); + + if (offset < 0 || length < 0 || offset + length > buffer.length) + throw new ArrayIndexOutOfBoundsException(); + + int numBytes = Math.min(buf.length - pos, length); + if (numBytes > 0) + { + System.arraycopy (buf, pos, buffer, offset, numBytes); + pos += numBytes; + return numBytes; + } + + return super.read(buffer, offset, length); + } + } + + /** + * This method pushes a single char of data into the pushback buffer. + * The char pushed back is the one that will be returned as the first char + * of the next read. + *

    + * If the pushback buffer is full, this method throws an exception. + *

    + * The argument to this method is an int. Only the low eight + * bits of this value are pushed back. + * + * @param b The char to be pushed back, passed as an int + * + * @exception IOException If the pushback buffer is full. + */ + public void unread(int b) throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("stream closed"); + if (pos == 0) + throw new IOException("Pushback buffer is full"); + + --pos; + buf[pos] = (char)(b & 0xFFFF); + } + } + + /** + * This method pushes all of the chars in the passed char array into + * the pushback buffer. These chars are pushed in reverse order so that + * the next char read from the stream after this operation will be + * buf[0] followed by buf[1], etc. + *

    + * If the pushback buffer cannot hold all of the requested chars, an + * exception is thrown. + * + * @param buf The char array to be pushed back + * + * @exception IOException If the pushback buffer is full + */ + public synchronized void unread(char[] buf) throws IOException + { + unread(buf, 0, buf.length); + } + + /** + * This method pushed back chars from the passed in array into the pushback + * buffer. The chars from buf[offset] to + * buf[offset + len] + * are pushed in reverse order so that the next char read from the stream + * after this operation will be buf[offset] followed by + * buf[offset + 1], etc. + *

    + * If the pushback buffer cannot hold all of the requested chars, an + * exception is thrown. + * + * @param buffer The char array to be pushed back + * @param offset The index into the array where the chars to be push start + * @param length The number of chars to be pushed. + * + * @exception IOException If the pushback buffer is full + */ + public synchronized void unread(char[] buffer, int offset, int length) + throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("stream closed"); + if (pos < length) + throw new IOException("Pushback buffer is full"); + + // Note the order that these chars are being added is the opposite + // of what would be done if they were added to the buffer one at a time. + // See the Java Class Libraries book p. 1397. + System.arraycopy(buffer, offset, buf, pos - length, length); + + // Don't put this into the arraycopy above, an exception might be thrown + // and in that case we don't want to modify pos. + pos -= length; + } + } +} + diff --git a/libjava/classpath/java/io/RandomAccessFile.java b/libjava/classpath/java/io/RandomAccessFile.java new file mode 100644 index 0000000..23be5a3 --- /dev/null +++ b/libjava/classpath/java/io/RandomAccessFile.java @@ -0,0 +1,991 @@ +/* RandomAccessFile.java -- Class supporting random file I/O + Copyright (C) 1998, 1999, 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 java.io; + +import gnu.java.nio.channels.FileChannelImpl; + +import java.nio.channels.FileChannel; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Believe complete and correct to 1.1. + */ + +/** + * This class allows reading and writing of files at random locations. + * Most Java I/O classes are either pure sequential input or output. This + * class fulfills the need to be able to read the bytes of a file in an + * arbitrary order. In addition, this class implements the + * DataInput and DataOutput interfaces to allow + * the reading and writing of Java primitives. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class RandomAccessFile implements DataOutput, DataInput +{ + + // The underlying file. + private FileChannelImpl ch; + private FileDescriptor fd; + // The corresponding input and output streams. + private DataOutputStream out; + private DataInputStream in; + + + /** + * This method initializes a new instance of RandomAccessFile + * to read from the specified File object with the specified + * access mode. The access mode is either "r" for read only access or "rw" + * for read-write access. + *

    + * Note that a SecurityManager check is made prior to + * opening the file to determine whether or not this file is allowed to + * be read or written. + * + * @param file The File object to read and/or write. + * @param mode "r" for read only or "rw" for read-write access to the file + * + * @exception IllegalArgumentException If mode has an + * illegal value + * @exception SecurityException If the requested access to the file + * is not allowed + * @exception FileNotFoundException If the file is a directory, or + * any other error occurs + */ + public RandomAccessFile (File file, String mode) + throws FileNotFoundException + { + int fdmode; + if (mode.equals("r")) + fdmode = FileChannelImpl.READ; + else if (mode.equals("rw")) + fdmode = FileChannelImpl.READ | FileChannelImpl.WRITE; + else if (mode.equals("rws")) + { + fdmode = (FileChannelImpl.READ | FileChannelImpl.WRITE + | FileChannelImpl.SYNC); + } + else if (mode.equals("rwd")) + { + fdmode = (FileChannelImpl.READ | FileChannelImpl.WRITE + | FileChannelImpl.DSYNC); + } + else + throw new IllegalArgumentException ("invalid mode: " + mode); + + final String fileName = file.getPath(); + + // The obligatory SecurityManager stuff + SecurityManager s = System.getSecurityManager(); + if (s != null) + { + s.checkRead(fileName); + + if ((fdmode & FileChannelImpl.WRITE) != 0) + s.checkWrite(fileName); + } + + ch = FileChannelImpl.create(file, fdmode); + fd = new FileDescriptor(ch); + out = new DataOutputStream (new FileOutputStream (fd)); + in = new DataInputStream (new FileInputStream (fd)); + } + + /** + * This method initializes a new instance of RandomAccessFile + * to read from the specified file name with the specified access mode. + * The access mode is either "r" for read only access, "rw" for read + * write access, "rws" for synchronized read/write access of both + * content and metadata, or "rwd" for read/write access + * where only content is required to be synchronous. + *

    + * Note that a SecurityManager check is made prior to + * opening the file to determine whether or not this file is allowed to + * be read or written. + * + * @param fileName The name of the file to read and/or write + * @param mode "r", "rw", "rws", or "rwd" + * + * @exception IllegalArgumentException If mode has an + * illegal value + * @exception SecurityException If the requested access to the file + * is not allowed + * @exception FileNotFoundException If the file is a directory or + * any other error occurs + */ + public RandomAccessFile (String fileName, String mode) + throws FileNotFoundException + { + this (new File(fileName), mode); + } + + /** + * This method closes the file and frees up all file related system + * resources. Since most operating systems put a limit on how many files + * may be opened at any given time, it is a good idea to close all files + * when no longer needed to avoid hitting this limit + */ + public void close () throws IOException + { + ch.close(); + } + + /** + * This method returns a FileDescriptor object that + * represents the native file handle for this file. + * + * @return The FileDescriptor object for this file + * + * @exception IOException If an error occurs + */ + public final FileDescriptor getFD () throws IOException + { + synchronized (this) + { + if (fd == null) + fd = new FileDescriptor (ch); + return fd; + } + } + + /** + * This method returns the current offset in the file at which the next + * read or write will occur + * + * @return The current file position + * + * @exception IOException If an error occurs + */ + public long getFilePointer () throws IOException + { + return ch.position(); + } + + /** + * This method sets the length of the file to the specified length. + * If the currently length of the file is longer than the specified + * length, then the file is truncated to the specified length (the + * file position is set to the end of file in this case). If the + * current length of the file is shorter than the specified length, + * the file is extended with bytes of an undefined value (the file + * position is unchanged in this case). + *

    + * The file must be open for write access for this operation to succeed. + * + * @param newLen The new length of the file + * + * @exception IOException If an error occurs + */ + public void setLength (long newLen) throws IOException + { + // FIXME: Extending a file should probably be done by one method call. + + // FileChannel.truncate() can only shrink a file. + // To expand it we need to seek forward and write at least one byte. + if (newLen < length()) + ch.truncate (newLen); + else if (newLen > length()) + { + long pos = getFilePointer(); + seek(newLen - 1); + write(0); + seek(pos); + } + } + + /** + * This method returns the length of the file in bytes + * + * @return The length of the file + * + * @exception IOException If an error occurs + */ + public long length () throws IOException + { + return ch.size(); + } + + /** + * This method reads a single byte of data from the file and returns it + * as an integer. + * + * @return The byte read as an int, or -1 if the end of the file was reached. + * + * @exception IOException If an error occurs + */ + public int read () throws IOException + { + return in.read(); + } + + /** + * This method reads bytes from the file into the specified array. The + * bytes are stored starting at the beginning of the array and up to + * buf.length bytes can be read. + * + * @param buffer The buffer to read bytes from the file into + * + * @return The actual number of bytes read or -1 if end of file + * + * @exception IOException If an error occurs + */ + public int read (byte[] buffer) throws IOException + { + return in.read (buffer); + } + + /** + * This methods reads up to len bytes from the file into the + * specified array starting at position offset into the array. + * + * @param buffer The array to read the bytes into + * @param offset The index into the array to start storing bytes + * @param len The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of file + * + * @exception IOException If an error occurs + */ + public int read (byte[] buffer, int offset, int len) throws IOException + { + return in.read (buffer, offset, len); + } + + /** + * This method reads a Java boolean value from an input stream. It does + * so by reading a single byte of data. If that byte is zero, then the + * value returned is false If the byte is non-zero, then + * the value returned is true + *

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

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

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

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

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

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

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

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

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

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

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

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

    + * This method can read data that was written by an object implementing the + * writeLine() method in DataOutput + * + * @return The line read as a String + * + * @exception IOException If an error occurs + * + * @see DataOutput + */ + public final String readLine () throws IOException + { + return in.readLine (); + } + + /** + * This method reads a Java long value from an input stream + * It operates by reading eight bytes from the stream and converting them to + * a single Java long The bytes are stored most + * significant byte first (i.e., "big endian") regardless of the native + * host byte ordering. + *

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

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

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

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

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

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

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

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

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

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

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

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

    + * This method can read an unsigned short written by an object implementing + * the writeUnsignedShort() method in the + * DataOutput interface. + * + * @return The unsigned short value read as a Java int + * + * @exception EOFException If end of file is reached before reading the value + * @exception IOException If any other error occurs + */ + public final int readUnsignedShort () throws IOException + { + return in.readUnsignedShort(); + } + + /** + * This method reads a String from an input stream that + * is encoded in + * a modified UTF-8 format. This format has a leading two byte sequence + * that contains the remaining number of bytes to read. This two byte + * sequence is read using the readUnsignedShort() method of this + * interface. + *

    + * After the number of remaining bytes have been determined, these bytes + * are read an transformed into char values. + * These char values + * are encoded in the stream using either a one, two, or three byte format. + * The particular format in use can be determined by examining the first + * byte read. + *

    + * If the first byte has a high order bit of 0 then + * that character consists on only one byte. This character value consists + * of seven bits that are at positions 0 through 6 of the byte. As an + * example, if byte1 is the byte read from the stream, it would + * be converted to a char like so: + *

    + * (char)byte1 + *

    + * If the first byte has 110 as its high order bits, then the + * character consists of two bytes. The bits that make up the character + * value are in positions 0 through 4 of the first byte and bit positions + * 0 through 5 of the second byte. (The second byte should have + * 10 as its high order bits). These values are in most significant + * byte first (i.e., "big endian") order. + *

    + * As an example, if byte1 and byte2 + * are the first two bytes + * read respectively, and the high order bits of them match the patterns + * which indicate a two byte character encoding, then they would be + * converted to a Java char like so: + *

    + * (char)(((byte1 & 0x1F) << 6) | (byte2 & 0x3F)) + *

    + * If the first byte has a 1110 as its high order bits, then the + * character consists of three bytes. The bits that make up the character + * value are in positions 0 through 3 of the first byte and bit positions + * 0 through 5 of the other two bytes. (The second and third bytes should + * have 10 as their high order bits). These values are in most + * significant byte first (i.e., "big endian") order. + *

    + * As an example, if byte1 byte2 + * and byte3 are the + * three bytes read, and the high order bits of them match the patterns + * which indicate a three byte character encoding, then they would be + * converted to a Java char like so: + *

    + * (char)(((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | + * (byte3 & 0x3F)) + *

    + * Note that all characters are encoded in the method that requires the + * fewest number of bytes with the exception of the character with the + * value of \u0000 which is encoded as two bytes. This is + * a modification of the UTF standard used to prevent C language style + * NUL values from appearing in the byte stream. + *

    + * This method can read data that was written by an object implementing the + * writeUTF() method in DataOutput + * + * @return The String read + * + * @exception EOFException If end of file is reached before reading the + * String + * @exception UTFDataFormatException If the data is not in UTF-8 format + * @exception IOException If any other error occurs + * + * @see DataOutput + */ + public final String readUTF () throws IOException + { + return in.readUTF(); + } + + /** + * This method sets the current file position to the specified offset + * from the beginning of the file. Note that some operating systems will + * allow the file pointer to be set past the current end of the file. + * + * @param pos The offset from the beginning of the file at which to set + * the file pointer + * + * @exception IOException If an error occurs + */ + public void seek (long pos) throws IOException + { + ch.position(pos); + } + + /** + * This method attempts to skip and discard the specified number of bytes + * in the input stream. It may actually skip fewer bytes than requested. + * The actual number of bytes skipped is returned. This method will not + * skip any bytes if passed a negative number of bytes to skip. + * + * @param numBytes The requested number of bytes to skip. + * + * @return The number of bytes actually skipped. + * + * @exception IOException If an error occurs. + */ + public int skipBytes (int numBytes) throws IOException + { + if (numBytes < 0) + throw new IllegalArgumentException ("Can't skip negative bytes: " + + numBytes); + + if (numBytes == 0) + return 0; + + long oldPos = ch.position(); + long newPos = oldPos + numBytes; + long size = ch.size(); + if (newPos > size) + newPos = size; + ch.position(newPos); + return (int) (ch.position() - oldPos); + } + + /** + * This method writes a single byte of data to the file. The file must + * be open for read-write in order for this operation to succeed. + * + * @param oneByte The byte of data to write, passed as an int. + * + * @exception IOException If an error occurs + */ + public void write (int oneByte) throws IOException + { + out.write(oneByte); + } + + /** + * This method writes all the bytes in the specified array to the file. + * The file must be open read-write in order for this operation to succeed. + * + * @param buffer The array of bytes to write to the file + */ + public void write (byte[] buffer) throws IOException + { + out.write(buffer); + } + + /** + * This method writes len bytes to the file from the specified + * array starting at index offset into the array. + * + * @param buffer The array of bytes to write to the file + * @param offset The index into the array to start writing file + * @param len The number of bytes to write + * + * @exception IOException If an error occurs + */ + public void write (byte[] buffer, int offset, int len) throws IOException + { + out.write (buffer, offset, len); + } + + /** + * This method writes a Java boolean to the underlying output + * stream. For a value of true, 1 is written to the stream. + * For a value of false, 0 is written. + * + * @param val The boolean value to write to the stream + * + * @exception IOException If an error occurs + */ + public final void writeBoolean (boolean val) throws IOException + { + out.writeBoolean(val); + } + + /** + * This method writes a Java byte value to the underlying + * output stream. + * + * @param val The byte to write to the stream, passed + * as an int. + * + * @exception IOException If an error occurs + */ + public final void writeByte (int val) throws IOException + { + out.writeByte(val); + } + + /** + * This method writes a Java short to the stream, high byte + * first. This method requires two bytes to encode the value. + * + * @param val The short value to write to the stream, + * passed as an int. + * + * @exception IOException If an error occurs + */ + public final void writeShort (int val) throws IOException + { + out.writeShort(val); + } + + /** + * This method writes a single char value to the stream, + * high byte first. + * + * @param val The char value to write, passed as + * an int. + * + * @exception IOException If an error occurs + */ + public final void writeChar (int val) throws IOException + { + out.writeChar(val); + } + + /** + * This method writes a Java int to the stream, high bytes + * first. This method requires four bytes to encode the value. + * + * @param val The int value to write to the stream. + * + * @exception IOException If an error occurs + */ + public final void writeInt (int val) throws IOException + { + out.writeInt(val); + } + + /** + * This method writes a Java long to the stream, high bytes + * first. This method requires eight bytes to encode the value. + * + * @param val The long value to write to the stream. + * + * @exception IOException If an error occurs + */ + public final void writeLong (long val) throws IOException + { + out.writeLong(val); + } + + /** + * This method writes a Java float value to the stream. This + * value is written by first calling the method + * Float.floatToIntBits + * to retrieve an int representing the floating point number, + * then writing this int value to the stream exactly the same + * as the writeInt() method does. + * + * @param val The floating point number to write to the stream. + * + * @exception IOException If an error occurs + * + * @see #writeInt(int) + */ + public final void writeFloat (float val) throws IOException + { + out.writeFloat(val); + } + + /** + * This method writes a Java double value to the stream. This + * value is written by first calling the method + * Double.doubleToLongBits + * to retrieve an long representing the floating point number, + * then writing this long value to the stream exactly the same + * as the writeLong() method does. + * + * @param val The double precision floating point number to write to the + * stream. + * + * @exception IOException If an error occurs + * + * @see #writeLong(long) + */ + public final void writeDouble (double val) throws IOException + { + out.writeDouble(val); + } + + /** + * This method writes all the bytes in a String out to the + * stream. One byte is written for each character in the String. + * The high eight bits of each character are discarded. + * + * @param val The String to write to the stream + * + * @exception IOException If an error occurs + */ + public final void writeBytes (String val) throws IOException + { + out.writeBytes(val); + } + + /** + * This method writes all the characters in a String to the + * stream. There will be two bytes for each character value. The high + * byte of the character will be written first. + * + * @param val The String to write to the stream. + * + * @exception IOException If an error occurs + */ + public final void writeChars (String val) throws IOException + { + out.writeChars(val); + } + + /** + * This method writes a Java String to the stream in a modified + * UTF-8 format. First, two bytes are written to the stream indicating the + * number of bytes to follow. Note that this is the number of bytes in the + * encoded String not the String length. Next + * come the encoded characters. Each character in the String + * is encoded as either one, two or three bytes. For characters in the + * range of \u0001 to \u007F, + * one byte is used. The character + * value goes into bits 0-7 and bit eight is 0. For characters in the range + * of \u0080 to \u007FF, two + * bytes are used. Bits + * 6-10 of the character value are encoded bits 0-4 of the first byte, with + * the high bytes having a value of "110". Bits 0-5 of the character value + * are stored in bits 0-5 of the second byte, with the high bits set to + * "10". This type of encoding is also done for the null character + * \u0000. This eliminates any C style NUL character values + * in the output. All remaining characters are stored as three bytes. + * Bits 12-15 of the character value are stored in bits 0-3 of the first + * byte. The high bits of the first bytes are set to "1110". Bits 6-11 + * of the character value are stored in bits 0-5 of the second byte. The + * high bits of the second byte are set to "10". And bits 0-5 of the + * character value are stored in bits 0-5 of byte three, with the high bits + * of that byte set to "10". + * + * @param val The String to write to the output in UTF format + * + * @exception IOException If an error occurs + */ + public final void writeUTF (String val) throws IOException + { + out.writeUTF(val); + } + + /** + * This method creates a java.nio.channels.FileChannel. + * Nio does not allow one to create a file channel directly. + * A file channel must be created by first creating an instance of + * Input/Output/RandomAccessFile and invoking the getChannel() method on it. + */ + public final synchronized FileChannel getChannel () + { + return ch; + } +} diff --git a/libjava/classpath/java/io/Reader.java b/libjava/classpath/java/io/Reader.java new file mode 100644 index 0000000..7970d9a --- /dev/null +++ b/libjava/classpath/java/io/Reader.java @@ -0,0 +1,271 @@ +/* Reader.java -- base class of classes that read input as a stream of chars + Copyright (C) 1998, 1999, 2000, 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This abstract class forms the base of the hierarchy of classes that read + * input as a stream of characters. It provides a common set of methods for + * reading characters from streams. Subclasses implement and extend these + * methods to read characters from a particular input source such as a file + * or network connection. + * + * @author Per Bothner (bothner@cygnus.com) + * @date April 21, 1998. + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class Reader +{ + /** + * This is the Object used for synchronizing critical code + * sections. Subclasses should use this variable instead of a + * synchronized method or an explicit synchronization on this + */ + protected Object lock; + + /** + * Unitializes a Reader that will use the object + * itself for synchronization of critical code sections. + */ + protected Reader() + { + this.lock = this; + } + + /** + * Initializes a Reader that will use the specified + * Object for synchronization of critical code sections. + * + * @param lock The Object to use for synchronization + */ + protected Reader(Object lock) + { + this.lock = lock; + } + + /** + * Read chars from a stream and stores them into a caller + * supplied buffer. It starts storing the data at index offset + * into the buffer and attempts to read len chars. This method + * can return before reading the number of chars requested. The actual + * number of chars read is returned as an int. A -1 is returned to indicate + * the end of the stream. + *

    + * This method will block until some data can be read. + *

    + * This method operates by calling the single char read() method + * in a loop until the desired number of chars are read. The read loop + * stops short if the end of the stream is encountered or if an IOException + * is encountered on any read operation except the first. If the first + * attempt to read a chars fails, the IOException is allowed to propagate + * upward. And subsequent IOException is caught and treated identically + * to an end of stream condition. Subclasses can (and should if possible) + * override this method to provide a more efficient implementation. + * + * @param buf The array into which the chars read should be stored + * @param offset The offset into the array to start storing chars + * @param count The requested number of chars to read + * + * @return The actual number of chars read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public abstract int read(char buf[], int offset, int count) + throws IOException; + + /** + * Reads chars from a stream and stores them into a caller + * supplied buffer. This method attempts to completely fill the buffer, + * but can return before doing so. The actual number of chars read is + * returned as an int. A -1 is returned to indicate the end of the stream. + *

    + * This method will block until some data can be read. + *

    + * This method operates by calling an overloaded read method like so: + * read(buf, 0, buf.length) + * + * @param buf The buffer into which the chars read will be stored. + * + * @return The number of chars read or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public int read(char buf[]) throws IOException + { + return read(buf, 0, buf.length); + } + + /** + * Reads an char from the input stream and returns it + * as an int in the range of 0-65535. This method also will return -1 if + * the end of the stream has been reached. + *

    + * This method will block until the char can be read. + * + * @return The char read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + char[] buf = new char[1]; + int count = read(buf, 0, 1); + return count > 0 ? buf[0] : -1; + } + + /** + * Closes the stream. Any futher attempts to read from the + * stream may generate an IOException. + * + * @exception IOException If an error occurs + */ + public abstract void close() throws IOException; + + /** + * Returns a boolean that indicates whether the mark/reset + * methods are supported in this class. Those methods can be used to + * remember a specific point in the stream and reset the stream to that + * point. + *

    + * This method always returns false in this class, but + * subclasses can override this method to return true if they + * support mark/reset functionality. + * + * @return true if mark/reset functionality is supported, + * false otherwise + * + */ + public boolean markSupported() + { + return false; + } + + /** + * Marks a position in the input to which the stream can be + * "reset" by calling the reset() method. The parameter + * readlimit is the number of chars that can be read from the + * stream after setting the mark before the mark becomes invalid. For + * example, if mark() is called with a read limit of 10, then + * when 11 chars of data are read from the stream before the + * reset() method is called, then the mark is invalid and the + * stream object instance is not required to remember the mark. + * + * @param readLimit The number of chars that can be read before the mark + * becomes invalid + * + * @exception IOException If an error occurs such as mark not being + * supported for this class + */ + public void mark(int readLimit) throws IOException + { + throw new IOException("mark not supported"); + } + + /** + * Resets a stream to the point where the mark() + * method was called. Any chars that were read after the mark point was + * set will be re-read during subsequent reads. + *

    + * This method always throws an IOException in this class, but subclasses + * can override this method if they provide mark/reset functionality. + * + * @exception IOException Always thrown for this class + */ + public void reset() throws IOException + { + throw new IOException("reset not supported"); + } + + /** + * Determines whether or not this stream is ready to be + * read. If it returns false the stream may block if a + * read is attempted, but it is not guaranteed to do so. + *

    + * This method always returns false in this class + * + * @return true if the stream is ready to be read, + * false otherwise. + * + * @exception IOException If an error occurs + */ + public boolean ready() throws IOException + { + return false; + } + + /** + * Skips the specified number of chars in the stream. It + * returns the actual number of chars skipped, which may be less than the + * requested amount. + *

    + * This method reads and discards chars into a 256 char array until the + * specified number of chars were skipped or until either the end of stream + * is reached or a read attempt returns a short count. Subclasses can + * override this method to provide a more efficient implementation where + * one exists. + * + * @param count The requested number of chars to skip + * + * @return The actual number of chars skipped. + * + * @exception IOException If an error occurs + */ + public long skip(long count) throws IOException + { + if (count <= 0) + return 0; + int bsize = count > 1024 ? 1024 : (int) count; + char[] buffer = new char[bsize]; + long todo = count; + synchronized (lock) + { + while (todo > 0) + { + int skipped = read(buffer, 0, bsize > todo ? (int) todo : bsize); + if (skipped <= 0) + break; + todo -= skipped; + } + } + return count - todo; + } +} diff --git a/libjava/classpath/java/io/SequenceInputStream.java b/libjava/classpath/java/io/SequenceInputStream.java new file mode 100644 index 0000000..7fefe24 --- /dev/null +++ b/libjava/classpath/java/io/SequenceInputStream.java @@ -0,0 +1,221 @@ +/* SequenceInputStream.java -- Reads multiple input streams in sequence + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +import java.util.Enumeration; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This class merges a sequence of multiple InputStream's in + * order to form a single logical stream that can be read by applications + * that expect only one stream. + *

    + * The streams passed to the constructor method are read in order until + * they return -1 to indicate they are at end of stream. When a stream + * reports end of stream, it is closed, then the next stream is read. + * When the last stream is closed, the next attempt to read from this + * stream will return a -1 to indicate it is at end of stream. + *

    + * If this stream is closed prior to all subordinate streams being read + * to completion, all subordinate streams are closed. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class SequenceInputStream extends InputStream +{ + /** The handle for the current input stream. */ + private InputStream in; + + /** Secondary input stream; not used if constructed w/ enumeration. */ + private InputStream in2; + + /** The enumeration handle; not used if constructed w/ 2 explicit input streams. */ + private Enumeration e; + + /** + * This method creates a new SequenceInputStream that obtains + * its list of subordinate InputStreams from the specified + * Enumeration + * + * @param e An Enumeration that will return a list of + * InputStreams to read in sequence + */ + public SequenceInputStream(Enumeration e) + { + this.e = e; + in = (InputStream) e.nextElement(); + in2 = null; + } + + /** + * This method creates a new SequenceInputStream that will read + * the two specified subordinate InputStreams in sequence. + * + * @param s1 The first InputStream to read + * @param s2 The second InputStream to read + */ + public SequenceInputStream(InputStream s1, InputStream s2) + { + in = s1; + in2 = s2; + } + + /** + * This method returns the number of bytes than can be read from the + * currently being read subordinate stream before that stream could + * block. Note that it is possible more bytes than this can actually + * be read without the stream blocking. If a 0 is returned, then the + * stream could block on the very next read. + * + * @return The number of bytes that can be read before blocking could occur + * + * @exception IOException If an error occurs + */ + public int available() throws IOException + { + if (in == null) + return 0; + + return in.available(); + } + + /** + * Closes this stream. This will cause any remaining unclosed subordinate + * InputStream's to be closed as well. Subsequent attempts to + * read from this stream may cause an exception. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + while (in != null) + { + in.close(); + in = getNextStream (); + } + } + + /** + * This method reads an unsigned byte from the input stream and returns it + * as an int in the range of 0-255. This method also will return -1 if + * the end of the stream has been reached. This will only happen when + * all of the subordinate streams have been read. + *

    + * This method will block until the byte can be read. + * + * @return The byte read, or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + int ch = -1; + + while (in != null && (ch = in.read()) < 0) + { + in.close(); + in = getNextStream(); + } + + return ch; + } + + /** + * This method reads bytes from a stream and stores them into a caller + * supplied buffer. It starts storing the data at index offset + * into the buffer and attempts to read len bytes. This method + * can return before reading the number of bytes requested. The actual number + * of bytes read is returned as an int. A -1 is returend to indicate the + * end of the stream. This will only happen when all of the subordinate + * streams have been read. + *

    + * This method will block until at least one byte can be read. + * + * @param b The array into which bytes read should be stored + * @param off The offset into the array to start storing bytes + * @param len The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public int read(byte[] b, int off, int len) throws IOException + { + int ch = -1; + + // The validity of the parameters will be checked by in.read so + // don't bother doing it here. + while (in != null && (ch = in.read(b, off, len)) < 0) + { + in.close(); + in = getNextStream(); + } + + return ch; + } + + /** + * This private method is used to get the next InputStream to + * read from. Returns null when no more streams are available. + */ + private InputStream getNextStream() + { + InputStream nextIn = null; + + if (e != null) + { + if (e.hasMoreElements()) + nextIn = (InputStream) e.nextElement(); + } + else + if (in2 != null) + { + nextIn = in2; + in2 = null; + } + + return nextIn; + } +} diff --git a/libjava/classpath/java/io/Serializable.java b/libjava/classpath/java/io/Serializable.java new file mode 100644 index 0000000..a6d99f6 --- /dev/null +++ b/libjava/classpath/java/io/Serializable.java @@ -0,0 +1,54 @@ +/* Serializable.java -- Interface to indicate a class may be serialized + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * Status: Believed complete + */ + +/** + * This interface has no methods. It simply serves to indicate that + * the implementing class may be serialized. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public interface Serializable +{ +} // interface Serializable diff --git a/libjava/classpath/java/io/SerializablePermission.java b/libjava/classpath/java/io/SerializablePermission.java new file mode 100644 index 0000000..b5c07e4 --- /dev/null +++ b/libjava/classpath/java/io/SerializablePermission.java @@ -0,0 +1,113 @@ +/* SerializablePermission.java -- Basic permissions related to serialization. + Copyright (C) 1998, 2000, 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 java.io; + +import java.security.BasicPermission; + +/** + * This class models permissions related to serialization. As a subclass + * of BasicPermission, this class has permissions that have + * a name only. There is no associated action list. + *

    + * There are currently two allowable permission names for this class: + *

      + *
    • enableSubclassImplementation - Allows a subclass to + * override the default serialization behavior of objects.
    • + *
    • enableSubstitution - Allows substitution of one object + * for another during serialization or deserialization.
    • + *
    + * + * @see java.security.BasicPermission + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public final class SerializablePermission extends BasicPermission +{ + static final long serialVersionUID = 8537212141160296410L; + + /* + * Class Variables + */ + + private static final String[] legal_names = { "enableSubclassImplementation", + "enableSubstitution" }; + /* + * Constructors + */ + + /** + * This method initializes a new instance of + * SerializablePermission + * that has the specified name. + * + * @param name The name of the permission. + * + * @exception IllegalArgumentException If the name is not valid for + * this class. + */ + public SerializablePermission(String name) + { + this(name, null); + } + + /** + * This method initializes a new instance of + * SerializablePermission + * that has the specified name and action list. Note that the action list + * is unused in this class. + * + * @param name The name of the permission. + * @param actions The action list (unused). + * + * @exception IllegalArgumentException If the name is not valid for + * this class. + */ + public SerializablePermission(String name, String actions) + { + super(name, actions); + + for (int i = 0; i < legal_names.length; i++) + if (legal_names[i].equals(name)) + return; + + throw new IllegalArgumentException("Bad permission name: " + name); + } + +} // class SerializablePermission + diff --git a/libjava/classpath/java/io/StreamCorruptedException.java b/libjava/classpath/java/io/StreamCorruptedException.java new file mode 100644 index 0000000..d24d121 --- /dev/null +++ b/libjava/classpath/java/io/StreamCorruptedException.java @@ -0,0 +1,73 @@ +/* StreamCorruptedException.java -- Error in stream during serialization + Copyright (C) 1998, 2000, 2001, 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 java.io; + +/** + * This exception is thrown when there is an error in the data that is + * read from a stream during de-serialization. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class StreamCorruptedException extends ObjectStreamException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 8983558202217591746L; + + /** + * Create an exception without a descriptive error message. + */ + public StreamCorruptedException() + { + } + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + public StreamCorruptedException(String message) + { + super(message); + } +} // class StreamCorruptedException diff --git a/libjava/classpath/java/io/StreamTokenizer.java b/libjava/classpath/java/io/StreamTokenizer.java new file mode 100644 index 0000000..bd7773b --- /dev/null +++ b/libjava/classpath/java/io/StreamTokenizer.java @@ -0,0 +1,708 @@ +/* StreamTokenizer.java -- parses streams of characters into tokens + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +/** + * This class parses streams of characters into tokens. There are a + * million-zillion flags that can be set to control the parsing, as + * described under the various method headings. + * + * @author Warren Levy (warrenl@cygnus.com) + * @date October 25, 1998. + */ +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +public class StreamTokenizer +{ + /** A constant indicating that the end of the stream has been read. */ + public static final int TT_EOF = -1; + + /** A constant indicating that the end of the line has been read. */ + public static final int TT_EOL = '\n'; + + /** A constant indicating that a number token has been read. */ + public static final int TT_NUMBER = -2; + + /** A constant indicating that a word token has been read. */ + public static final int TT_WORD = -3; + + /** A constant indicating that no tokens have been read yet. */ + private static final int TT_NONE = -4; + + /** + * Contains the type of the token read resulting from a call to nextToken + * The rules are as follows: + *
      + *
    • For a token consisting of a single ordinary character, this is the + * value of that character.
    • + *
    • For a quoted string, this is the value of the quote character
    • + *
    • For a word, this is TT_WORD
    • + *
    • For a number, this is TT_NUMBER
    • + *
    • For the end of the line, this is TT_EOL
    • + *
    • For the end of the stream, this is TT_EOF
    • + *
    + */ + public int ttype = TT_NONE; + + /** The String associated with word and string tokens. */ + public String sval; + + /** The numeric value associated with number tokens. */ + public double nval; + + /* Indicates whether end-of-line is recognized as a token. */ + private boolean eolSignificant = false; + + /* Indicates whether word tokens are automatically made lower case. */ + private boolean lowerCase = false; + + /* Indicates whether C++ style comments are recognized and skipped. */ + private boolean slashSlash = false; + + /* Indicates whether C style comments are recognized and skipped. */ + private boolean slashStar = false; + + /* Attribute tables of each byte from 0x00 to 0xFF. */ + private boolean[] whitespace = new boolean[256]; + private boolean[] alphabetic = new boolean[256]; + private boolean[] numeric = new boolean[256]; + private boolean[] quote = new boolean[256]; + private boolean[] comment = new boolean[256]; + + /* The Reader associated with this class. */ + private PushbackReader in; + + /* Indicates if a token has been pushed back. */ + private boolean pushedBack = false; + + /* Contains the current line number of the reader. */ + private int lineNumber = 1; + + /** + * This method reads bytes from an InputStream and tokenizes + * them. For details on how this method operates by default, see + * StreamTokenizer(Reader). + * + * @param is The InputStream to read from + * + * @deprecated Since JDK 1.1. + */ + public StreamTokenizer(InputStream is) + { + this(new InputStreamReader(is)); + } + + /** + * This method initializes a new StreamTokenizer to read + * characters from a Reader and parse them. The char values + * have their hight bits masked so that the value is treated a character + * in the range of 0x0000 to 0x00FF. + *

    + * This constructor sets up the parsing table to parse the stream in the + * following manner: + *

      + *
    • The values 'A' through 'Z', 'a' through 'z' and 0xA0 through 0xFF + * are initialized as alphabetic
    • + *
    • The values 0x00 through 0x20 are initialized as whitespace
    • + *
    • The values '\'' and '"' are initialized as quote characters
    • + *
    • '/' is a comment character
    • + *
    • Numbers will be parsed
    • + *
    • EOL is not treated as significant
    • + *
    • C and C++ (//) comments are not recognized
    • + *
    + * + * @param r The Reader to read chars from + */ + public StreamTokenizer(Reader r) + { + in = new PushbackReader(r); + + whitespaceChars(0x00, 0x20); + wordChars('A', 'Z'); + wordChars('a', 'z'); + wordChars(0xA0, 0xFF); + commentChar('/'); + quoteChar('\''); + quoteChar('"'); + parseNumbers(); + } + + /** + * This method sets the comment attribute on the specified + * character. Other attributes for the character are cleared. + * + * @param ch The character to set the comment attribute for, passed as an int + */ + public void commentChar(int ch) + { + if (ch >= 0 && ch <= 255) + { + comment[ch] = true; + whitespace[ch] = false; + alphabetic[ch] = false; + numeric[ch] = false; + quote[ch] = false; + } + } + + /** + * This method sets a flag that indicates whether or not the end of line + * sequence terminates and is a token. The defaults to false + * + * @param flag true if EOF is significant, false + * otherwise + */ + public void eolIsSignificant(boolean flag) + { + eolSignificant = flag; + } + + /** + * This method returns the current line number. Note that if the + * pushBack() method is called, it has no effect on the + * line number returned by this method. + * + * @return The current line number + */ + public int lineno() + { + return lineNumber; + } + + /** + * This method sets a flag that indicates whether or not alphabetic + * tokens that are returned should be converted to lower case. + * + * @param flag true to convert to lower case, + * false otherwise + */ + public void lowerCaseMode(boolean flag) + { + lowerCase = flag; + } + + private boolean isWhitespace(int ch) + { + return (ch >= 0 && ch <= 255 && whitespace[ch]); + } + + private boolean isAlphabetic(int ch) + { + return ((ch > 255) || (ch >= 0 && alphabetic[ch])); + } + + private boolean isNumeric(int ch) + { + return (ch >= 0 && ch <= 255 && numeric[ch]); + } + + private boolean isQuote(int ch) + { + return (ch >= 0 && ch <= 255 && quote[ch]); + } + + private boolean isComment(int ch) + { + return (ch >= 0 && ch <= 255 && comment[ch]); + } + + /** + * This method reads the next token from the stream. It sets the + * ttype variable to the appropriate token type and + * returns it. It also can set sval or nval + * as described below. The parsing strategy is as follows: + *
      + *
    • Skip any whitespace characters.
    • + *
    • If a numeric character is encountered, attempt to parse a numeric + * value. Leading '-' characters indicate a numeric only if followed by + * another non-'-' numeric. The value of the numeric token is terminated + * by either the first non-numeric encountered, or the second occurrence of + * '-' or '.'. The token type returned is TT_NUMBER and nval + * is set to the value parsed.
    • + *
    • If an alphabetic character is parsed, all subsequent characters + * are read until the first non-alphabetic or non-numeric character is + * encountered. The token type returned is TT_WORD and the value parsed + * is stored in sval. If lower case mode is set, the token + * stored in sval is converted to lower case. The end of line + * sequence terminates a word only if EOL signficance has been turned on. + * The start of a comment also terminates a word. Any character with a + * non-alphabetic and non-numeric attribute (such as white space, a quote, + * or a commet) are treated as non-alphabetic and terminate the word.
    • + *
    • If a comment character is parsed, then all remaining characters on + * the current line are skipped and another token is parsed. Any EOL or + * EOF's encountered are not discarded, but rather terminate the comment.
    • + *
    • If a quote character is parsed, then all characters up to the + * second occurrence of the same quote character are parsed into a + * String. This String is stored as + * sval, but is not converted to lower case, even if lower case + * mode is enabled. The token type returned is the value of the quote + * character encountered. Any escape sequences + * (\b (backspace), \t (HTAB), \n (linefeed), \f (form feed), \r + * (carriage return), \" (double quote), \' (single quote), \\ + * (backslash), \XXX (octal esacpe)) are converted to the appropriate + * char values. Invalid esacape sequences are left in untranslated. + * Unicode characters like ('\ u0000') are not recognized.
    • + *
    • If the C++ comment sequence "//" is encountered, and the parser + * is configured to handle that sequence, then the remainder of the line + * is skipped and another token is read exactly as if a character with + * the comment attribute was encountered.
    • + *
    • If the C comment sequence "/*" is encountered, and the parser + * is configured to handle that sequence, then all characters up to and + * including the comment terminator sequence are discarded and another + * token is parsed.
    • + *
    • If all cases above are not met, then the character is an ordinary + * character that is parsed as a token by itself. The char encountered + * is returned as the token type.
    • + *
    + * + * @return The token type + * @exception IOException If an I/O error occurs + */ + public int nextToken() throws IOException + { + if (pushedBack) + { + pushedBack = false; + if (ttype != TT_NONE) + return ttype; + } + + sval = null; + int ch; + + // Skip whitespace. Deal with EOL along the way. + while (isWhitespace(ch = in.read())) + if (ch == '\n' || ch == '\r') + { + lineNumber++; + + // Throw away \n if in combination with \r. + if (ch == '\r' && (ch = in.read()) != '\n') + { + if (ch != TT_EOF) + in.unread(ch); + } + if (eolSignificant) + return (ttype = TT_EOL); + } + + if (ch == '/') + if ((ch = in.read()) == '/' && slashSlash) + { + while ((ch = in.read()) != '\n' && ch != '\r' && ch != TT_EOF) + ; + if (ch != TT_EOF) + in.unread(ch); + return nextToken(); // Recursive, but not too deep in normal cases + } + else if (ch == '*' && slashStar) + { + while (true) + { + ch = in.read(); + if (ch == '*') + { + if ((ch = in.read()) == '/') + break; + else if (ch != TT_EOF) + in.unread(ch); + } + else if (ch == '\n' || ch == '\r') + { + lineNumber++; + if (ch == '\r' && (ch = in.read()) != '\n') + { + if (ch != TT_EOF) + in.unread(ch); + } + } + else if (ch == TT_EOF) + { + break; + } + } + return nextToken(); // Recursive, but not too deep in normal cases + } + else + { + if (ch != TT_EOF) + in.unread(ch); + ch = '/'; + } + + if (ch == TT_EOF) + ttype = TT_EOF; + else if (isNumeric(ch)) + { + boolean isNegative = false; + if (ch == '-') + { + // Read ahead to see if this is an ordinary '-' rather than numeric. + ch = in.read(); + if (isNumeric(ch) && ch != '-') + { + isNegative = true; + } + else + { + if (ch != TT_EOF) + in.unread(ch); + return (ttype = '-'); + } + } + + StringBuffer tokbuf = new StringBuffer(); + tokbuf.append((char) ch); + + int decCount = 0; + while (isNumeric(ch = in.read()) && ch != '-') + if (ch == '.' && decCount++ > 0) + break; + else + tokbuf.append((char) ch); + + if (ch != TT_EOF) + in.unread(ch); + ttype = TT_NUMBER; + try + { + nval = Double.valueOf(tokbuf.toString()).doubleValue(); + } + catch (NumberFormatException _) + { + nval = 0.0; + } + if (isNegative) + nval = -nval; + } + else if (isAlphabetic(ch)) + { + StringBuffer tokbuf = new StringBuffer(); + tokbuf.append((char) ch); + while (isAlphabetic(ch = in.read()) || isNumeric(ch)) + tokbuf.append((char) ch); + if (ch != TT_EOF) + in.unread(ch); + ttype = TT_WORD; + sval = tokbuf.toString(); + if (lowerCase) + sval = sval.toLowerCase(); + } + else if (isComment(ch)) + { + while ((ch = in.read()) != '\n' && ch != '\r' && ch != TT_EOF) + ; + if (ch != TT_EOF) + in.unread(ch); + return nextToken(); // Recursive, but not too deep in normal cases. + } + else if (isQuote(ch)) + { + ttype = ch; + StringBuffer tokbuf = new StringBuffer(); + while ((ch = in.read()) != ttype && ch != '\n' && ch != '\r' && + ch != TT_EOF) + { + if (ch == '\\') + switch (ch = in.read()) + { + case 'a': ch = 0x7; + break; + case 'b': ch = '\b'; + break; + case 'f': ch = 0xC; + break; + case 'n': ch = '\n'; + break; + case 'r': ch = '\r'; + break; + case 't': ch = '\t'; + break; + case 'v': ch = 0xB; + break; + case '\n': ch = '\n'; + break; + case '\r': ch = '\r'; + break; + case '\"': + case '\'': + case '\\': + break; + default: + int ch1, nextch; + if ((nextch = ch1 = ch) >= '0' && ch <= '7') + { + ch -= '0'; + if ((nextch = in.read()) >= '0' && nextch <= '7') + { + ch = ch * 8 + nextch - '0'; + if ((nextch = in.read()) >= '0' && nextch <= '7' && + ch1 >= '0' && ch1 <= '3') + { + ch = ch * 8 + nextch - '0'; + nextch = in.read(); + } + } + } + + if (nextch != TT_EOF) + in.unread(nextch); + } + + tokbuf.append((char) ch); + } + + // Throw away matching quote char. + if (ch != ttype && ch != TT_EOF) + in.unread(ch); + + sval = tokbuf.toString(); + } + else + { + ttype = ch; + } + + return ttype; + } + + private void resetChar(int ch) + { + whitespace[ch] = alphabetic[ch] = numeric[ch] = quote[ch] = comment[ch] = + false; + } + + /** + * This method makes the specified character an ordinary character. This + * means that none of the attributes (whitespace, alphabetic, numeric, + * quote, or comment) will be set on this character. This character will + * parse as its own token. + * + * @param ch The character to make ordinary, passed as an int + */ + public void ordinaryChar(int ch) + { + if (ch >= 0 && ch <= 255) + resetChar(ch); + } + + /** + * This method makes all the characters in the specified range, range + * terminators included, ordinary. This means the none of the attributes + * (whitespace, alphabetic, numeric, quote, or comment) will be set on + * any of the characters in the range. This makes each character in this + * range parse as its own token. + * + * @param low The low end of the range of values to set the whitespace + * attribute for + * @param hi The high end of the range of values to set the whitespace + * attribute for + */ + public void ordinaryChars(int low, int hi) + { + if (low < 0) + low = 0; + if (hi > 255) + hi = 255; + for (int i = low; i <= hi; i++) + resetChar(i); + } + + /** + * This method sets the numeric attribute on the characters '0' - '9' and + * the characters '.' and '-'. + */ + public void parseNumbers() + { + for (int i = 0; i <= 9; i++) + numeric['0' + i] = true; + + numeric['.'] = true; + numeric['-'] = true; + } + + /** + * Puts the current token back into the StreamTokenizer so + * nextToken will return the same value on the next call. + * May cause the lineno method to return an incorrect value + * if lineno is called before the next call to nextToken. + */ + public void pushBack() + { + pushedBack = true; + } + + /** + * This method sets the quote attribute on the specified character. + * Other attributes for the character are cleared. + * + * @param ch The character to set the quote attribute for, passed as an int. + */ + public void quoteChar(int ch) + { + if (ch >= 0 && ch <= 255) + { + quote[ch] = true; + comment[ch] = false; + whitespace[ch] = false; + alphabetic[ch] = false; + numeric[ch] = false; + } + } + + /** + * This method removes all attributes (whitespace, alphabetic, numeric, + * quote, and comment) from all characters. It is equivalent to calling + * ordinaryChars(0x00, 0xFF). + * + * @see #ordinaryChars(int, int) + */ + public void resetSyntax() + { + ordinaryChars(0x00, 0xFF); + } + + /** + * This method sets a flag that indicates whether or not "C++" language style + * comments ("//" comments through EOL ) are handled by the parser. + * If this is true commented out sequences are skipped and + * ignored by the parser. This defaults to false. + * + * @param flag true to recognized and handle "C++" style + * comments, false otherwise + */ + public void slashSlashComments(boolean flag) + { + slashSlash = flag; + } + + /** + * This method sets a flag that indicates whether or not "C" language style + * comments (with nesting not allowed) are handled by the parser. + * If this is true commented out sequences are skipped and + * ignored by the parser. This defaults to false. + * + * @param flag true to recognized and handle "C" style comments, + * false otherwise + */ + public void slashStarComments(boolean flag) + { + slashStar = flag; + } + + /** + * This method returns the current token value as a String in + * the form "Token[x], line n", where 'n' is the current line numbers and + * 'x' is determined as follows. + *

    + *

      + *
    • If no token has been read, then 'x' is "NOTHING" and 'n' is 0
    • + *
    • If ttype is TT_EOF, then 'x' is "EOF"
    • + *
    • If ttype is TT_EOL, then 'x' is "EOL"
    • + *
    • If ttype is TT_WORD, then 'x' is sval
    • + *
    • If ttype is TT_NUMBER, then 'x' is "n=strnval" where + * 'strnval' is String.valueOf(nval).
    • + *
    • If ttype is a quote character, then 'x' is + * sval
    • + *
    • For all other cases, 'x' is ttype
    • + *
    + */ + public String toString() + { + String tempstr; + if (ttype == TT_EOF) + tempstr = "EOF"; + else if (ttype == TT_EOL) + tempstr = "EOL"; + else if (ttype == TT_WORD) + tempstr = sval; + else if (ttype == TT_NUMBER) + tempstr = "n=" + nval; + else if (ttype == TT_NONE) + tempstr = "NOTHING"; + else // must be an ordinary char. + tempstr = "\'" + (char) ttype + "\'"; + + return "Token[" + tempstr + "], line " + lineno(); + } + + /** + * This method sets the whitespace attribute for all characters in the + * specified range, range terminators included. + * + * @param low The low end of the range of values to set the whitespace + * attribute for + * @param hi The high end of the range of values to set the whitespace + * attribute for + */ + public void whitespaceChars(int low, int hi) + { + if (low < 0) + low = 0; + if (hi > 255) + hi = 255; + for (int i = low; i <= hi; i++) + { + resetChar(i); + whitespace[i] = true; + } + } + + /** + * This method sets the alphabetic attribute for all characters in the + * specified range, range terminators included. + * + * @param low The low end of the range of values to set the alphabetic + * attribute for + * @param hi The high end of the range of values to set the alphabetic + * attribute for + */ + public void wordChars(int low, int hi) + { + if (low < 0) + low = 0; + if (hi > 255) + hi = 255; + for (int i = low; i <= hi; i++) + alphabetic[i] = true; + } +} diff --git a/libjava/classpath/java/io/StringBufferInputStream.java b/libjava/classpath/java/io/StringBufferInputStream.java new file mode 100644 index 0000000..0908819 --- /dev/null +++ b/libjava/classpath/java/io/StringBufferInputStream.java @@ -0,0 +1,187 @@ +/* StringBufferInputStream.java -- Read an String as a stream + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. Deprecated in JDK 1.1. + */ + +/** + * This class permits a String to be read as an input stream. + * The low eight bits of each character in the String are the + * bytes that are returned. The high eight bits of each character are + * discarded. + *

    + * The mark/reset functionality in this class behaves differently than + * normal. The mark() method is always ignored and the + * reset() method always resets in stream to start reading from + * position 0 in the String. Note that since this method does not override + * markSupported() in InputStream, calling that + * method will return false. + *

    + * Note that this class is deprecated because it does not properly handle + * 16-bit Java characters. It is provided for backwards compatibility only + * and should not be used for new development. The StringReader + * class should be used instead. + * + * @deprecated + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class StringBufferInputStream extends InputStream +{ + /** The String which is the input to this stream. */ + protected String buffer; + + /** Position of the next byte in buffer to be read. */ + protected int pos = 0; + + /** The length of the String buffer. */ + protected int count; + + /** + * Create a new StringBufferInputStream that will read bytes + * from the passed in String. This stream will read from the + * beginning to the end of the String. + * + * @param s The String this stream will read from. + */ + public StringBufferInputStream(String s) + { + buffer = s; + count = s.length(); + } + + /** + * This method returns the number of bytes available to be read from this + * stream. The value returned will be equal to count - pos. + * + * @return The number of bytes that can be read from this stream before + * blocking, which is all of them + */ + public int available() + { + return count - pos; + } + + /** + * This method reads one byte from the stream. The pos counter + * is advanced to the next byte to be read. The byte read is returned as + * an int in the range of 0-255. If the stream position is already at the + * end of the buffer, no byte is read and a -1 is returned in order to + * indicate the end of the stream. + * + * @return The byte read, or -1 if end of stream + */ + public int read() + { + if (pos >= count) + return -1; // EOF + + return ((int) buffer.charAt(pos++)) & 0xFF; + } + +/** + * This method reads bytes from the stream and stores them into a caller + * supplied buffer. It starts storing the data at index offset + * into the buffer and attempts to read len bytes. This method + * can return before reading the number of bytes requested if the end of the + * stream is encountered first. The actual number of bytes read is + * returned. If no bytes can be read because the stream is already at + * the end of stream position, a -1 is returned. + *

    + * This method does not block. + * + * @param b The array into which the bytes read should be stored. + * @param off The offset into the array to start storing bytes + * @param len The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of stream. + */ + public int read(byte[] b, int off, int len) + { + if (off < 0 || len < 0 || off + len > b.length) + throw new ArrayIndexOutOfBoundsException(); + + if (pos >= count) + return -1; // EOF + + int numRead = Math.min(len, count - pos); + if (numRead < 0) + return 0; + + buffer.getBytes(pos, pos + numRead, b, off); + pos += numRead; + return numRead; + } + + /** + * This method sets the read position in the stream to the beginning + * setting the pos variable equal to 0. Note that this differs + * from the common implementation of the reset() method. + */ + public void reset() + { + pos = 0; + } + + /** + * This method attempts to skip the requested number of bytes in the + * input stream. It does this by advancing the pos value by the + * specified number of bytes. It this would exceed the length of the + * buffer, then only enough bytes are skipped to position the stream at + * the end of the buffer. The actual number of bytes skipped is returned. + * + * @param n The requested number of bytes to skip + * + * @return The actual number of bytes skipped. + */ + public long skip(long n) + { + if (n < 0) + return 0L; + + long actualSkip = Math.min(n, count - pos); + pos += actualSkip; + return actualSkip; + } +} diff --git a/libjava/classpath/java/io/StringReader.java b/libjava/classpath/java/io/StringReader.java new file mode 100644 index 0000000..7e4e7d8 --- /dev/null +++ b/libjava/classpath/java/io/StringReader.java @@ -0,0 +1,209 @@ +/* StringReader.java -- permits a String to be read as a character input stream + Copyright (C) 1998, 1999, 2000, 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct + */ + +/** + * This class permits a String to be read as a character + * input stream. + *

    + * The mark/reset functionality in this class behaves differently than + * normal. If no mark has been set, then calling the reset() + * method rewinds the read pointer to the beginning of the String. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @date October 19, 1998. + */ +public class StringReader extends Reader +{ + /* A String provided by the creator of the stream. */ + private String buf; + + /* Position of the next char in buf to be read. */ + private int pos; + + /* The currently marked position in the stream. */ + private int markedPos; + + /* The index in buf one greater than the last valid character. */ + private int count; + + /** + * Create a new StringReader that will read chars from the + * passed in String. This stream will read from the beginning + * to the end of the String. + * + * @param buffer The String this stream will read from. + */ + public StringReader(String buffer) + { + super(); + buf = buffer; + + count = buffer.length(); + markedPos = pos = 0; + } + + public void close() + { + synchronized (lock) + { + buf = null; + } + } + + public void mark(int readAheadLimit) throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + + // readAheadLimit is ignored per Java Class Lib. book, p. 1692. + markedPos = pos; + } + } + + public boolean markSupported() + { + return true; + } + + public int read() throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + + if (pos < count) + return ((int) buf.charAt(pos++)) & 0xFFFF; + return -1; + } + } + + public int read(char[] b, int off, int len) throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + + /* Don't need to check pos value, arraycopy will check it. */ + if (off < 0 || len < 0 || off + len > b.length) + throw new ArrayIndexOutOfBoundsException(); + + if (pos >= count) + return -1; + + int lastChar = Math.min(count, pos + len); + buf.getChars(pos, lastChar, b, off); + int numChars = lastChar - pos; + pos = lastChar; + return numChars; + } + } + + /** + * This method determines if the stream is ready to be read. This class + * is always ready to read and so always returns true, unless + * close() has previously been called in which case an IOException is + * thrown. + * + * @return true to indicate that this object is ready to be read. + * @exception IOException If the stream is closed. + */ + public boolean ready() throws IOException + { + if (buf == null) + throw new IOException("Stream closed"); + + return true; + } + + /** + * Sets the read position in the stream to the previously + * marked position or to 0 (i.e., the beginning of the stream) if the mark + * has not already been set. + */ + public void reset() throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + + pos = markedPos; + } + } + + /** + * This method attempts to skip the requested number of chars in the + * input stream. It does this by advancing the pos value by + * the specified number of chars. It this would exceed the length of the + * buffer, then only enough chars are skipped to position the stream at + * the end of the buffer. The actual number of chars skipped is returned. + * + * @param n The requested number of chars to skip + * + * @return The actual number of chars skipped. + */ + public long skip(long n) throws IOException + { + synchronized (lock) + { + if (buf == null) + throw new IOException("Stream closed"); + + // Even though the var numChars is a long, in reality it can never + // be larger than an int since the result of subtracting 2 positive + // ints will always fit in an int. Since we have to return a long + // anyway, numChars might as well just be a long. + long numChars = Math.min((long) (count - pos), n < 0 ? 0L : n); + pos += numChars; + return numChars; + } + } +} + diff --git a/libjava/classpath/java/io/StringWriter.java b/libjava/classpath/java/io/StringWriter.java new file mode 100644 index 0000000..a1e9aeb --- /dev/null +++ b/libjava/classpath/java/io/StringWriter.java @@ -0,0 +1,191 @@ +/* StringWriter.java -- Writes bytes to a StringBuffer + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +// Wow is this a dumb class. CharArrayWriter can do all this and +// more. I would redirect all calls to one in fact, but the javadocs say +// use a StringBuffer so I will comply. + +/** + * This class writes chars to an internal StringBuffer that + * can then be used to retrieve a String. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class StringWriter extends Writer +{ + /** + * This is the default size of the buffer if the user doesn't specify it. + * @specnote The JCL Volume 1 says that 16 is the default size. + */ + private static final int DEFAULT_BUFFER_SIZE = 16; + + /** + * This method closes the stream. The contents of the internal buffer + * can still be retrieved, but future writes are not guaranteed to work. + * + * @exception IOException If an error orrurs. + */ + public void close () throws IOException + { + // JCL says this does nothing. This seems to violate the Writer + // contract, in that other methods should still throw an + // IOException after a close. Still, we just follow JCL. + } + + /** + * This method flushes any buffered characters to the underlying output. + * It does nothing in this class. + */ + public void flush () + { + } + + /** + * This method returns the StringBuffer object that this + * object is writing to. Note that this is the actual internal buffer, so + * any operations performed on it will affect this stream object. + * + * @return The StringBuffer object being written to + */ + public StringBuffer getBuffer () + { + return buffer; + } + + /** + * This method initializes a new StringWriter to write to a + * StringBuffer initially sized to a default size of 16 + * chars. + */ + public StringWriter () + { + this (DEFAULT_BUFFER_SIZE); + } + + /** + * This method initializes a new StringWriter to write to a + * StringBuffer with the specified initial size. + * + * @param size The initial size to make the StringBuffer + */ + public StringWriter (int size) + { + super (); + buffer = new StringBuffer (size); + lock = buffer; + } + + /** + * This method returns the contents of the internal StringBuffer + * as a String. + * + * @return A String representing the chars written to + * this stream. + */ + public String toString () + { + return buffer.toString(); + } + + /** + * This method writes a single character to the output, storing it in + * the internal buffer. + * + * @param oneChar The char to write, passed as an int. + */ + public void write (int oneChar) + { + buffer.append((char) (oneChar & 0xFFFF)); + } + + /** + * This method writes len chars from the specified + * array starting at index offset in that array to this + * stream by appending the chars to the end of the internal buffer. + * + * @param chars The array of chars to write + * @param offset The index into the array to start writing from + * @param len The number of chars to write + */ + public void write (char[] chars, int offset, int len) + { + buffer.append(chars, offset, len); + } + + /** + * This method writes the characters in the specified String + * to the stream by appending them to the end of the internal buffer. + * + * @param str The String to write to the stream. + */ + public void write (String str) + { + buffer.append(str); + } + + /** + * This method writes out len characters of the specified + * String to the stream starting at character position + * offset into the stream. This is done by appending the + * characters to the internal buffer. + * + * @param str The String to write characters from + * @param offset The character position to start writing from + * @param len The number of characters to write. + */ + public void write (String str, int offset, int len) + { +// char[] tmpbuf = new char[len]; +// str.getChars(offset, offset+len, tmpbuf, 0); +// buf.append(tmpbuf, 0, tmpbuf.length); + // This implementation assumes that String.substring is more + // efficient than using String.getChars and copying the data + // twice. For libgcj, this is true. For Classpath, it is not. + // FIXME. + buffer.append(str.substring(offset, offset + len)); + } + + /** + * This is the StringBuffer that we use to store bytes that + * are written. + */ + private StringBuffer buffer; +} diff --git a/libjava/classpath/java/io/SyncFailedException.java b/libjava/classpath/java/io/SyncFailedException.java new file mode 100644 index 0000000..c514c44 --- /dev/null +++ b/libjava/classpath/java/io/SyncFailedException.java @@ -0,0 +1,66 @@ +/* SyncFailedException.java -- a file sync failed + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * Thrown when a file synchronization fails. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @see FileDescriptor#sync() + * @since 1.1 + * @status updated to 1.4 + */ +public class SyncFailedException extends IOException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -2353342684412443330L; + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + public SyncFailedException(String message) + { + super(message); + } +} // class SyncFailedException diff --git a/libjava/classpath/java/io/UTFDataFormatException.java b/libjava/classpath/java/io/UTFDataFormatException.java new file mode 100644 index 0000000..6bb76ae --- /dev/null +++ b/libjava/classpath/java/io/UTFDataFormatException.java @@ -0,0 +1,74 @@ +/* UTFDataFormatException.java -- thrown on bad format in UTF data + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * When reading a UTF string from an input stream, this exception is thrown + * to indicate that the data read is invalid. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @see DataInput + * @see DataInputStream#readUTF(DataInput) + * @status updated to 1.4 + */ +public class UTFDataFormatException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 420743449228280612L; + + /** + * Create a new UTFDataFormatException without a descriptive error message. + */ + public UTFDataFormatException() + { + } + + /** + * Create a new UTFDataFormatException with a descriptive error message. + * + * @param message the descriptive error message + */ + public UTFDataFormatException(String message) + { + super(message); + } +} // class UTFDataFormatException diff --git a/libjava/classpath/java/io/UnsupportedEncodingException.java b/libjava/classpath/java/io/UnsupportedEncodingException.java new file mode 100644 index 0000000..cf0ab64 --- /dev/null +++ b/libjava/classpath/java/io/UnsupportedEncodingException.java @@ -0,0 +1,73 @@ +/* UnsupportedEncodingException.java -- the requested encoding isn't supported + Copyright (C) 1998, 1999, 2001, 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 java.io; + +/** + * This exception is thrown when the requested character encoding is + * not supported. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class UnsupportedEncodingException extends IOException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -4274276298326136670L; + + /** + * Create an exception without a descriptive error message. + */ + public UnsupportedEncodingException() + { + } + + /** + * Create an exception with a descriptive error message. + * + * @param message the descriptive error message + */ + public UnsupportedEncodingException(String message) + { + super(message); + } +} // class UnsupportedEncodingException diff --git a/libjava/classpath/java/io/WriteAbortedException.java b/libjava/classpath/java/io/WriteAbortedException.java new file mode 100644 index 0000000..f051dc9 --- /dev/null +++ b/libjava/classpath/java/io/WriteAbortedException.java @@ -0,0 +1,109 @@ +/* WriteAbortedException.java -- wraps an exception thrown while writing + Copyright (C) 1998, 2000, 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 java.io; + +/** + * This exception is thrown when another ObjectStreamException occurs during + * a serialization read or write. The stream is reset, and deserialized + * objects are discarded. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public class WriteAbortedException extends ObjectStreamException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -3326426625597282442L; + + /** + * The cause of this exception. This pre-dates the exception chaining + * of Throwable; and although you can change this field, you are wiser + * to leave it alone. + * + * @serial the exception cause + */ + public Exception detail; + + /** + * Create a new WriteAbortedException with a specified message and + * cause. + * + * @param msg the message + * @param detail the cause + */ + public WriteAbortedException(String msg, Exception detail) + { + super(msg); + initCause(detail); + this.detail = detail; + } + + /** + * This method returns a message indicating what went wrong, in this + * format: + * super.getMessage() + (detail == null ? "" : "; " + detail). + * + * @return the chained message + */ + public String getMessage() + { + if (detail == this || detail == null) + return super.getMessage(); + return super.getMessage() + "; " + detail; + } + + /** + * Returns the cause of this exception. Note that this may not be the + * original cause, thanks to the detail field being public + * and non-final (yuck). However, to avoid violating the contract of + * Throwable.getCause(), this returns null if detail == this, + * as no exception can be its own cause. + * + * @return the cause + * @since 1.4 + */ + public Throwable getCause() + { + return detail == this ? null : detail; + } +} // class WriteAbortedException diff --git a/libjava/classpath/java/io/Writer.java b/libjava/classpath/java/io/Writer.java new file mode 100644 index 0000000..f153e31 --- /dev/null +++ b/libjava/classpath/java/io/Writer.java @@ -0,0 +1,192 @@ +/* Writer.java -- Base class for character output streams + Copyright (C) 1998, 1999, 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 java.io; + +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This abstract class forms the base of the hierarchy of classes that + * write output as a stream of chars. It provides a common set of methods + * for writing chars to stream. Subclasses implement and/or extend these + * methods to write chars in a particular manner or to a particular + * destination such as a file on disk or network connection. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + */ +public abstract class Writer +{ + /** + * This is the object used to synchronize criticial code sections for + * thread safety. Subclasses should use this field instead of using + * synchronized methods or explicity synchronizations on this + */ + protected Object lock; + + /** + * This is the default no-argument constructor for this class. This method + * will set up the class to synchronize criticial sections on itself. + */ + protected Writer() + { + lock = this; + } + + /** + * This method initializes a Writer that will synchronize + * on the specified Object. + * + * @param lock The Object to use for synchronizing critical + * sections. Must not be null. + */ + protected Writer(Object lock) + { + if (lock == null) + throw new NullPointerException(); + + this.lock = lock; + } + + /** + * This method forces any data that may have been buffered to be written + * to the underlying output device. Please note that the host environment + * might perform its own buffering unbeknowst to Java. In that case, a + * write made (for example, to a disk drive) might be cached in OS + * buffers instead of actually being written to disk. + * + * @exception IOException If an error occurs + */ + public abstract void flush() throws IOException; + + /** + * This method closes the stream. Any internal or native resources + * associated + * with this stream are freed. Any subsequent attempt to access the stream + * might throw an exception. + *

    + * This method in this class does nothing. + * + * @exception IOException If an error occurs + */ + public abstract void close() throws IOException; + + /** + * This method writes a single char to the output stream. + * + * @param b The char to be written to the output stream, passed as an int + * + * @exception IOException If an error occurs + */ + public void write(int b) throws IOException + { + char[] buf = new char[1]; + + buf[0] = (char)b; + write(buf, 0, buf.length); + } + + /** + * This method all the writes char from the passed array to the output + * stream. This method is equivalent to + * write(buf, 0, buf.length) which + * is exactly how it is implemented in this class. + * + * @param buf The array of char to write + * + * @exception IOException If an error occurs + */ + public void write(char[] buf) throws IOException + { + write(buf, 0, buf.length); + } + + /** + * This method writes len char from the specified array + * buf starting at index offset into the array. + *

    + * Subclasses must provide an implementation of this abstract method. + * + * @param buf The array of char to write from + * @param offset The index into the array to start writing from + * @param len The number of char to write + * + * @exception IOException If an error occurs + */ + public abstract void write(char[] buf, int offset, int len) + throws IOException; + + /** + * This method writes all the characters in a String to the + * output. + * + * @param str The String whose chars are to be written. + * + * @exception IOException If an error occurs + */ + public void write(String str) throws IOException + { + write(str, 0, str.length()); + } + + /** + * This method writes len chars from the String + * starting at position offset. + * + * @param str The String that is to be written + * @param offset The character offset into the String to start + * writing from + * @param len The number of chars to write + * + * @exception IOException If an error occurs + */ + public void write(String str, int offset, int len) throws IOException + { + // FIXME - for libgcj re-write using native code to not require + // copied buffer. + char[] buf = new char[len]; + + str.getChars(offset, offset + len, buf, 0); + write(buf, 0, len); + } + +} // class Writer + diff --git a/libjava/classpath/java/io/class-dependencies.conf b/libjava/classpath/java/io/class-dependencies.conf new file mode 100644 index 0000000..633bb17 --- /dev/null +++ b/libjava/classpath/java/io/class-dependencies.conf @@ -0,0 +1,100 @@ +# This property file contains dependencies of classes, methods, and +# field on other methods or classes. +# +# Syntax: +# +# : [... ] +# +# means that when is included, (... ) must +# be included as well. +# +# and are of the form +# +# +# +# or just +# +# +# +# Within dependencies, variables can be used. A variable is defined as +# follows: +# +# {variable}: value1 value2 ... value +# +# variables can be used on the right side of dependencies as follows: +# +# : com.bla.blu.{variable}.Class.m()V +# +# The use of the variable will expand to dependencies of the form +# +# : com.bla.blu.value1.Class.m()V +# : com.bla.blu.value2.Class.m()V +# ... +# : com.bla.blu.value.Class.m()V +# +# Variables can be redefined when building a system to select the +# required support for features like encodings, protocols, etc. +# +# Hints: +# +# - For methods and fields, the signature is mandatory. For +# specification, please see the Java Virtual Machine Specification by +# SUN. Unlike in the spec, field signatures (types) are in brackets. +# +# - Package names must be separated by '/' (and not '.'). E.g., +# java/lang/Class (this is necessary, because the '.' is used to +# separate method or field names from classes) +# +# - In case refers to a class, only the class itself will be +# included in the resulting binary, NOT necessarily all its methods +# and fields. If you want to refer to all methods and fields, you can +# write class.* as an abbreviation. +# +# - Abbreviations for packages are also possible: my/package/* means all +# methods and fields of all classes in my/package. +# +# - A line with a trailing '\' continues in the next line. + +java/io/File: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/io/IOException.(Ljava/lang/String;)V \ + java/lang/IllegalArgumentException.(Ljava/lang/String;)V + +java/io/FileDescriptor: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/lang/IllegalArgumentException.(Ljava/lang/String;)V \ + java/io/IOException.(Ljava/lang/String;)V + +java/io/FileInputStream: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/io/IOException.(Ljava/lang/String;)V \ + java/io/FileNotFoundException.(Ljava/lang/String;)V + +java/io/FileOutputStream: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/io/FileNotFoundException.(Ljava/lang/String;)V \ + java/io/IOException.(Ljava/lang/String;)V + +java/io/ObjectInputStream: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/lang/SecurityManager.currentClassLoader()Ljava/lang/ClassLoader; \ + java/lang/IllegalArgumentException.(Ljava/lang/String;)V + +java/io/ObjectOutputStream: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/lang/SecurityManager.currentClassLoader()Ljava/lang/ClassLoader; \ + java/lang/IllegalArgumentException.(Ljava/lang/String;)V + +java/io/RandomAccessFile: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/io/FileNotFoundException.(Ljava/lang/String;)V \ + java/io/IOException.(Ljava/lang/String;)V + +# end of file diff --git a/libjava/classpath/java/io/package.html b/libjava/classpath/java/io/package.html new file mode 100644 index 0000000..02e1c5b --- /dev/null +++ b/libjava/classpath/java/io/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.io + + +

    Classes for manipulating character and byte streams and files.

    + + + diff --git a/libjava/classpath/java/lang/AbstractMethodError.java b/libjava/classpath/java/lang/AbstractMethodError.java new file mode 100644 index 0000000..b9eb622 --- /dev/null +++ b/libjava/classpath/java/lang/AbstractMethodError.java @@ -0,0 +1,75 @@ +/* AbstractMethodError.java -- thrown if an abstract method is invoked + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * An AbstractMethodError is thrown when an application attempts + * to access an abstract method. Compilers typically detect this error, but + * it can be thrown at run time if the definition of a class has changed + * since the application was last compiled. This can also occur when + * reflecting on methods. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class AbstractMethodError extends IncompatibleClassChangeError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -1654391082989018462L; + + /** + * Create an error without a message. + */ + public AbstractMethodError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public AbstractMethodError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/Appendable.java b/libjava/classpath/java/lang/Appendable.java new file mode 100644 index 0000000..c096677 --- /dev/null +++ b/libjava/classpath/java/lang/Appendable.java @@ -0,0 +1,122 @@ +/* Appendable.java -- Something to which characters can be appended + 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 java.lang; + +import java.io.IOException; + +/** + *

    + * An Appendable object is one to which a sequence of Unicode + * characters can be added. The appended characters must be valid Unicode + * characters, and may include supplementary characters, composed of multiple + * 16-bit char values. + *

    + *

    + * The behaviour of the Appendable object is heavily dependent + * on the particular implementation being used. Some implementations may be + * thread-safe, while others may not. Likewise, some implementing classes + * may produce errors which aren't propogated to the invoking class, due + * to differences in the error handling used. + *

    + *

    + * Note: implementation of this interface is required for + * any class that wishes to receive data from a Formatter + * instance. + *

    + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface Appendable +{ + + /** + * Appends the Unicode character, c, to this Appendable + * object. + * + * @param c the character to append. + * @return a reference to this object. + * @throws IOException if an I/O error occurs. + */ + Appendable append(char c) + throws IOException; + + /** + * Appends the specified sequence of Unicode characters to this + * Appendable object. The entire sequence may not + * be appended, if constrained by the underlying implementation. + * For example, a buffer may reach its size limit before the entire + * sequence is appended. + * + * @param seq the character sequence to append. If seq is null, + * then the string "null" (the string representation of null) + * is appended. + * @return a reference to this object. + * @throws IOException if an I/O error occurs. + */ + Appendable append(CharSequence seq) + throws IOException; + + /** + * Appends the specified subsequence of Unicode characters to this + * Appendable object, starting and ending at the specified + * positions within the sequence. The entire sequence may not + * be appended, if constrained by the underlying implementation. + * For example, a buffer may reach its size limit before the entire + * sequence is appended. The behaviour of this method matches the + * behaviour of append(seq.subSequence(start,end)) when + * the sequence is not null. + * + * @param seq the character sequence to append. If seq is null, + * then the string "null" (the string representation of null) + * is appended. + * @param start the index of the first Unicode character to use from + * the sequence. + * @param end the index of the last Unicode character to use from the + * sequence. + * @return a reference to this object. + * @throws IOException if an I/O error occurs. + * @throws IndexOutOfBoundsException if either of the indices are negative, + * the start index occurs after the end index, or the end index is + * beyond the end of the sequence. + */ + Appendable append(CharSequence seq, int start, int end) + throws IOException; + +} diff --git a/libjava/classpath/java/lang/ArithmeticException.java b/libjava/classpath/java/lang/ArithmeticException.java new file mode 100644 index 0000000..5acea43 --- /dev/null +++ b/libjava/classpath/java/lang/ArithmeticException.java @@ -0,0 +1,77 @@ +/* ArithmeticException.java -- exception thrown to indicate conditions + like divide by zero. + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when a math error has occured, such as trying to divide an + * integer by zero. For example:
    + *
    + * int i = 0;
    + * int j = 2 / i;
    + * 
    + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class ArithmeticException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 2256477558314496007L; + + /** + * Create an exception without a message. + */ + public ArithmeticException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ArithmeticException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/ArrayIndexOutOfBoundsException.java b/libjava/classpath/java/lang/ArrayIndexOutOfBoundsException.java new file mode 100644 index 0000000..371623b --- /dev/null +++ b/libjava/classpath/java/lang/ArrayIndexOutOfBoundsException.java @@ -0,0 +1,87 @@ +/* ArrayIndexOutOfBoundsException.java -- exception thrown when accessing + an illegal index. + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when attempting to access a position outside the valid range of + * an array. For example:
    + *
    + * int[] i = { 1 };
    + * i[1] = 2;
    + * 
    + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -5116101128118950844L; + + /** + * Create an exception without a message. + */ + public ArrayIndexOutOfBoundsException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ArrayIndexOutOfBoundsException(String s) + { + super(s); + } + + /** + * Create an exception indicating the illegal index. + * + * @param index the invalid index + */ + public ArrayIndexOutOfBoundsException(int index) + { + super("Array index out of range: " + index); + } +} diff --git a/libjava/classpath/java/lang/ArrayStoreException.java b/libjava/classpath/java/lang/ArrayStoreException.java new file mode 100644 index 0000000..042e78c --- /dev/null +++ b/libjava/classpath/java/lang/ArrayStoreException.java @@ -0,0 +1,77 @@ +/* ArrayStoreException.java -- exception thrown to when trying to store an + object into an array of a different type. + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when trying to store an object of the wrong runtime type in an + * array. For example:
    + *
    + * Object[] o = new Integer[1];
    + * o[0] = "oops";
    + * 
    + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class ArrayStoreException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4522193890499838241L; + + /** + * Create an exception without a message. + */ + public ArrayStoreException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ArrayStoreException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/AssertionError.java b/libjava/classpath/java/lang/AssertionError.java new file mode 100644 index 0000000..778eb58 --- /dev/null +++ b/libjava/classpath/java/lang/AssertionError.java @@ -0,0 +1,148 @@ +/* AssertionError.java -- indication of a failed assertion + 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 java.lang; + +/** + * An assertion error normally occurs as a result of the assert + * statement added in JDK 1.4, to indicate that an assertion failed. There + * are enough constructors to ensure that + * new AssertionError(expression) will work for all + * expressions, regardless of type, as if the error message were given by + * the string "" + expression. This extends Error, + * because you usually do not want to inadvertently trap an assertion failure. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public class AssertionError extends Error +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = -5013299493970297370L; + + /** + * Construct an AssertionError with no detail message. + */ + public AssertionError() + { + } + + /** + * Construct an AssertionError with the string conversion of the given + * object as its error message. If the object is a Throwable, it is also + * set as the cause of this error. + * + * @param msg the source of the error message + * @see Throwable#getCause() + */ + public AssertionError(Object msg) + { + super("" + msg); + if (msg instanceof Throwable) + initCause((Throwable) msg); + } + + /** + * Construct an AssertionError with the string conversion of the given + * boolean as its error message. + * + * @param msg the source of the error message + */ + public AssertionError(boolean msg) + { + super(msg ? "true" : "false"); + } + + /** + * Construct an AssertionError with the string conversion of the given + * char as its error message. + * + * @param msg the source of the error message + */ + public AssertionError(char msg) + { + super(String.valueOf(msg)); + } + + /** + * Construct an AssertionError with the string conversion of the given + * int as its error message. + * + * @param msg the source of the error message + */ + public AssertionError(int msg) + { + super(Integer.toString(msg, 10)); + } + + /** + * Construct an AssertionError with the string conversion of the given + * long as its error message. + * + * @param msg the source of the error message + */ + public AssertionError(long msg) + { + super(Long.toString(msg)); + } + + /** + * Construct an AssertionError with the string conversion of the given + * float as its error message. + * + * @param msg the source of the error message + */ + public AssertionError(float msg) + { + super(Float.toString(msg)); + } + + /** + * Construct an AssertionError with the string conversion of the given + * double as its error message. + * + * @param msg the source of the error message + */ + public AssertionError(double msg) + { + super(Double.toString(msg)); + } +} diff --git a/libjava/classpath/java/lang/Boolean.java b/libjava/classpath/java/lang/Boolean.java new file mode 100644 index 0000000..b691028 --- /dev/null +++ b/libjava/classpath/java/lang/Boolean.java @@ -0,0 +1,224 @@ +/* Boolean.java -- object wrapper for boolean + Copyright (C) 1998, 2001, 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 java.lang; + +import java.io.Serializable; + +/** + * Instances of class Boolean represent primitive + * boolean values. + * + * @author Paul Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public final class Boolean implements Serializable +{ + /** + * Compatible with JDK 1.0.2+. + */ + private static final long serialVersionUID = -3665804199014368530L; + + /** + * This field is a Boolean object representing the + * primitive value true. This instance is returned + * by the static valueOf() methods if they return + * a Boolean representing true. + */ + public static final Boolean TRUE = new Boolean(true); + + /** + * This field is a Boolean object representing the + * primitive value false. This instance is returned + * by the static valueOf() methods if they return + * a Boolean representing false. + */ + public static final Boolean FALSE = new Boolean(false); + + /** + * The primitive type boolean is represented by this + * Class object. + * + * @since 1.1 + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass('Z'); + + /** + * The immutable value of this Boolean. + * @serial the wrapped value + */ + private final boolean value; + + /** + * Create a Boolean object representing the value of the + * argument value. In general the use of the static + * method valueof(boolean) is more efficient since it will + * not create a new object. + * + * @param value the primitive value of this Boolean + * @see #valueOf(boolean) + */ + public Boolean(boolean value) + { + this.value = value; + } + + /** + * Creates a Boolean object representing the primitive + * true if and only if s matches + * the string "true" ignoring case, otherwise the object will represent + * the primitive false. In general the use of the static + * method valueof(String) is more efficient since it will + * not create a new object. + * + * @param s the String representation of true + * or false + */ + public Boolean(String s) + { + value = "true".equalsIgnoreCase(s); + } + + /** + * Return the primitive boolean value of this + * Boolean object. + * + * @return true or false, depending on the value of this Boolean + */ + public boolean booleanValue() + { + return value; + } + + /** + * Returns the Boolean TRUE if the given boolean is + * true, otherwise it will return the Boolean + * FALSE. + * + * @param b the boolean to wrap + * @return the wrapper object + * @see #TRUE + * @see #FALSE + * @since 1.4 + */ + public static Boolean valueOf(boolean b) + { + return b ? TRUE : FALSE; + } + + /** + * Returns the Boolean TRUE if and only if the given + * String is equal, ignoring case, to the the String "true", otherwise + * it will return the Boolean FALSE. + * + * @param s the string to convert + * @return a wrapped boolean from the string + */ + public static Boolean valueOf(String s) + { + return "true".equalsIgnoreCase(s) ? TRUE : FALSE; + } + + /** + * Returns "true" if the value of the give boolean is true and + * returns "false" if the value of the given boolean is false. + * + * @param b the boolean to convert + * @return the string representation of the boolean + * @since 1.4 + */ + public static String toString(boolean b) + { + return b ? "true" : "false"; + } + + /** + * Returns "true" if the value of this object is true and + * returns "false" if the value of this object is false. + * + * @return the string representation of this + */ + public String toString() + { + return value ? "true" : "false"; + } + + /** + * Returns the integer 1231 if this object represents + * the primitive true and the integer 1237 + * otherwise. + * + * @return the hash code + */ + public int hashCode() + { + return value ? 1231 : 1237; + } + + /** + * If the obj is an instance of Boolean and + * has the same primitive value as this object then true + * is returned. In all other cases, including if the obj + * is null, false is returned. + * + * @param obj possibly an instance of any Class + * @return true if obj equals this + */ + public boolean equals(Object obj) + { + return obj instanceof Boolean && value == ((Boolean) obj).value; + } + + /** + * If the value of the system property name matches + * "true" ignoring case then the function returns true. + * + * @param name the property name to look up + * @return true if the property resulted in "true" + * @throws SecurityException if accessing the system property is forbidden + * @see System#getProperty(String) + */ + public static boolean getBoolean(String name) + { + if (name == null || "".equals(name)) + return false; + return "true".equalsIgnoreCase(System.getProperty(name)); + } +} diff --git a/libjava/classpath/java/lang/Byte.java b/libjava/classpath/java/lang/Byte.java new file mode 100644 index 0000000..338e216 --- /dev/null +++ b/libjava/classpath/java/lang/Byte.java @@ -0,0 +1,357 @@ +/* Byte.java -- object wrapper for byte + Copyright (C) 1998, 2001, 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 java.lang; + +/** + * Instances of class Byte represent primitive byte + * values. + * + * Additionally, this class provides various helper functions and variables + * useful to bytes. + * + * @author Paul Fisher + * @author John Keiser + * @author Per Bothner + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public final class Byte extends Number implements Comparable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -7183698231559129828L; + + /** + * The minimum value a byte can represent is -128 (or + * -27). + */ + public static final byte MIN_VALUE = -128; + + /** + * The maximum value a byte can represent is 127 (or + * 27 - 1). + */ + public static final byte MAX_VALUE = 127; + + /** + * The primitive type byte is represented by this + * Class object. + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass('B'); + + /** + * The immutable value of this Byte. + * + * @serial the wrapped byte + */ + private final byte value; + + /** + * Create a Byte object representing the value of the + * byte argument. + * + * @param value the value to use + */ + public Byte(byte value) + { + this.value = value; + } + + /** + * Create a Byte object representing the value specified + * by the String argument + * + * @param s the string to convert + * @throws NumberFormatException if the String does not contain a byte + * @see #valueOf(String) + */ + public Byte(String s) + { + value = parseByte(s, 10); + } + + /** + * Converts the byte to a String and assumes + * a radix of 10. + * + * @param b the byte to convert to String + * @return the String representation of the argument + */ + public static String toString(byte b) + { + return String.valueOf(b); + } + + /** + * Converts the specified String into a byte. + * This function assumes a radix of 10. + * + * @param s the String to convert + * @return the byte value of s + * @throws NumberFormatException if s cannot be parsed as a + * byte + * @see #parseByte(String) + */ + public static byte parseByte(String s) + { + return parseByte(s, 10); + } + + /** + * Converts the specified String into an int + * using the specified radix (base). The string must not be null + * or empty. It may begin with an optional '-', which will negate the answer, + * provided that there are also valid digits. Each digit is parsed as if by + * Character.digit(d, radix), and must be in the range + * 0 to radix - 1. Finally, the result must be + * within MIN_VALUE to MAX_VALUE, inclusive. + * Unlike Double.parseDouble, you may not have a leading '+'. + * + * @param s the String to convert + * @param radix the radix (base) to use in the conversion + * @return the String argument converted to byte + * @throws NumberFormatException if s cannot be parsed as a + * byte + */ + public static byte parseByte(String s, int radix) + { + int i = Integer.parseInt(s, radix, false); + if ((byte) i != i) + throw new NumberFormatException(); + return (byte) i; + } + + /** + * Creates a new Byte object using the String + * and specified radix (base). + * + * @param s the String to convert + * @param radix the radix (base) to convert with + * @return the new Byte + * @throws NumberFormatException if s cannot be parsed as a + * byte + * @see #parseByte(String, int) + */ + public static Byte valueOf(String s, int radix) + { + return new Byte(parseByte(s, radix)); + } + + /** + * Creates a new Byte object using the String, + * assuming a radix of 10. + * + * @param s the String to convert + * @return the new Byte + * @throws NumberFormatException if s cannot be parsed as a + * byte + * @see #Byte(String) + * @see #parseByte(String) + */ + public static Byte valueOf(String s) + { + return new Byte(parseByte(s, 10)); + } + + /** + * Convert the specified String into a Byte. + * The String may represent decimal, hexadecimal, or + * octal numbers. + * + *

    The extended BNF grammar is as follows:
    + *

    +   * DecodableString:
    +   *      ( [ - ] DecimalNumber )
    +   *    | ( [ - ] ( 0x | 0X
    +   *              | # ) { HexDigit }+ )
    +   *    | ( [ - ] 0 { OctalDigit } )
    +   * DecimalNumber:
    +   *        DecimalDigit except '0' { DecimalDigit }
    +   * DecimalDigit:
    +   *        Character.digit(d, 10) has value 0 to 9
    +   * OctalDigit:
    +   *        Character.digit(d, 8) has value 0 to 7
    +   * DecimalDigit:
    +   *        Character.digit(d, 16) has value 0 to 15
    +   * 
    + * Finally, the value must be in the range MIN_VALUE to + * MAX_VALUE, or an exception is thrown. + * + * @param s the String to interpret + * @return the value of the String as a Byte + * @throws NumberFormatException if s cannot be parsed as a + * byte + * @throws NullPointerException if s is null + * @see Integer#decode(String) + */ + public static Byte decode(String s) + { + int i = Integer.parseInt(s, 10, true); + if ((byte) i != i) + throw new NumberFormatException(); + return new Byte((byte) i); + } + + /** + * Return the value of this Byte. + * + * @return the byte value + */ + public byte byteValue() + { + return value; + } + + /** + * Return the value of this Byte as a short. + * + * @return the short value + */ + public short shortValue() + { + return value; + } + + /** + * Return the value of this Byte as an int. + * + * @return the int value + */ + public int intValue() + { + return value; + } + + /** + * Return the value of this Byte as a long. + * + * @return the long value + */ + public long longValue() + { + return value; + } + + /** + * Return the value of this Byte as a float. + * + * @return the float value + */ + public float floatValue() + { + return value; + } + + /** + * Return the value of this Byte as a double. + * + * @return the double value + */ + public double doubleValue() + { + return value; + } + + /** + * Converts the Byte value to a String and + * assumes a radix of 10. + * + * @return the String representation of this Byte + * @see Integer#toString() + */ + public String toString() + { + return String.valueOf(value); + } + + /** + * Return a hashcode representing this Object. Byte's hash + * code is simply its value. + * + * @return this Object's hash code + */ + public int hashCode() + { + return value; + } + + /** + * Returns true if obj is an instance of + * Byte and represents the same byte value. + * + * @param obj the object to compare + * @return whether these Objects are semantically equal + */ + public boolean equals(Object obj) + { + return obj instanceof Byte && value == ((Byte) obj).value; + } + + /** + * Compare two Bytes numerically by comparing their byte values. + * The result is positive if the first is greater, negative if the second + * is greater, and 0 if the two are equal. + * + * @param b the Byte to compare + * @return the comparison + * @since 1.2 + */ + public int compareTo(Byte b) + { + return value - b.value; + } + + /** + * Behaves like compareTo(Byte) unless the Object + * is not a Byte. + * + * @param o the object to compare + * @return the comparison + * @throws ClassCastException if the argument is not a Byte + * @see #compareTo(Byte) + * @see Comparable + * @since 1.2 + */ + public int compareTo(Object o) + { + return compareTo((Byte) o); + } +} diff --git a/libjava/classpath/java/lang/CharSequence.java b/libjava/classpath/java/lang/CharSequence.java new file mode 100644 index 0000000..5c014e1 --- /dev/null +++ b/libjava/classpath/java/lang/CharSequence.java @@ -0,0 +1,99 @@ +/* CharSequence.java -- Anything that has an indexed sequence of chars + 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 java.lang; + +/** + * General functions on a sequence of chars. This interface is implemented + * by String, StringBuffer and + * CharBuffer to give a uniform way to get chars at a certain + * index, the number of characters in the sequence and a subrange of the + * chars. Indexes start at 0 and the last index is length()-1. + * + *

    Even when classes implement this interface they are not always + * exchangeble because they might implement their compare, equals or hash + * function differently. This means that in general one should not use a + * CharSequence as keys in collections since two sequences + * with the same chars at the same indexes with the same length might not + * have the same hash code, be equal or be comparable since the are + * represented by different classes. + * + * @author Mark Wielaard (mark@klomp.org) + * @since 1.4 + * @status updated to 1.4 + */ +public interface CharSequence +{ + /** + * Returns the character at the given index. + * + * @param i the index to retrieve from + * @return the character at that location + * @throws IndexOutOfBoundsException if i < 0 || i >= length() - 1 + */ + char charAt(int i); + + /** + * Returns the length of the sequence. This is the number of 16-bit + * characters in the sequence, which may differ from the length of the + * underlying encoding. + * + * @return the sequence length + */ + int length(); + + /** + * Returns a new CharSequence of the indicated range. + * + * @param begin the start index (inclusive) + * @param end the end index (exclusive) + * @return a subsequence of this + * @throws IndexOutOfBoundsException if begin > end || begin < 0 || + * end > length() + */ + CharSequence subSequence(int begin, int end); + + /** + * Returns the complete CharSequence as a String. + * Classes that implement this interface should return a String + * which contains only the characters in the sequence in the correct order. + * + * @return the character sequence as a String + */ + String toString(); +} diff --git a/libjava/classpath/java/lang/Character.java b/libjava/classpath/java/lang/Character.java new file mode 100644 index 0000000..4eac147 --- /dev/null +++ b/libjava/classpath/java/lang/Character.java @@ -0,0 +1,2253 @@ +/* java.lang.Character -- Wrapper class for char, and Unicode subsets + Copyright (C) 1998, 1999, 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 java.lang; + +import gnu.java.lang.CharData; + +import java.io.Serializable; + +/** + * Wrapper class for the primitive char data type. In addition, this class + * allows one to retrieve property information and perform transformations + * on the 57,707 defined characters in the Unicode Standard, Version 3.0.0. + * java.lang.Character is designed to be very dynamic, and as such, it + * retrieves information on the Unicode character set from a separate + * database, gnu.java.lang.CharData, which can be easily upgraded. + * + *

    For predicates, boundaries are used to describe + * the set of characters for which the method will return true. + * This syntax uses fairly normal regular expression notation. + * See 5.13 of the Unicode Standard, Version 3.0, for the + * boundary specification. + * + *

    See http://www.unicode.org + * for more information on the Unicode Standard. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Paul N. Fisher + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @see CharData + * @since 1.0 + * @status updated to 1.4 + */ +public final class Character implements Serializable, Comparable +{ + /** + * A subset of Unicode blocks. + * + * @author Paul N. Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + */ + public static class Subset + { + /** The name of the subset. */ + private final String name; + + /** + * Construct a new subset of characters. + * + * @param name the name of the subset + * @throws NullPointerException if name is null + */ + protected Subset(String name) + { + // Note that name.toString() is name, unless name was null. + this.name = name.toString(); + } + + /** + * Compares two Subsets for equality. This is final, and + * restricts the comparison on the == operator, so it returns + * true only for the same object. + * + * @param o the object to compare + * @return true if o is this + */ + public final boolean equals(Object o) + { + return o == this; + } + + /** + * Makes the original hashCode of Object final, to be consistent with + * equals. + * + * @return the hash code for this object + */ + public final int hashCode() + { + return super.hashCode(); + } + + /** + * Returns the name of the subset. + * + * @return the name + */ + public final String toString() + { + return name; + } + } // class Subset + + /** + * A family of character subsets in the Unicode specification. A character + * is in at most one of these blocks. + * + * This inner class was generated automatically from + * doc/unicode/Block-3.txt, by some perl scripts. + * This Unicode definition file can be found on the + * http://www.unicode.org website. + * JDK 1.4 uses Unicode version 3.0.0. + * + * @author scripts/unicode-blocks.pl (written by Eric Blake) + * @since 1.2 + */ + public static final class UnicodeBlock extends Subset + { + /** The start of the subset. */ + private final char start; + + /** The end of the subset. */ + private final char end; + + /** + * Constructor for strictly defined blocks. + * + * @param start the start character of the range + * @param end the end character of the range + * @param name the block name + */ + private UnicodeBlock(char start, char end, String name) + { + super(name); + this.start = start; + this.end = end; + } + + /** + * Returns the Unicode character block which a character belongs to. + * + * @param ch the character to look up + * @return the set it belongs to, or null if it is not in one + */ + public static UnicodeBlock of(char ch) + { + // Special case, since SPECIALS contains two ranges. + if (ch == '\uFEFF') + return SPECIALS; + // Simple binary search for the correct block. + int low = 0; + int hi = sets.length - 1; + while (low <= hi) + { + int mid = (low + hi) >> 1; + UnicodeBlock b = sets[mid]; + if (ch < b.start) + hi = mid - 1; + else if (ch > b.end) + low = mid + 1; + else + return b; + } + return null; + } + + /** + * Basic Latin. + * '\u0000' - '\u007F'. + */ + public static final UnicodeBlock BASIC_LATIN + = new UnicodeBlock('\u0000', '\u007F', + "BASIC_LATIN"); + + /** + * Latin-1 Supplement. + * '\u0080' - '\u00FF'. + */ + public static final UnicodeBlock LATIN_1_SUPPLEMENT + = new UnicodeBlock('\u0080', '\u00FF', + "LATIN_1_SUPPLEMENT"); + + /** + * Latin Extended-A. + * '\u0100' - '\u017F'. + */ + public static final UnicodeBlock LATIN_EXTENDED_A + = new UnicodeBlock('\u0100', '\u017F', + "LATIN_EXTENDED_A"); + + /** + * Latin Extended-B. + * '\u0180' - '\u024F'. + */ + public static final UnicodeBlock LATIN_EXTENDED_B + = new UnicodeBlock('\u0180', '\u024F', + "LATIN_EXTENDED_B"); + + /** + * IPA Extensions. + * '\u0250' - '\u02AF'. + */ + public static final UnicodeBlock IPA_EXTENSIONS + = new UnicodeBlock('\u0250', '\u02AF', + "IPA_EXTENSIONS"); + + /** + * Spacing Modifier Letters. + * '\u02B0' - '\u02FF'. + */ + public static final UnicodeBlock SPACING_MODIFIER_LETTERS + = new UnicodeBlock('\u02B0', '\u02FF', + "SPACING_MODIFIER_LETTERS"); + + /** + * Combining Diacritical Marks. + * '\u0300' - '\u036F'. + */ + public static final UnicodeBlock COMBINING_DIACRITICAL_MARKS + = new UnicodeBlock('\u0300', '\u036F', + "COMBINING_DIACRITICAL_MARKS"); + + /** + * Greek. + * '\u0370' - '\u03FF'. + */ + public static final UnicodeBlock GREEK + = new UnicodeBlock('\u0370', '\u03FF', + "GREEK"); + + /** + * Cyrillic. + * '\u0400' - '\u04FF'. + */ + public static final UnicodeBlock CYRILLIC + = new UnicodeBlock('\u0400', '\u04FF', + "CYRILLIC"); + + /** + * Armenian. + * '\u0530' - '\u058F'. + */ + public static final UnicodeBlock ARMENIAN + = new UnicodeBlock('\u0530', '\u058F', + "ARMENIAN"); + + /** + * Hebrew. + * '\u0590' - '\u05FF'. + */ + public static final UnicodeBlock HEBREW + = new UnicodeBlock('\u0590', '\u05FF', + "HEBREW"); + + /** + * Arabic. + * '\u0600' - '\u06FF'. + */ + public static final UnicodeBlock ARABIC + = new UnicodeBlock('\u0600', '\u06FF', + "ARABIC"); + + /** + * Syriac. + * '\u0700' - '\u074F'. + * @since 1.4 + */ + public static final UnicodeBlock SYRIAC + = new UnicodeBlock('\u0700', '\u074F', + "SYRIAC"); + + /** + * Thaana. + * '\u0780' - '\u07BF'. + * @since 1.4 + */ + public static final UnicodeBlock THAANA + = new UnicodeBlock('\u0780', '\u07BF', + "THAANA"); + + /** + * Devanagari. + * '\u0900' - '\u097F'. + */ + public static final UnicodeBlock DEVANAGARI + = new UnicodeBlock('\u0900', '\u097F', + "DEVANAGARI"); + + /** + * Bengali. + * '\u0980' - '\u09FF'. + */ + public static final UnicodeBlock BENGALI + = new UnicodeBlock('\u0980', '\u09FF', + "BENGALI"); + + /** + * Gurmukhi. + * '\u0A00' - '\u0A7F'. + */ + public static final UnicodeBlock GURMUKHI + = new UnicodeBlock('\u0A00', '\u0A7F', + "GURMUKHI"); + + /** + * Gujarati. + * '\u0A80' - '\u0AFF'. + */ + public static final UnicodeBlock GUJARATI + = new UnicodeBlock('\u0A80', '\u0AFF', + "GUJARATI"); + + /** + * Oriya. + * '\u0B00' - '\u0B7F'. + */ + public static final UnicodeBlock ORIYA + = new UnicodeBlock('\u0B00', '\u0B7F', + "ORIYA"); + + /** + * Tamil. + * '\u0B80' - '\u0BFF'. + */ + public static final UnicodeBlock TAMIL + = new UnicodeBlock('\u0B80', '\u0BFF', + "TAMIL"); + + /** + * Telugu. + * '\u0C00' - '\u0C7F'. + */ + public static final UnicodeBlock TELUGU + = new UnicodeBlock('\u0C00', '\u0C7F', + "TELUGU"); + + /** + * Kannada. + * '\u0C80' - '\u0CFF'. + */ + public static final UnicodeBlock KANNADA + = new UnicodeBlock('\u0C80', '\u0CFF', + "KANNADA"); + + /** + * Malayalam. + * '\u0D00' - '\u0D7F'. + */ + public static final UnicodeBlock MALAYALAM + = new UnicodeBlock('\u0D00', '\u0D7F', + "MALAYALAM"); + + /** + * Sinhala. + * '\u0D80' - '\u0DFF'. + * @since 1.4 + */ + public static final UnicodeBlock SINHALA + = new UnicodeBlock('\u0D80', '\u0DFF', + "SINHALA"); + + /** + * Thai. + * '\u0E00' - '\u0E7F'. + */ + public static final UnicodeBlock THAI + = new UnicodeBlock('\u0E00', '\u0E7F', + "THAI"); + + /** + * Lao. + * '\u0E80' - '\u0EFF'. + */ + public static final UnicodeBlock LAO + = new UnicodeBlock('\u0E80', '\u0EFF', + "LAO"); + + /** + * Tibetan. + * '\u0F00' - '\u0FFF'. + */ + public static final UnicodeBlock TIBETAN + = new UnicodeBlock('\u0F00', '\u0FFF', + "TIBETAN"); + + /** + * Myanmar. + * '\u1000' - '\u109F'. + * @since 1.4 + */ + public static final UnicodeBlock MYANMAR + = new UnicodeBlock('\u1000', '\u109F', + "MYANMAR"); + + /** + * Georgian. + * '\u10A0' - '\u10FF'. + */ + public static final UnicodeBlock GEORGIAN + = new UnicodeBlock('\u10A0', '\u10FF', + "GEORGIAN"); + + /** + * Hangul Jamo. + * '\u1100' - '\u11FF'. + */ + public static final UnicodeBlock HANGUL_JAMO + = new UnicodeBlock('\u1100', '\u11FF', + "HANGUL_JAMO"); + + /** + * Ethiopic. + * '\u1200' - '\u137F'. + * @since 1.4 + */ + public static final UnicodeBlock ETHIOPIC + = new UnicodeBlock('\u1200', '\u137F', + "ETHIOPIC"); + + /** + * Cherokee. + * '\u13A0' - '\u13FF'. + * @since 1.4 + */ + public static final UnicodeBlock CHEROKEE + = new UnicodeBlock('\u13A0', '\u13FF', + "CHEROKEE"); + + /** + * Unified Canadian Aboriginal Syllabics. + * '\u1400' - '\u167F'. + * @since 1.4 + */ + public static final UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS + = new UnicodeBlock('\u1400', '\u167F', + "UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS"); + + /** + * Ogham. + * '\u1680' - '\u169F'. + * @since 1.4 + */ + public static final UnicodeBlock OGHAM + = new UnicodeBlock('\u1680', '\u169F', + "OGHAM"); + + /** + * Runic. + * '\u16A0' - '\u16FF'. + * @since 1.4 + */ + public static final UnicodeBlock RUNIC + = new UnicodeBlock('\u16A0', '\u16FF', + "RUNIC"); + + /** + * Khmer. + * '\u1780' - '\u17FF'. + * @since 1.4 + */ + public static final UnicodeBlock KHMER + = new UnicodeBlock('\u1780', '\u17FF', + "KHMER"); + + /** + * Mongolian. + * '\u1800' - '\u18AF'. + * @since 1.4 + */ + public static final UnicodeBlock MONGOLIAN + = new UnicodeBlock('\u1800', '\u18AF', + "MONGOLIAN"); + + /** + * Latin Extended Additional. + * '\u1E00' - '\u1EFF'. + */ + public static final UnicodeBlock LATIN_EXTENDED_ADDITIONAL + = new UnicodeBlock('\u1E00', '\u1EFF', + "LATIN_EXTENDED_ADDITIONAL"); + + /** + * Greek Extended. + * '\u1F00' - '\u1FFF'. + */ + public static final UnicodeBlock GREEK_EXTENDED + = new UnicodeBlock('\u1F00', '\u1FFF', + "GREEK_EXTENDED"); + + /** + * General Punctuation. + * '\u2000' - '\u206F'. + */ + public static final UnicodeBlock GENERAL_PUNCTUATION + = new UnicodeBlock('\u2000', '\u206F', + "GENERAL_PUNCTUATION"); + + /** + * Superscripts and Subscripts. + * '\u2070' - '\u209F'. + */ + public static final UnicodeBlock SUPERSCRIPTS_AND_SUBSCRIPTS + = new UnicodeBlock('\u2070', '\u209F', + "SUPERSCRIPTS_AND_SUBSCRIPTS"); + + /** + * Currency Symbols. + * '\u20A0' - '\u20CF'. + */ + public static final UnicodeBlock CURRENCY_SYMBOLS + = new UnicodeBlock('\u20A0', '\u20CF', + "CURRENCY_SYMBOLS"); + + /** + * Combining Marks for Symbols. + * '\u20D0' - '\u20FF'. + */ + public static final UnicodeBlock COMBINING_MARKS_FOR_SYMBOLS + = new UnicodeBlock('\u20D0', '\u20FF', + "COMBINING_MARKS_FOR_SYMBOLS"); + + /** + * Letterlike Symbols. + * '\u2100' - '\u214F'. + */ + public static final UnicodeBlock LETTERLIKE_SYMBOLS + = new UnicodeBlock('\u2100', '\u214F', + "LETTERLIKE_SYMBOLS"); + + /** + * Number Forms. + * '\u2150' - '\u218F'. + */ + public static final UnicodeBlock NUMBER_FORMS + = new UnicodeBlock('\u2150', '\u218F', + "NUMBER_FORMS"); + + /** + * Arrows. + * '\u2190' - '\u21FF'. + */ + public static final UnicodeBlock ARROWS + = new UnicodeBlock('\u2190', '\u21FF', + "ARROWS"); + + /** + * Mathematical Operators. + * '\u2200' - '\u22FF'. + */ + public static final UnicodeBlock MATHEMATICAL_OPERATORS + = new UnicodeBlock('\u2200', '\u22FF', + "MATHEMATICAL_OPERATORS"); + + /** + * Miscellaneous Technical. + * '\u2300' - '\u23FF'. + */ + public static final UnicodeBlock MISCELLANEOUS_TECHNICAL + = new UnicodeBlock('\u2300', '\u23FF', + "MISCELLANEOUS_TECHNICAL"); + + /** + * Control Pictures. + * '\u2400' - '\u243F'. + */ + public static final UnicodeBlock CONTROL_PICTURES + = new UnicodeBlock('\u2400', '\u243F', + "CONTROL_PICTURES"); + + /** + * Optical Character Recognition. + * '\u2440' - '\u245F'. + */ + public static final UnicodeBlock OPTICAL_CHARACTER_RECOGNITION + = new UnicodeBlock('\u2440', '\u245F', + "OPTICAL_CHARACTER_RECOGNITION"); + + /** + * Enclosed Alphanumerics. + * '\u2460' - '\u24FF'. + */ + public static final UnicodeBlock ENCLOSED_ALPHANUMERICS + = new UnicodeBlock('\u2460', '\u24FF', + "ENCLOSED_ALPHANUMERICS"); + + /** + * Box Drawing. + * '\u2500' - '\u257F'. + */ + public static final UnicodeBlock BOX_DRAWING + = new UnicodeBlock('\u2500', '\u257F', + "BOX_DRAWING"); + + /** + * Block Elements. + * '\u2580' - '\u259F'. + */ + public static final UnicodeBlock BLOCK_ELEMENTS + = new UnicodeBlock('\u2580', '\u259F', + "BLOCK_ELEMENTS"); + + /** + * Geometric Shapes. + * '\u25A0' - '\u25FF'. + */ + public static final UnicodeBlock GEOMETRIC_SHAPES + = new UnicodeBlock('\u25A0', '\u25FF', + "GEOMETRIC_SHAPES"); + + /** + * Miscellaneous Symbols. + * '\u2600' - '\u26FF'. + */ + public static final UnicodeBlock MISCELLANEOUS_SYMBOLS + = new UnicodeBlock('\u2600', '\u26FF', + "MISCELLANEOUS_SYMBOLS"); + + /** + * Dingbats. + * '\u2700' - '\u27BF'. + */ + public static final UnicodeBlock DINGBATS + = new UnicodeBlock('\u2700', '\u27BF', + "DINGBATS"); + + /** + * Braille Patterns. + * '\u2800' - '\u28FF'. + * @since 1.4 + */ + public static final UnicodeBlock BRAILLE_PATTERNS + = new UnicodeBlock('\u2800', '\u28FF', + "BRAILLE_PATTERNS"); + + /** + * CJK Radicals Supplement. + * '\u2E80' - '\u2EFF'. + * @since 1.4 + */ + public static final UnicodeBlock CJK_RADICALS_SUPPLEMENT + = new UnicodeBlock('\u2E80', '\u2EFF', + "CJK_RADICALS_SUPPLEMENT"); + + /** + * Kangxi Radicals. + * '\u2F00' - '\u2FDF'. + * @since 1.4 + */ + public static final UnicodeBlock KANGXI_RADICALS + = new UnicodeBlock('\u2F00', '\u2FDF', + "KANGXI_RADICALS"); + + /** + * Ideographic Description Characters. + * '\u2FF0' - '\u2FFF'. + * @since 1.4 + */ + public static final UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS + = new UnicodeBlock('\u2FF0', '\u2FFF', + "IDEOGRAPHIC_DESCRIPTION_CHARACTERS"); + + /** + * CJK Symbols and Punctuation. + * '\u3000' - '\u303F'. + */ + public static final UnicodeBlock CJK_SYMBOLS_AND_PUNCTUATION + = new UnicodeBlock('\u3000', '\u303F', + "CJK_SYMBOLS_AND_PUNCTUATION"); + + /** + * Hiragana. + * '\u3040' - '\u309F'. + */ + public static final UnicodeBlock HIRAGANA + = new UnicodeBlock('\u3040', '\u309F', + "HIRAGANA"); + + /** + * Katakana. + * '\u30A0' - '\u30FF'. + */ + public static final UnicodeBlock KATAKANA + = new UnicodeBlock('\u30A0', '\u30FF', + "KATAKANA"); + + /** + * Bopomofo. + * '\u3100' - '\u312F'. + */ + public static final UnicodeBlock BOPOMOFO + = new UnicodeBlock('\u3100', '\u312F', + "BOPOMOFO"); + + /** + * Hangul Compatibility Jamo. + * '\u3130' - '\u318F'. + */ + public static final UnicodeBlock HANGUL_COMPATIBILITY_JAMO + = new UnicodeBlock('\u3130', '\u318F', + "HANGUL_COMPATIBILITY_JAMO"); + + /** + * Kanbun. + * '\u3190' - '\u319F'. + */ + public static final UnicodeBlock KANBUN + = new UnicodeBlock('\u3190', '\u319F', + "KANBUN"); + + /** + * Bopomofo Extended. + * '\u31A0' - '\u31BF'. + * @since 1.4 + */ + public static final UnicodeBlock BOPOMOFO_EXTENDED + = new UnicodeBlock('\u31A0', '\u31BF', + "BOPOMOFO_EXTENDED"); + + /** + * Enclosed CJK Letters and Months. + * '\u3200' - '\u32FF'. + */ + public static final UnicodeBlock ENCLOSED_CJK_LETTERS_AND_MONTHS + = new UnicodeBlock('\u3200', '\u32FF', + "ENCLOSED_CJK_LETTERS_AND_MONTHS"); + + /** + * CJK Compatibility. + * '\u3300' - '\u33FF'. + */ + public static final UnicodeBlock CJK_COMPATIBILITY + = new UnicodeBlock('\u3300', '\u33FF', + "CJK_COMPATIBILITY"); + + /** + * CJK Unified Ideographs Extension A. + * '\u3400' - '\u4DB5'. + * @since 1.4 + */ + public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A + = new UnicodeBlock('\u3400', '\u4DB5', + "CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A"); + + /** + * CJK Unified Ideographs. + * '\u4E00' - '\u9FFF'. + */ + public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS + = new UnicodeBlock('\u4E00', '\u9FFF', + "CJK_UNIFIED_IDEOGRAPHS"); + + /** + * Yi Syllables. + * '\uA000' - '\uA48F'. + * @since 1.4 + */ + public static final UnicodeBlock YI_SYLLABLES + = new UnicodeBlock('\uA000', '\uA48F', + "YI_SYLLABLES"); + + /** + * Yi Radicals. + * '\uA490' - '\uA4CF'. + * @since 1.4 + */ + public static final UnicodeBlock YI_RADICALS + = new UnicodeBlock('\uA490', '\uA4CF', + "YI_RADICALS"); + + /** + * Hangul Syllables. + * '\uAC00' - '\uD7A3'. + */ + public static final UnicodeBlock HANGUL_SYLLABLES + = new UnicodeBlock('\uAC00', '\uD7A3', + "HANGUL_SYLLABLES"); + + /** + * Surrogates Area. + * '\uD800' - '\uDFFF'. + */ + public static final UnicodeBlock SURROGATES_AREA + = new UnicodeBlock('\uD800', '\uDFFF', + "SURROGATES_AREA"); + + /** + * Private Use Area. + * '\uE000' - '\uF8FF'. + */ + public static final UnicodeBlock PRIVATE_USE_AREA + = new UnicodeBlock('\uE000', '\uF8FF', + "PRIVATE_USE_AREA"); + + /** + * CJK Compatibility Ideographs. + * '\uF900' - '\uFAFF'. + */ + public static final UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS + = new UnicodeBlock('\uF900', '\uFAFF', + "CJK_COMPATIBILITY_IDEOGRAPHS"); + + /** + * Alphabetic Presentation Forms. + * '\uFB00' - '\uFB4F'. + */ + public static final UnicodeBlock ALPHABETIC_PRESENTATION_FORMS + = new UnicodeBlock('\uFB00', '\uFB4F', + "ALPHABETIC_PRESENTATION_FORMS"); + + /** + * Arabic Presentation Forms-A. + * '\uFB50' - '\uFDFF'. + */ + public static final UnicodeBlock ARABIC_PRESENTATION_FORMS_A + = new UnicodeBlock('\uFB50', '\uFDFF', + "ARABIC_PRESENTATION_FORMS_A"); + + /** + * Combining Half Marks. + * '\uFE20' - '\uFE2F'. + */ + public static final UnicodeBlock COMBINING_HALF_MARKS + = new UnicodeBlock('\uFE20', '\uFE2F', + "COMBINING_HALF_MARKS"); + + /** + * CJK Compatibility Forms. + * '\uFE30' - '\uFE4F'. + */ + public static final UnicodeBlock CJK_COMPATIBILITY_FORMS + = new UnicodeBlock('\uFE30', '\uFE4F', + "CJK_COMPATIBILITY_FORMS"); + + /** + * Small Form Variants. + * '\uFE50' - '\uFE6F'. + */ + public static final UnicodeBlock SMALL_FORM_VARIANTS + = new UnicodeBlock('\uFE50', '\uFE6F', + "SMALL_FORM_VARIANTS"); + + /** + * Arabic Presentation Forms-B. + * '\uFE70' - '\uFEFE'. + */ + public static final UnicodeBlock ARABIC_PRESENTATION_FORMS_B + = new UnicodeBlock('\uFE70', '\uFEFE', + "ARABIC_PRESENTATION_FORMS_B"); + + /** + * Halfwidth and Fullwidth Forms. + * '\uFF00' - '\uFFEF'. + */ + public static final UnicodeBlock HALFWIDTH_AND_FULLWIDTH_FORMS + = new UnicodeBlock('\uFF00', '\uFFEF', + "HALFWIDTH_AND_FULLWIDTH_FORMS"); + + /** + * Specials. + * '\uFEFF', '\uFFF0' - '\uFFFD'. + */ + public static final UnicodeBlock SPECIALS + = new UnicodeBlock('\uFFF0', '\uFFFD', + "SPECIALS"); + + /** + * The defined subsets. + */ + private static final UnicodeBlock sets[] = { + BASIC_LATIN, + LATIN_1_SUPPLEMENT, + LATIN_EXTENDED_A, + LATIN_EXTENDED_B, + IPA_EXTENSIONS, + SPACING_MODIFIER_LETTERS, + COMBINING_DIACRITICAL_MARKS, + GREEK, + CYRILLIC, + ARMENIAN, + HEBREW, + ARABIC, + SYRIAC, + THAANA, + DEVANAGARI, + BENGALI, + GURMUKHI, + GUJARATI, + ORIYA, + TAMIL, + TELUGU, + KANNADA, + MALAYALAM, + SINHALA, + THAI, + LAO, + TIBETAN, + MYANMAR, + GEORGIAN, + HANGUL_JAMO, + ETHIOPIC, + CHEROKEE, + UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS, + OGHAM, + RUNIC, + KHMER, + MONGOLIAN, + LATIN_EXTENDED_ADDITIONAL, + GREEK_EXTENDED, + GENERAL_PUNCTUATION, + SUPERSCRIPTS_AND_SUBSCRIPTS, + CURRENCY_SYMBOLS, + COMBINING_MARKS_FOR_SYMBOLS, + LETTERLIKE_SYMBOLS, + NUMBER_FORMS, + ARROWS, + MATHEMATICAL_OPERATORS, + MISCELLANEOUS_TECHNICAL, + CONTROL_PICTURES, + OPTICAL_CHARACTER_RECOGNITION, + ENCLOSED_ALPHANUMERICS, + BOX_DRAWING, + BLOCK_ELEMENTS, + GEOMETRIC_SHAPES, + MISCELLANEOUS_SYMBOLS, + DINGBATS, + BRAILLE_PATTERNS, + CJK_RADICALS_SUPPLEMENT, + KANGXI_RADICALS, + IDEOGRAPHIC_DESCRIPTION_CHARACTERS, + CJK_SYMBOLS_AND_PUNCTUATION, + HIRAGANA, + KATAKANA, + BOPOMOFO, + HANGUL_COMPATIBILITY_JAMO, + KANBUN, + BOPOMOFO_EXTENDED, + ENCLOSED_CJK_LETTERS_AND_MONTHS, + CJK_COMPATIBILITY, + CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A, + CJK_UNIFIED_IDEOGRAPHS, + YI_SYLLABLES, + YI_RADICALS, + HANGUL_SYLLABLES, + SURROGATES_AREA, + PRIVATE_USE_AREA, + CJK_COMPATIBILITY_IDEOGRAPHS, + ALPHABETIC_PRESENTATION_FORMS, + ARABIC_PRESENTATION_FORMS_A, + COMBINING_HALF_MARKS, + CJK_COMPATIBILITY_FORMS, + SMALL_FORM_VARIANTS, + ARABIC_PRESENTATION_FORMS_B, + HALFWIDTH_AND_FULLWIDTH_FORMS, + SPECIALS, + }; + } // class UnicodeBlock + + /** + * The immutable value of this Character. + * + * @serial the value of this Character + */ + private final char value; + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3786198910865385080L; + + /** + * Smallest value allowed for radix arguments in Java. This value is 2. + * + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) + */ + public static final int MIN_RADIX = 2; + + /** + * Largest value allowed for radix arguments in Java. This value is 36. + * + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) + */ + public static final int MAX_RADIX = 36; + + /** + * The minimum value the char data type can hold. + * This value is '\\u0000'. + */ + public static final char MIN_VALUE = '\u0000'; + + /** + * The maximum value the char data type can hold. + * This value is '\\uFFFF'. + */ + public static final char MAX_VALUE = '\uFFFF'; + + /** + * Class object representing the primitive char data type. + * + * @since 1.1 + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass('C'); + + /** + * Lu = Letter, Uppercase (Informative). + * + * @since 1.1 + */ + public static final byte UPPERCASE_LETTER = 1; + + /** + * Ll = Letter, Lowercase (Informative). + * + * @since 1.1 + */ + public static final byte LOWERCASE_LETTER = 2; + + /** + * Lt = Letter, Titlecase (Informative). + * + * @since 1.1 + */ + public static final byte TITLECASE_LETTER = 3; + + /** + * Mn = Mark, Non-Spacing (Normative). + * + * @since 1.1 + */ + public static final byte NON_SPACING_MARK = 6; + + /** + * Mc = Mark, Spacing Combining (Normative). + * + * @since 1.1 + */ + public static final byte COMBINING_SPACING_MARK = 8; + + /** + * Me = Mark, Enclosing (Normative). + * + * @since 1.1 + */ + public static final byte ENCLOSING_MARK = 7; + + /** + * Nd = Number, Decimal Digit (Normative). + * + * @since 1.1 + */ + public static final byte DECIMAL_DIGIT_NUMBER = 9; + + /** + * Nl = Number, Letter (Normative). + * + * @since 1.1 + */ + public static final byte LETTER_NUMBER = 10; + + /** + * No = Number, Other (Normative). + * + * @since 1.1 + */ + public static final byte OTHER_NUMBER = 11; + + /** + * Zs = Separator, Space (Normative). + * + * @since 1.1 + */ + public static final byte SPACE_SEPARATOR = 12; + + /** + * Zl = Separator, Line (Normative). + * + * @since 1.1 + */ + public static final byte LINE_SEPARATOR = 13; + + /** + * Zp = Separator, Paragraph (Normative). + * + * @since 1.1 + */ + public static final byte PARAGRAPH_SEPARATOR = 14; + + /** + * Cc = Other, Control (Normative). + * + * @since 1.1 + */ + public static final byte CONTROL = 15; + + /** + * Cf = Other, Format (Normative). + * + * @since 1.1 + */ + public static final byte FORMAT = 16; + + /** + * Cs = Other, Surrogate (Normative). + * + * @since 1.1 + */ + public static final byte SURROGATE = 19; + + /** + * Co = Other, Private Use (Normative). + * + * @since 1.1 + */ + public static final byte PRIVATE_USE = 18; + + /** + * Cn = Other, Not Assigned (Normative). + * + * @since 1.1 + */ + public static final byte UNASSIGNED = 0; + + /** + * Lm = Letter, Modifier (Informative). + * + * @since 1.1 + */ + public static final byte MODIFIER_LETTER = 4; + + /** + * Lo = Letter, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_LETTER = 5; + + /** + * Pc = Punctuation, Connector (Informative). + * + * @since 1.1 + */ + public static final byte CONNECTOR_PUNCTUATION = 23; + + /** + * Pd = Punctuation, Dash (Informative). + * + * @since 1.1 + */ + public static final byte DASH_PUNCTUATION = 20; + + /** + * Ps = Punctuation, Open (Informative). + * + * @since 1.1 + */ + public static final byte START_PUNCTUATION = 21; + + /** + * Pe = Punctuation, Close (Informative). + * + * @since 1.1 + */ + public static final byte END_PUNCTUATION = 22; + + /** + * Pi = Punctuation, Initial Quote (Informative). + * + * @since 1.4 + */ + public static final byte INITIAL_QUOTE_PUNCTUATION = 29; + + /** + * Pf = Punctuation, Final Quote (Informative). + * + * @since 1.4 + */ + public static final byte FINAL_QUOTE_PUNCTUATION = 30; + + /** + * Po = Punctuation, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_PUNCTUATION = 24; + + /** + * Sm = Symbol, Math (Informative). + * + * @since 1.1 + */ + public static final byte MATH_SYMBOL = 25; + + /** + * Sc = Symbol, Currency (Informative). + * + * @since 1.1 + */ + public static final byte CURRENCY_SYMBOL = 26; + + /** + * Sk = Symbol, Modifier (Informative). + * + * @since 1.1 + */ + public static final byte MODIFIER_SYMBOL = 27; + + /** + * So = Symbol, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_SYMBOL = 28; + + /** + * Undefined bidirectional character type. Undefined char values have + * undefined directionality in the Unicode specification. + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_UNDEFINED = -1; + + /** + * Strong bidirectional character type "L". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = 0; + + /** + * Strong bidirectional character type "R". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = 1; + + /** + * Strong bidirectional character type "AL". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2; + + /** + * Weak bidirectional character type "EN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = 3; + + /** + * Weak bidirectional character type "ES". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4; + + /** + * Weak bidirectional character type "ET". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5; + + /** + * Weak bidirectional character type "AN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_ARABIC_NUMBER = 6; + + /** + * Weak bidirectional character type "CS". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7; + + /** + * Weak bidirectional character type "NSM". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_NONSPACING_MARK = 8; + + /** + * Weak bidirectional character type "BN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 9; + + /** + * Neutral bidirectional character type "B". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10; + + /** + * Neutral bidirectional character type "S". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = 11; + + /** + * Strong bidirectional character type "WS". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_WHITESPACE = 12; + + /** + * Neutral bidirectional character type "ON". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_OTHER_NEUTRALS = 13; + + /** + * Strong bidirectional character type "LRE". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14; + + /** + * Strong bidirectional character type "LRO". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15; + + /** + * Strong bidirectional character type "RLE". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16; + + /** + * Strong bidirectional character type "RLO". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17; + + /** + * Weak bidirectional character type "PDF". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18; + + /** + * Stores unicode block offset lookup table. Exploit package visibility of + * String.value to avoid copying the array. + * @see #readChar(char) + * @see CharData#BLOCKS + */ + private static final char[] blocks = String.zeroBasedStringValue(CharData.BLOCKS); + + /** + * Stores unicode attribute offset lookup table. Exploit package visibility + * of String.value to avoid copying the array. + * @see CharData#DATA + */ + private static final char[] data = String.zeroBasedStringValue(CharData.DATA); + + /** + * Stores unicode numeric value attribute table. Exploit package visibility + * of String.value to avoid copying the array. + * @see CharData#NUM_VALUE + */ + private static final char[] numValue + = String.zeroBasedStringValue(CharData.NUM_VALUE); + + /** + * Stores unicode uppercase attribute table. Exploit package visibility + * of String.value to avoid copying the array. + * @see CharData#UPPER + */ + private static final char[] upper = String.zeroBasedStringValue(CharData.UPPER); + + /** + * Stores unicode lowercase attribute table. Exploit package visibility + * of String.value to avoid copying the array. + * @see CharData#LOWER + */ + private static final char[] lower = String.zeroBasedStringValue(CharData.LOWER); + + /** + * Stores unicode direction attribute table. Exploit package visibility + * of String.value to avoid copying the array. + * @see CharData#DIRECTION + */ + // Package visible for use by String. + static final char[] direction = String.zeroBasedStringValue(CharData.DIRECTION); + + /** + * Stores unicode titlecase table. Exploit package visibility of + * String.value to avoid copying the array. + * @see CharData#TITLE + */ + private static final char[] title = String.zeroBasedStringValue(CharData.TITLE); + + /** + * Mask for grabbing the type out of the contents of data. + * @see CharData#DATA + */ + private static final int TYPE_MASK = 0x1F; + + /** + * Mask for grabbing the non-breaking space flag out of the contents of + * data. + * @see CharData#DATA + */ + private static final int NO_BREAK_MASK = 0x20; + + /** + * Mask for grabbing the mirrored directionality flag out of the contents + * of data. + * @see CharData#DATA + */ + private static final int MIRROR_MASK = 0x40; + + /** + * Grabs an attribute offset from the Unicode attribute database. The lower + * 5 bits are the character type, the next 2 bits are flags, and the top + * 9 bits are the offset into the attribute tables. + * + * @param ch the character to look up + * @return the character's attribute offset and type + * @see #TYPE_MASK + * @see #NO_BREAK_MASK + * @see #MIRROR_MASK + * @see CharData#DATA + * @see CharData#SHIFT + */ + // Package visible for use in String. + static char readChar(char ch) + { + // Perform 16-bit addition to find the correct entry in data. + return data[(char) (blocks[ch >> CharData.SHIFT] + ch)]; + } + + /** + * Wraps up a character. + * + * @param value the character to wrap + */ + public Character(char value) + { + this.value = value; + } + + /** + * Returns the character which has been wrapped by this class. + * + * @return the character wrapped + */ + public char charValue() + { + return value; + } + + /** + * Returns the numerical value (unsigned) of the wrapped character. + * Range of returned values: 0x0000-0xFFFF. + * + * @return the value of the wrapped character + */ + public int hashCode() + { + return value; + } + + /** + * Determines if an object is equal to this object. This is only true for + * another Character object wrapping the same value. + * + * @param o object to compare + * @return true if o is a Character with the same value + */ + public boolean equals(Object o) + { + return o instanceof Character && value == ((Character) o).value; + } + + /** + * Converts the wrapped character into a String. + * + * @return a String containing one character -- the wrapped character + * of this instance + */ + public String toString() + { + // Package constructor avoids an array copy. + return new String(new char[] { value }, 0, 1, true); + } + + /** + * Returns a String of length 1 representing the specified character. + * + * @param ch the character to convert + * @return a String containing the character + * @since 1.4 + */ + public static String toString(char ch) + { + // Package constructor avoids an array copy. + return new String(new char[] { ch }, 0, 1, true); + } + + /** + * Determines if a character is a Unicode lowercase letter. For example, + * 'a' is lowercase. + *
    + * lowercase = [Ll] + * + * @param ch character to test + * @return true if ch is a Unicode lowercase letter, else false + * @see #isUpperCase(char) + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #getType(char) + */ + public static boolean isLowerCase(char ch) + { + return getType(ch) == LOWERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode uppercase letter. For example, + * 'A' is uppercase. + *
    + * uppercase = [Lu] + * + * @param ch character to test + * @return true if ch is a Unicode uppercase letter, else false + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #toUpperCase(char) + * @see #getType(char) + */ + public static boolean isUpperCase(char ch) + { + return getType(ch) == UPPERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode titlecase letter. For example, + * the character "Lj" (Latin capital L with small letter j) is titlecase. + *
    + * titlecase = [Lt] + * + * @param ch character to test + * @return true if ch is a Unicode titlecase letter, else false + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #getType(char) + */ + public static boolean isTitleCase(char ch) + { + return getType(ch) == TITLECASE_LETTER; + } + + /** + * Determines if a character is a Unicode decimal digit. For example, + * '0' is a digit. + *
    + * Unicode decimal digit = [Nd] + * + * @param ch character to test + * @return true if ch is a Unicode decimal digit, else false + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see #getType(char) + */ + public static boolean isDigit(char ch) + { + return getType(ch) == DECIMAL_DIGIT_NUMBER; + } + + /** + * Determines if a character is part of the Unicode Standard. This is an + * evolving standard, but covers every character in the data file. + *
    + * defined = not [Cn] + * + * @param ch character to test + * @return true if ch is a Unicode character, else false + * @see #isDigit(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUpperCase(char) + */ + public static boolean isDefined(char ch) + { + return getType(ch) != UNASSIGNED; + } + + /** + * Determines if a character is a Unicode letter. Not all letters have case, + * so this may return true when isLowerCase and isUpperCase return false. + *
    + * letter = [Lu]|[Ll]|[Lt]|[Lm]|[Lo] + * + * @param ch character to test + * @return true if ch is a Unicode letter, else false + * @see #isDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUnicodeIdentifierStart(char) + * @see #isUpperCase(char) + */ + public static boolean isLetter(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER))) != 0; + } + + /** + * Determines if a character is a Unicode letter or a Unicode digit. This + * is the combination of isLetter and isDigit. + *
    + * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * + * @param ch character to test + * @return true if ch is a Unicode letter or a Unicode digit, else false + * @see #isDigit(char) + * @see #isJavaIdentifierPart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + */ + public static boolean isLetterOrDigit(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER))) != 0; + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + * + * @param ch character to test + * @return true if ch can start a Java identifier, else false + * @deprecated Replaced by {@link #isJavaIdentifierStart(char)} + * @see #isJavaLetterOrDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + */ + public static boolean isJavaLetter(char ch) + { + return isJavaIdentifierStart(ch); + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + * + * @param ch character to test + * @return true if ch can follow the first letter in a Java identifier + * @deprecated Replaced by {@link #isJavaIdentifierPart(char)} + * @see #isJavaLetter(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @see #isIdentifierIgnorable(char) + */ + public static boolean isJavaLetterOrDigit(char ch) + { + return isJavaIdentifierPart(ch); + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + *
    + * Java identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc] + * + * @param ch character to test + * @return true if ch can start a Java identifier, else false + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.1 + */ + public static boolean isJavaIdentifierStart(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION))) != 0; + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + *
    + * Java identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc]|[Mn]|[Mc]|[Nd]|[Cf] + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param ch character to test + * @return true if ch can follow the first letter in a Java identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierStart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isJavaIdentifierPart(char ch) + { + int category = getType(ch); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(ch)); + } + + /** + * Determines if a character can start a Unicode identifier. Only + * letters can start a Unicode identifier, but this includes characters + * in LETTER_NUMBER. + *
    + * Unicode identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl] + * + * @param ch character to test + * @return true if ch can start a Unicode identifier, else false + * @see #isJavaIdentifierStart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isUnicodeIdentifierStart(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER))) != 0; + } + + /** + * Determines if a character can follow the first letter in + * a Unicode identifier. This includes letters, connecting punctuation, + * digits, numeric letters, combining marks, non-spacing marks, and + * isIdentifierIgnorable. + *
    + * Unicode identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Mn]|[Mc]|[Nd]|[Pc]|[Cf]| + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param ch character to test + * @return true if ch can follow the first letter in a Unicode identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.1 + */ + public static boolean isUnicodeIdentifierPart(char ch) + { + int category = getType(ch); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(ch)); + } + + /** + * Determines if a character is ignorable in a Unicode identifier. This + * includes the non-whitespace ISO control characters ('\u0000' + * through '\u0008', '\u000E' through + * '\u001B', and '\u007F' through + * '\u009F'), and FORMAT characters. + *
    + * Unicode identifier ignorable = [Cf]|U+0000-U+0008|U+000E-U+001B + * |U+007F-U+009F + * + * @param ch character to test + * @return true if ch is ignorable in a Unicode or Java identifier + * @see #isJavaIdentifierPart(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isIdentifierIgnorable(char ch) + { + return (ch <= '\u009F' && (ch < '\t' || ch >= '\u007F' + || (ch <= '\u001B' && ch >= '\u000E'))) + || getType(ch) == FORMAT; + } + + /** + * Converts a Unicode character into its lowercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isLowerCase(toLowerCase(ch)) does not always return true. + * + * @param ch character to convert to lowercase + * @return lowercase mapping of ch, or ch if lowercase mapping does + * not exist + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #toUpperCase(char) + */ + public static char toLowerCase(char ch) + { + // Signedness doesn't matter, as result is cast back to char. + return (char) (ch + lower[readChar(ch) >> 7]); + } + + /** + * Converts a Unicode character into its uppercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isUpperCase(toUpperCase(ch)) does not always return true. + * + * @param ch character to convert to uppercase + * @return uppercase mapping of ch, or ch if uppercase mapping does + * not exist + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toLowerCase(char) + * @see #toTitleCase(char) + */ + public static char toUpperCase(char ch) + { + // Signedness doesn't matter, as result is cast back to char. + return (char) (ch + upper[readChar(ch) >> 7]); + } + + /** + * Converts a Unicode character into its titlecase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isTitleCase(toTitleCase(ch)) does not always return true. + * + * @param ch character to convert to titlecase + * @return titlecase mapping of ch, or ch if titlecase mapping does + * not exist + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #toUpperCase(char) + */ + public static char toTitleCase(char ch) + { + // As title is short, it doesn't hurt to exhaustively iterate over it. + for (int i = title.length - 2; i >= 0; i -= 2) + if (title[i] == ch) + return title[i + 1]; + return toUpperCase(ch); + } + + /** + * Converts a character into a digit of the specified radix. If the radix + * exceeds MIN_RADIX or MAX_RADIX, or if the result of getNumericValue(ch) + * exceeds the radix, or if ch is not a decimal digit or in the case + * insensitive set of 'a'-'z', the result is -1. + *
    + * character argument boundary = [Nd]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param ch character to convert into a digit + * @param radix radix in which ch is a digit + * @return digit which ch represents in radix, or -1 not a valid digit + * @see #MIN_RADIX + * @see #MAX_RADIX + * @see #forDigit(int, int) + * @see #isDigit(char) + * @see #getNumericValue(char) + */ + public static int digit(char ch, int radix) + { + if (radix < MIN_RADIX || radix > MAX_RADIX) + return -1; + char attr = readChar(ch); + if (((1 << (attr & TYPE_MASK)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER))) != 0) + { + // Signedness doesn't matter; 0xffff vs. -1 are both rejected. + int digit = numValue[attr >> 7]; + return (digit < radix) ? digit : -1; + } + return -1; + } + + /** + * Returns the Unicode numeric value property of a character. For example, + * '\\u216C' (the Roman numeral fifty) returns 50. + * + *

    This method also returns values for the letters A through Z, (not + * specified by Unicode), in these ranges: '\u0041' + * through '\u005A' (uppercase); '\u0061' + * through '\u007A' (lowercase); and '\uFF21' + * through '\uFF3A', '\uFF41' through + * '\uFF5A' (full width variants). + * + *

    If the character lacks a numeric value property, -1 is returned. + * If the character has a numeric value property which is not representable + * as a nonnegative integer, such as a fraction, -2 is returned. + * + * character argument boundary = [Nd]|[Nl]|[No]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param ch character from which the numeric value property will + * be retrieved + * @return the numeric value property of ch, or -1 if it does not exist, or + * -2 if it is not representable as a nonnegative integer + * @see #forDigit(int, int) + * @see #digit(char, int) + * @see #isDigit(char) + * @since 1.1 + */ + public static int getNumericValue(char ch) + { + // Treat numValue as signed. + return (short) numValue[readChar(ch) >> 7]; + } + + /** + * Determines if a character is a ISO-LATIN-1 space. This is only the five + * characters '\t', '\n', '\f', + * '\r', and ' '. + *
    + * Java space = U+0020|U+0009|U+000A|U+000C|U+000D + * + * @param ch character to test + * @return true if ch is a space, else false + * @deprecated Replaced by {@link #isWhitespace(char)} + * @see #isSpaceChar(char) + * @see #isWhitespace(char) + */ + public static boolean isSpace(char ch) + { + // Performing the subtraction up front alleviates need to compare longs. + return ch-- <= ' ' && ((1 << ch) + & ((1 << (' ' - 1)) + | (1 << ('\t' - 1)) + | (1 << ('\n' - 1)) + | (1 << ('\r' - 1)) + | (1 << ('\f' - 1)))) != 0; + } + + /** + * Determines if a character is a Unicode space character. This includes + * SPACE_SEPARATOR, LINE_SEPARATOR, and PARAGRAPH_SEPARATOR. + *
    + * Unicode space = [Zs]|[Zp]|[Zl] + * + * @param ch character to test + * @return true if ch is a Unicode space, else false + * @see #isWhitespace(char) + * @since 1.1 + */ + public static boolean isSpaceChar(char ch) + { + return ((1 << getType(ch)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0; + } + + /** + * Determines if a character is Java whitespace. This includes Unicode + * space characters (SPACE_SEPARATOR, LINE_SEPARATOR, and + * PARAGRAPH_SEPARATOR) except the non-breaking spaces + * ('\u00A0', '\u2007', and '\u202F'); + * and these characters: '\u0009', '\u000A', + * '\u000B', '\u000C', '\u000D', + * '\u001C', '\u001D', '\u001E', + * and '\u001F'. + *
    + * Java whitespace = ([Zs] not Nb)|[Zl]|[Zp]|U+0009-U+000D|U+001C-U+001F + * + * @param ch character to test + * @return true if ch is Java whitespace, else false + * @see #isSpaceChar(char) + * @since 1.1 + */ + public static boolean isWhitespace(char ch) + { + int attr = readChar(ch); + return ((((1 << (attr & TYPE_MASK)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0) + && (attr & NO_BREAK_MASK) == 0) + || (ch <= '\u001F' && ((1 << ch) + & ((1 << '\t') + | (1 << '\n') + | (1 << '\u000B') + | (1 << '\u000C') + | (1 << '\r') + | (1 << '\u001C') + | (1 << '\u001D') + | (1 << '\u001E') + | (1 << '\u001F'))) != 0); + } + + /** + * Determines if a character has the ISO Control property. + *
    + * ISO Control = [Cc] + * + * @param ch character to test + * @return true if ch is an ISO Control character, else false + * @see #isSpaceChar(char) + * @see #isWhitespace(char) + * @since 1.1 + */ + public static boolean isISOControl(char ch) + { + return getType(ch) == CONTROL; + } + + /** + * Returns the Unicode general category property of a character. + * + * @param ch character from which the general category property will + * be retrieved + * @return the character category property of ch as an integer + * @see #UNASSIGNED + * @see #UPPERCASE_LETTER + * @see #LOWERCASE_LETTER + * @see #TITLECASE_LETTER + * @see #MODIFIER_LETTER + * @see #OTHER_LETTER + * @see #NON_SPACING_MARK + * @see #ENCLOSING_MARK + * @see #COMBINING_SPACING_MARK + * @see #DECIMAL_DIGIT_NUMBER + * @see #LETTER_NUMBER + * @see #OTHER_NUMBER + * @see #SPACE_SEPARATOR + * @see #LINE_SEPARATOR + * @see #PARAGRAPH_SEPARATOR + * @see #CONTROL + * @see #FORMAT + * @see #PRIVATE_USE + * @see #SURROGATE + * @see #DASH_PUNCTUATION + * @see #START_PUNCTUATION + * @see #END_PUNCTUATION + * @see #CONNECTOR_PUNCTUATION + * @see #OTHER_PUNCTUATION + * @see #MATH_SYMBOL + * @see #CURRENCY_SYMBOL + * @see #MODIFIER_SYMBOL + * @see #INITIAL_QUOTE_PUNCTUATION + * @see #FINAL_QUOTE_PUNCTUATION + * @since 1.1 + */ + public static int getType(char ch) + { + return readChar(ch) & TYPE_MASK; + } + + /** + * Converts a digit into a character which represents that digit + * in a specified radix. If the radix exceeds MIN_RADIX or MAX_RADIX, + * or the digit exceeds the radix, then the null character '\0' + * is returned. Otherwise the return value is in '0'-'9' and 'a'-'z'. + *
    + * return value boundary = U+0030-U+0039|U+0061-U+007A + * + * @param digit digit to be converted into a character + * @param radix radix of digit + * @return character representing digit in radix, or '\0' + * @see #MIN_RADIX + * @see #MAX_RADIX + * @see #digit(char, int) + */ + public static char forDigit(int digit, int radix) + { + if (radix < MIN_RADIX || radix > MAX_RADIX + || digit < 0 || digit >= radix) + return '\0'; + return Number.digits[digit]; + } + + /** + * Returns the Unicode directionality property of the character. This + * is used in the visual ordering of text. + * + * @param ch the character to look up + * @return the directionality constant, or DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_LEFT_TO_RIGHT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC + * @see #DIRECTIONALITY_EUROPEAN_NUMBER + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR + * @see #DIRECTIONALITY_ARABIC_NUMBER + * @see #DIRECTIONALITY_COMMON_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_NONSPACING_MARK + * @see #DIRECTIONALITY_BOUNDARY_NEUTRAL + * @see #DIRECTIONALITY_PARAGRAPH_SEPARATOR + * @see #DIRECTIONALITY_SEGMENT_SEPARATOR + * @see #DIRECTIONALITY_WHITESPACE + * @see #DIRECTIONALITY_OTHER_NEUTRALS + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE + * @see #DIRECTIONALITY_POP_DIRECTIONAL_FORMAT + * @since 1.4 + */ + public static byte getDirectionality(char ch) + { + // The result will correctly be signed. + return (byte) (direction[readChar(ch) >> 7] >> 2); + } + + /** + * Determines whether the character is mirrored according to Unicode. For + * example, \u0028 (LEFT PARENTHESIS) appears as '(' in + * left-to-right text, but ')' in right-to-left text. + * + * @param ch the character to look up + * @return true if the character is mirrored + * @since 1.4 + */ + public static boolean isMirrored(char ch) + { + return (readChar(ch) & MIRROR_MASK) != 0; + } + + /** + * Compares another Character to this Character, numerically. + * + * @param anotherCharacter Character to compare with this Character + * @return a negative integer if this Character is less than + * anotherCharacter, zero if this Character is equal, and + * a positive integer if this Character is greater + * @throws NullPointerException if anotherCharacter is null + * @since 1.2 + */ + public int compareTo(Character anotherCharacter) + { + return value - anotherCharacter.value; + } + + /** + * Compares an object to this Character. Assuming the object is a + * Character object, this method performs the same comparison as + * compareTo(Character). + * + * @param o object to compare + * @return the comparison value + * @throws ClassCastException if o is not a Character object + * @throws NullPointerException if o is null + * @see #compareTo(Character) + * @since 1.2 + */ + public int compareTo(Object o) + { + return compareTo((Character) o); + } +} // class Character diff --git a/libjava/classpath/java/lang/Class.java b/libjava/classpath/java/lang/Class.java new file mode 100644 index 0000000..6b8bc93 --- /dev/null +++ b/libjava/classpath/java/lang/Class.java @@ -0,0 +1,1324 @@ +/* Class.java -- Representation of a Java class. + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005 + Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import gnu.classpath.VMStackWalker; + +import java.io.InputStream; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.security.AccessController; +import java.security.AllPermission; +import java.security.Permissions; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; + + +/** + * A Class represents a Java type. There will never be multiple Class + * objects with identical names and ClassLoaders. Primitive types, array + * types, and void also have a Class object. + * + *

    Arrays with identical type and number of dimensions share the same class. + * The array class ClassLoader is the same as the ClassLoader of the element + * type of the array (which can be null to indicate the bootstrap classloader). + * The name of an array class is [<signature format>;. + *

    For example, + * String[]'s class is [Ljava.lang.String;. boolean, byte, + * short, char, int, long, float and double have the "type name" of + * Z,B,S,C,I,J,F,D for the purposes of array classes. If it's a + * multidimensioned array, the same principle applies: + * int[][][] == [[[I. + * + *

    There is no public constructor - Class objects are obtained only through + * the virtual machine, as defined in ClassLoaders. + * + * @serialData Class objects serialize specially: + * TC_CLASS ClassDescriptor. For more serialization information, + * see {@link ObjectStreamClass}. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@cygnus.com) + * @since 1.0 + * @see ClassLoader + */ +public final class Class implements Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3206093459760846163L; + + /** The class signers. */ + private Object[] signers = null; + /** The class protection domain. */ + private final ProtectionDomain pd; + + /* We use an inner class, so that Class doesn't have a static initializer */ + private static final class StaticData + { + static final ProtectionDomain unknownProtectionDomain; + + static + { + Permissions permissions = new Permissions(); + permissions.add(new AllPermission()); + unknownProtectionDomain = new ProtectionDomain(null, permissions); + } + } + + final transient Object vmdata; + + /** newInstance() caches the default constructor */ + private transient Constructor constructor; + + /** + * Class is non-instantiable from Java code; only the VM can create + * instances of this class. + */ + Class(Object vmdata) + { + this(vmdata, null); + } + + Class(Object vmdata, ProtectionDomain pd) + { + this.vmdata = vmdata; + // If the VM didn't supply a protection domain and the class is an array, + // we "inherit" the protection domain from the component type class. This + // saves the VM from having to worry about protection domains for array + // classes. + if (pd == null && isArray()) + this.pd = getComponentType().pd; + else + this.pd = pd; + } + + /** + * Use the classloader of the current class to load, link, and initialize + * a class. This is equivalent to your code calling + * Class.forName(name, true, getClass().getClassLoader()). + * + * @param name the name of the class to find + * @return the Class object representing the class + * @throws ClassNotFoundException if the class was not found by the + * classloader + * @throws LinkageError if linking the class fails + * @throws ExceptionInInitializerError if the class loads, but an exception + * occurs during initialization + */ + public static Class forName(String name) throws ClassNotFoundException + { + Class result = VMClass.forName (name); + if (result == null) + result = Class.forName(name, true, + VMStackWalker.getCallingClassLoader()); + return result; + } + + /** + * Use the specified classloader to load and link a class. If the loader + * is null, this uses the bootstrap class loader (provide the security + * check succeeds). Unfortunately, this method cannot be used to obtain + * the Class objects for primitive types or for void, you have to use + * the fields in the appropriate java.lang wrapper classes. + * + *

    Calls classloader.loadclass(name, initialize). + * + * @param name the name of the class to find + * @param initialize whether or not to initialize the class at this time + * @param classloader the classloader to use to find the class; null means + * to use the bootstrap class loader + * + * @return the class object for the given class + * + * @throws ClassNotFoundException if the class was not found by the + * classloader + * @throws LinkageError if linking the class fails + * @throws ExceptionInInitializerError if the class loads, but an exception + * occurs during initialization + * @throws SecurityException if the classloader argument + * is null and the caller does not have the + * RuntimePermission("getClassLoader") permission + * @see ClassLoader + * @since 1.2 + */ + public static Class forName(String name, boolean initialize, + ClassLoader classloader) + throws ClassNotFoundException + { + if (classloader == null) + { + // Check if we may access the bootstrap classloader + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + // Get the calling classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + if (name.startsWith("[")) + return VMClass.loadArrayClass(name, null); + Class c = VMClassLoader.loadClass(name, true); + if (c != null) + { + if (initialize) + VMClass.initialize(c); + return c; + } + throw new ClassNotFoundException(name); + } + if (name.startsWith("[")) + return VMClass.loadArrayClass(name, classloader); + Class c = classloader.loadClass(name); + classloader.resolveClass(c); + if (initialize) + VMClass.initialize(c); + return c; + } + + /** + * Get all the public member classes and interfaces declared in this + * class or inherited from superclasses. This returns an array of length + * 0 if there are no member classes, including for primitive types. A + * security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @return all public member classes in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Class[] getClasses() + { + memberAccessCheck(Member.PUBLIC); + return internalGetClasses(); + } + + /** + * Like getClasses() but without the security checks. + */ + private Class[] internalGetClasses() + { + ArrayList list = new ArrayList(); + list.addAll(Arrays.asList(getDeclaredClasses(true))); + Class superClass = getSuperclass(); + if (superClass != null) + list.addAll(Arrays.asList(superClass.internalGetClasses())); + return (Class[])list.toArray(new Class[list.size()]); + } + + /** + * Get the ClassLoader that loaded this class. If the class was loaded + * by the bootstrap classloader, this method will return null. + * If there is a security manager, and the caller's class loader is not + * an ancestor of the requested one, a security check of + * RuntimePermission("getClassLoader") + * must first succeed. Primitive types and void return null. + * + * @return the ClassLoader that loaded this class + * @throws SecurityException if the security check fails + * @see ClassLoader + * @see RuntimePermission + */ + public ClassLoader getClassLoader() + { + if (isPrimitive()) + return null; + + ClassLoader loader = VMClass.getClassLoader(this); + // Check if we may get the classloader + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + // Get the calling classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && !cl.isAncestorOf(loader)) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + return loader; + } + + /** + * If this is an array, get the Class representing the type of array. + * Examples: "[[Ljava.lang.String;" would return "[Ljava.lang.String;", and + * calling getComponentType on that would give "java.lang.String". If + * this is not an array, returns null. + * + * @return the array type of this class, or null + * @see Array + * @since 1.1 + */ + public Class getComponentType() + { + return VMClass.getComponentType (this); + } + + /** + * Get a public constructor declared in this class. If the constructor takes + * no argument, an array of zero elements and null are equivalent for the + * types argument. A security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @param types the type of each parameter + * @return the constructor + * @throws NoSuchMethodException if the constructor does not exist + * @throws SecurityException if the security check fails + * @see #getConstructors() + * @since 1.1 + */ + public Constructor getConstructor(Class[] types) throws NoSuchMethodException + { + memberAccessCheck(Member.PUBLIC); + Constructor[] constructors = getDeclaredConstructors(true); + for (int i = 0; i < constructors.length; i++) + { + Constructor constructor = constructors[i]; + if (matchParameters(types, constructor.getParameterTypes())) + return constructor; + } + throw new NoSuchMethodException(); + } + + /** + * Get all the public constructors of this class. This returns an array of + * length 0 if there are no constructors, including for primitive types, + * arrays, and interfaces. It does, however, include the default + * constructor if one was supplied by the compiler. A security check may + * be performed, with checkMemberAccess(this, Member.PUBLIC) + * as well as checkPackageAccess both having to succeed. + * + * @return all public constructors in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Constructor[] getConstructors() + { + memberAccessCheck(Member.PUBLIC); + return getDeclaredConstructors(true); + } + + /** + * Get a constructor declared in this class. If the constructor takes no + * argument, an array of zero elements and null are equivalent for the + * types argument. A security check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @param types the type of each parameter + * @return the constructor + * @throws NoSuchMethodException if the constructor does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredConstructors() + * @since 1.1 + */ + public Constructor getDeclaredConstructor(Class[] types) + throws NoSuchMethodException + { + memberAccessCheck(Member.DECLARED); + Constructor[] constructors = getDeclaredConstructors(false); + for (int i = 0; i < constructors.length; i++) + { + Constructor constructor = constructors[i]; + if (matchParameters(types, constructor.getParameterTypes())) + return constructor; + } + throw new NoSuchMethodException(); + } + + /** + * Get all the declared member classes and interfaces in this class, but + * not those inherited from superclasses. This returns an array of length + * 0 if there are no member classes, including for primitive types. A + * security check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @return all declared member classes in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Class[] getDeclaredClasses() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredClasses(false); + } + + Class[] getDeclaredClasses (boolean publicOnly) + { + return VMClass.getDeclaredClasses (this, publicOnly); + } + + /** + * Get all the declared constructors of this class. This returns an array of + * length 0 if there are no constructors, including for primitive types, + * arrays, and interfaces. It does, however, include the default + * constructor if one was supplied by the compiler. A security check may + * be performed, with checkMemberAccess(this, Member.DECLARED) + * as well as checkPackageAccess both having to succeed. + * + * @return all constructors in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Constructor[] getDeclaredConstructors() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredConstructors(false); + } + + Constructor[] getDeclaredConstructors (boolean publicOnly) + { + return VMClass.getDeclaredConstructors (this, publicOnly); + } + + /** + * Get a field declared in this class, where name is its simple name. The + * implicit length field of arrays is not available. A security check may + * be performed, with checkMemberAccess(this, Member.DECLARED) + * as well as checkPackageAccess both having to succeed. + * + * @param name the name of the field + * @return the field + * @throws NoSuchFieldException if the field does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredFields() + * @since 1.1 + */ + public Field getDeclaredField(String name) throws NoSuchFieldException + { + memberAccessCheck(Member.DECLARED); + Field[] fields = getDeclaredFields(false); + for (int i = 0; i < fields.length; i++) + { + if (fields[i].getName().equals(name)) + return fields[i]; + } + throw new NoSuchFieldException(); + } + + /** + * Get all the declared fields in this class, but not those inherited from + * superclasses. This returns an array of length 0 if there are no fields, + * including for primitive types. This does not return the implicit length + * field of arrays. A security check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @return all declared fields in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Field[] getDeclaredFields() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredFields(false); + } + + Field[] getDeclaredFields (boolean publicOnly) + { + return VMClass.getDeclaredFields (this, publicOnly); + } + + /** + * Get a method declared in this class, where name is its simple name. The + * implicit methods of Object are not available from arrays or interfaces. + * Constructors (named "<init>" in the class file) and class initializers + * (name "<clinit>") are not available. The Virtual Machine allows + * multiple methods with the same signature but differing return types; in + * such a case the most specific return types are favored, then the final + * choice is arbitrary. If the method takes no argument, an array of zero + * elements and null are equivalent for the types argument. A security + * check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @param methodName the name of the method + * @param types the type of each parameter + * @return the method + * @throws NoSuchMethodException if the method does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredMethods() + * @since 1.1 + */ + public Method getDeclaredMethod(String methodName, Class[] types) + throws NoSuchMethodException + { + memberAccessCheck(Member.DECLARED); + Method match = matchMethod(getDeclaredMethods(false), methodName, types); + if (match == null) + throw new NoSuchMethodException(methodName); + return match; + } + + /** + * Get all the declared methods in this class, but not those inherited from + * superclasses. This returns an array of length 0 if there are no methods, + * including for primitive types. This does include the implicit methods of + * arrays and interfaces which mirror methods of Object, nor does it + * include constructors or the class initialization methods. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types; all such methods are in the returned array. A security + * check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @return all declared methods in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Method[] getDeclaredMethods() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredMethods(false); + } + + Method[] getDeclaredMethods (boolean publicOnly) + { + return VMClass.getDeclaredMethods (this, publicOnly); + } + + /** + * If this is a nested or inner class, return the class that declared it. + * If not, return null. + * + * @return the declaring class of this class + * @since 1.1 + */ + public Class getDeclaringClass() + { + return VMClass.getDeclaringClass (this); + } + + /** + * Get a public field declared or inherited in this class, where name is + * its simple name. If the class contains multiple accessible fields by + * that name, an arbitrary one is returned. The implicit length field of + * arrays is not available. A security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @param fieldName the name of the field + * @return the field + * @throws NoSuchFieldException if the field does not exist + * @throws SecurityException if the security check fails + * @see #getFields() + * @since 1.1 + */ + public Field getField(String fieldName) + throws NoSuchFieldException + { + memberAccessCheck(Member.PUBLIC); + Field field = internalGetField(fieldName); + if (field == null) + throw new NoSuchFieldException(fieldName); + return field; + } + + /** + * Get all the public fields declared in this class or inherited from + * superclasses. This returns an array of length 0 if there are no fields, + * including for primitive types. This does not return the implicit length + * field of arrays. A security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @return all public fields in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Field[] getFields() + { + memberAccessCheck(Member.PUBLIC); + return internalGetFields(); + } + + /** + * Like getFields() but without the security checks. + */ + private Field[] internalGetFields() + { + HashSet set = new HashSet(); + set.addAll(Arrays.asList(getDeclaredFields(true))); + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + set.addAll(Arrays.asList(interfaces[i].internalGetFields())); + Class superClass = getSuperclass(); + if (superClass != null) + set.addAll(Arrays.asList(superClass.internalGetFields())); + return (Field[])set.toArray(new Field[set.size()]); + } + + /** + * Returns the Package in which this class is defined + * Returns null when this information is not available from the + * classloader of this class or when the classloader of this class + * is null. + * + * @return the package for this class, if it is available + * @since 1.2 + */ + public Package getPackage() + { + ClassLoader cl = getClassLoader(); + if (cl != null) + return cl.getPackage(getPackagePortion(getName())); + return null; + } + + /** + * Get the interfaces this class directly implements, in the + * order that they were declared. This returns an empty array, not null, + * for Object, primitives, void, and classes or interfaces with no direct + * superinterface. Array types return Cloneable and Serializable. + * + * @return the interfaces this class directly implements + */ + public Class[] getInterfaces() + { + return VMClass.getInterfaces (this); + } + + private static final class MethodKey + { + private String name; + private Class[] params; + private Class returnType; + private int hash; + + MethodKey(Method m) + { + name = m.getName(); + params = m.getParameterTypes(); + returnType = m.getReturnType(); + hash = name.hashCode() ^ returnType.hashCode(); + for(int i = 0; i < params.length; i++) + { + hash ^= params[i].hashCode(); + } + } + + public boolean equals(Object o) + { + if(o instanceof MethodKey) + { + MethodKey m = (MethodKey)o; + if(m.name.equals(name) && m.params.length == params.length && m.returnType == returnType) + { + for(int i = 0; i < params.length; i++) + { + if(m.params[i] != params[i]) + { + return false; + } + } + return true; + } + } + return false; + } + + public int hashCode() + { + return hash; + } + } + + /** + * Get a public method declared or inherited in this class, where name is + * its simple name. The implicit methods of Object are not available from + * interfaces. Constructors (named "<init>" in the class file) and class + * initializers (name "<clinit>") are not available. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types, and the class can inherit multiple methods of the same + * return type; in such a case the most specific return types are favored, + * then the final choice is arbitrary. If the method takes no argument, an + * array of zero elements and null are equivalent for the types argument. + * A security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @param methodName the name of the method + * @param types the type of each parameter + * @return the method + * @throws NoSuchMethodException if the method does not exist + * @throws SecurityException if the security check fails + * @see #getMethods() + * @since 1.1 + */ + public Method getMethod(String methodName, Class[] types) + throws NoSuchMethodException + { + memberAccessCheck(Member.PUBLIC); + Method method = internalGetMethod(methodName, types); + if (method == null) + throw new NoSuchMethodException(methodName); + return method; + } + + /** + * Like getMethod(String,Class[]) but without the security + * checks and returns null instead of throwing NoSuchMethodException. + */ + private Method internalGetMethod(String methodName, Class[] args) + { + Method match = matchMethod(getDeclaredMethods(true), methodName, args); + if (match != null) + return match; + Class superClass = getSuperclass(); + if (superClass != null) + { + match = superClass.internalGetMethod(methodName, args); + if(match != null) + return match; + } + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + { + match = interfaces[i].internalGetMethod(methodName, args); + if (match != null) + return match; + } + return null; + } + + /** + * Find the best matching method in list according to + * the definition of ``best matching'' used by getMethod() + * + *

    + * Returns the method if any, otherwise null. + * + * @param list List of methods to search + * @param name Name of method + * @param args Method parameter types + * @see #getMethod() + */ + private static Method matchMethod(Method[] list, String name, Class[] args) + { + Method match = null; + for (int i = 0; i < list.length; i++) + { + Method method = list[i]; + if (!method.getName().equals(name)) + continue; + if (!matchParameters(args, method.getParameterTypes())) + continue; + if (match == null + || match.getReturnType().isAssignableFrom(method.getReturnType())) + match = method; + } + return match; + } + + /** + * Check for an exact match between parameter type lists. + * Either list may be null to mean a list of + * length zero. + */ + private static boolean matchParameters(Class[] types1, Class[] types2) + { + if (types1 == null) + return types2 == null || types2.length == 0; + if (types2 == null) + return types1 == null || types1.length == 0; + if (types1.length != types2.length) + return false; + for (int i = 0; i < types1.length; i++) + { + if (types1[i] != types2[i]) + return false; + } + return true; + } + + /** + * Get all the public methods declared in this class or inherited from + * superclasses. This returns an array of length 0 if there are no methods, + * including for primitive types. This does not include the implicit + * methods of interfaces which mirror methods of Object, nor does it + * include constructors or the class initialization methods. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types; all such methods are in the returned array. A security + * check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @return all public methods in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Method[] getMethods() + { + memberAccessCheck(Member.PUBLIC); + // NOTE the API docs claim that no methods are returned for arrays, + // but Sun's implementation *does* return the public methods of Object + // (as would be expected), so we follow their implementation instead + // of their documentation. + return internalGetMethods(); + } + + /** + * Like getMethods() but without the security checks. + */ + private Method[] internalGetMethods() + { + HashMap map = new HashMap(); + Method[] methods; + Class[] interfaces = getInterfaces(); + for(int i = 0; i < interfaces.length; i++) + { + methods = interfaces[i].internalGetMethods(); + for(int j = 0; j < methods.length; j++) + { + map.put(new MethodKey(methods[j]), methods[j]); + } + } + Class superClass = getSuperclass(); + if(superClass != null) + { + methods = superClass.internalGetMethods(); + for(int i = 0; i < methods.length; i++) + { + map.put(new MethodKey(methods[i]), methods[i]); + } + } + methods = getDeclaredMethods(true); + for(int i = 0; i < methods.length; i++) + { + map.put(new MethodKey(methods[i]), methods[i]); + } + return (Method[])map.values().toArray(new Method[map.size()]); + } + + /** + * Get the modifiers of this class. These can be decoded using Modifier, + * and is limited to one of public, protected, or private, and any of + * final, static, abstract, or interface. An array class has the same + * public, protected, or private modifier as its component type, and is + * marked final but not an interface. Primitive types and void are marked + * public and final, but not an interface. + * + * @return the modifiers of this class + * @see Modifer + * @since 1.1 + */ + public int getModifiers() + { + return VMClass.getModifiers (this, false); + } + + /** + * Get the name of this class, separated by dots for package separators. + * If the class represents a primitive type, or void, then the + * name of the type as it appears in the Java programming language + * is returned. For instance, Byte.TYPE.getName() + * returns "byte". + * + * Arrays are specially encoded as shown on this table. + *

    +   * array type          [element type
    +   *                     (note that the element type is encoded per
    +   *                      this table)
    +   * boolean             Z
    +   * byte                B
    +   * char                C
    +   * short               S
    +   * int                 I
    +   * long                J
    +   * float               F
    +   * double              D
    +   * void                V
    +   * class or interface, alone: <dotted name>
    +   * class or interface, as element type: L<dotted name>;
    +   * 
    + * + * @return the name of this class + */ + public String getName() + { + return VMClass.getName (this); + } + + /** + * Get a resource URL using this class's package using the + * getClassLoader().getResource() method. If this class was loaded using + * the system classloader, ClassLoader.getSystemResource() is used instead. + * + *

    If the name you supply is absolute (it starts with a /), + * then the leading / is removed and it is passed on to + * getResource(). If it is relative, the package name is prepended, and + * .'s are replaced with /. + * + *

    The URL returned is system- and classloader-dependent, and could + * change across implementations. + * + * @param resourceName the name of the resource, generally a path + * @return the URL to the resource + * @throws NullPointerException if name is null + * @since 1.1 + */ + public URL getResource(String resourceName) + { + String name = resourcePath(resourceName); + ClassLoader loader = getClassLoader(); + if (loader == null) + return ClassLoader.getSystemResource(name); + return loader.getResource(name); + } + + /** + * Get a resource using this class's package using the + * getClassLoader().getResourceAsStream() method. If this class was loaded + * using the system classloader, ClassLoader.getSystemResource() is used + * instead. + * + *

    If the name you supply is absolute (it starts with a /), + * then the leading / is removed and it is passed on to + * getResource(). If it is relative, the package name is prepended, and + * .'s are replaced with /. + * + *

    The URL returned is system- and classloader-dependent, and could + * change across implementations. + * + * @param resourceName the name of the resource, generally a path + * @return an InputStream with the contents of the resource in it, or null + * @throws NullPointerException if name is null + * @since 1.1 + */ + public InputStream getResourceAsStream(String resourceName) + { + String name = resourcePath(resourceName); + ClassLoader loader = getClassLoader(); + if (loader == null) + return ClassLoader.getSystemResourceAsStream(name); + return loader.getResourceAsStream(name); + } + + private String resourcePath(String resourceName) + { + if (resourceName.length() > 0) + { + if (resourceName.charAt(0) != '/') + { + String pkg = getPackagePortion(getName()); + if (pkg.length() > 0) + resourceName = pkg.replace('.','/') + '/' + resourceName; + } + else + { + resourceName = resourceName.substring(1); + } + } + return resourceName; + } + + /** + * Get the signers of this class. This returns null if there are no signers, + * such as for primitive types or void. + * + * @return the signers of this class + * @since 1.1 + */ + public Object[] getSigners() + { + return signers == null ? null : (Object[]) signers.clone (); + } + + /** + * Set the signers of this class. + * + * @param signers the signers of this class + */ + void setSigners(Object[] signers) + { + this.signers = signers; + } + + /** + * Get the direct superclass of this class. If this is an interface, + * Object, a primitive type, or void, it will return null. If this is an + * array type, it will return Object. + * + * @return the direct superclass of this class + */ + public Class getSuperclass() + { + return VMClass.getSuperclass (this); + } + + /** + * Return whether this class is an array type. + * + * @return whether this class is an array type + * @since 1.1 + */ + public boolean isArray() + { + return VMClass.isArray (this); + } + + /** + * Discover whether an instance of the Class parameter would be an + * instance of this Class as well. Think of doing + * isInstance(c.newInstance()) or even + * c.newInstance() instanceof (this class). While this + * checks widening conversions for objects, it must be exact for primitive + * types. + * + * @param c the class to check + * @return whether an instance of c would be an instance of this class + * as well + * @throws NullPointerException if c is null + * @since 1.1 + */ + public boolean isAssignableFrom(Class c) + { + return VMClass.isAssignableFrom (this, c); + } + + /** + * Discover whether an Object is an instance of this Class. Think of it + * as almost like o instanceof (this class). + * + * @param o the Object to check + * @return whether o is an instance of this class + * @since 1.1 + */ + public boolean isInstance(Object o) + { + return VMClass.isInstance (this, o); + } + + /** + * Check whether this class is an interface or not. Array types are not + * interfaces. + * + * @return whether this class is an interface or not + */ + public boolean isInterface() + { + return VMClass.isInterface (this); + } + + /** + * Return whether this class is a primitive type. A primitive type class + * is a class representing a kind of "placeholder" for the various + * primitive types, or void. You can access the various primitive type + * classes through java.lang.Boolean.TYPE, java.lang.Integer.TYPE, etc., + * or through boolean.class, int.class, etc. + * + * @return whether this class is a primitive type + * @see Boolean#TYPE + * @see Byte#TYPE + * @see Character#TYPE + * @see Short#TYPE + * @see Integer#TYPE + * @see Long#TYPE + * @see Float#TYPE + * @see Double#TYPE + * @see Void#TYPE + * @since 1.1 + */ + public boolean isPrimitive() + { + return VMClass.isPrimitive (this); + } + + /** + * Get a new instance of this class by calling the no-argument constructor. + * The class is initialized if it has not been already. A security check + * may be performed, with checkMemberAccess(this, Member.PUBLIC) + * as well as checkPackageAccess both having to succeed. + * + * @return a new instance of this class + * @throws InstantiationException if there is not a no-arg constructor + * for this class, including interfaces, abstract classes, arrays, + * primitive types, and void; or if an exception occurred during + * the constructor + * @throws IllegalAccessException if you are not allowed to access the + * no-arg constructor because of scoping reasons + * @throws SecurityException if the security check fails + * @throws ExceptionInInitializerError if class initialization caused by + * this call fails with an exception + */ + public Object newInstance() + throws InstantiationException, IllegalAccessException + { + memberAccessCheck(Member.PUBLIC); + Constructor constructor; + synchronized(this) + { + constructor = this.constructor; + } + if (constructor == null) + { + Constructor[] constructors = getDeclaredConstructors(false); + for (int i = 0; i < constructors.length; i++) + { + if (constructors[i].getParameterTypes().length == 0) + { + constructor = constructors[i]; + break; + } + } + if (constructor == null) + throw new InstantiationException(getName()); + if (!Modifier.isPublic(constructor.getModifiers()) + || !Modifier.isPublic(VMClass.getModifiers(this, true))) + { + final Constructor finalConstructor = constructor; + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + finalConstructor.setAccessible(true); + return null; + } + }); + } + synchronized(this) + { + if (this.constructor == null) + this.constructor = constructor; + } + } + int modifiers = constructor.getModifiers(); + if (!Modifier.isPublic(modifiers) + || !Modifier.isPublic(VMClass.getModifiers(this, true))) + { + Class caller = VMStackWalker.getCallingClass(); + if (caller != null && + caller != this && + (Modifier.isPrivate(modifiers) + || getClassLoader() != caller.getClassLoader() + || !getPackagePortion(getName()) + .equals(getPackagePortion(caller.getName())))) + throw new IllegalAccessException(getName() + + " has an inaccessible constructor"); + } + try + { + return constructor.newInstance(null); + } + catch (InvocationTargetException e) + { + VMClass.throwException(e.getTargetException()); + throw (InternalError) new InternalError + ("VMClass.throwException returned").initCause(e); + } + } + + /** + * Returns the protection domain of this class. If the classloader did not + * record the protection domain when creating this class the unknown + * protection domain is returned which has a null code source + * and all permissions. A security check may be performed, with + * RuntimePermission("getProtectionDomain"). + * + * @return the protection domain + * @throws SecurityException if the security manager exists and the caller + * does not have RuntimePermission("getProtectionDomain"). + * @see RuntimePermission + * @since 1.2 + */ + public ProtectionDomain getProtectionDomain() + { + SecurityManager sm = SecurityManager.current; + if (sm != null) + sm.checkPermission(new RuntimePermission("getProtectionDomain")); + + return pd == null ? StaticData.unknownProtectionDomain : pd; + } + + /** + * Return the human-readable form of this Object. For an object, this + * is either "interface " or "class " followed by getName(), + * for primitive types and void it is just getName(). + * + * @return the human-readable form of this Object + */ + public String toString() + { + if (isPrimitive()) + return getName(); + return (isInterface() ? "interface " : "class ") + getName(); + } + + /** + * Returns the desired assertion status of this class, if it were to be + * initialized at this moment. The class assertion status, if set, is + * returned; the backup is the default package status; then if there is + * a class loader, that default is returned; and finally the system default + * is returned. This method seldom needs calling in user code, but exists + * for compilers to implement the assert statement. Note that there is no + * guarantee that the result of this method matches the class's actual + * assertion status. + * + * @return the desired assertion status + * @see ClassLoader#setClassAssertionStatus(String, boolean) + * @see ClassLoader#setPackageAssertionStatus(String, boolean) + * @see ClassLoader#setDefaultAssertionStatus(boolean) + * @since 1.4 + */ + public boolean desiredAssertionStatus() + { + ClassLoader c = getClassLoader(); + Object status; + if (c == null) + return VMClassLoader.defaultAssertionStatus(); + if (c.classAssertionStatus != null) + synchronized (c) + { + status = c.classAssertionStatus.get(getName()); + if (status != null) + return status.equals(Boolean.TRUE); + } + else + { + status = ClassLoader.StaticData. + systemClassAssertionStatus.get(getName()); + if (status != null) + return status.equals(Boolean.TRUE); + } + if (c.packageAssertionStatus != null) + synchronized (c) + { + String name = getPackagePortion(getName()); + if ("".equals(name)) + status = c.packageAssertionStatus.get(null); + else + do + { + status = c.packageAssertionStatus.get(name); + name = getPackagePortion(name); + } + while (! "".equals(name) && status == null); + if (status != null) + return status.equals(Boolean.TRUE); + } + else + { + String name = getPackagePortion(getName()); + if ("".equals(name)) + status = ClassLoader.StaticData. + systemPackageAssertionStatus.get(null); + else + do + { + status = ClassLoader.StaticData. + systemPackageAssertionStatus.get(name); + name = getPackagePortion(name); + } + while (! "".equals(name) && status == null); + if (status != null) + return status.equals(Boolean.TRUE); + } + return c.defaultAssertionStatus; + } + + /** + * Like getField(String) but without the security checks and returns null + * instead of throwing NoSuchFieldException. + */ + private Field internalGetField(String name) + { + Field[] fields = getDeclaredFields(true); + for (int i = 0; i < fields.length; i++) + { + Field field = fields[i]; + if (field.getName().equals(name)) + return field; + } + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + { + Field field = interfaces[i].internalGetField(name); + if(field != null) + return field; + } + Class superClass = getSuperclass(); + if (superClass != null) + return superClass.internalGetField(name); + return null; + } + + /** + * Strip the last portion of the name (after the last dot). + * + * @param name the name to get package of + * @return the package name, or "" if no package + */ + private static String getPackagePortion(String name) + { + int lastInd = name.lastIndexOf('.'); + if (lastInd == -1) + return ""; + return name.substring(0, lastInd); + } + + /** + * Perform security checks common to all of the methods that + * get members of this Class. + */ + private void memberAccessCheck(int which) + { + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + sm.checkMemberAccess(this, which); + Package pkg = getPackage(); + if (pkg != null) + sm.checkPackageAccess(pkg.getName()); + } + } +} diff --git a/libjava/classpath/java/lang/ClassCastException.java b/libjava/classpath/java/lang/ClassCastException.java new file mode 100644 index 0000000..c490f42 --- /dev/null +++ b/libjava/classpath/java/lang/ClassCastException.java @@ -0,0 +1,76 @@ +/* ClassCastException.java -- exception thrown on bad cast + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when an attempt is made to cast an object which is not of the + * appropriate runtime type. For example:
    + *

    + * Object o = new Vector();
    + * String s = (String) o;
    + * 
    + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class ClassCastException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -9223365651070458532L; + + /** + * Create an exception without a message. + */ + public ClassCastException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ClassCastException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/ClassCircularityError.java b/libjava/classpath/java/lang/ClassCircularityError.java new file mode 100644 index 0000000..ecdfb7a --- /dev/null +++ b/libjava/classpath/java/lang/ClassCircularityError.java @@ -0,0 +1,73 @@ +/* ClassCircularityError.java -- thrown when linking circular classes + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * A ClassCircularityError is thrown when a circular dependency + * has been detected while initializing a class. This signals binary + * incompatible versions of class files, as the compiler normally catches this. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class ClassCircularityError extends LinkageError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 1054362542914539689L; + + /** + * Create an error without a message. + */ + public ClassCircularityError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public ClassCircularityError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/ClassFormatError.java b/libjava/classpath/java/lang/ClassFormatError.java new file mode 100644 index 0000000..7f90f5c --- /dev/null +++ b/libjava/classpath/java/lang/ClassFormatError.java @@ -0,0 +1,72 @@ +/* ClassFormatError.java -- thrown if a class file is invalid + Copyright (C) 1998, 1999, 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 java.lang; + +/** + * A ClassFormatError is thrown when a Java Virtual Machine + * unable to read a class file because the file is corrupted or cannot be + * interpreted as a class file. + * + * @author Brian Jones + * @status updated to 1.4 + */ +public class ClassFormatError extends LinkageError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -8420114879011949195L; + + /** + * Create an error without a message. + */ + public ClassFormatError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public ClassFormatError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/ClassLoader.java b/libjava/classpath/java/lang/ClassLoader.java new file mode 100644 index 0000000..b644511 --- /dev/null +++ b/libjava/classpath/java/lang/ClassLoader.java @@ -0,0 +1,1116 @@ +/* ClassLoader.java -- responsible for loading classes into the VM + Copyright (C) 1998, 1999, 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 java.lang; + +import gnu.classpath.SystemProperties; +import gnu.classpath.VMStackWalker; +import gnu.java.util.DoubleEnumeration; +import gnu.java.util.EmptyEnumeration; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.security.Policy; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * The ClassLoader is a way of customizing the way Java gets its classes + * and loads them into memory. The verifier and other standard Java things + * still run, but the ClassLoader is allowed great flexibility in determining + * where to get the classfiles and when to load and resolve them. For that + * matter, a custom ClassLoader can perform on-the-fly code generation or + * modification! + * + *

    Every classloader has a parent classloader that is consulted before + * the 'child' classloader when classes or resources should be loaded. + * This is done to make sure that classes can be loaded from an hierarchy of + * multiple classloaders and classloaders do not accidentially redefine + * already loaded classes by classloaders higher in the hierarchy. + * + *

    The grandparent of all classloaders is the bootstrap classloader, which + * loads all the standard system classes as implemented by GNU Classpath. The + * other special classloader is the system classloader (also called + * application classloader) that loads all classes from the CLASSPATH + * (java.class.path system property). The system classloader + * is responsible for finding the application classes from the classpath, + * and delegates all requests for the standard library classes to its parent + * the bootstrap classloader. Most programs will load all their classes + * through the system classloaders. + * + *

    The bootstrap classloader in GNU Classpath is implemented as a couple of + * static (native) methods on the package private class + * java.lang.VMClassLoader, the system classloader is an + * anonymous inner class of ClassLoader and a subclass of + * java.net.URLClassLoader. + * + *

    Users of a ClassLoader will normally just use the methods + *

      + *
    • loadClass() to load a class.
    • + *
    • getResource() or getResourceAsStream() + * to access a resource.
    • + *
    • getResources() to get an Enumeration of URLs to all + * the resources provided by the classloader and its parents with the + * same name.
    • + *
    + * + *

    Subclasses should implement the methods + *

      + *
    • findClass() which is called by loadClass() + * when the parent classloader cannot provide a named class.
    • + *
    • findResource() which is called by + * getResource() when the parent classloader cannot provide + * a named resource.
    • + *
    • findResources() which is called by + * getResource() to combine all the resources with the + * same name from the classloader and its parents.
    • + *
    • findLibrary() which is called by + * Runtime.loadLibrary() when a class defined by the + * classloader wants to load a native library.
    • + *
    + * + * @author John Keiser + * @author Mark Wielaard + * @author Eric Blake (ebb9@email.byu.edu) + * @see Class + * @since 1.0 + * @status still missing 1.4 functionality + */ +public abstract class ClassLoader +{ + /** + * All classes loaded by this classloader. VM's may choose to implement + * this cache natively; but it is here available for use if necessary. It + * is not private in order to allow native code (and trusted subclasses) + * access to this field. + */ + final HashMap loadedClasses = new HashMap(); + + /** + * All packages defined by this classloader. It is not private in order to + * allow native code (and trusted subclasses) access to this field. + */ + final HashMap definedPackages = new HashMap(); + + /** + * The classloader that is consulted before this classloader. + * If null then the parent is the bootstrap classloader. + */ + private final ClassLoader parent; + + /** + * This is true if this classloader was successfully initialized. + * This flag is needed to avoid a class loader attack: even if the + * security manager rejects an attempt to create a class loader, the + * malicious class could have a finalize method which proceeds to + * define classes. + */ + private final boolean initialized; + + static class StaticData + { + /** + * The System Class Loader (a.k.a. Application Class Loader). The one + * returned by ClassLoader.getSystemClassLoader. + */ + static final ClassLoader systemClassLoader = + VMClassLoader.getSystemClassLoader(); + static + { + // Find out if we have to install a default security manager. Note that + // this is done here because we potentially need the system class loader + // to load the security manager and note also that we don't need the + // security manager until the system class loader is created. + // If the runtime chooses to use a class loader that doesn't have the + // system class loader as its parent, it is responsible for setting + // up a security manager before doing so. + String secman = SystemProperties.getProperty("java.security.manager"); + if (secman != null && SecurityManager.current == null) + { + if (secman.equals("") || secman.equals("default")) + { + SecurityManager.current = new SecurityManager(); + } + else + { + try + { + Class cl = Class.forName(secman, false, StaticData.systemClassLoader); + SecurityManager.current = (SecurityManager)cl.newInstance(); + } + catch (Exception x) + { + throw (InternalError) + new InternalError("Unable to create SecurityManager") + .initCause(x); + } + } + } + } + + /** + * The default protection domain, used when defining a class with a null + * parameter for the domain. + */ + static final ProtectionDomain defaultProtectionDomain; + static + { + CodeSource cs = new CodeSource(null, null); + PermissionCollection perm = Policy.getPolicy().getPermissions(cs); + defaultProtectionDomain = new ProtectionDomain(cs, perm); + } + /** + * The command-line state of the package assertion status overrides. This + * map is never modified, so it does not need to be synchronized. + */ + // Package visible for use by Class. + static final Map systemPackageAssertionStatus + = VMClassLoader.packageAssertionStatus(); + /** + * The command-line state of the class assertion status overrides. This + * map is never modified, so it does not need to be synchronized. + */ + // Package visible for use by Class. + static final Map systemClassAssertionStatus + = VMClassLoader.classAssertionStatus(); + } + + /** + * The desired assertion status of classes loaded by this loader, if not + * overridden by package or class instructions. + */ + // Package visible for use by Class. + boolean defaultAssertionStatus = VMClassLoader.defaultAssertionStatus(); + + /** + * The map of package assertion status overrides, or null if no package + * overrides have been specified yet. The values of the map should be + * Boolean.TRUE or Boolean.FALSE, and the unnamed package is represented + * by the null key. This map must be synchronized on this instance. + */ + // Package visible for use by Class. + Map packageAssertionStatus; + + /** + * The map of class assertion status overrides, or null if no class + * overrides have been specified yet. The values of the map should be + * Boolean.TRUE or Boolean.FALSE. This map must be synchronized on this + * instance. + */ + // Package visible for use by Class. + Map classAssertionStatus; + + /** + * VM private data. + */ + transient Object vmdata; + + /** + * Create a new ClassLoader with as parent the system classloader. There + * may be a security check for checkCreateClassLoader. + * + * @throws SecurityException if the security check fails + */ + protected ClassLoader() throws SecurityException + { + this(StaticData.systemClassLoader); + } + + /** + * Create a new ClassLoader with the specified parent. The parent will + * be consulted when a class or resource is requested through + * loadClass() or getResource(). Only when the + * parent classloader cannot provide the requested class or resource the + * findClass() or findResource() method + * of this classloader will be called. There may be a security check for + * checkCreateClassLoader. + * + * @param parent the classloader's parent, or null for the bootstrap + * classloader + * @throws SecurityException if the security check fails + * @since 1.2 + */ + protected ClassLoader(ClassLoader parent) + { + // May we create a new classloader? + SecurityManager sm = SecurityManager.current; + if (sm != null) + sm.checkCreateClassLoader(); + this.parent = parent; + this.initialized = true; + } + + /** + * Load a class using this ClassLoader or its parent, without resolving + * it. Calls loadClass(name, false). + * + *

    Subclasses should not override this method but should override + * findClass() which is called by this method.

    + * + * @param name the name of the class relative to this ClassLoader + * @return the loaded class + * @throws ClassNotFoundException if the class cannot be found + */ + public Class loadClass(String name) throws ClassNotFoundException + { + return loadClass(name, false); + } + + /** + * Load a class using this ClassLoader or its parent, possibly resolving + * it as well using resolveClass(). It first tries to find + * out if the class has already been loaded through this classloader by + * calling findLoadedClass(). Then it calls + * loadClass() on the parent classloader (or when there is + * no parent it uses the VM bootclassloader). If the class is still + * not loaded it tries to create a new class by calling + * findClass(). Finally when resolve is + * true it also calls resolveClass() on the + * newly loaded class. + * + *

    Subclasses should not override this method but should override + * findClass() which is called by this method.

    + * + * @param name the fully qualified name of the class to load + * @param resolve whether or not to resolve the class + * @return the loaded class + * @throws ClassNotFoundException if the class cannot be found + */ + protected synchronized Class loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + // Have we already loaded this class? + Class c = findLoadedClass(name); + if (c == null) + { + // Can the class be loaded by a parent? + try + { + if (parent == null) + { + c = VMClassLoader.loadClass(name, resolve); + if (c != null) + return c; + } + else + { + return parent.loadClass(name, resolve); + } + } + catch (ClassNotFoundException e) + { + } + // Still not found, we have to do it ourself. + c = findClass(name); + } + if (resolve) + resolveClass(c); + return c; + } + + /** + * Called for every class name that is needed but has not yet been + * defined by this classloader or one of its parents. It is called by + * loadClass() after both findLoadedClass() and + * parent.loadClass() couldn't provide the requested class. + * + *

    The default implementation throws a + * ClassNotFoundException. Subclasses should override this + * method. An implementation of this method in a subclass should get the + * class bytes of the class (if it can find them), if the package of the + * requested class doesn't exist it should define the package and finally + * it should call define the actual class. It does not have to resolve the + * class. It should look something like the following:
    + * + *

    +   * // Get the bytes that describe the requested class
    +   * byte[] classBytes = classLoaderSpecificWayToFindClassBytes(name);
    +   * // Get the package name
    +   * int lastDot = name.lastIndexOf('.');
    +   * if (lastDot != -1)
    +   *   {
    +   *     String packageName = name.substring(0, lastDot);
    +   *     // Look if the package already exists
    +   *     if (getPackage(packageName) == null)
    +   *       {
    +   *         // define the package
    +   *         definePackage(packageName, ...);
    +   *       }
    +   *   }
    +   * // Define and return the class
    +   *  return defineClass(name, classBytes, 0, classBytes.length);
    +   * 
    + * + *

    loadClass() makes sure that the Class + * returned by findClass() will later be returned by + * findLoadedClass() when the same class name is requested. + * + * @param name class name to find (including the package name) + * @return the requested Class + * @throws ClassNotFoundException when the class can not be found + * @since 1.2 + */ + protected Class findClass(String name) throws ClassNotFoundException + { + throw new ClassNotFoundException(name); + } + + /** + * Helper to define a class using a string of bytes. This version is not + * secure. + * + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws IndexOutOfBoundsException if offset or len is negative, or + * offset + len exceeds data + * @deprecated use {@link #defineClass(String, byte[], int, int)} instead + */ + protected final Class defineClass(byte[] data, int offset, int len) + throws ClassFormatError + { + return defineClass(null, data, offset, len); + } + + /** + * Helper to define a class using a string of bytes without a + * ProtectionDomain. Subclasses should call this method from their + * findClass() implementation. The name should use '.' + * separators, and discard the trailing ".class". The default protection + * domain has the permissions of + * Policy.getPolicy().getPermissions(new CodeSource(null, null)). + * + * @param name the name to give the class, or null if unknown + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws IndexOutOfBoundsException if offset or len is negative, or + * offset + len exceeds data + * @throws SecurityException if name starts with "java." + * @since 1.1 + */ + protected final Class defineClass(String name, byte[] data, int offset, + int len) throws ClassFormatError + { + return defineClass(name, data, offset, len, null); + } + + /** + * Helper to define a class using a string of bytes. Subclasses should call + * this method from their findClass() implementation. If the + * domain is null, the default of + * Policy.getPolicy().getPermissions(new CodeSource(null, null)) + * is used. Once a class has been defined in a package, all further classes + * in that package must have the same set of certificates or a + * SecurityException is thrown. + * + * @param name the name to give the class. null if unknown + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @param domain the ProtectionDomain to give to the class, null for the + * default protection domain + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws IndexOutOfBoundsException if offset or len is negative, or + * offset + len exceeds data + * @throws SecurityException if name starts with "java.", or if certificates + * do not match up + * @since 1.2 + */ + protected final synchronized Class defineClass(String name, byte[] data, + int offset, int len, + ProtectionDomain domain) + throws ClassFormatError + { + if (domain == null) + domain = StaticData.defaultProtectionDomain; + if (! initialized) + throw new SecurityException("attempt to define class from uninitialized class loader"); + + Class retval = VMClassLoader.defineClass(this, name, data, + offset, len, domain); + loadedClasses.put(retval.getName(), retval); + return retval; + } + + /** + * Links the class, if that has not already been done. Linking basically + * resolves all references to other classes made by this class. + * + * @param c the class to resolve + * @throws NullPointerException if c is null + * @throws LinkageError if linking fails + */ + protected final void resolveClass(Class c) + { + VMClassLoader.resolveClass(c); + } + + /** + * Helper to find a Class using the system classloader, possibly loading it. + * A subclass usually does not need to call this, if it correctly + * overrides findClass(String). + * + * @param name the name of the class to find + * @return the found class + * @throws ClassNotFoundException if the class cannot be found + */ + protected final Class findSystemClass(String name) + throws ClassNotFoundException + { + return Class.forName(name, false, StaticData.systemClassLoader); + } + + /** + * Returns the parent of this classloader. If the parent of this + * classloader is the bootstrap classloader then this method returns + * null. A security check may be performed on + * RuntimePermission("getClassLoader"). + * + * @return the parent ClassLoader + * @throws SecurityException if the security check fails + * @since 1.2 + */ + public final ClassLoader getParent() + { + // Check if we may return the parent classloader. + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && ! cl.isAncestorOf(this)) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + return parent; + } + + /** + * Helper to set the signers of a class. This should be called after + * defining the class. + * + * @param c the Class to set signers of + * @param signers the signers to set + * @since 1.1 + */ + protected final void setSigners(Class c, Object[] signers) + { + c.setSigners(signers); + } + + /** + * Helper to find an already-loaded class in this ClassLoader. + * + * @param name the name of the class to find + * @return the found Class, or null if it is not found + * @since 1.1 + */ + protected final synchronized Class findLoadedClass(String name) + { + // NOTE: If the VM is keeping its own cache, it may make sense to have + // this method be native. + return (Class) loadedClasses.get(name); + } + + /** + * Get the URL to a resource using this classloader or one of its parents. + * First tries to get the resource by calling getResource() + * on the parent classloader. If the parent classloader returns null then + * it tries finding the resource by calling findResource() on + * this classloader. The resource name should be separated by '/' for path + * elements. + * + *

    Subclasses should not override this method but should override + * findResource() which is called by this method. + * + * @param name the name of the resource relative to this classloader + * @return the URL to the resource or null when not found + */ + public URL getResource(String name) + { + URL result; + + if (parent == null) + result = VMClassLoader.getResource(name); + else + result = parent.getResource(name); + + if (result == null) + result = findResource(name); + return result; + } + + /** + * Returns an Enumeration of all resources with a given name that can + * be found by this classloader and its parents. Certain classloaders + * (such as the URLClassLoader when given multiple jar files) can have + * multiple resources with the same name that come from multiple locations. + * It can also occur that a parent classloader offers a resource with a + * certain name and the child classloader also offers a resource with that + * same name. getResource() only offers the first resource (of the + * parent) with a given name. This method lists all resources with the + * same name. The name should use '/' as path separators. + * + *

    The Enumeration is created by first calling getResources() + * on the parent classloader and then calling findResources() + * on this classloader.

    + * + * @param name the resource name + * @return an enumaration of all resources found + * @throws IOException if I/O errors occur in the process + * @since 1.2 + */ + public final Enumeration getResources(String name) throws IOException + { + Enumeration parentResources; + if (parent == null) + parentResources = VMClassLoader.getResources(name); + else + parentResources = parent.getResources(name); + return new DoubleEnumeration(parentResources, findResources(name)); + } + + /** + * Called whenever all locations of a named resource are needed. + * It is called by getResources() after it has called + * parent.getResources(). The results are combined by + * the getResources() method. + * + *

    The default implementation always returns an empty Enumeration. + * Subclasses should override it when they can provide an Enumeration of + * URLs (possibly just one element) to the named resource. + * The first URL of the Enumeration should be the same as the one + * returned by findResource. + * + * @param name the name of the resource to be found + * @return a possibly empty Enumeration of URLs to the named resource + * @throws IOException if I/O errors occur in the process + * @since 1.2 + */ + protected Enumeration findResources(String name) throws IOException + { + return EmptyEnumeration.getInstance(); + } + + /** + * Called whenever a resource is needed that could not be provided by + * one of the parents of this classloader. It is called by + * getResource() after parent.getResource() + * couldn't provide the requested resource. + * + *

    The default implementation always returns null. Subclasses should + * override this method when they can provide a way to return a URL + * to a named resource. + * + * @param name the name of the resource to be found + * @return a URL to the named resource or null when not found + * @since 1.2 + */ + protected URL findResource(String name) + { + return null; + } + + /** + * Get the URL to a resource using the system classloader. + * + * @param name the name of the resource relative to the system classloader + * @return the URL to the resource + * @since 1.1 + */ + public static final URL getSystemResource(String name) + { + return StaticData.systemClassLoader.getResource(name); + } + + /** + * Get an Enumeration of URLs to resources with a given name using the + * the system classloader. The enumeration firsts lists the resources with + * the given name that can be found by the bootstrap classloader followed + * by the resources with the given name that can be found on the classpath. + * + * @param name the name of the resource relative to the system classloader + * @return an Enumeration of URLs to the resources + * @throws IOException if I/O errors occur in the process + * @since 1.2 + */ + public static Enumeration getSystemResources(String name) throws IOException + { + return StaticData.systemClassLoader.getResources(name); + } + + /** + * Get a resource as stream using this classloader or one of its parents. + * First calls getResource() and if that returns a URL to + * the resource then it calls and returns the InputStream given by + * URL.openStream(). + * + *

    Subclasses should not override this method but should override + * findResource() which is called by this method. + * + * @param name the name of the resource relative to this classloader + * @return an InputStream to the resource, or null + * @since 1.1 + */ + public InputStream getResourceAsStream(String name) + { + try + { + URL url = getResource(name); + if (url == null) + return null; + return url.openStream(); + } + catch (IOException e) + { + return null; + } + } + + /** + * Get a resource using the system classloader. + * + * @param name the name of the resource relative to the system classloader + * @return an input stream for the resource, or null + * @since 1.1 + */ + public static final InputStream getSystemResourceAsStream(String name) + { + try + { + URL url = getSystemResource(name); + if (url == null) + return null; + return url.openStream(); + } + catch (IOException e) + { + return null; + } + } + + /** + * Returns the system classloader. The system classloader (also called + * the application classloader) is the classloader that is used to + * load the application classes on the classpath (given by the system + * property java.class.path. This is set as the context + * class loader for a thread. The system property + * java.system.class.loader, if defined, is taken to be the + * name of the class to use as the system class loader, which must have + * a public constructor which takes a ClassLoader as a parent. The parent + * class loader passed in the constructor is the default system class + * loader. + * + *

    Note that this is different from the bootstrap classloader that + * actually loads all the real "system" classes. + * + *

    A security check will be performed for + * RuntimePermission("getClassLoader") if the calling class + * is not a parent of the system class loader. + * + * @return the system class loader + * @throws SecurityException if the security check fails + * @throws IllegalStateException if this is called recursively + * @throws Error if java.system.class.loader fails to load + * @since 1.2 + */ + public static ClassLoader getSystemClassLoader() + { + // Check if we may return the system classloader + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && cl != StaticData.systemClassLoader) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + + return StaticData.systemClassLoader; + } + + /** + * Defines a new package and creates a Package object. The package should + * be defined before any class in the package is defined with + * defineClass(). The package should not yet be defined + * before in this classloader or in one of its parents (which means that + * getPackage() should return null). All + * parameters except the name of the package may be + * null. + * + *

    Subclasses should call this method from their findClass() + * implementation before calling defineClass() on a Class + * in a not yet defined Package (which can be checked by calling + * getPackage()). + * + * @param name the name of the Package + * @param specTitle the name of the specification + * @param specVendor the name of the specification designer + * @param specVersion the version of this specification + * @param implTitle the name of the implementation + * @param implVendor the vendor that wrote this implementation + * @param implVersion the version of this implementation + * @param sealed if sealed the origin of the package classes + * @return the Package object for the specified package + * @throws IllegalArgumentException if the package name is null or it + * was already defined by this classloader or one of its parents + * @see Package + * @since 1.2 + */ + protected Package definePackage(String name, String specTitle, + String specVendor, String specVersion, + String implTitle, String implVendor, + String implVersion, URL sealed) + { + if (getPackage(name) != null) + throw new IllegalArgumentException("Package " + name + + " already defined"); + Package p = new Package(name, specTitle, specVendor, specVersion, + implTitle, implVendor, implVersion, sealed); + synchronized (definedPackages) + { + definedPackages.put(name, p); + } + return p; + } + + /** + * Returns the Package object for the requested package name. It returns + * null when the package is not defined by this classloader or one of its + * parents. + * + * @param name the package name to find + * @return the package, if defined + * @since 1.2 + */ + protected Package getPackage(String name) + { + Package p; + if (parent == null) + p = VMClassLoader.getPackage(name); + else + p = parent.getPackage(name); + + if (p == null) + { + synchronized (definedPackages) + { + p = (Package) definedPackages.get(name); + } + } + return p; + } + + /** + * Returns all Package objects defined by this classloader and its parents. + * + * @return an array of all defined packages + * @since 1.2 + */ + protected Package[] getPackages() + { + // Get all our packages. + Package[] packages; + synchronized(definedPackages) + { + packages = new Package[definedPackages.size()]; + definedPackages.values().toArray(packages); + } + + // If we have a parent get all packages defined by our parents. + Package[] parentPackages; + if (parent == null) + parentPackages = VMClassLoader.getPackages(); + else + parentPackages = parent.getPackages(); + + Package[] allPackages = new Package[parentPackages.length + + packages.length]; + System.arraycopy(parentPackages, 0, allPackages, 0, + parentPackages.length); + System.arraycopy(packages, 0, allPackages, parentPackages.length, + packages.length); + return allPackages; + } + + /** + * Called by Runtime.loadLibrary() to get an absolute path + * to a (system specific) library that was requested by a class loaded + * by this classloader. The default implementation returns + * null. It should be implemented by subclasses when they + * have a way to find the absolute path to a library. If this method + * returns null the library is searched for in the default locations + * (the directories listed in the java.library.path system + * property). + * + * @param name the (system specific) name of the requested library + * @return the full pathname to the requested library, or null + * @see Runtime#loadLibrary() + * @since 1.2 + */ + protected String findLibrary(String name) + { + return null; + } + + /** + * Set the default assertion status for classes loaded by this classloader, + * used unless overridden by a package or class request. + * + * @param enabled true to set the default to enabled + * @see #setClassAssertionStatus(String, boolean) + * @see #setPackageAssertionStatus(String, boolean) + * @see #clearAssertionStatus() + * @since 1.4 + */ + public void setDefaultAssertionStatus(boolean enabled) + { + defaultAssertionStatus = enabled; + } + + /** + * Set the default assertion status for packages, used unless overridden + * by a class request. This default also covers subpackages, unless they + * are also specified. The unnamed package should use null for the name. + * + * @param name the package (and subpackages) to affect + * @param enabled true to set the default to enabled + * @see #setDefaultAssertionStatus(String, boolean) + * @see #setClassAssertionStatus(String, boolean) + * @see #clearAssertionStatus() + * @since 1.4 + */ + public synchronized void setPackageAssertionStatus(String name, + boolean enabled) + { + if (packageAssertionStatus == null) + packageAssertionStatus + = new HashMap(StaticData.systemPackageAssertionStatus); + packageAssertionStatus.put(name, Boolean.valueOf(enabled)); + } + + /** + * Set the default assertion status for a class. This only affects the + * status of top-level classes, any other string is harmless. + * + * @param name the class to affect + * @param enabled true to set the default to enabled + * @throws NullPointerException if name is null + * @see #setDefaultAssertionStatus(String, boolean) + * @see #setPackageAssertionStatus(String, boolean) + * @see #clearAssertionStatus() + * @since 1.4 + */ + public synchronized void setClassAssertionStatus(String name, + boolean enabled) + { + if (classAssertionStatus == null) + classAssertionStatus = + new HashMap(StaticData.systemClassAssertionStatus); + // The toString() hack catches null, as required. + classAssertionStatus.put(name.toString(), Boolean.valueOf(enabled)); + } + + /** + * Resets the default assertion status of this classloader, its packages + * and classes, all to false. This allows overriding defaults inherited + * from the command line. + * + * @see #setDefaultAssertionStatus(boolean) + * @see #setClassAssertionStatus(String, boolean) + * @see #setPackageAssertionStatus(String, boolean) + * @since 1.4 + */ + public synchronized void clearAssertionStatus() + { + defaultAssertionStatus = false; + packageAssertionStatus = new HashMap(); + classAssertionStatus = new HashMap(); + } + + /** + * Return true if this loader is either the specified class loader + * or an ancestor thereof. + * @param loader the class loader to check + */ + final boolean isAncestorOf(ClassLoader loader) + { + while (loader != null) + { + if (this == loader) + return true; + loader = loader.parent; + } + return false; + } + + private static URL[] getExtClassLoaderUrls() + { + String classpath = SystemProperties.getProperty("java.ext.dirs", ""); + StringTokenizer tok = new StringTokenizer(classpath, File.pathSeparator); + ArrayList list = new ArrayList(); + while (tok.hasMoreTokens()) + { + try + { + File f = new File(tok.nextToken()); + File[] files = f.listFiles(); + if (files != null) + for (int i = 0; i < files.length; i++) + list.add(files[i].toURL()); + } + catch(Exception x) + { + } + } + URL[] urls = new URL[list.size()]; + list.toArray(urls); + return urls; + } + + private static void addFileURL(ArrayList list, String file) + { + try + { + list.add(new File(file).toURL()); + } + catch(java.net.MalformedURLException x) + { + } + } + + private static URL[] getSystemClassLoaderUrls() + { + String classpath = SystemProperties.getProperty("java.class.path", "."); + StringTokenizer tok = new StringTokenizer(classpath, File.pathSeparator, true); + ArrayList list = new ArrayList(); + while (tok.hasMoreTokens()) + { + String s = tok.nextToken(); + if (s.equals(File.pathSeparator)) + addFileURL(list, "."); + else + { + addFileURL(list, s); + if (tok.hasMoreTokens()) + { + // Skip the separator. + tok.nextToken(); + // If the classpath ended with a separator, + // append the current directory. + if (!tok.hasMoreTokens()) + addFileURL(list, "."); + } + } + } + URL[] urls = new URL[list.size()]; + list.toArray(urls); + return urls; + } + + static ClassLoader defaultGetSystemClassLoader() + { + return createAuxiliarySystemClassLoader( + createSystemClassLoader(getSystemClassLoaderUrls(), + createExtClassLoader(getExtClassLoaderUrls(), null))); + } + + static ClassLoader createExtClassLoader(URL[] urls, ClassLoader parent) + { + if (urls.length > 0) + return new URLClassLoader(urls, parent); + else + return parent; + } + + static ClassLoader createSystemClassLoader(URL[] urls, ClassLoader parent) + { + return + new URLClassLoader(urls, parent) + { + protected synchronized Class loadClass(String name, + boolean resolve) + throws ClassNotFoundException + { + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + int lastDot = name.lastIndexOf('.'); + if (lastDot != -1) + sm.checkPackageAccess(name.substring(0, lastDot)); + } + return super.loadClass(name, resolve); + } + }; + } + + static ClassLoader createAuxiliarySystemClassLoader(ClassLoader parent) + { + String loader = SystemProperties.getProperty("java.system.class.loader", null); + if (loader == null) + { + return parent; + } + try + { + Constructor c = Class.forName(loader, false, parent) + .getConstructor(new Class[] { ClassLoader.class }); + return (ClassLoader)c.newInstance(new Object[] { parent }); + } + catch (Exception e) + { + System.err.println("Requested system classloader " + loader + " failed."); + throw (Error) + new Error("Requested system classloader " + loader + " failed.") + .initCause(e); + } + } +} diff --git a/libjava/classpath/java/lang/ClassNotFoundException.java b/libjava/classpath/java/lang/ClassNotFoundException.java new file mode 100644 index 0000000..6b6ae94 --- /dev/null +++ b/libjava/classpath/java/lang/ClassNotFoundException.java @@ -0,0 +1,125 @@ +/* ClassNotFoundException.java -- thrown when class definition cannot be found + Copyright (C) 1998, 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 java.lang; + +/** + * Thrown when a class is requested by reflection, but the class definition + * cannot be found. This exception is often chained from another Throwable. + * + * @author Brian Jones + * @author Eric Blake (ebb9@email.byu.edu) + * @see Class#forName(String) + * @see ClassLoader#findSystemClass(String) + * @see ClassLoader#loadClass(String, boolean) + * @status updated to 1.4 + */ +public class ClassNotFoundException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 9176873029745254542L; + + /** + * The cause of this exception (duplicates the one stored in Throwable). + * + * @serial the exception cause + * @since 1.2 + */ + private final Throwable ex; + + /** + * Create an exception without a message. Note that this initializes the + * cause to null. + */ + public ClassNotFoundException() + { + this(null, null); + } + + /** + * Create an exception with a message. Note that this initializes the + * cause to null. + * + * @param s the message + */ + public ClassNotFoundException(String s) + { + this(s, null); + } + + /** + * Create an exception with a message and chain it to the exception + * which occurred while loading the class. + * + * @param s the message + * @param ex the chained exception + * @since 1.2 + */ + public ClassNotFoundException(String s, Throwable ex) + { + super(s, ex); + this.ex = ex; + } + + /** + * Returns the exception which occurred while loading the class, + * otherwise returns null. This is a legacy method; the preferred choice + * now is {@link Throwable#getCause()}. + * + * @return the cause of this exception + * @since 1.2 + */ + public Throwable getException() + { + return ex; + } + + /** + * Returns the exception which occurred while loading the class, + * otherwise returns null. + * + * @return the cause of this exception + * @since 1.4 + */ + public Throwable getCause() + { + return ex; + } +} diff --git a/libjava/classpath/java/lang/CloneNotSupportedException.java b/libjava/classpath/java/lang/CloneNotSupportedException.java new file mode 100644 index 0000000..9d10cf3 --- /dev/null +++ b/libjava/classpath/java/lang/CloneNotSupportedException.java @@ -0,0 +1,92 @@ +/* CloneNotSupportedException.java -- thrown when an object cannot be cloned + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown to indicate an object should not or could not be cloned. This + * includes the case when {@link Object#clone()} is called on an object + * which does not implement the {@link Cloneable} interface. For example:
    + *

    + * void m() throws CloneNotSupportedException
    + * {
    + *   clone();
    + * }
    + * 
    + * + *

    Notice that calling clone() on an array will never produce + * this exception, as the VM will always succeed in copying the array, or + * cause an OutOfMemoryError first. For example:
    + *

    + * void m(int[] array)
    + * {
    + *   int[] copy = (int[]) array.clone();
    + * }
    + * 
    + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Cloneable + * @see Object#clone() + * @status updated to 1.4 + */ +public class CloneNotSupportedException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 5195511250079656443L; + + /** + * Create an exception without a message. + */ + public CloneNotSupportedException() + { + } + + /** + * Create an exception with a message. + * + * @param s the error message + */ + public CloneNotSupportedException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/Cloneable.java b/libjava/classpath/java/lang/Cloneable.java new file mode 100644 index 0000000..10f20ce --- /dev/null +++ b/libjava/classpath/java/lang/Cloneable.java @@ -0,0 +1,78 @@ +/* Cloneable.java -- Interface for marking objects cloneable by Object.clone() + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * This interface should be implemented by classes wishing to + * support of override Object.clone(). The default + * behaviour of clone() performs a shallow copy, but + * subclasses often change this to perform a deep copy. Therefore, + * it is a good idea to document how deep your clone will go. + * If clone() is called on an object which does not + * implement this interface, a CloneNotSupportedException + * will be thrown. + * + *

    This interface is simply a tagging interface; it carries no + * requirements on methods to implement. However, it is typical for + * a Cloneable class to implement at least equals, + * hashCode, and clone, sometimes + * increasing the accessibility of clone to be public. The typical + * implementation of clone invokes super.clone() + * rather than a constructor, but this is not a requirement. + * + *

    If an object that implement Cloneable should not be cloned, + * simply override the clone method to throw a + * CloneNotSupportedException. + * + *

    All array types implement Cloneable, and have a public + * clone method that will never fail with a + * CloneNotSupportedException. + * + * @author Paul Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @author Warren Levy (warrenl@cygnus.com) + * @see Object#clone() + * @see CloneNotSupportedException + * @since 1.0 + * @status updated to 1.4 + */ +public interface Cloneable +{ + // Tagging interface only. +} diff --git a/libjava/classpath/java/lang/Comparable.java b/libjava/classpath/java/lang/Comparable.java new file mode 100644 index 0000000..a8afe1e --- /dev/null +++ b/libjava/classpath/java/lang/Comparable.java @@ -0,0 +1,98 @@ +/* Comparable.java -- Interface for comparaing objects to obtain an ordering + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Interface for objects that can be ordering among other objects. The + * ordering can be total, such that two objects only compare equal + * if they are also equal by the equals method, or partial such + * that this is not necessarily true. For example, a case-sensitive + * dictionary order comparison of Strings is total, but if it is + * case-insensitive it is partial, because "abc" and "ABC" compare as + * equal even though "abc".equals("ABC") returns false. However, if you use + * a partial ordering, it is a good idea to document your class as + * "inconsistent with equals", because the behavior of your class in a + * SortedMap will be different than in a HashMap. + * + *

    Lists, arrays, and sets of objects that implement this interface can + * be sorted automatically, without the need for an explicit + * {@link java.util.Comparator}. Note that e1.compareTo(null) + * should throw an Exception; as should comparison between incompatible + * classes. + * + * @author Geoff Berry + * @author Warren Levy (warrenl@cygnus.com) + * @see java.util.Comparator + * @see java.util.Collections#sort(java.util.List) + * @see java.util.Arrays#sort(Object[]) + * @see java.util.SortedSet + * @see java.util.SortedMap + * @see java.util.TreeSet + * @see java.util.TreeMap + * @since 1.2 + * @status updated to 1.4 + */ +public interface Comparable +{ + /** + * Compares this object with another, and returns a numerical result based + * on the comparison. If the result is negative, this object sorts less + * than the other; if 0, the two are equal, and if positive, this object + * sorts greater than the other. To translate this into boolean, simply + * perform o1.compareTo(o2) <op> 0, where op + * is one of <, <=, =, !=, >, or >=. + * + *

    You must make sure that the comparison is mutual, ie. + * sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) (where sgn() is + * defined as -1, 0, or 1 based on the sign). This includes throwing an + * exception in either direction if the two are not comparable; hence, + * compareTo(null) should always throw an Exception. + * + *

    You should also ensure transitivity, in two forms: + * x.compareTo(y) > 0 && y.compareTo(z) > 0 implies + * x.compareTo(z) > 0; and x.compareTo(y) == 0 + * implies x.compareTo(z) == y.compareTo(z). + * + * @param o the object to be compared + * @return an integer describing the comparison + * @throws NullPointerException if o is null + * @throws ClassCastException if o cannot be compared + */ + int compareTo(Object o); +} diff --git a/libjava/classpath/java/lang/Compiler.java b/libjava/classpath/java/lang/Compiler.java new file mode 100644 index 0000000..56fb951 --- /dev/null +++ b/libjava/classpath/java/lang/Compiler.java @@ -0,0 +1,127 @@ +/* Compiler.java -- placeholder for Java-to-native runtime compilers + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * The Compiler class is a placeholder for a JIT compiler + * implementation, and does nothing unless there is such a compiler. + * + *

    The system property java.compiler may contain the name + * of a library to load with System.loadLibrary when the + * virtual machine first starts. If so, and loading the library succeeds, + * then a function by the name of java_lang_Compiler_start() + * in that library is called. + * + *

    Note that a VM might not have implemented any of this. + * + * @author Tom Tromey (tromey@cygnus.com) + * @see System#getProperty(String) + * @see System#getProperty(String, String) + * @see System#loadLibrary(String) + * @since JDK 1.0 + * @status updated to 1.4 + */ +public final class Compiler +{ + /** + * Don't allow new `Compiler's to be made. + */ + private Compiler() + { + } + + /** + * Compile the class named by oneClass. + * + * @param oneClass the class to compile + * @return false if no compiler is available or + * compilation failed, true if compilation succeeded + * @throws NullPointerException if oneClass is null + */ + public static boolean compileClass(Class oneClass) + { + return VMCompiler.compileClass(oneClass); + } + + /** + * Compile the classes whose name matches classNames. + * + * @param classNames the name of classes to compile + * @return false if no compiler is available or + * compilation failed, true if compilation succeeded + * @throws NullPointerException if classNames is null + */ + public static boolean compileClasses(String classNames) + { + return VMCompiler.compileClasses(classNames); + } + + /** + * This method examines the argument and performs an operation + * according to the compilers documentation. No specific operation + * is required. + * + * @param arg a compiler-specific argument + * @return a compiler-specific value, including null + * @throws NullPointerException if the compiler doesn't like a null arg + */ + public static Object command(Object arg) + { + return VMCompiler.command(arg); + } + + /** + * Calling Compiler.enable() will cause the compiler + * to resume operation if it was previously disabled; provided that a + * compiler even exists. + */ + public static void enable() + { + VMCompiler.enable(); + } + + /** + * Calling Compiler.disable() will cause the compiler + * to be suspended; provided that a compiler even exists. + */ + public static void disable() + { + VMCompiler.disable(); + } +} diff --git a/libjava/classpath/java/lang/Double.java b/libjava/classpath/java/lang/Double.java new file mode 100644 index 0000000..4fa47f4 --- /dev/null +++ b/libjava/classpath/java/lang/Double.java @@ -0,0 +1,521 @@ +/* Double.java -- object wrapper for double + Copyright (C) 1998, 1999, 2000, 2001, 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 java.lang; + +import gnu.classpath.Configuration; + +/** + * Instances of class Double represent primitive + * double values. + * + * Additionally, this class provides various helper functions and variables + * related to doubles. + * + * @author Paul Fisher + * @author Andrew Haley (aph@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public final class Double extends Number implements Comparable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -9172774392245257468L; + + /** + * The maximum positive value a double may represent + * is 1.7976931348623157e+308. + */ + public static final double MAX_VALUE = 1.7976931348623157e+308; + + /** + * The minimum positive value a double may represent + * is 5e-324. + */ + public static final double MIN_VALUE = 5e-324; + + /** + * The value of a double representation -1.0/0.0, negative + * infinity. + */ + public static final double NEGATIVE_INFINITY = -1.0 / 0.0; + + /** + * The value of a double representing 1.0/0.0, positive infinity. + */ + public static final double POSITIVE_INFINITY = 1.0 / 0.0; + + /** + * All IEEE 754 values of NaN have the same value in Java. + */ + public static final double NaN = 0.0 / 0.0; + + /** + * The primitive type double is represented by this + * Class object. + * @since 1.1 + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass('D'); + + /** + * The immutable value of this Double. + * + * @serial the wrapped double + */ + private final double value; + + /** + * Create a Double from the primitive double + * specified. + * + * @param value the double argument + */ + public Double(double value) + { + this.value = value; + } + + /** + * Create a Double from the specified String. + * This method calls Double.parseDouble(). + * + * @param s the String to convert + * @throws NumberFormatException if s cannot be parsed as a + * double + * @throws NullPointerException if s is null + * @see #parseDouble(String) + */ + public Double(String s) + { + value = parseDouble(s); + } + + /** + * Convert the double to a String. + * Floating-point string representation is fairly complex: here is a + * rundown of the possible values. "[-]" indicates that a + * negative sign will be printed if the value (or exponent) is negative. + * "<number>" means a string of digits ('0' to '9'). + * "<digit>" means a single digit ('0' to '9').
    + * + * + * + * + * + * + * + * + * + * + *
    Value of DoubleString Representation
    [+-] 0 [-]0.0
    Between [+-] 10-3 and 107, exclusive[-]number.number
    Other numeric value[-]<digit>.<number> + * E[-]<number>
    [+-] infinity [-]Infinity
    NaN NaN
    + * + * Yes, negative zero is a possible value. Note that there is + * always a . and at least one digit printed after + * it: even if the number is 3, it will be printed as 3.0. + * After the ".", all digits will be printed except trailing zeros. The + * result is rounded to the shortest decimal number which will parse back + * to the same double. + * + *

    To create other output formats, use {@link java.text.NumberFormat}. + * + * @XXX specify where we are not in accord with the spec. + * + * @param d the double to convert + * @return the String representing the double + */ + public static String toString(double d) + { + return VMDouble.toString(d, false); + } + + /** + * Create a new Double object using the String. + * + * @param s the String to convert + * @return the new Double + * @throws NumberFormatException if s cannot be parsed as a + * double + * @throws NullPointerException if s is null. + * @see #parseDouble(String) + */ + public static Double valueOf(String s) + { + return new Double(parseDouble(s)); + } + + /** + * Parse the specified String as a double. The + * extended BNF grammar is as follows:
    + *

    +   * DecodableString:
    +   *      ( [ - | + ] NaN )
    +   *    | ( [ - | + ] Infinity )
    +   *    | ( [ - | + ] FloatingPoint
    +   *              [ f | F | d
    +   *                | D] )
    +   * FloatingPoint:
    +   *      ( { Digit }+ [ . { Digit } ]
    +   *              [ Exponent ] )
    +   *    | ( . { Digit }+ [ Exponent ] )
    +   * Exponent:
    +   *      ( ( e | E )
    +   *              [ - | + ] { Digit }+ )
    +   * Digit: '0' through '9'
    +   * 
    + * + *

    NaN and infinity are special cases, to allow parsing of the output + * of toString. Otherwise, the result is determined by calculating + * n * 10exponent to infinite precision, then rounding + * to the nearest double. Remember that many numbers cannot be precisely + * represented in floating point. In case of overflow, infinity is used, + * and in case of underflow, signed zero is used. Unlike Integer.parseInt, + * this does not accept Unicode digits outside the ASCII range. + * + *

    If an unexpected character is found in the String, a + * NumberFormatException will be thrown. Leading and trailing + * 'whitespace' is ignored via String.trim(), but spaces + * internal to the actual number are not allowed. + * + *

    To parse numbers according to another format, consider using + * {@link java.text.NumberFormat}. + * + * @XXX specify where/how we are not in accord with the spec. + * + * @param str the String to convert + * @return the double value of s + * @throws NumberFormatException if s cannot be parsed as a + * double + * @throws NullPointerException if s is null + * @see #MIN_VALUE + * @see #MAX_VALUE + * @see #POSITIVE_INFINITY + * @see #NEGATIVE_INFINITY + * @since 1.2 + */ + public static double parseDouble(String str) + { + return VMDouble.parseDouble(str); + } + + /** + * Return true if the double has the same + * value as NaN, otherwise return false. + * + * @param v the double to compare + * @return whether the argument is NaN. + */ + public static boolean isNaN(double v) + { + // This works since NaN != NaN is the only reflexive inequality + // comparison which returns true. + return v != v; + } + + /** + * Return true if the double has a value + * equal to either NEGATIVE_INFINITY or + * POSITIVE_INFINITY, otherwise return false. + * + * @param v the double to compare + * @return whether the argument is (-/+) infinity. + */ + public static boolean isInfinite(double v) + { + return v == POSITIVE_INFINITY || v == NEGATIVE_INFINITY; + } + + /** + * Return true if the value of this Double + * is the same as NaN, otherwise return false. + * + * @return whether this Double is NaN + */ + public boolean isNaN() + { + return isNaN(value); + } + + /** + * Return true if the value of this Double + * is the same as NEGATIVE_INFINITY or + * POSITIVE_INFINITY, otherwise return false. + * + * @return whether this Double is (-/+) infinity + */ + public boolean isInfinite() + { + return isInfinite(value); + } + + /** + * Convert the double value of this Double + * to a String. This method calls + * Double.toString(double) to do its dirty work. + * + * @return the String representation + * @see #toString(double) + */ + public String toString() + { + return toString(value); + } + + /** + * Return the value of this Double as a byte. + * + * @return the byte value + * @since 1.1 + */ + public byte byteValue() + { + return (byte) value; + } + + /** + * Return the value of this Double as a short. + * + * @return the short value + * @since 1.1 + */ + public short shortValue() + { + return (short) value; + } + + /** + * Return the value of this Double as an int. + * + * @return the int value + */ + public int intValue() + { + return (int) value; + } + + /** + * Return the value of this Double as a long. + * + * @return the long value + */ + public long longValue() + { + return (long) value; + } + + /** + * Return the value of this Double as a float. + * + * @return the float value + */ + public float floatValue() + { + return (float) value; + } + + /** + * Return the value of this Double. + * + * @return the double value + */ + public double doubleValue() + { + return value; + } + + /** + * Return a hashcode representing this Object. Double's hash + * code is calculated by:
    + * long v = Double.doubleToLongBits(doubleValue());
    + * int hash = (int)(v^(v>>32))
    . + * + * @return this Object's hash code + * @see #doubleToLongBits(double) + */ + public int hashCode() + { + long v = doubleToLongBits(value); + return (int) (v ^ (v >>> 32)); + } + + /** + * Returns true if obj is an instance of + * Double and represents the same double value. Unlike comparing + * two doubles with ==, this treats two instances of + * Double.NaN as equal, but treats 0.0 and + * -0.0 as unequal. + * + *

    Note that d1.equals(d2) is identical to + * doubleToLongBits(d1.doubleValue()) == + * doubleToLongBits(d2.doubleValue()). + * + * @param obj the object to compare + * @return whether the objects are semantically equal + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Double)) + return false; + + double d = ((Double) obj).value; + + // Avoid call to native method. However, some implementations, like gcj, + // are better off using floatToIntBits(value) == floatToIntBits(f). + // Check common case first, then check NaN and 0. + if (value == d) + return (value != 0) || (1 / value == 1 / d); + return isNaN(value) && isNaN(d); + } + + /** + * Convert the double to the IEEE 754 floating-point "double format" bit + * layout. Bit 63 (the most significant) is the sign bit, bits 62-52 + * (masked by 0x7ff0000000000000L) represent the exponent, and bits 51-0 + * (masked by 0x000fffffffffffffL) are the mantissa. This function + * collapses all versions of NaN to 0x7ff8000000000000L. The result of this + * function can be used as the argument to + * Double.longBitsToDouble(long) to obtain the original + * double value. + * + * @param value the double to convert + * @return the bits of the double + * @see #longBitsToDouble(long) + */ + public static long doubleToLongBits(double value) + { + return VMDouble.doubleToLongBits(value); + } + + /** + * Convert the double to the IEEE 754 floating-point "double format" bit + * layout. Bit 63 (the most significant) is the sign bit, bits 62-52 + * (masked by 0x7ff0000000000000L) represent the exponent, and bits 51-0 + * (masked by 0x000fffffffffffffL) are the mantissa. This function + * leaves NaN alone, rather than collapsing to a canonical value. The + * result of this function can be used as the argument to + * Double.longBitsToDouble(long) to obtain the original + * double value. + * + * @param value the double to convert + * @return the bits of the double + * @see #longBitsToDouble(long) + */ + public static long doubleToRawLongBits(double value) + { + return VMDouble.doubleToRawLongBits(value); + } + + /** + * Convert the argument in IEEE 754 floating-point "double format" bit + * layout to the corresponding float. Bit 63 (the most significant) is the + * sign bit, bits 62-52 (masked by 0x7ff0000000000000L) represent the + * exponent, and bits 51-0 (masked by 0x000fffffffffffffL) are the mantissa. + * This function leaves NaN alone, so that you can recover the bit pattern + * with Double.doubleToRawLongBits(double). + * + * @param bits the bits to convert + * @return the double represented by the bits + * @see #doubleToLongBits(double) + * @see #doubleToRawLongBits(double) + */ + public static double longBitsToDouble(long bits) + { + return VMDouble.longBitsToDouble(bits); + } + + /** + * Compare two Doubles numerically by comparing their double + * values. The result is positive if the first is greater, negative if the + * second is greater, and 0 if the two are equal. However, this special + * cases NaN and signed zero as follows: NaN is considered greater than + * all other doubles, including POSITIVE_INFINITY, and positive + * zero is considered greater than negative zero. + * + * @param d the Double to compare + * @return the comparison + * @since 1.2 + */ + public int compareTo(Double d) + { + return compare(value, d.value); + } + + /** + * Behaves like compareTo(Double) unless the Object + * is not an Double. + * + * @param o the object to compare + * @return the comparison + * @throws ClassCastException if the argument is not a Double + * @see #compareTo(Double) + * @see Comparable + * @since 1.2 + */ + public int compareTo(Object o) + { + return compare(value, ((Double) o).value); + } + + /** + * Behaves like new Double(x).compareTo(new Double(y)); in + * other words this compares two doubles, special casing NaN and zero, + * without the overhead of objects. + * + * @param x the first double to compare + * @param y the second double to compare + * @return the comparison + * @since 1.4 + */ + public static int compare(double x, double y) + { + if (isNaN(x)) + return isNaN(y) ? 0 : 1; + if (isNaN(y)) + return -1; + // recall that 0.0 == -0.0, so we convert to infinites and try again + if (x == 0 && y == 0) + return (int) (1 / x - 1 / y); + if (x == y) + return 0; + + return x > y ? 1 : -1; + } +} diff --git a/libjava/classpath/java/lang/Error.java b/libjava/classpath/java/lang/Error.java new file mode 100644 index 0000000..f66c754 --- /dev/null +++ b/libjava/classpath/java/lang/Error.java @@ -0,0 +1,107 @@ +/* Error.java -- Indication of fatal abnormal conditions + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Applications should not try to catch errors since they indicate + * abnormal conditions. An abnormal condition is something which should not + * occur, or which should not be recovered from. This latter category + * includes ThreadDeath and AssertionError. + * + *

    A method is not required to declare any subclass of Error in + * its throws clause which might be thrown but not caught while + * executing the method. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Error extends Throwable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 4980196508277280342L; + + /** + * Create an error without a message. The cause remains uninitialized. + * + * @see #initCause(Throwable) + */ + public Error() + { + } + + /** + * Create an error with a message. The cause remains uninitialized. + * + * @param s the message string + * @see #initCause(Throwable) + */ + public Error(String s) + { + super(s); + } + + /** + * Create an error with a message and a cause. + * + * @param s the message string + * @param cause the cause of this error + * @since 1.4 + */ + public Error(String s, Throwable cause) + { + super(s, cause); + } + + /** + * Create an error with a given cause, and a message of + * cause == null ? null : cause.toString(). + * + * @param cause the cause of this error + * @since 1.4 + */ + public Error(Throwable cause) + { + super(cause); + } +} diff --git a/libjava/classpath/java/lang/Exception.java b/libjava/classpath/java/lang/Exception.java new file mode 100644 index 0000000..42f7c64 --- /dev/null +++ b/libjava/classpath/java/lang/Exception.java @@ -0,0 +1,104 @@ +/* Exception.java -- generic exception thrown to indicate an exceptional + condition has occurred. + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * The root class of all exceptions worth catching in a program. This + * includes the special category of RuntimeException, which + * does not need to be declared in a throws clause. Exceptions can be used + * to represent almost any exceptional behavior, such as programming errors, + * mouse movements, keyboard clicking, etc. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class Exception extends Throwable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -3387516993124229948L; + + /** + * Create an exception without a message. The cause remains uninitialized. + * + * @see #initCause(Throwable) + */ + public Exception() + { + } + + /** + * Create an exception with a message. The cause remains uninitialized. + * + * @param s the message + * @see #initCause(Throwable) + */ + public Exception(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message string + * @param cause the cause of this error + * @since 1.4 + */ + public Exception(String s, Throwable cause) + { + super(s, cause); + } + + /** + * Create an exception with a given cause, and a message of + * cause == null ? null : cause.toString(). + * + * @param cause the cause of this exception + * @since 1.4 + */ + public Exception(Throwable cause) + { + super(cause); + } +} diff --git a/libjava/classpath/java/lang/ExceptionInInitializerError.java b/libjava/classpath/java/lang/ExceptionInInitializerError.java new file mode 100644 index 0000000..1e58095 --- /dev/null +++ b/libjava/classpath/java/lang/ExceptionInInitializerError.java @@ -0,0 +1,123 @@ +/* ExceptionInInitializerError.java -- thrown when class initialization fails + with an uncaught exception + Copyright (C) 1998, 1999, 2000, 2001, 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 java.lang; + +/** + * An ExceptionInInitializerError is thrown when an uncaught + * exception has occurred in a static initializer or the initializer for a + * static variable. In general, this wraps only RuntimeExceptions, since the + * compiler does not allow a checked exception to be uncaught in an + * initializer. This exception only occurs during reflection, when a class + * is initialized as part of another action. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public class ExceptionInInitializerError extends LinkageError +{ + /** + * Compatible with JDK 1.1+. + */ + static final long serialVersionUID = 1521711792217232256L; + + /** + * The cause of this exception (duplicates the one stored in Throwable). + * + * @serial the exception cause + */ + private final Throwable exception; + + /** + * Create an error without a message. The cause is initialized as null. + */ + public ExceptionInInitializerError() + { + this((String) null); + } + + /** + * Create an error with a message. The cause is initialized as null. + * + * @param s the message + */ + public ExceptionInInitializerError(String s) + { + super(s); + exception = null; + } + + /** + * Creates an error an saves a reference to the Throwable + * object. The message string is null. + * + * @param t the exception thrown + */ + public ExceptionInInitializerError(Throwable t) + { + super(null); + initCause(t); + exception = t; + } + + /** + * Return the exception that caused this error to be created. This is a + * legacy method; the preferred choice now is {@link Throwable#getCause()}. + * + * @return the cause, or null if unknown + */ + public Throwable getException() + { + return exception; + } + + /** + * Return the exception that cause this error to be created. + * + * @return the cause, or null if unknown + * @since 1.4 + */ + public Throwable getCause() + { + return exception; + } +} diff --git a/libjava/classpath/java/lang/Float.java b/libjava/classpath/java/lang/Float.java new file mode 100644 index 0000000..e6200da --- /dev/null +++ b/libjava/classpath/java/lang/Float.java @@ -0,0 +1,527 @@ +/* Float.java -- object wrapper for float + Copyright (C) 1998, 1999, 2000, 2001, 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 java.lang; + +/** + * Instances of class Float represent primitive + * float values. + * + * Additionally, this class provides various helper functions and variables + * related to floats. + * + * @author Paul Fisher + * @author Andrew Haley (aph@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public final class Float extends Number implements Comparable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -2671257302660747028L; + + /** + * The maximum positive value a double may represent + * is 3.4028235e+38f. + */ + public static final float MAX_VALUE = 3.4028235e+38f; + + /** + * The minimum positive value a float may represent + * is 1.4e-45. + */ + public static final float MIN_VALUE = 1.4e-45f; + + /** + * The value of a float representation -1.0/0.0, negative infinity. + */ + public static final float NEGATIVE_INFINITY = -1.0f / 0.0f; + + /** + * The value of a float representation 1.0/0.0, positive infinity. + */ + public static final float POSITIVE_INFINITY = 1.0f / 0.0f; + + /** + * All IEEE 754 values of NaN have the same value in Java. + */ + public static final float NaN = 0.0f / 0.0f; + + /** + * The primitive type float is represented by this + * Class object. + * @since 1.1 + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass('F'); + + /** + * The immutable value of this Float. + * + * @serial the wrapped float + */ + private final float value; + + /** + * Create a Float from the primitive float + * specified. + * + * @param value the float argument + */ + public Float(float value) + { + this.value = value; + } + + /** + * Create a Float from the primitive double + * specified. + * + * @param value the double argument + */ + public Float(double value) + { + this.value = (float) value; + } + + /** + * Create a Float from the specified String. + * This method calls Float.parseFloat(). + * + * @param s the String to convert + * @throws NumberFormatException if s cannot be parsed as a + * float + * @throws NullPointerException if s is null + * @see #parseFloat(String) + */ + public Float(String s) + { + value = parseFloat(s); + } + + /** + * Convert the float to a String. + * Floating-point string representation is fairly complex: here is a + * rundown of the possible values. "[-]" indicates that a + * negative sign will be printed if the value (or exponent) is negative. + * "<number>" means a string of digits ('0' to '9'). + * "<digit>" means a single digit ('0' to '9').
    + * + * + * + * + * + * + * + * + * + * + *
    Value of FloatString Representation
    [+-] 0 [-]0.0
    Between [+-] 10-3 and 107, exclusive[-]number.number
    Other numeric value[-]<digit>.<number> + * E[-]<number>
    [+-] infinity [-]Infinity
    NaN NaN
    + * + * Yes, negative zero is a possible value. Note that there is + * always a . and at least one digit printed after + * it: even if the number is 3, it will be printed as 3.0. + * After the ".", all digits will be printed except trailing zeros. The + * result is rounded to the shortest decimal number which will parse back + * to the same float. + * + *

    To create other output formats, use {@link java.text.NumberFormat}. + * + * @XXX specify where we are not in accord with the spec. + * + * @param f the float to convert + * @return the String representing the float + */ + public static String toString(float f) + { + return VMDouble.toString(f, true); + } + + /** + * Creates a new Float object using the String. + * + * @param s the String to convert + * @return the new Float + * @throws NumberFormatException if s cannot be parsed as a + * float + * @throws NullPointerException if s is null + * @see #parseFloat(String) + */ + public static Float valueOf(String s) + { + return new Float(parseFloat(s)); + } + + /** + * Parse the specified String as a float. The + * extended BNF grammar is as follows:
    + *

    +   * DecodableString:
    +   *      ( [ - | + ] NaN )
    +   *    | ( [ - | + ] Infinity )
    +   *    | ( [ - | + ] FloatingPoint
    +   *              [ f | F | d
    +   *                | D] )
    +   * FloatingPoint:
    +   *      ( { Digit }+ [ . { Digit } ]
    +   *              [ Exponent ] )
    +   *    | ( . { Digit }+ [ Exponent ] )
    +   * Exponent:
    +   *      ( ( e | E )
    +   *              [ - | + ] { Digit }+ )
    +   * Digit: '0' through '9'
    +   * 
    + * + *

    NaN and infinity are special cases, to allow parsing of the output + * of toString. Otherwise, the result is determined by calculating + * n * 10exponent to infinite precision, then rounding + * to the nearest float. Remember that many numbers cannot be precisely + * represented in floating point. In case of overflow, infinity is used, + * and in case of underflow, signed zero is used. Unlike Integer.parseInt, + * this does not accept Unicode digits outside the ASCII range. + * + *

    If an unexpected character is found in the String, a + * NumberFormatException will be thrown. Leading and trailing + * 'whitespace' is ignored via String.trim(), but spaces + * internal to the actual number are not allowed. + * + *

    To parse numbers according to another format, consider using + * {@link java.text.NumberFormat}. + * + * @XXX specify where/how we are not in accord with the spec. + * + * @param str the String to convert + * @return the float value of s + * @throws NumberFormatException if s cannot be parsed as a + * float + * @throws NullPointerException if s is null + * @see #MIN_VALUE + * @see #MAX_VALUE + * @see #POSITIVE_INFINITY + * @see #NEGATIVE_INFINITY + * @since 1.2 + */ + public static float parseFloat(String str) + { + // XXX Rounding parseDouble() causes some errors greater than 1 ulp from + // the infinitely precise decimal. + return (float) Double.parseDouble(str); + } + + /** + * Return true if the float has the same + * value as NaN, otherwise return false. + * + * @param v the float to compare + * @return whether the argument is NaN + */ + public static boolean isNaN(float v) + { + // This works since NaN != NaN is the only reflexive inequality + // comparison which returns true. + return v != v; + } + + /** + * Return true if the float has a value + * equal to either NEGATIVE_INFINITY or + * POSITIVE_INFINITY, otherwise return false. + * + * @param v the float to compare + * @return whether the argument is (-/+) infinity + */ + public static boolean isInfinite(float v) + { + return v == POSITIVE_INFINITY || v == NEGATIVE_INFINITY; + } + + /** + * Return true if the value of this Float + * is the same as NaN, otherwise return false. + * + * @return whether this Float is NaN + */ + public boolean isNaN() + { + return isNaN(value); + } + + /** + * Return true if the value of this Float + * is the same as NEGATIVE_INFINITY or + * POSITIVE_INFINITY, otherwise return false. + * + * @return whether this Float is (-/+) infinity + */ + public boolean isInfinite() + { + return isInfinite(value); + } + + /** + * Convert the float value of this Float + * to a String. This method calls + * Float.toString(float) to do its dirty work. + * + * @return the String representation + * @see #toString(float) + */ + public String toString() + { + return toString(value); + } + + /** + * Return the value of this Float as a byte. + * + * @return the byte value + * @since 1.1 + */ + public byte byteValue() + { + return (byte) value; + } + + /** + * Return the value of this Float as a short. + * + * @return the short value + * @since 1.1 + */ + public short shortValue() + { + return (short) value; + } + + /** + * Return the value of this Integer as an int. + * + * @return the int value + */ + public int intValue() + { + return (int) value; + } + + /** + * Return the value of this Integer as a long. + * + * @return the long value + */ + public long longValue() + { + return (long) value; + } + + /** + * Return the value of this Float. + * + * @return the float value + */ + public float floatValue() + { + return value; + } + + /** + * Return the value of this Float as a double + * + * @return the double value + */ + public double doubleValue() + { + return value; + } + + /** + * Return a hashcode representing this Object. Float's hash + * code is calculated by calling floatToIntBits(floatValue()). + * + * @return this Object's hash code + * @see #floatToIntBits(float) + */ + public int hashCode() + { + return floatToIntBits(value); + } + + /** + * Returns true if obj is an instance of + * Float and represents the same float value. Unlike comparing + * two floats with ==, this treats two instances of + * Float.NaN as equal, but treats 0.0 and + * -0.0 as unequal. + * + *

    Note that f1.equals(f2) is identical to + * floatToIntBits(f1.floatValue()) == + * floatToIntBits(f2.floatValue()). + * + * @param obj the object to compare + * @return whether the objects are semantically equal + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Float)) + return false; + + float f = ((Float) obj).value; + + // Avoid call to native method. However, some implementations, like gcj, + // are better off using floatToIntBits(value) == floatToIntBits(f). + // Check common case first, then check NaN and 0. + if (value == f) + return (value != 0) || (1 / value == 1 / f); + return isNaN(value) && isNaN(f); + } + + /** + * Convert the float to the IEEE 754 floating-point "single format" bit + * layout. Bit 31 (the most significant) is the sign bit, bits 30-23 + * (masked by 0x7f800000) represent the exponent, and bits 22-0 + * (masked by 0x007fffff) are the mantissa. This function collapses all + * versions of NaN to 0x7fc00000. The result of this function can be used + * as the argument to Float.intBitsToFloat(int) to obtain the + * original float value. + * + * @param value the float to convert + * @return the bits of the float + * @see #intBitsToFloat(int) + */ + public static int floatToIntBits(float value) + { + return VMFloat.floatToIntBits(value); + } + + /** + * Convert the float to the IEEE 754 floating-point "single format" bit + * layout. Bit 31 (the most significant) is the sign bit, bits 30-23 + * (masked by 0x7f800000) represent the exponent, and bits 22-0 + * (masked by 0x007fffff) are the mantissa. This function leaves NaN alone, + * rather than collapsing to a canonical value. The result of this function + * can be used as the argument to Float.intBitsToFloat(int) to + * obtain the original float value. + * + * @param value the float to convert + * @return the bits of the float + * @see #intBitsToFloat(int) + */ + public static int floatToRawIntBits(float value) + { + return VMFloat.floatToRawIntBits(value); + } + + /** + * Convert the argument in IEEE 754 floating-point "single format" bit + * layout to the corresponding float. Bit 31 (the most significant) is the + * sign bit, bits 30-23 (masked by 0x7f800000) represent the exponent, and + * bits 22-0 (masked by 0x007fffff) are the mantissa. This function leaves + * NaN alone, so that you can recover the bit pattern with + * Float.floatToRawIntBits(float). + * + * @param bits the bits to convert + * @return the float represented by the bits + * @see #floatToIntBits(float) + * @see #floatToRawIntBits(float) + */ + public static float intBitsToFloat(int bits) + { + return VMFloat.intBitsToFloat(bits); + } + + /** + * Compare two Floats numerically by comparing their float + * values. The result is positive if the first is greater, negative if the + * second is greater, and 0 if the two are equal. However, this special + * cases NaN and signed zero as follows: NaN is considered greater than + * all other floats, including POSITIVE_INFINITY, and positive + * zero is considered greater than negative zero. + * + * @param f the Float to compare + * @return the comparison + * @since 1.2 + */ + public int compareTo(Float f) + { + return compare(value, f.value); + } + + /** + * Behaves like compareTo(Float) unless the Object + * is not an Float. + * + * @param o the object to compare + * @return the comparison + * @throws ClassCastException if the argument is not a Float + * @see #compareTo(Float) + * @see Comparable + * @since 1.2 + */ + public int compareTo(Object o) + { + return compare(value, ((Float) o).value); + } + + /** + * Behaves like new Float(x).compareTo(new Float(y)); in + * other words this compares two floats, special casing NaN and zero, + * without the overhead of objects. + * + * @param x the first float to compare + * @param y the second float to compare + * @return the comparison + * @since 1.4 + */ + public static int compare(float x, float y) + { + if (isNaN(x)) + return isNaN(y) ? 0 : 1; + if (isNaN(y)) + return -1; + // recall that 0.0 == -0.0, so we convert to infinities and try again + if (x == 0 && y == 0) + return (int) (1 / x - 1 / y); + if (x == y) + return 0; + + return x > y ? 1 : -1; + } +} diff --git a/libjava/classpath/java/lang/IllegalAccessError.java b/libjava/classpath/java/lang/IllegalAccessError.java new file mode 100644 index 0000000..e482160 --- /dev/null +++ b/libjava/classpath/java/lang/IllegalAccessError.java @@ -0,0 +1,76 @@ +/* IllegalAccessError.java -- thrown when linking to an inaccessible member + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * An IllegalAccessError is thrown when an attempt is made to + * call a method, or access or modify a field that the application does not + * have access to. Because this error is usually caught by a compiler, + * the error only occurs at runtime when the definition of a class has + * changed in a way that is incompatible with the previously compiled + * application. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class IllegalAccessError extends IncompatibleClassChangeError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -8988904074992417891L; + + /** + * Create an error without a message. + */ + public IllegalAccessError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public IllegalAccessError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/IllegalAccessException.java b/libjava/classpath/java/lang/IllegalAccessException.java new file mode 100644 index 0000000..a352c8b --- /dev/null +++ b/libjava/classpath/java/lang/IllegalAccessException.java @@ -0,0 +1,99 @@ +/* IllegalAccessException.java -- thrown on attempt to reflect on + inaccessible data + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * Thrown whenever a reflective method tries to do something that the + * compiler would not allow. For example, using reflection to set a private + * variable that belongs to a class in another package is bad. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @see Class#newInstance() + * @see Field#set(Object, Object) + * @see Field#setBoolean(Object, boolean) + * @see Field#setByte(Object, byte) + * @see Field#setShort(Object, short) + * @see Field#setChar(Object, char) + * @see Field#setInt(Object, int) + * @see Field#setLong(Object, long) + * @see Field#setFloat(Object, float) + * @see Field#setDouble(Object, double) + * @see Field#get(Object) + * @see Field#getBoolean(Object) + * @see Field#getByte(Object) + * @see Field#getShort(Object) + * @see Field#getChar(Object) + * @see Field#getInt(Object) + * @see Field#getLong(Object) + * @see Field#getFloat(Object) + * @see Field#getDouble(Object) + * @see Method#invoke(Object, Object[]) + * @see Constructor#newInstance(Object[]) + * @status updated to 1.4 + */ +public class IllegalAccessException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 6616958222490762034L; + + /** + * Create an exception without a message. + */ + public IllegalAccessException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public IllegalAccessException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/IllegalArgumentException.java b/libjava/classpath/java/lang/IllegalArgumentException.java new file mode 100644 index 0000000..7b822b9 --- /dev/null +++ b/libjava/classpath/java/lang/IllegalArgumentException.java @@ -0,0 +1,75 @@ +/* IllegalArgumentException.java -- thrown when a method is passed an + illegal or inappropriate argument + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when a method is passed an illegal or inappropriate argument. For + * example:
    + *

    + * wait(-1);
    + * 
    + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class IllegalArgumentException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -5365630128856068164L; + + /** + * Create an exception without a message. + */ + public IllegalArgumentException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public IllegalArgumentException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/IllegalMonitorStateException.java b/libjava/classpath/java/lang/IllegalMonitorStateException.java new file mode 100644 index 0000000..13b3f95 --- /dev/null +++ b/libjava/classpath/java/lang/IllegalMonitorStateException.java @@ -0,0 +1,78 @@ +/* IllegalMonitorStateException.java -- thrown when trying to wait or + notify a monitor that is not owned + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when a thread attempts to wait or notify on a monitor that it + * does not own (ie. it has not synchronized on the object). For example:
    + *
    + * void m() {
    + *   notify();
    + * }
    + * 
    + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class IllegalMonitorStateException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3713306369498869069L; + + /** + * Create an exception without a message. + */ + public IllegalMonitorStateException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public IllegalMonitorStateException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/IllegalStateException.java b/libjava/classpath/java/lang/IllegalStateException.java new file mode 100644 index 0000000..5c2bbad --- /dev/null +++ b/libjava/classpath/java/lang/IllegalStateException.java @@ -0,0 +1,80 @@ +/* IllegalStateException.java -- thrown when invoking a method at + an illegal or inappropriate time + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when a method is invoked at an illegal or inappropriate time. For + * example:
    + *
    + * void m(Collecion c)
    + * {
    + *   c.iterator().remove();
    + * }
    + * 
    + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class IllegalStateException extends RuntimeException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -1848914673093119416L; + + /** + * Create an exception without a message. + */ + public IllegalStateException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public IllegalStateException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/IllegalThreadStateException.java b/libjava/classpath/java/lang/IllegalThreadStateException.java new file mode 100644 index 0000000..e14385a --- /dev/null +++ b/libjava/classpath/java/lang/IllegalThreadStateException.java @@ -0,0 +1,75 @@ +/* IllegalThreadStateException.java -- thrown when trying to manipulate a + Thread when it is not in an appropriate state + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown When trying to manipulate a Thread which is in an inappropriate + * state. Since the documentation suggests that this can happen with + * Thread.suspend or Thread.resume, but these + * two methods are deprecated, this exception is likely very rare. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class IllegalThreadStateException extends IllegalArgumentException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -7626246362397460174L; + + /** + * Create an exception without a message. + */ + public IllegalThreadStateException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public IllegalThreadStateException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/IncompatibleClassChangeError.java b/libjava/classpath/java/lang/IncompatibleClassChangeError.java new file mode 100644 index 0000000..637410a --- /dev/null +++ b/libjava/classpath/java/lang/IncompatibleClassChangeError.java @@ -0,0 +1,73 @@ +/* IncompatibleClassChangeError.java -- thrown for binary incompatible classes + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * An IncompatibleClassChangeError is thrown when the definition + * of a class used by the currently executing method has changed in an + * incompatible way. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class IncompatibleClassChangeError extends LinkageError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4914975503642802119L; + + /** + * Create an error without a message. + */ + public IncompatibleClassChangeError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public IncompatibleClassChangeError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/IndexOutOfBoundsException.java b/libjava/classpath/java/lang/IndexOutOfBoundsException.java new file mode 100644 index 0000000..c53c67e --- /dev/null +++ b/libjava/classpath/java/lang/IndexOutOfBoundsException.java @@ -0,0 +1,75 @@ +/* IndexOutOfBoundsException.java -- thrown for an invalid index + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * This exception can be thrown to indicate an attempt to access an + * index which is out of bounds on objects like String, Array, or Vector. + * Usually any negative integer less than or equal to -1 and positive + * integer greater than or equal to the size of the object is an index + * which would be out of bounds. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class IndexOutOfBoundsException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 234122996006267687L; + + /** + * Create an exception without a message. + */ + public IndexOutOfBoundsException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public IndexOutOfBoundsException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/InheritableThreadLocal.java b/libjava/classpath/java/lang/InheritableThreadLocal.java new file mode 100644 index 0000000..69ff613 --- /dev/null +++ b/libjava/classpath/java/lang/InheritableThreadLocal.java @@ -0,0 +1,116 @@ +/* InheritableThreadLocal -- a ThreadLocal which inherits values across threads + Copyright (C) 2000, 2001, 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 java.lang; + +import java.util.Iterator; +import java.util.WeakHashMap; + +/** + * A ThreadLocal whose value is inherited by child Threads. The value of the + * InheritableThreadLocal associated with the (parent) Thread is copied to + * the new (child) Thread at the moment of creation. + * + *

    It is possible to make the value associated with the child Thread a + * function of the value that is associated with the parent Thread by + * overriding the childValue() method. The utility of this class + * is in transferring items like User ID or Transaction ID across threads + * automatically. + * + * @author Mark Wielaard (mark@klomp.org) + * @author Eric Blake (ebb9@email.byu.edu) + * @see ThreadLocal + * @since 1.2 + * @status updated to 1.4 + */ +public class InheritableThreadLocal extends ThreadLocal +{ + /** + * Creates a new InheritableThreadLocal that has no values associated + * with it yet. + */ + public InheritableThreadLocal() + { + } + + /** + * Determines the value associated with a newly created child Thread as a + * function of the value associated with the currently executing (parent) + * Thread. The default implementation just returns the parentValue. + * + * @param parentValue the value of this object in the parent thread at + * the moment of creation of the child + * @return the initial value for the child thread + */ + protected Object childValue(Object parentValue) + { + return parentValue; + } + + /** + * Generates the childValues of all InheritableThreadLocals + * that are in the heritage of the current Thread for the newly created + * childThread. Should be called from the contructor Thread. + * + * @param childThread the newly created thread, to inherit from this thread + * @see Thread#Thread(ThreadGroup, Runnable, String) + */ + static void newChildThread(Thread childThread) + { + // The currentThread is the parent of the new thread. + Thread parentThread = Thread.currentThread(); + if (parentThread.locals != null) + { + Iterator keys = parentThread.locals.keySet().iterator(); + while (keys.hasNext()) + { + Key key = (Key)keys.next(); + if (key.get() instanceof InheritableThreadLocal) + { + InheritableThreadLocal local = (InheritableThreadLocal)key.get(); + Object parentValue = parentThread.locals.get(key); + Object childValue = local.childValue(parentValue == NULL + ? null : parentValue); + if (childThread.locals == null) + childThread.locals = new WeakHashMap(); + childThread.locals.put(key, (childValue == null + ? NULL : childValue)); + } + } + } + } +} diff --git a/libjava/classpath/java/lang/InstantiationError.java b/libjava/classpath/java/lang/InstantiationError.java new file mode 100644 index 0000000..dd12b51 --- /dev/null +++ b/libjava/classpath/java/lang/InstantiationError.java @@ -0,0 +1,75 @@ +/* InstantiationError.java -- thrown when the linker cannot create an instance + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * An InstantiationError is thrown when an attempt is made to + * create an instance of an abstract class or an interface. Because this + * error is usually caught by a compiler, the error only occurs at runtime + * when the definition of a class has changed in a way that is incompatible + * with the previously compiled application. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class InstantiationError extends IncompatibleClassChangeError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4885810657349421204L; + + /** + * Create an error without a message. + */ + public InstantiationError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public InstantiationError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/InstantiationException.java b/libjava/classpath/java/lang/InstantiationException.java new file mode 100644 index 0000000..367b14b --- /dev/null +++ b/libjava/classpath/java/lang/InstantiationException.java @@ -0,0 +1,74 @@ +/* InstantiationException.java -- thrown when reflection cannot create an + instance + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when an attempt is made to use reflection to build a + * non-instantiable class (an interface or abstract class). + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @see Class#newInstance() + * @status updated to 1.4 + */ +public class InstantiationException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -8441929162975509110L; + + /** + * Create an exception without a message. + */ + public InstantiationException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public InstantiationException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/Integer.java b/libjava/classpath/java/lang/Integer.java new file mode 100644 index 0000000..07be4e3 --- /dev/null +++ b/libjava/classpath/java/lang/Integer.java @@ -0,0 +1,772 @@ +/* Integer.java -- object wrapper for int + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Instances of class Integer represent primitive + * int values. + * + * Additionally, this class provides various helper functions and variables + * related to ints. + * + * @author Paul Fisher + * @author John Keiser + * @author Warren Levy + * @author Eric Blake (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@redhat.com) + * @since 1.0 + * @status largely updated to 1.5 + */ +public final class Integer extends Number implements Comparable +{ + /** + * Compatible with JDK 1.0.2+. + */ + private static final long serialVersionUID = 1360826667806852920L; + + /** + * The minimum value an int can represent is -2147483648 (or + * -231). + */ + public static final int MIN_VALUE = 0x80000000; + + /** + * The maximum value an int can represent is 2147483647 (or + * 231 - 1). + */ + public static final int MAX_VALUE = 0x7fffffff; + + /** + * The primitive type int is represented by this + * Class object. + * @since 1.1 + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass('I'); + + /** + * The number of bits needed to represent an int. + * @since 1.5 + */ + public static final int SIZE = 32; + + // This caches some Integer values, and is used by boxing + // conversions via valueOf(). We must cache at least -128..127; + // these constants control how much we actually cache. + private static final int MIN_CACHE = -128; + private static final int MAX_CACHE = 127; + private static Integer[] intCache = new Integer[MAX_CACHE - MIN_CACHE + 1]; + + /** + * The immutable value of this Integer. + * + * @serial the wrapped int + */ + private final int value; + + /** + * Create an Integer object representing the value of the + * int argument. + * + * @param value the value to use + */ + public Integer(int value) + { + this.value = value; + } + + /** + * Create an Integer object representing the value of the + * argument after conversion to an int. + * + * @param s the string to convert + * @throws NumberFormatException if the String does not contain an int + * @see #valueOf(String) + */ + public Integer(String s) + { + value = parseInt(s, 10, false); + } + + /** + * Converts the int to a String using + * the specified radix (base). If the radix exceeds + * Character.MIN_RADIX or Character.MAX_RADIX, 10 + * is used instead. If the result is negative, the leading character is + * '-' ('\\u002D'). The remaining characters come from + * Character.forDigit(digit, radix) ('0'-'9','a'-'z'). + * + * @param num the int to convert to String + * @param radix the radix (base) to use in the conversion + * @return the String representation of the argument + */ + public static String toString(int num, int radix) + { + if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) + radix = 10; + + // For negative numbers, print out the absolute value w/ a leading '-'. + // Use an array large enough for a binary number. + char[] buffer = new char[33]; + int i = 33; + boolean isNeg = false; + if (num < 0) + { + isNeg = true; + num = -num; + + // When the value is MIN_VALUE, it overflows when made positive + if (num < 0) + { + buffer[--i] = digits[(int) (-(num + radix) % radix)]; + num = -(num / radix); + } + } + + do + { + buffer[--i] = digits[num % radix]; + num /= radix; + } + while (num > 0); + + if (isNeg) + buffer[--i] = '-'; + + // Package constructor avoids an array copy. + return new String(buffer, i, 33 - i, true); + } + + /** + * Converts the int to a String assuming it is + * unsigned in base 16. + * + * @param i the int to convert to String + * @return the String representation of the argument + */ + public static String toHexString(int i) + { + return toUnsignedString(i, 4); + } + + /** + * Converts the int to a String assuming it is + * unsigned in base 8. + * + * @param i the int to convert to String + * @return the String representation of the argument + */ + public static String toOctalString(int i) + { + return toUnsignedString(i, 3); + } + + /** + * Converts the int to a String assuming it is + * unsigned in base 2. + * + * @param i the int to convert to String + * @return the String representation of the argument + */ + public static String toBinaryString(int i) + { + return toUnsignedString(i, 1); + } + + /** + * Converts the int to a String and assumes + * a radix of 10. + * + * @param i the int to convert to String + * @return the String representation of the argument + * @see #toString(int, int) + */ + public static String toString(int i) + { + // This is tricky: in libgcj, String.valueOf(int) is a fast native + // implementation. In Classpath it just calls back to + // Integer.toString(int, int). + return String.valueOf(i); + } + + /** + * Converts the specified String into an int + * using the specified radix (base). The string must not be null + * or empty. It may begin with an optional '-', which will negate the answer, + * provided that there are also valid digits. Each digit is parsed as if by + * Character.digit(d, radix), and must be in the range + * 0 to radix - 1. Finally, the result must be + * within MIN_VALUE to MAX_VALUE, inclusive. + * Unlike Double.parseDouble, you may not have a leading '+'. + * + * @param str the String to convert + * @param radix the radix (base) to use in the conversion + * @return the String argument converted to int + * @throws NumberFormatException if s cannot be parsed as an + * int + */ + public static int parseInt(String str, int radix) + { + return parseInt(str, radix, false); + } + + /** + * Converts the specified String into an int. + * This function assumes a radix of 10. + * + * @param s the String to convert + * @return the int value of s + * @throws NumberFormatException if s cannot be parsed as an + * int + * @see #parseInt(String, int) + */ + public static int parseInt(String s) + { + return parseInt(s, 10, false); + } + + /** + * Creates a new Integer object using the String + * and specified radix (base). + * + * @param s the String to convert + * @param radix the radix (base) to convert with + * @return the new Integer + * @throws NumberFormatException if s cannot be parsed as an + * int + * @see #parseInt(String, int) + */ + public static Integer valueOf(String s, int radix) + { + return new Integer(parseInt(s, radix, false)); + } + + /** + * Creates a new Integer object using the String, + * assuming a radix of 10. + * + * @param s the String to convert + * @return the new Integer + * @throws NumberFormatException if s cannot be parsed as an + * int + * @see #Integer(String) + * @see #parseInt(String) + */ + public static Integer valueOf(String s) + { + return new Integer(parseInt(s, 10, false)); + } + + /** + * Returns an Integer object wrapping the value. + * In contrast to the Integer constructor, this method + * will cache some values. It is used by boxing conversion. + * + * @param val the value to wrap + * @return the Integer + */ + public static Integer valueOf(int val) + { + if (val < MIN_CACHE || val > MAX_CACHE) + return new Integer(val); + synchronized (intCache) + { + if (intCache[val - MIN_CACHE] == null) + intCache[val - MIN_CACHE] = new Integer(val); + return intCache[val - MIN_CACHE]; + } + } + + /** + * Return the value of this Integer as a byte. + * + * @return the byte value + */ + public byte byteValue() + { + return (byte) value; + } + + /** + * Return the value of this Integer as a short. + * + * @return the short value + */ + public short shortValue() + { + return (short) value; + } + + /** + * Return the value of this Integer. + * @return the int value + */ + public int intValue() + { + return value; + } + + /** + * Return the value of this Integer as a long. + * + * @return the long value + */ + public long longValue() + { + return value; + } + + /** + * Return the value of this Integer as a float. + * + * @return the float value + */ + public float floatValue() + { + return value; + } + + /** + * Return the value of this Integer as a double. + * + * @return the double value + */ + public double doubleValue() + { + return value; + } + + /** + * Converts the Integer value to a String and + * assumes a radix of 10. + * + * @return the String representation + */ + public String toString() + { + return String.valueOf(value); + } + + /** + * Return a hashcode representing this Object. Integer's hash + * code is simply its value. + * + * @return this Object's hash code + */ + public int hashCode() + { + return value; + } + + /** + * Returns true if obj is an instance of + * Integer and represents the same int value. + * + * @param obj the object to compare + * @return whether these Objects are semantically equal + */ + public boolean equals(Object obj) + { + return obj instanceof Integer && value == ((Integer) obj).value; + } + + /** + * Get the specified system property as an Integer. The + * decode() method will be used to interpret the value of + * the property. + * + * @param nm the name of the system property + * @return the system property as an Integer, or null if the + * property is not found or cannot be decoded + * @throws SecurityException if accessing the system property is forbidden + * @see System#getProperty(String) + * @see #decode(String) + */ + public static Integer getInteger(String nm) + { + return getInteger(nm, null); + } + + /** + * Get the specified system property as an Integer, or use a + * default int value if the property is not found or is not + * decodable. The decode() method will be used to interpret + * the value of the property. + * + * @param nm the name of the system property + * @param val the default value + * @return the value of the system property, or the default + * @throws SecurityException if accessing the system property is forbidden + * @see System#getProperty(String) + * @see #decode(String) + */ + public static Integer getInteger(String nm, int val) + { + Integer result = getInteger(nm, null); + return result == null ? new Integer(val) : result; + } + + /** + * Get the specified system property as an Integer, or use a + * default Integer value if the property is not found or is + * not decodable. The decode() method will be used to + * interpret the value of the property. + * + * @param nm the name of the system property + * @param def the default value + * @return the value of the system property, or the default + * @throws SecurityException if accessing the system property is forbidden + * @see System#getProperty(String) + * @see #decode(String) + */ + public static Integer getInteger(String nm, Integer def) + { + if (nm == null || "".equals(nm)) + return def; + nm = System.getProperty(nm); + if (nm == null) + return def; + try + { + return decode(nm); + } + catch (NumberFormatException e) + { + return def; + } + } + + /** + * Convert the specified String into an Integer. + * The String may represent decimal, hexadecimal, or + * octal numbers. + * + *

    The extended BNF grammar is as follows:
    + *

    +   * DecodableString:
    +   *      ( [ - ] DecimalNumber )
    +   *    | ( [ - ] ( 0x | 0X
    +   *              | # ) HexDigit { HexDigit } )
    +   *    | ( [ - ] 0 { OctalDigit } )
    +   * DecimalNumber:
    +   *        DecimalDigit except '0' { DecimalDigit }
    +   * DecimalDigit:
    +   *        Character.digit(d, 10) has value 0 to 9
    +   * OctalDigit:
    +   *        Character.digit(d, 8) has value 0 to 7
    +   * DecimalDigit:
    +   *        Character.digit(d, 16) has value 0 to 15
    +   * 
    + * Finally, the value must be in the range MIN_VALUE to + * MAX_VALUE, or an exception is thrown. + * + * @param str the String to interpret + * @return the value of the String as an Integer + * @throws NumberFormatException if s cannot be parsed as a + * int + * @throws NullPointerException if s is null + * @since 1.2 + */ + public static Integer decode(String str) + { + return new Integer(parseInt(str, 10, true)); + } + + /** + * Compare two Integers numerically by comparing their int + * values. The result is positive if the first is greater, negative if the + * second is greater, and 0 if the two are equal. + * + * @param i the Integer to compare + * @return the comparison + * @since 1.2 + */ + public int compareTo(Integer i) + { + if (value == i.value) + return 0; + // Returns just -1 or 1 on inequality; doing math might overflow. + return value > i.value ? 1 : -1; + } + + /** + * Behaves like compareTo(Integer) unless the Object + * is not an Integer. + * + * @param o the object to compare + * @return the comparison + * @throws ClassCastException if the argument is not an Integer + * @see #compareTo(Integer) + * @see Comparable + * @since 1.2 + */ + public int compareTo(Object o) + { + return compareTo((Integer) o); + } + + /** + * Return the number of bits set in x. + * @param x value to examine + * @since 1.5 + */ + public static int bitCount(int x) + { + // Successively collapse alternating bit groups into a sum. + x = ((x >> 1) & 0x55555555) + (x & 0x55555555); + x = ((x >> 2) & 0x33333333) + (x & 0x33333333); + x = ((x >> 4) & 0x0f0f0f0f) + (x & 0x0f0f0f0f); + x = ((x >> 8) & 0x00ff00ff) + (x & 0x00ff00ff); + return ((x >> 16) & 0x0000ffff) + (x & 0x0000ffff); + } + + /** + * Rotate x to the left by distance bits. + * @param x the value to rotate + * @param distance the number of bits by which to rotate + * @since 1.5 + */ + public static int rotateLeft(int x, int distance) + { + // This trick works because the shift operators implicitly mask + // the shift count. + return (x << distance) | (x >>> - distance); + } + + /** + * Rotate x to the right by distance bits. + * @param x the value to rotate + * @param distance the number of bits by which to rotate + * @since 1.5 + */ + public static int rotateRight(int x, int distance) + { + // This trick works because the shift operators implicitly mask + // the shift count. + return (x << - distance) | (x >>> distance); + } + + /** + * Find the highest set bit in value, and return a new value + * with only that bit set. + * @param value the value to examine + * @since 1.5 + */ + public static int highestOneBit(int value) + { + value |= value >>> 1; + value |= value >>> 2; + value |= value >>> 4; + value |= value >>> 8; + value |= value >>> 16; + return value ^ (value >>> 1); + } + + /** + * Return the number of leading zeros in value. + * @param value the value to examine + * @since 1.5 + */ + public static int numberOfLeadingZeros(int value) + { + value |= value >>> 1; + value |= value >>> 2; + value |= value >>> 4; + value |= value >>> 8; + value |= value >>> 16; + return bitCount(~value); + } + + /** + * Find the lowest set bit in value, and return a new value + * with only that bit set. + * @param value the value to examine + * @since 1.5 + */ + public static int lowestOneBit(int value) + { + // Classic assembly trick. + return value & - value; + } + + /** + * Find the number of trailing zeros in value. + * @param value the value to examine + * @since 1.5 + */ + public static int numberOfTrailingZeros(int value) + { + return bitCount((value & -value) - 1); + } + + /** + * Return 1 if x is positive, -1 if it is negative, and 0 if it is + * zero. + * @param x the value to examine + * @since 1.5 + */ + public static int signum(int x) + { + return x < 0 ? -1 : (x > 0 ? 1 : 0); + } + + /** + * Reverse the bytes in val. + * @since 1.5 + */ + public static int reverseBytes(int val) + { + return ( ((val >> 24) & 0xff) + | ((val >> 8) & 0xff00) + | ((val << 8) & 0xff0000) + | ((val << 24) & 0xff000000)); + } + + /** + * Reverse the bits in val. + * @since 1.5 + */ + public static int reverse(int val) + { + // Successively swap alternating bit groups. + val = ((val >> 1) & 0x55555555) + ((val << 1) & ~0x55555555); + val = ((val >> 2) & 0x33333333) + ((val << 2) & ~0x33333333); + val = ((val >> 4) & 0x0f0f0f0f) + ((val << 4) & ~0x0f0f0f0f); + val = ((val >> 8) & 0x00ff00ff) + ((val << 8) & ~0x00ff00ff); + return ((val >> 16) & 0x0000ffff) + ((val << 16) & ~0x0000ffff); + } + + /** + * Helper for converting unsigned numbers to String. + * + * @param num the number + * @param exp log2(digit) (ie. 1, 3, or 4 for binary, oct, hex) + */ + // Package visible for use by Long. + static String toUnsignedString(int num, int exp) + { + // Use an array large enough for a binary number. + int mask = (1 << exp) - 1; + char[] buffer = new char[32]; + int i = 32; + do + { + buffer[--i] = digits[num & mask]; + num >>>= exp; + } + while (num != 0); + + // Package constructor avoids an array copy. + return new String(buffer, i, 32 - i, true); + } + + /** + * Helper for parsing ints, used by Integer, Short, and Byte. + * + * @param str the string to parse + * @param radix the radix to use, must be 10 if decode is true + * @param decode if called from decode + * @return the parsed int value + * @throws NumberFormatException if there is an error + * @throws NullPointerException if decode is true and str if null + * @see #parseInt(String, int) + * @see #decode(String) + * @see Byte#parseInt(String, int) + * @see Short#parseInt(String, int) + */ + static int parseInt(String str, int radix, boolean decode) + { + if (! decode && str == null) + throw new NumberFormatException(); + int index = 0; + int len = str.length(); + boolean isNeg = false; + if (len == 0) + throw new NumberFormatException(); + int ch = str.charAt(index); + if (ch == '-') + { + if (len == 1) + throw new NumberFormatException(); + isNeg = true; + ch = str.charAt(++index); + } + if (decode) + { + if (ch == '0') + { + if (++index == len) + return 0; + if ((str.charAt(index) & ~('x' ^ 'X')) == 'X') + { + radix = 16; + index++; + } + else + radix = 8; + } + else if (ch == '#') + { + radix = 16; + index++; + } + } + if (index == len) + throw new NumberFormatException(); + + int max = MAX_VALUE / radix; + // We can't directly write `max = (MAX_VALUE + 1) / radix'. + // So instead we fake it. + if (isNeg && MAX_VALUE % radix == radix - 1) + ++max; + + int val = 0; + while (index < len) + { + if (val < 0 || val > max) + throw new NumberFormatException(); + + ch = Character.digit(str.charAt(index++), radix); + val = val * radix + ch; + if (ch < 0 || (val < 0 && (! isNeg || val != MIN_VALUE))) + throw new NumberFormatException(); + } + return isNeg ? -val : val; + } +} diff --git a/libjava/classpath/java/lang/InternalError.java b/libjava/classpath/java/lang/InternalError.java new file mode 100644 index 0000000..3a95bbea --- /dev/null +++ b/libjava/classpath/java/lang/InternalError.java @@ -0,0 +1,72 @@ +/* InternalError.java -- thrown when the VM encounters an internal error + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * An InternalError is thrown when a mystical error has + * occurred in the Java Virtual Machine. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class InternalError extends VirtualMachineError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -9062593416125562365L; + + /** + * Create an error without a message. + */ + public InternalError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public InternalError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/InterruptedException.java b/libjava/classpath/java/lang/InterruptedException.java new file mode 100644 index 0000000..da2173c --- /dev/null +++ b/libjava/classpath/java/lang/InterruptedException.java @@ -0,0 +1,80 @@ +/* InterruptedException.java -- thrown when a thread is interrupted + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when a thread interrupts another thread which was previously + * sleeping, waiting, or paused in some other way. See the + * interrupt method of class Thread. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @see Object#wait() + * @see Object#wait(long) + * @see Object#wait(long, int) + * @see Thread#sleep(long) + * @see Thread#interrupt() + * @see Thread#interrupted() + * @status updated to 1.4 + */ +public class InterruptedException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 6700697376100628473L; + + /** + * Create an exception without a message. + */ + public InterruptedException() + { + } + + /** + * Create an exception with a message. + * + * + * @param s the message + */ + public InterruptedException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/LinkageError.java b/libjava/classpath/java/lang/LinkageError.java new file mode 100644 index 0000000..0287020 --- /dev/null +++ b/libjava/classpath/java/lang/LinkageError.java @@ -0,0 +1,74 @@ +/* LinkageError.java -- thrown when classes valid at separate compile times + cannot be linked to each other + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Subclasses of LinkageError are thrown to indicate that two + * classes which were compatible at separate compilation times cannot be + * linked to one another. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class LinkageError extends Error +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3579600108157160122L; + + /** + * Create an error without a message. + */ + public LinkageError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public LinkageError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/Long.java b/libjava/classpath/java/lang/Long.java new file mode 100644 index 0000000..703eab8 --- /dev/null +++ b/libjava/classpath/java/lang/Long.java @@ -0,0 +1,614 @@ +/* Long.java -- object wrapper for long + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Instances of class Long represent primitive + * long values. + * + * Additionally, this class provides various helper functions and variables + * related to longs. + * + * @author Paul Fisher + * @author John Keiser + * @author Warren Levy + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public final class Long extends Number implements Comparable +{ + /** + * Compatible with JDK 1.0.2+. + */ + private static final long serialVersionUID = 4290774380558885855L; + + /** + * The minimum value a long can represent is + * -9223372036854775808L (or -263). + */ + public static final long MIN_VALUE = 0x8000000000000000L; + + /** + * The maximum value a long can represent is + * 9223372036854775807 (or 263 - 1). + */ + public static final long MAX_VALUE = 0x7fffffffffffffffL; + + /** + * The primitive type long is represented by this + * Class object. + * @since 1.1 + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass ('J'); + + /** + * The immutable value of this Long. + * + * @serial the wrapped long + */ + private final long value; + + /** + * Create a Long object representing the value of the + * long argument. + * + * @param value the value to use + */ + public Long(long value) + { + this.value = value; + } + + /** + * Create a Long object representing the value of the + * argument after conversion to a long. + * + * @param s the string to convert + * @throws NumberFormatException if the String does not contain a long + * @see #valueOf(String) + */ + public Long(String s) + { + value = parseLong(s, 10, false); + } + + /** + * Converts the long to a String using + * the specified radix (base). If the radix exceeds + * Character.MIN_RADIX or Character.MAX_RADIX, 10 + * is used instead. If the result is negative, the leading character is + * '-' ('\\u002D'). The remaining characters come from + * Character.forDigit(digit, radix) ('0'-'9','a'-'z'). + * + * @param num the long to convert to String + * @param radix the radix (base) to use in the conversion + * @return the String representation of the argument + */ + public static String toString(long num, int radix) + { + // Use the Integer toString for efficiency if possible. + if ((int) num == num) + return Integer.toString((int) num, radix); + + if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) + radix = 10; + + // For negative numbers, print out the absolute value w/ a leading '-'. + // Use an array large enough for a binary number. + char[] buffer = new char[65]; + int i = 65; + boolean isNeg = false; + if (num < 0) + { + isNeg = true; + num = -num; + + // When the value is MIN_VALUE, it overflows when made positive + if (num < 0) + { + buffer[--i] = digits[(int) (-(num + radix) % radix)]; + num = -(num / radix); + } + } + + do + { + buffer[--i] = digits[(int) (num % radix)]; + num /= radix; + } + while (num > 0); + + if (isNeg) + buffer[--i] = '-'; + + // Package constructor avoids an array copy. + return new String(buffer, i, 65 - i, true); + } + + /** + * Converts the long to a String assuming it is + * unsigned in base 16. + * + * @param l the long to convert to String + * @return the String representation of the argument + */ + public static String toHexString(long l) + { + return toUnsignedString(l, 4); + } + + /** + * Converts the long to a String assuming it is + * unsigned in base 8. + * + * @param l the long to convert to String + * @return the String representation of the argument + */ + public static String toOctalString(long l) + { + return toUnsignedString(l, 3); + } + + /** + * Converts the long to a String assuming it is + * unsigned in base 2. + * + * @param l the long to convert to String + * @return the String representation of the argument + */ + public static String toBinaryString(long l) + { + return toUnsignedString(l, 1); + } + + /** + * Converts the long to a String and assumes + * a radix of 10. + * + * @param num the long to convert to String + * @return the String representation of the argument + * @see #toString(long, int) + */ + public static String toString(long num) + { + return toString(num, 10); + } + + /** + * Converts the specified String into an int + * using the specified radix (base). The string must not be null + * or empty. It may begin with an optional '-', which will negate the answer, + * provided that there are also valid digits. Each digit is parsed as if by + * Character.digit(d, radix), and must be in the range + * 0 to radix - 1. Finally, the result must be + * within MIN_VALUE to MAX_VALUE, inclusive. + * Unlike Double.parseDouble, you may not have a leading '+'; and 'l' or + * 'L' as the last character is only valid in radices 22 or greater, where + * it is a digit and not a type indicator. + * + * @param str the String to convert + * @param radix the radix (base) to use in the conversion + * @return the String argument converted to long + * @throws NumberFormatException if s cannot be parsed as a + * long + */ + public static long parseLong(String str, int radix) + { + return parseLong(str, radix, false); + } + + /** + * Converts the specified String into a long. + * This function assumes a radix of 10. + * + * @param s the String to convert + * @return the int value of s + * @throws NumberFormatException if s cannot be parsed as a + * long + * @see #parseLong(String, int) + */ + public static long parseLong(String s) + { + return parseLong(s, 10, false); + } + + /** + * Creates a new Long object using the String + * and specified radix (base). + * + * @param s the String to convert + * @param radix the radix (base) to convert with + * @return the new Long + * @throws NumberFormatException if s cannot be parsed as a + * long + * @see #parseLong(String, int) + */ + public static Long valueOf(String s, int radix) + { + return new Long(parseLong(s, radix, false)); + } + + /** + * Creates a new Long object using the String, + * assuming a radix of 10. + * + * @param s the String to convert + * @return the new Long + * @throws NumberFormatException if s cannot be parsed as a + * long + * @see #Long(String) + * @see #parseLong(String) + */ + public static Long valueOf(String s) + { + return new Long(parseLong(s, 10, false)); + } + + /** + * Convert the specified String into a Long. + * The String may represent decimal, hexadecimal, or + * octal numbers. + * + *

    The extended BNF grammar is as follows:
    + *

    +   * DecodableString:
    +   *      ( [ - ] DecimalNumber )
    +   *    | ( [ - ] ( 0x | 0X
    +   *              | # ) HexDigit { HexDigit } )
    +   *    | ( [ - ] 0 { OctalDigit } )
    +   * DecimalNumber:
    +   *        DecimalDigit except '0' { DecimalDigit }
    +   * DecimalDigit:
    +   *        Character.digit(d, 10) has value 0 to 9
    +   * OctalDigit:
    +   *        Character.digit(d, 8) has value 0 to 7
    +   * DecimalDigit:
    +   *        Character.digit(d, 16) has value 0 to 15
    +   * 
    + * Finally, the value must be in the range MIN_VALUE to + * MAX_VALUE, or an exception is thrown. Note that you cannot + * use a trailing 'l' or 'L', unlike in Java source code. + * + * @param str the String to interpret + * @return the value of the String as a Long + * @throws NumberFormatException if s cannot be parsed as a + * long + * @throws NullPointerException if s is null + * @since 1.2 + */ + public static Long decode(String str) + { + return new Long(parseLong(str, 10, true)); + } + + /** + * Return the value of this Long as a byte. + * + * @return the byte value + */ + public byte byteValue() + { + return (byte) value; + } + + /** + * Return the value of this Long as a short. + * + * @return the short value + */ + public short shortValue() + { + return (short) value; + } + + /** + * Return the value of this Long as an int. + * + * @return the int value + */ + public int intValue() + { + return (int) value; + } + + /** + * Return the value of this Long. + * + * @return the long value + */ + public long longValue() + { + return value; + } + + /** + * Return the value of this Long as a float. + * + * @return the float value + */ + public float floatValue() + { + return value; + } + + /** + * Return the value of this Long as a double. + * + * @return the double value + */ + public double doubleValue() + { + return value; + } + + /** + * Converts the Long value to a String and + * assumes a radix of 10. + * + * @return the String representation + */ + public String toString() + { + return toString(value, 10); + } + + /** + * Return a hashcode representing this Object. Long's hash + * code is calculated by (int) (value ^ (value >> 32)). + * + * @return this Object's hash code + */ + public int hashCode() + { + return (int) (value ^ (value >>> 32)); + } + + /** + * Returns true if obj is an instance of + * Long and represents the same long value. + * + * @param obj the object to compare + * @return whether these Objects are semantically equal + */ + public boolean equals(Object obj) + { + return obj instanceof Long && value == ((Long) obj).value; + } + + /** + * Get the specified system property as a Long. The + * decode() method will be used to interpret the value of + * the property. + * + * @param nm the name of the system property + * @return the system property as a Long, or null if the + * property is not found or cannot be decoded + * @throws SecurityException if accessing the system property is forbidden + * @see System#getProperty(String) + * @see #decode(String) + */ + public static Long getLong(String nm) + { + return getLong(nm, null); + } + + /** + * Get the specified system property as a Long, or use a + * default long value if the property is not found or is not + * decodable. The decode() method will be used to interpret + * the value of the property. + * + * @param nm the name of the system property + * @param val the default value + * @return the value of the system property, or the default + * @throws SecurityException if accessing the system property is forbidden + * @see System#getProperty(String) + * @see #decode(String) + */ + public static Long getLong(String nm, long val) + { + Long result = getLong(nm, null); + return result == null ? new Long(val) : result; + } + + /** + * Get the specified system property as a Long, or use a + * default Long value if the property is not found or is + * not decodable. The decode() method will be used to + * interpret the value of the property. + * + * @param nm the name of the system property + * @param def the default value + * @return the value of the system property, or the default + * @throws SecurityException if accessing the system property is forbidden + * @see System#getProperty(String) + * @see #decode(String) + */ + public static Long getLong(String nm, Long def) + { + if (nm == null || "".equals(nm)) + return def; + nm = System.getProperty(nm); + if (nm == null) + return def; + try + { + return decode(nm); + } + catch (NumberFormatException e) + { + return def; + } + } + + /** + * Compare two Longs numerically by comparing their long + * values. The result is positive if the first is greater, negative if the + * second is greater, and 0 if the two are equal. + * + * @param l the Long to compare + * @return the comparison + * @since 1.2 + */ + public int compareTo(Long l) + { + if (value == l.value) + return 0; + // Returns just -1 or 1 on inequality; doing math might overflow the long. + return value > l.value ? 1 : -1; + } + + /** + * Behaves like compareTo(Long) unless the Object + * is not a Long. + * + * @param o the object to compare + * @return the comparison + * @throws ClassCastException if the argument is not a Long + * @see #compareTo(Long) + * @see Comparable + * @since 1.2 + */ + public int compareTo(Object o) + { + return compareTo((Long) o); + } + + /** + * Helper for converting unsigned numbers to String. + * + * @param num the number + * @param exp log2(digit) (ie. 1, 3, or 4 for binary, oct, hex) + */ + private static String toUnsignedString(long num, int exp) + { + // Use the Integer toUnsignedString for efficiency if possible. + // If NUM<0 then this particular optimization doesn't work + // properly. + if (num >= 0 && (int) num == num) + return Integer.toUnsignedString((int) num, exp); + + // Use an array large enough for a binary number. + int mask = (1 << exp) - 1; + char[] buffer = new char[64]; + int i = 64; + do + { + buffer[--i] = digits[(int) num & mask]; + num >>>= exp; + } + while (num != 0); + + // Package constructor avoids an array copy. + return new String(buffer, i, 64 - i, true); + } + + /** + * Helper for parsing longs. + * + * @param str the string to parse + * @param radix the radix to use, must be 10 if decode is true + * @param decode if called from decode + * @return the parsed long value + * @throws NumberFormatException if there is an error + * @throws NullPointerException if decode is true and str is null + * @see #parseLong(String, int) + * @see #decode(String) + */ + private static long parseLong(String str, int radix, boolean decode) + { + if (! decode && str == null) + throw new NumberFormatException(); + int index = 0; + int len = str.length(); + boolean isNeg = false; + if (len == 0) + throw new NumberFormatException(); + int ch = str.charAt(index); + if (ch == '-') + { + if (len == 1) + throw new NumberFormatException(); + isNeg = true; + ch = str.charAt(++index); + } + if (decode) + { + if (ch == '0') + { + if (++index == len) + return 0; + if ((str.charAt(index) & ~('x' ^ 'X')) == 'X') + { + radix = 16; + index++; + } + else + radix = 8; + } + else if (ch == '#') + { + radix = 16; + index++; + } + } + if (index == len) + throw new NumberFormatException(); + + long max = MAX_VALUE / radix; + // We can't directly write `max = (MAX_VALUE + 1) / radix'. + // So instead we fake it. + if (isNeg && MAX_VALUE % radix == radix - 1) + ++max; + + long val = 0; + while (index < len) + { + if (val < 0 || val > max) + throw new NumberFormatException(); + + ch = Character.digit(str.charAt(index++), radix); + val = val * radix + ch; + if (ch < 0 || (val < 0 && (! isNeg || val != MIN_VALUE))) + throw new NumberFormatException(); + } + return isNeg ? -val : val; + } +} diff --git a/libjava/classpath/java/lang/Math.java b/libjava/classpath/java/lang/Math.java new file mode 100644 index 0000000..08081e2 --- /dev/null +++ b/libjava/classpath/java/lang/Math.java @@ -0,0 +1,650 @@ +/* java.lang.Math -- common mathematical functions, native allowed + Copyright (C) 1998, 2001, 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 java.lang; + +import gnu.classpath.Configuration; + +import java.util.Random; + +/** + * Helper class containing useful mathematical functions and constants. + *

    + * + * Note that angles are specified in radians. Conversion functions are + * provided for your convenience. + * + * @author Paul Fisher + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + */ +public final class Math +{ + /** + * Math is non-instantiable + */ + private Math() + { + } + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javalang"); + } + } + + /** + * A random number generator, initialized on first use. + */ + private static Random rand; + + /** + * The most accurate approximation to the mathematical constant e: + * 2.718281828459045. Used in natural log and exp. + * + * @see #log(double) + * @see #exp(double) + */ + public static final double E = 2.718281828459045; + + /** + * The most accurate approximation to the mathematical constant pi: + * 3.141592653589793. This is the ratio of a circle's diameter + * to its circumference. + */ + public static final double PI = 3.141592653589793; + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + *

    + * + * Note that the the largest negative value (Integer.MIN_VALUE) cannot + * be made positive. In this case, because of the rules of negation in + * a computer, MIN_VALUE is what will be returned. + * This is a negative value. You have been warned. + * + * @param i the number to take the absolute value of + * @return the absolute value + * @see Integer#MIN_VALUE + */ + public static int abs(int i) + { + return (i < 0) ? -i : i; + } + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + *

    + * + * Note that the the largest negative value (Long.MIN_VALUE) cannot + * be made positive. In this case, because of the rules of negation in + * a computer, MIN_VALUE is what will be returned. + * This is a negative value. You have been warned. + * + * @param l the number to take the absolute value of + * @return the absolute value + * @see Long#MIN_VALUE + */ + public static long abs(long l) + { + return (l < 0) ? -l : l; + } + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + *

    + * + * This is equivalent, but faster than, calling + * Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(a)). + * + * @param f the number to take the absolute value of + * @return the absolute value + */ + public static float abs(float f) + { + return (f <= 0) ? 0 - f : f; + } + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + * + * This is equivalent, but faster than, calling + * Double.longBitsToDouble(Double.doubleToLongBits(a) + * << 1) >>> 1);. + * + * @param d the number to take the absolute value of + * @return the absolute value + */ + public static double abs(double d) + { + return (d <= 0) ? 0 - d : d; + } + + /** + * Return whichever argument is smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static int min(int a, int b) + { + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static long min(long a, long b) + { + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, -0 is always smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static float min(float a, float b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; < will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return -(-a - b); + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, -0 is always smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static double min(double a, double b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; < will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return -(-a - b); + return (a < b) ? a : b; + } + + /** + * Return whichever argument is larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static int max(int a, int b) + { + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static long max(long a, long b) + { + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, 0 is always larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static float max(float a, float b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; > will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return a - -b; + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, 0 is always larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static double max(double a, double b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; > will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return a - -b; + return (a > b) ? a : b; + } + + /** + * The trigonometric function sin. The sine of NaN or infinity is + * NaN, and the sine of 0 retains its sign. This is accurate within 1 ulp, + * and is semi-monotonic. + * + * @param a the angle (in radians) + * @return sin(a) + */ + public static native double sin(double a); + + /** + * The trigonometric function cos. The cosine of NaN or infinity is + * NaN. This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the angle (in radians) + * @return cos(a) + */ + public static native double cos(double a); + + /** + * The trigonometric function tan. The tangent of NaN or infinity + * is NaN, and the tangent of 0 retains its sign. This is accurate within 1 + * ulp, and is semi-monotonic. + * + * @param a the angle (in radians) + * @return tan(a) + */ + public static native double tan(double a); + + /** + * The trigonometric function arcsin. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN; and the arcsine of + * 0 retains its sign. This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the sin to turn back into an angle + * @return arcsin(a) + */ + public static native double asin(double a); + + /** + * The trigonometric function arccos. The range of angles returned + * is 0 to pi radians (0 to 180 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN. This is accurate + * within 1 ulp, and is semi-monotonic. + * + * @param a the cos to turn back into an angle + * @return arccos(a) + */ + public static native double acos(double a); + + /** + * The trigonometric function arcsin. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN, the + * result is NaN; and the arctangent of 0 retains its sign. This is accurate + * within 1 ulp, and is semi-monotonic. + * + * @param a the tan to turn back into an angle + * @return arcsin(a) + * @see #atan2(double, double) + */ + public static native double atan(double a); + + /** + * A special version of the trigonometric function arctan, for + * converting rectangular coordinates (x, y) to polar + * (r, theta). This computes the arctangent of x/y in the range + * of -pi to pi radians (-180 to 180 degrees). Special cases:

      + *
    • If either argument is NaN, the result is NaN.
    • + *
    • If the first argument is positive zero and the second argument is + * positive, or the first argument is positive and finite and the second + * argument is positive infinity, then the result is positive zero.
    • + *
    • If the first argument is negative zero and the second argument is + * positive, or the first argument is negative and finite and the second + * argument is positive infinity, then the result is negative zero.
    • + *
    • If the first argument is positive zero and the second argument is + * negative, or the first argument is positive and finite and the second + * argument is negative infinity, then the result is the double value + * closest to pi.
    • + *
    • If the first argument is negative zero and the second argument is + * negative, or the first argument is negative and finite and the second + * argument is negative infinity, then the result is the double value + * closest to -pi.
    • + *
    • If the first argument is positive and the second argument is + * positive zero or negative zero, or the first argument is positive + * infinity and the second argument is finite, then the result is the + * double value closest to pi/2.
    • + *
    • If the first argument is negative and the second argument is + * positive zero or negative zero, or the first argument is negative + * infinity and the second argument is finite, then the result is the + * double value closest to -pi/2.
    • + *
    • If both arguments are positive infinity, then the result is the + * double value closest to pi/4.
    • + *
    • If the first argument is positive infinity and the second argument + * is negative infinity, then the result is the double value closest to + * 3*pi/4.
    • + *
    • If the first argument is negative infinity and the second argument + * is positive infinity, then the result is the double value closest to + * -pi/4.
    • + *
    • If both arguments are negative infinity, then the result is the + * double value closest to -3*pi/4.
    • + * + *

    This is accurate within 2 ulps, and is semi-monotonic. To get r, + * use sqrt(x*x+y*y). + * + * @param y the y position + * @param x the x position + * @return theta in the conversion of (x, y) to (r, theta) + * @see #atan(double) + */ + public static native double atan2(double y, double x); + + /** + * Take ea. The opposite of log(). If the + * argument is NaN, the result is NaN; if the argument is positive infinity, + * the result is positive infinity; and if the argument is negative + * infinity, the result is positive zero. This is accurate within 1 ulp, + * and is semi-monotonic. + * + * @param a the number to raise to the power + * @return the number raised to the power of e + * @see #log(double) + * @see #pow(double, double) + */ + public static native double exp(double a); + + /** + * Take ln(a) (the natural log). The opposite of exp(). If the + * argument is NaN or negative, the result is NaN; if the argument is + * positive infinity, the result is positive infinity; and if the argument + * is either zero, the result is negative infinity. This is accurate within + * 1 ulp, and is semi-monotonic. + * + *

    Note that the way to get logb(a) is to do this: + * ln(a) / ln(b). + * + * @param a the number to take the natural log of + * @return the natural log of a + * @see #exp(double) + */ + public static native double log(double a); + + /** + * Take a square root. If the argument is NaN or negative, the result is + * NaN; if the argument is positive infinity, the result is positive + * infinity; and if the result is either zero, the result is the same. + * This is accurate within the limits of doubles. + * + *

    For other roots, use pow(a, 1 / rootNumber). + * + * @param a the numeric argument + * @return the square root of the argument + * @see #pow(double, double) + */ + public static native double sqrt(double a); + + /** + * Raise a number to a power. Special cases:

      + *
    • If the second argument is positive or negative zero, then the result + * is 1.0.
    • + *
    • If the second argument is 1.0, then the result is the same as the + * first argument.
    • + *
    • If the second argument is NaN, then the result is NaN.
    • + *
    • If the first argument is NaN and the second argument is nonzero, + * then the result is NaN.
    • + *
    • If the absolute value of the first argument is greater than 1 and + * the second argument is positive infinity, or the absolute value of the + * first argument is less than 1 and the second argument is negative + * infinity, then the result is positive infinity.
    • + *
    • If the absolute value of the first argument is greater than 1 and + * the second argument is negative infinity, or the absolute value of the + * first argument is less than 1 and the second argument is positive + * infinity, then the result is positive zero.
    • + *
    • If the absolute value of the first argument equals 1 and the second + * argument is infinite, then the result is NaN.
    • + *
    • If the first argument is positive zero and the second argument is + * greater than zero, or the first argument is positive infinity and the + * second argument is less than zero, then the result is positive zero.
    • + *
    • If the first argument is positive zero and the second argument is + * less than zero, or the first argument is positive infinity and the + * second argument is greater than zero, then the result is positive + * infinity.
    • + *
    • If the first argument is negative zero and the second argument is + * greater than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is less than zero but not a + * finite odd integer, then the result is positive zero.
    • + *
    • If the first argument is negative zero and the second argument is a + * positive finite odd integer, or the first argument is negative infinity + * and the second argument is a negative finite odd integer, then the result + * is negative zero.
    • + *
    • If the first argument is negative zero and the second argument is + * less than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is greater than zero but not a + * finite odd integer, then the result is positive infinity.
    • + *
    • If the first argument is negative zero and the second argument is a + * negative finite odd integer, or the first argument is negative infinity + * and the second argument is a positive finite odd integer, then the result + * is negative infinity.
    • + *
    • If the first argument is less than zero and the second argument is a + * finite even integer, then the result is equal to the result of raising + * the absolute value of the first argument to the power of the second + * argument.
    • + *
    • If the first argument is less than zero and the second argument is a + * finite odd integer, then the result is equal to the negative of the + * result of raising the absolute value of the first argument to the power + * of the second argument.
    • + *
    • If the first argument is finite and less than zero and the second + * argument is finite and not an integer, then the result is NaN.
    • + *
    • If both arguments are integers, then the result is exactly equal to + * the mathematical result of raising the first argument to the power of + * the second argument if that result can in fact be represented exactly as + * a double value.
    • + * + *

    (In the foregoing descriptions, a floating-point value is + * considered to be an integer if and only if it is a fixed point of the + * method {@link #ceil(double)} or, equivalently, a fixed point of the + * method {@link #floor(double)}. A value is a fixed point of a one-argument + * method if and only if the result of applying the method to the value is + * equal to the value.) This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the number to raise + * @param b the power to raise it to + * @return ab + */ + public static native double pow(double a, double b); + + /** + * Get the IEEE 754 floating point remainder on two numbers. This is the + * value of x - y * n, where n is the closest + * double to x / y (ties go to the even n); for a zero + * remainder, the sign is that of x. If either argument is NaN, + * the first argument is infinite, or the second argument is zero, the result + * is NaN; if x is finite but y is infinite, the result is x. This is + * accurate within the limits of doubles. + * + * @param x the dividend (the top half) + * @param y the divisor (the bottom half) + * @return the IEEE 754-defined floating point remainder of x/y + * @see #rint(double) + */ + public static native double IEEEremainder(double x, double y); + + /** + * Take the nearest integer that is that is greater than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same; if the argument is between -1 and 0, the result is negative zero. + * Note that Math.ceil(x) == -Math.floor(-x). + * + * @param a the value to act upon + * @return the nearest integer >= a + */ + public static native double ceil(double a); + + /** + * Take the nearest integer that is that is less than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same. Note that Math.ceil(x) == -Math.floor(-x). + * + * @param a the value to act upon + * @return the nearest integer <= a + */ + public static native double floor(double a); + + /** + * Take the nearest integer to the argument. If it is exactly between + * two integers, the even integer is taken. If the argument is NaN, + * infinite, or zero, the result is the same. + * + * @param a the value to act upon + * @return the nearest integer to a + */ + public static native double rint(double a); + + /** + * Take the nearest integer to the argument. This is equivalent to + * (int) Math.floor(a + 0.5f). If the argument is NaN, the result + * is 0; otherwise if the argument is outside the range of int, the result + * will be Integer.MIN_VALUE or Integer.MAX_VALUE, as appropriate. + * + * @param a the argument to round + * @return the nearest integer to the argument + * @see Integer#MIN_VALUE + * @see Integer#MAX_VALUE + */ + public static int round(float a) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return 0; + return (int) floor(a + 0.5f); + } + + /** + * Take the nearest long to the argument. This is equivalent to + * (long) Math.floor(a + 0.5). If the argument is NaN, the + * result is 0; otherwise if the argument is outside the range of long, the + * result will be Long.MIN_VALUE or Long.MAX_VALUE, as appropriate. + * + * @param a the argument to round + * @return the nearest long to the argument + * @see Long#MIN_VALUE + * @see Long#MAX_VALUE + */ + public static long round(double a) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return 0; + return (long) floor(a + 0.5d); + } + + /** + * Get a random number. This behaves like Random.nextDouble(), seeded by + * System.currentTimeMillis() when first called. In other words, the number + * is from a pseudorandom sequence, and lies in the range [+0.0, 1.0). + * This random sequence is only used by this method, and is threadsafe, + * although you may want your own random number generator if it is shared + * among threads. + * + * @return a random number + * @see Random#nextDouble() + * @see System#currentTimeMillis() + */ + public static synchronized double random() + { + if (rand == null) + rand = new Random(); + return rand.nextDouble(); + } + + /** + * Convert from degrees to radians. The formula for this is + * radians = degrees * (pi/180); however it is not always exact given the + * limitations of floating point numbers. + * + * @param degrees an angle in degrees + * @return the angle in radians + * @since 1.2 + */ + public static double toRadians(double degrees) + { + return (degrees * PI) / 180; + } + + /** + * Convert from radians to degrees. The formula for this is + * degrees = radians * (180/pi); however it is not always exact given the + * limitations of floating point numbers. + * + * @param rads an angle in radians + * @return the angle in degrees + * @since 1.2 + */ + public static double toDegrees(double rads) + { + return (rads * 180) / PI; + } +} diff --git a/libjava/classpath/java/lang/NegativeArraySizeException.java b/libjava/classpath/java/lang/NegativeArraySizeException.java new file mode 100644 index 0000000..fcfa52e --- /dev/null +++ b/libjava/classpath/java/lang/NegativeArraySizeException.java @@ -0,0 +1,77 @@ +/* NegativeArraySizeException.java -- thrown on attempt to create array + with a negative size + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when an attempt is made to create an array with a negative + * size. For example:
    + *

    + * int i = -1;
    + * int[] array = new int[i];
    + * 
    + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class NegativeArraySizeException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -8960118058596991861L; + + /** + * Create an exception without a message. + */ + public NegativeArraySizeException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public NegativeArraySizeException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/NoClassDefFoundError.java b/libjava/classpath/java/lang/NoClassDefFoundError.java new file mode 100644 index 0000000..7e8e6ca --- /dev/null +++ b/libjava/classpath/java/lang/NoClassDefFoundError.java @@ -0,0 +1,76 @@ +/* NoClassDefFoundError.java -- thrown when a ClassLoader cannot find a class + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * A NoClassDefFoundError is thrown when a classloader or the + * Java Virtual Machine tries to load a class and no definition of the class + * can be found. This could happen when using the new expression + * or during a normal method call. The reason this would occur at runtime is + * because the missing class definition existed when the currently executing + * class was compiled, but now that definition cannot be found. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class NoClassDefFoundError extends LinkageError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 9095859863287012458L; + + /** + * Create an error without a message. + */ + public NoClassDefFoundError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public NoClassDefFoundError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/NoSuchFieldError.java b/libjava/classpath/java/lang/NoSuchFieldError.java new file mode 100644 index 0000000..af42e35 --- /dev/null +++ b/libjava/classpath/java/lang/NoSuchFieldError.java @@ -0,0 +1,74 @@ +/* NoSuchFieldError.java -- thrown when the linker does not find a field + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * A NoSuchFieldError is thrown if an application attempts + * to access a field of a class, and that class no longer has that field. + * This is normally detected by the compiler, so it signals that you are + * using binary incompatible class versions. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class NoSuchFieldError extends IncompatibleClassChangeError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -3456430195886129035L; + + /** + * Create an error without a message. + */ + public NoSuchFieldError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public NoSuchFieldError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/NoSuchFieldException.java b/libjava/classpath/java/lang/NoSuchFieldException.java new file mode 100644 index 0000000..74d52d1 --- /dev/null +++ b/libjava/classpath/java/lang/NoSuchFieldException.java @@ -0,0 +1,73 @@ +/* NoSuchFieldException.java -- thrown when reflecting a non-existant field + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown to indicate the class does not have the specified field. This is + * caused by a variety of reflection methods, when looking up a field by name. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class NoSuchFieldException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -6143714805279938260L; + + /** + * Create an exception without a message. + */ + public NoSuchFieldException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public NoSuchFieldException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/NoSuchMethodError.java b/libjava/classpath/java/lang/NoSuchMethodError.java new file mode 100644 index 0000000..2bda776 --- /dev/null +++ b/libjava/classpath/java/lang/NoSuchMethodError.java @@ -0,0 +1,74 @@ +/* NoSuchMethodError.java -- thrown when the linker does not find a method + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * A NoSuchMethodError is thrown if an application attempts + * to access a method of a class, and that class no longer has that method. + * This is normally detected by the compiler, so it signals that you are + * using binary incompatible class versions. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class NoSuchMethodError extends IncompatibleClassChangeError +{ + /** + * Compatible with JDK 1.0+. + */ + static final long serialVersionUID = -3765521442372831335L; + + /** + * Create an error without a message. + */ + public NoSuchMethodError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public NoSuchMethodError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/NoSuchMethodException.java b/libjava/classpath/java/lang/NoSuchMethodException.java new file mode 100644 index 0000000..e423efb --- /dev/null +++ b/libjava/classpath/java/lang/NoSuchMethodException.java @@ -0,0 +1,72 @@ +/* NoSuchMethodException.java -- thrown when reflecting a non-existant method + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown to indicate the class does not have the specified method. This is + * caused by a variety of reflection methods, when looking up a method by name. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class NoSuchMethodException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 5034388446362600923L; + + /** + * Create an exception without a message. + */ + public NoSuchMethodException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public NoSuchMethodException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/NullPointerException.java b/libjava/classpath/java/lang/NullPointerException.java new file mode 100644 index 0000000..29a4ee0 --- /dev/null +++ b/libjava/classpath/java/lang/NullPointerException.java @@ -0,0 +1,82 @@ +/* NullPointerException.java -- thrown when using null instead of an object + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when attempting to use null where an object + * is required. The Virtual Machine automatically throws this exception + * for the following:
      + *
    • Calling an instance method on a null object
    • + *
    • Accessing or modifying a field of a null object
    • + *
    • Taking the array length of a null array
    • + *
    • Accessing or modifying the slots of a null array
    • + *
    • Throwing a null Throwable
    • + *
    • Synchronizing on a null object
    • + *
    + *

    Applications should also throw NullPointerExceptions whenever + * null is an inappropriate parameter to a method. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class NullPointerException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 5162710183389028792L; + + /** + * Create an exception without a message. + */ + public NullPointerException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public NullPointerException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/Number.java b/libjava/classpath/java/lang/Number.java new file mode 100644 index 0000000..eb81f78 --- /dev/null +++ b/libjava/classpath/java/lang/Number.java @@ -0,0 +1,131 @@ +/* Number.java =- abstract superclass of numeric objects + Copyright (C) 1998, 2001, 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 java.lang; + +import java.io.Serializable; + +/** + * Number is a generic superclass of all the numeric classes, including + * the wrapper classes {@link Byte}, {@link Short}, {@link Integer}, + * {@link Long}, {@link Float}, and {@link Double}. Also worth mentioning + * are the classes in {@link java.math}. + * + * It provides ways to convert numeric objects to any primitive. + * + * @author Paul Fisher + * @author John Keiser + * @author Warren Levy + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public abstract class Number implements Serializable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -8742448824652078965L; + + /** + * Table for calculating digits, used in Character, Long, and Integer. + */ + static final char[] digits = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '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', + }; + + /** + * The basic constructor (often called implicitly). + */ + public Number() + { + } + + /** + * Return the value of this Number as an int. + * + * @return the int value + */ + public abstract int intValue(); + + /** + * Return the value of this Number as a long. + * + * @return the long value + */ + public abstract long longValue(); + + /** + * Return the value of this Number as a float. + * + * @return the float value + */ + public abstract float floatValue(); + + /** + * Return the value of this Number as a float. + * + * @return the double value + */ + public abstract double doubleValue(); + + /** + * Return the value of this Number as a byte. + * + * @return the byte value + * @since 1.1 + */ + public byte byteValue() + { + return (byte) intValue(); + } + + /** + * Return the value of this Number as a short. + * + * @return the short value + * @since 1.1 + */ + public short shortValue() + { + return (short) intValue(); + } +} diff --git a/libjava/classpath/java/lang/NumberFormatException.java b/libjava/classpath/java/lang/NumberFormatException.java new file mode 100644 index 0000000..bf98156 --- /dev/null +++ b/libjava/classpath/java/lang/NumberFormatException.java @@ -0,0 +1,73 @@ +/* NumberFormatException.java -- thrown when parsing a bad string as a number + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Can be thrown when attempting to convert a String to + * one of the numeric types, but the operation fails because the string + * has the wrong format. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class NumberFormatException extends IllegalArgumentException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -2848938806368998894L; + + /** + * Create an exception without a message. + */ + public NumberFormatException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public NumberFormatException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/Object.java b/libjava/classpath/java/lang/Object.java new file mode 100644 index 0000000..f8c389a --- /dev/null +++ b/libjava/classpath/java/lang/Object.java @@ -0,0 +1,530 @@ +/* java.lang.Object - The universal superclass in Java + Copyright (C) 1998, 1999, 2000, 2001, 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 java.lang; + + +/** + * Object is the ultimate superclass of every class + * (excepting interfaces). When you define a class that + * does not extend any other class, it implicitly extends + * java.lang.Object. Also, an anonymous class based on + * an interface will extend Object. + * + *

    It provides general-purpose methods that every single + * Object, regardless of race, sex or creed, implements. + * All of the public methods may be invoked on arrays or + * interfaces. The protected methods clone + * and finalize are not accessible on arrays + * or interfaces, but all array types have a public version + * of clone which is accessible. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class Object +{ + // WARNING: Object is a CORE class in the bootstrap cycle. See the comments + // in vm/reference/java/lang/Runtime for implications of this fact. + + // Many JVMs do not allow for static initializers in this class, + // hence we do not use them in the default implementation. + + // Some VM's rely on the order that these methods appear when laying + // out their internal structure. Therefore, do not haphazardly + // rearrange these methods. + + /** + * The basic constructor. Object is special, because it has no + * superclass, so there is no call to super(). + * + * @throws OutOfMemoryError Technically, this constructor never + * throws an OutOfMemoryError, because the memory has + * already been allocated by this point. But as all + * instance creation expressions eventually trace back + * to this constructor, and creating an object allocates + * memory, we list that possibility here. + */ + // This could be implicit, but then javadoc would not document it! + public Object() {} + + /** + * Determine whether this Object is semantically equal + * to another Object. + * + *

    There are some fairly strict requirements on this + * method which subclasses must follow:
    + *

      + *
    • It must be transitive. If a.equals(b) and + * b.equals(c), then a.equals(c) + * must be true as well.
    • + *
    • It must be symmetric. a.equals(b) and + * b.equals(a) must have the same value.
    • + *
    • It must be reflexive. a.equals(a) must + * always be true.
    • + *
    • It must be consistent. Whichever value a.equals(b) + * returns on the first invocation must be the value + * returned on all later invocations.
    • + *
    • a.equals(null) must be false.
    • + *
    • It must be consistent with hashCode(). That is, + * a.equals(b) must imply + * a.hashCode() == b.hashCode(). + * The reverse is not true; two objects that are not + * equal may have the same hashcode, but that has + * the potential to harm hashing performance.
    • + *
    + * + *

    This is typically overridden to throw a {@link ClassCastException} + * if the argument is not comparable to the class performing + * the comparison, but that is not a requirement. It is legal + * for a.equals(b) to be true even though + * a.getClass() != b.getClass(). Also, it + * is typical to never cause a {@link NullPointerException}. + * + *

    In general, the Collections API ({@link java.util}) use the + * equals method rather than the == + * operator to compare objects. However, {@link java.util.IdentityHashMap} + * is an exception to this rule, for its own good reasons. + * + *

    The default implementation returns this == o. + * + * @param obj the Object to compare to + * @return whether this Object is semantically equal to another + * @see #hashCode() + */ + public boolean equals(Object obj) + { + return this == obj; + } + + /** + * Get a value that represents this Object, as uniquely as + * possible within the confines of an int. + * + *

    There are some requirements on this method which + * subclasses must follow:
    + * + *

      + *
    • Semantic equality implies identical hashcodes. In other + * words, if a.equals(b) is true, then + * a.hashCode() == b.hashCode() must be as well. + * However, the reverse is not necessarily true, and two + * objects may have the same hashcode without being equal.
    • + *
    • It must be consistent. Whichever value o.hashCode() + * returns on the first invocation must be the value + * returned on all later invocations as long as the object + * exists. Notice, however, that the result of hashCode may + * change between separate executions of a Virtual Machine, + * because it is not invoked on the same object.
    • + *
    + * + *

    Notice that since hashCode is used in + * {@link java.util.Hashtable} and other hashing classes, + * a poor implementation will degrade the performance of hashing + * (so don't blindly implement it as returning a constant!). Also, + * if calculating the hash is time-consuming, a class may consider + * caching the results. + * + *

    The default implementation returns + * System.identityHashCode(this) + * + * @return the hash code for this Object + * @see #equals(Object) + * @see System#identityHashCode(Object) + */ + public int hashCode() + { + return System.identityHashCode(this); + } + + /** + * Convert this Object to a human-readable String. + * There are no limits placed on how long this String + * should be or what it should contain. We suggest you + * make it as intuitive as possible to be able to place + * it into {@link java.io.PrintStream#println() System.out.println()} + * and such. + * + *

    It is typical, but not required, to ensure that this method + * never completes abruptly with a {@link RuntimeException}. + * + *

    This method will be called when performing string + * concatenation with this object. If the result is + * null, string concatenation will instead + * use "null". + * + *

    The default implementation returns + * getClass().getName() + "@" + + * Integer.toHexString(hashCode()). + * + * @return the String representing this Object, which may be null + * @throws OutOfMemoryError The default implementation creates a new + * String object, therefore it must allocate memory + * @see #getClass() + * @see #hashCode() + * @see Class#getName() + * @see Integer#toHexString(int) + */ + public String toString() + { + return getClass().getName() + '@' + Integer.toHexString(hashCode()); + } + + /** + * Called on an object by the Virtual Machine at most once, + * at some point after the Object is determined unreachable + * but before it is destroyed. You would think that this + * means it eventually is called on every Object, but this is + * not necessarily the case. If execution terminates + * abnormally, garbage collection does not always happen. + * Thus you cannot rely on this method to always work. + * For finer control over garbage collection, use references + * from the {@link java.lang.ref} package. + * + *

    Virtual Machines are free to not call this method if + * they can determine that it does nothing important; for + * example, if your class extends Object and overrides + * finalize to do simply super.finalize(). + * + *

    finalize() will be called by a {@link Thread} that has no + * locks on any Objects, and may be called concurrently. + * There are no guarantees on the order in which multiple + * objects are finalized. This means that finalize() is + * usually unsuited for performing actions that must be + * thread-safe, and that your implementation must be + * use defensive programming if it is to always work. + * + *

    If an Exception is thrown from finalize() during garbage + * collection, it will be patently ignored and the Object will + * still be destroyed. + * + *

    It is allowed, although not typical, for user code to call + * finalize() directly. User invocation does not affect whether + * automatic invocation will occur. It is also permitted, + * although not recommended, for a finalize() method to "revive" + * an object by making it reachable from normal code again. + * + *

    Unlike constructors, finalize() does not get called + * for an object's superclass unless the implementation + * specifically calls super.finalize(). + * + *

    The default implementation does nothing. + * + * @throws Throwable permits a subclass to throw anything in an + * overridden version; but the default throws nothing + * @see System#gc() + * @see System#runFinalizersOnExit(boolean) + * @see java.lang.ref + */ + protected void finalize() throws Throwable + { + } + + /** + * This method may be called to create a new copy of the + * Object. The typical behavior is as follows:
    + *

      + *
    • o == o.clone() is false
    • + *
    • o.getClass() == o.clone().getClass() + * is true
    • + *
    • o.equals(o) is true
    • + *
    + * + *

    However, these are not strict requirements, and may + * be violated if necessary. Of the three requirements, the + * last is the most commonly violated, particularly if the + * subclass does not override {@link #equals(Object)}. + * + *

    If the Object you call clone() on does not implement + * {@link Cloneable} (which is a placeholder interface), then + * a CloneNotSupportedException is thrown. Notice that + * Object does not implement Cloneable; this method exists + * as a convenience for subclasses that do. + * + *

    Object's implementation of clone allocates space for the + * new Object using the correct class, without calling any + * constructors, and then fills in all of the new field values + * with the old field values. Thus, it is a shallow copy. + * However, subclasses are permitted to make a deep copy. + * + *

    All array types implement Cloneable, and override + * this method as follows (it should never fail):
    + *

    +   * public Object clone()
    +   * {
    +   *   try
    +   *     {
    +   *       super.clone();
    +   *     }
    +   *   catch (CloneNotSupportedException e)
    +   *     {
    +   *       throw new InternalError(e.getMessage());
    +   *     }
    +   * }
    +   * 
    + * + * @return a copy of the Object + * @throws CloneNotSupportedException If this Object does not + * implement Cloneable + * @throws OutOfMemoryError Since cloning involves memory allocation, + * even though it may bypass constructors, you might run + * out of memory + * @see Cloneable + */ + protected Object clone() throws CloneNotSupportedException + { + if (this instanceof Cloneable) + return VMObject.clone((Cloneable) this); + throw new CloneNotSupportedException("Object not cloneable"); + } + + /** + * Returns the runtime {@link Class} of this Object. + * + *

    The class object can also be obtained without a runtime + * instance by using the class literal, as in: + * Foo.class. Notice that the class literal + * also works on primitive types, making it useful for + * reflection purposes. + * + * @return the class of this Object + */ + public final Class getClass() + { + return VMObject.getClass(this); + } + + /** + * Wakes up one of the {@link Thread}s that has called + * wait on this Object. Only the owner + * of a lock on this Object may call this method. This lock + * is obtained by a synchronized method or statement. + * + *

    The Thread to wake up is chosen arbitrarily. The + * awakened thread is not guaranteed to be the next thread + * to actually obtain the lock on this object. + * + *

    This thread still holds a lock on the object, so it is + * typical to release the lock by exiting the synchronized + * code, calling wait(), or calling {@link Thread#sleep()}, so + * that the newly awakened thread can actually resume. The + * awakened thread will most likely be awakened with an + * {@link InterruptedException}, but that is not guaranteed. + * + * @throws IllegalMonitorStateException if this Thread + * does not own the lock on the Object + * @see #notifyAll() + * @see #wait() + * @see #wait(long) + * @see #wait(long, int) + * @see Thread + */ + public final void notify() throws IllegalMonitorStateException + { + VMObject.notify(this); + } + + /** + * Wakes up all of the {@link Thread}s that have called + * wait on this Object. Only the owner + * of a lock on this Object may call this method. This lock + * is obtained by a synchronized method or statement. + * + *

    There are no guarantees as to which thread will next + * obtain the lock on the object. + * + *

    This thread still holds a lock on the object, so it is + * typical to release the lock by exiting the synchronized + * code, calling wait(), or calling {@link Thread#sleep()}, so + * that one of the newly awakened threads can actually resume. + * The resuming thread will most likely be awakened with an + * {@link InterruptedException}, but that is not guaranteed. + * + * @throws IllegalMonitorStateException if this Thread + * does not own the lock on the Object + * @see #notify() + * @see #wait() + * @see #wait(long) + * @see #wait(long, int) + * @see Thread + */ + public final void notifyAll() throws IllegalMonitorStateException + { + VMObject.notifyAll(this); + } + + /** + * Waits indefinitely for notify() or notifyAll() to be + * called on the Object in question. Implementation is + * identical to wait(0). + * + *

    The Thread that calls wait must have a lock on this Object, + * obtained by a synchronized method or statement. + * After calling wait, the thread loses the lock on this + * object until the method completes (abruptly or normally), + * at which time it regains the lock. All locks held on + * other objects remain in force, even though the thread is + * inactive. Therefore, caution must be used to avoid deadlock. + * + *

    While it is typical that this method will complete abruptly + * with an {@link InterruptedException}, it is not guaranteed. So, + * it is typical to call wait inside an infinite loop:
    + * + *

    +   * try
    +   *   {
    +   *     while (true)
    +   *       lock.wait();
    +   *   }
    +   * catch (InterruptedException e)
    +   *   {
    +   *   }
    +   * 
    + * + * @throws IllegalMonitorStateException if this Thread + * does not own a lock on this Object + * @throws InterruptedException if some other Thread + * interrupts this Thread + * @see #notify() + * @see #notifyAll() + * @see #wait(long) + * @see #wait(long, int) + * @see Thread + */ + public final void wait() + throws IllegalMonitorStateException, InterruptedException + { + VMObject.wait(this, 0, 0); + } + + /** + * Waits a specified amount of time (or indefinitely if + * the time specified is 0) for someone to call notify() + * or notifyAll() on this Object, waking up this Thread. + * + *

    The Thread that calls wait must have a lock on this Object, + * obtained by a synchronized method or statement. + * After calling wait, the thread loses the lock on this + * object until the method completes (abruptly or normally), + * at which time it regains the lock. All locks held on + * other objects remain in force, even though the thread is + * inactive. Therefore, caution must be used to avoid deadlock. + * + *

    Usually, this call will complete normally if the time + * expires, or abruptly with {@link InterruptedException} + * if another thread called notify, but neither result + * is guaranteed. + * + *

    The waiting period is only *roughly* the amount of time + * you requested. It cannot be exact because of the overhead + * of the call itself. Most Virtual Machiness treat the + * argument as a lower limit on the time spent waiting, but + * even that is not guaranteed. Besides, some other thread + * may hold the lock on the object when the time expires, so + * the current thread may still have to wait to reobtain the + * lock. + * + * @param ms the minimum number of milliseconds to wait (1000 + * milliseconds = 1 second), or 0 for an indefinite wait + * @throws IllegalArgumentException if ms < 0 + * @throws IllegalMonitorStateException if this Thread + * does not own a lock on this Object + * @throws InterruptedException if some other Thread + * interrupts this Thread + * @see #notify() + * @see #notifyAll() + * @see #wait() + * @see #wait(long, int) + * @see Thread + */ + public final void wait(long ms) + throws IllegalMonitorStateException, InterruptedException + { + wait(ms, 0); + } + + /** + * Waits a specified amount of time (or indefinitely if + * the time specified is 0) for someone to call notify() + * or notifyAll() on this Object, waking up this Thread. + * + *

    The Thread that calls wait must have a lock on this Object, + * obtained by a synchronized method or statement. + * After calling wait, the thread loses the lock on this + * object until the method completes (abruptly or normally), + * at which time it regains the lock. All locks held on + * other objects remain in force, even though the thread is + * inactive. Therefore, caution must be used to avoid deadlock. + * + *

    Usually, this call will complete normally if the time + * expires, or abruptly with {@link InterruptedException} + * if another thread called notify, but neither result + * is guaranteed. + * + *

    The waiting period is nowhere near as precise as + * nanoseconds; considering that even wait(int) is inaccurate, + * how much can you expect? But on supporting + * implementations, this offers somewhat more granularity + * than milliseconds. + * + * @param ms the number of milliseconds to wait (1,000 + * milliseconds = 1 second) + * @param ns the number of nanoseconds to wait over and + * above ms (1,000,000 nanoseconds = 1 millisecond) + * @throws IllegalArgumentException if ms < 0 or ns is not + * in the range 0 to 999,999 + * @throws IllegalMonitorStateException if this Thread + * does not own a lock on this Object + * @throws InterruptedException if some other Thread + * interrupts this Thread + * @see #notify() + * @see #notifyAll() + * @see #wait() + * @see #wait(long) + * @see Thread + */ + public final void wait(long ms, int ns) + throws IllegalMonitorStateException, InterruptedException + { + if (ms < 0 || ns < 0 || ns > 999999) + throw new IllegalArgumentException("argument out of range"); + VMObject.wait(this, ms, ns); + } +} // class Object diff --git a/libjava/classpath/java/lang/OutOfMemoryError.java b/libjava/classpath/java/lang/OutOfMemoryError.java new file mode 100644 index 0000000..66da563 --- /dev/null +++ b/libjava/classpath/java/lang/OutOfMemoryError.java @@ -0,0 +1,73 @@ +/* OutOfMemoryError.java -- thrown when a memory allocation fails + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Thrown when the Java Virtual Machine is unable to allocate an object + * because it is out of memory and no more memory could be made available + * by the garbage collector. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class OutOfMemoryError extends VirtualMachineError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 8228564086184010517L; + + /** + * Create an error without a message. + */ + public OutOfMemoryError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public OutOfMemoryError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/Package.java b/libjava/classpath/java/lang/Package.java new file mode 100644 index 0000000..4cded0a --- /dev/null +++ b/libjava/classpath/java/lang/Package.java @@ -0,0 +1,318 @@ +/* Package.java -- information about a package + Copyright (C) 2000, 2001, 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 java.lang; + +import gnu.classpath.VMStackWalker; + +import java.net.URL; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + + +/** + * Everything you ever wanted to know about a package. This class makes it + * possible to attach specification and implementation information to a + * package as explained in the + * Package Versioning Specification + * section of the + * Product Versioning Specification. + * It also allows packages to be sealed with respect to the originating URL. + * + *

    The most useful method is the isCompatibleWith() method that + * compares a desired version of a specification with the version of the + * specification as implemented by a package. A package is considered + * compatible with another version if the version of the specification is + * equal or higher then the requested version. Version numbers are represented + * as strings of positive numbers separated by dots (e.g. "1.2.0"). + * The first number is called the major number, the second the minor, + * the third the micro, etc. A version is considered higher then another + * version if it has a bigger major number then the another version or when + * the major numbers of the versions are equal if it has a bigger minor number + * then the other version, etc. (If a version has no minor, micro, etc numbers + * then they are considered the be 0.) + * + * @author Mark Wielaard (mark@klomp.org) + * @see ClassLoader#definePackage(String, String, String, String, String, + * String, String, URL) + * @since 1.2 + * @status updated to 1.4 + */ +public class Package +{ + /** The name of the Package */ + private final String name; + + /** The name if the implementation */ + private final String implTitle; + + /** The vendor that wrote this implementation */ + private final String implVendor; + + /** The version of this implementation */ + private final String implVersion; + + /** The name of the specification */ + private final String specTitle; + + /** The name of the specification designer */ + private final String specVendor; + + /** The version of this specification */ + private final String specVersion; + + /** If sealed the origin of the package classes, otherwise null */ + private final URL sealed; + + /** + * A package local constructor for the Package class. All parameters except + * the name of the package may be null. + * There are no public constructors defined for Package; this is a package + * local constructor that is used by java.lang.Classloader.definePackage(). + * + * @param name The name of the Package + * @param specTitle The name of the specification + * @param specVendor The name of the specification designer + * @param specVersion The version of this specification + * @param implTitle The name of the implementation + * @param implVendor The vendor that wrote this implementation + * @param implVersion The version of this implementation + * @param sealed If sealed the origin of the package classes + */ + Package(String name, + String specTitle, String specVendor, String specVersion, + String implTitle, String implVendor, String implVersion, URL sealed) + { + if (name == null) + throw new IllegalArgumentException("null Package name"); + + this.name = name; + this.implTitle = implTitle; + this.implVendor = implVendor; + this.implVersion = implVersion; + this.specTitle = specTitle; + this.specVendor = specVendor; + this.specVersion = specVersion; + this.sealed = sealed; + } + + /** + * Returns the Package name in dot-notation. + * + * @return the non-null package name + */ + public String getName() + { + return name; + } + + /** + * Returns the name of the specification, or null if unknown. + * + * @return the specification title + */ + public String getSpecificationTitle() + { + return specTitle; + } + + /** + * Returns the version of the specification, or null if unknown. + * + * @return the specification version + */ + public String getSpecificationVersion() + { + return specVersion; + } + + /** + * Returns the name of the specification designer, or null if unknown. + * + * @return the specification vendor + */ + public String getSpecificationVendor() + { + return specVendor; + } + + /** + * Returns the name of the implementation, or null if unknown. + * + * @return the implementation title + */ + public String getImplementationTitle() + { + return implTitle; + } + + /** + * Returns the version of this implementation, or null if unknown. + * + * @return the implementation version + */ + public String getImplementationVersion() + { + return implVersion; + } + + /** + * Returns the vendor that wrote this implementation, or null if unknown. + * + * @return the implementation vendor + */ + public String getImplementationVendor() + { + return implVendor; + } + + /** + * Returns true if this Package is sealed. + * + * @return true if the package is sealed + */ + public boolean isSealed() + { + return sealed != null; + } + + /** + * Returns true if this Package is sealed and the origin of the classes is + * the given URL. + * + * @param url the URL to test + * @return true if the package is sealed by this URL + * @throws NullPointerException if url is null + */ + public boolean isSealed(URL url) + { + return url.equals(sealed); + } + + /** + * Checks if the version of the specification is higher or at least as high + * as the desired version. Comparison is done by sequentially comparing + * dotted decimal numbers from the parameter and from + * getSpecificationVersion. + * + * @param version the (minimal) desired version of the specification + * + * @return true if the version is compatible, false otherwise + * + * @Throws NumberFormatException if either version string is invalid + * @throws NullPointerException if either version string is null + */ + public boolean isCompatibleWith(String version) + { + StringTokenizer versionTokens = new StringTokenizer(version, "."); + StringTokenizer specTokens = new StringTokenizer(specVersion, "."); + try + { + while (versionTokens.hasMoreElements()) + { + int vers = Integer.parseInt(versionTokens.nextToken()); + int spec = Integer.parseInt(specTokens.nextToken()); + if (spec < vers) + return false; + else if (spec > vers) + return true; + // They must be equal, next Token please! + } + } + catch (NoSuchElementException e) + { + // This must have been thrown by spec.nextToken() so return false. + return false; + } + // They must have been exactly the same version. + // Or the specVersion has more subversions. That is also good. + return true; + } + + /** + * Returns the named package if it is known by the callers class loader. + * It may return null if the package is unknown, when there is no + * information on that particular package available or when the callers + * classloader is null. + * + * @param name the name of the desired package + * @return the package by that name in the current ClassLoader + */ + public static Package getPackage(String name) + { + // Get the caller's classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + return cl != null ? cl.getPackage(name) : VMClassLoader.getPackage(name); + } + + /** + * Returns all the packages that are known to the callers class loader. + * It may return an empty array if the classloader of the caller is null. + * + * @return an array of all known packages + */ + public static Package[] getPackages() + { + // Get the caller's classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + return cl != null ? cl.getPackages() : VMClassLoader.getPackages(); + } + + /** + * Returns the hashCode of the name of this package. + * + * @return the hash code + */ + public int hashCode() + { + return name.hashCode(); + } + + /** + * Returns a string representation of this package. It is specified to + * be "package " + getName() + (getSpecificationTitle() == null + * ? "" : ", " + getSpecificationTitle()) + (getSpecificationVersion() + * == null ? "" : ", version " + getSpecificationVersion()). + * + * @return the string representation of the package + */ + public String toString() + { + return ("package " + name + (specTitle == null ? "" : ", " + specTitle) + + (specVersion == null ? "" : ", version " + specVersion)); + } +} // class Package diff --git a/libjava/classpath/java/lang/Process.java b/libjava/classpath/java/lang/Process.java new file mode 100644 index 0000000..b6e18ca --- /dev/null +++ b/libjava/classpath/java/lang/Process.java @@ -0,0 +1,129 @@ +/* Process.java - Represent spawned system process + Copyright (C) 1998, 1999, 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 java.lang; + +import java.io.InputStream; +import java.io.OutputStream; + +/** + * An instance of a subclass of Process is created by the + * Runtime.exec methods. Methods in Process + * provide a means to send input to a process, obtain the output from a + * subprocess, destroy a subprocess, obtain the exit value from a + * subprocess, and wait for a subprocess to complete. + * + *

    This is dependent on the platform, and some processes (like native + * windowing processes, 16-bit processes in Windows, or shell scripts) may + * be limited in functionality. Because some platforms have limited buffers + * between processes, you may need to provide input and read output to prevent + * the process from blocking, or even deadlocking. + * + *

    Even if all references to this object disapper, the process continues + * to execute to completion. There are no guarantees that the + * subprocess execute asynchronously or concurrently with the process which + * owns this object. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @see Runtime#exec(String[], String[], File) + * @since 1.0 + * @status updated to 1.4 + */ +public abstract class Process +{ + /** + * Empty constructor does nothing. + */ + public Process() + { + } + + /** + * Obtain the output stream that sends data to the subprocess. This is + * the STDIN of the subprocess. When implementing, you should probably + * use a buffered stream. + * + * @return the output stream that pipes to the process input + */ + public abstract OutputStream getOutputStream(); + + /** + * Obtain the input stream that receives data from the subprocess. This is + * the STDOUT of the subprocess. When implementing, you should probably + * use a buffered stream. + * + * @return the input stream that pipes data from the process output + */ + public abstract InputStream getInputStream(); + + /** + * Obtain the input stream that receives data from the subprocess. This is + * the STDERR of the subprocess. When implementing, you should probably + * use a buffered stream. + * + * @return the input stream that pipes data from the process error output + */ + public abstract InputStream getErrorStream(); + + /** + * The thread calling waitFor will block until the subprocess + * has terminated. If the process has already terminated then the method + * immediately returns with the exit value of the subprocess. + * + * @return the subprocess exit value; 0 conventionally denotes success + * @throws InterruptedException if another thread interrupts the blocked one + */ + public abstract int waitFor() throws InterruptedException; + + /** + * When a process terminates there is associated with that termination + * an exit value for the process to indicate why it terminated. A return + * of 0 denotes normal process termination by convention. + * + * @return the exit value of the subprocess + * @throws IllegalThreadStateException if the subprocess has not terminated + */ + public abstract int exitValue(); + + /** + * Kills the subprocess and all of its children forcibly. + */ + public abstract void destroy(); +} // class Process diff --git a/libjava/classpath/java/lang/Readable.java b/libjava/classpath/java/lang/Readable.java new file mode 100644 index 0000000..efc1985 --- /dev/null +++ b/libjava/classpath/java/lang/Readable.java @@ -0,0 +1,71 @@ +/* Readable.java -- A character source + Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.io.IOException; +import java.nio.CharBuffer; + +/** + * A Readable object is simply a source for Unicode character + * data. On request, a Readable will provide its data in + * a supplied CharBuffer. + * + * @author Tom Tromey + * @author Andrew John Hughes + * @since 1.5 + */ +public interface Readable +{ + + /** + * Adds the character data supplied by this Readable + * to the specified character buffer. This method simply places + * each character into the buffer as supplied, using put(), + * without flipping or rewinding. + * + * @param buf the buffer to place the character data in. + * @return the number of char values placed in the buffer, + * or -1 if no more characters are available. + * @throws IOException if an I/O error occurs. + * @throws NullPointerException if buf is null. + * @throws ReadOnlyBufferException if buf is read only. + */ + int read(CharBuffer buf) + throws IOException; + +} diff --git a/libjava/classpath/java/lang/Runnable.java b/libjava/classpath/java/lang/Runnable.java new file mode 100644 index 0000000..32c52b9 --- /dev/null +++ b/libjava/classpath/java/lang/Runnable.java @@ -0,0 +1,62 @@ +/* Runnable -- interface for a method tied to an Object; often for Threads + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * Runnable is an interface you implement to indicate that your class can be + * executed as the main part of a Thread, among other places. When you want + * an entry point to run a piece of code, implement this interface and + * override run. + * + * @author Paul Fisher + * @author Tom Tromey (tromey@cygnus.com) + * @see Thread + * @since 1.0 + * @status updated to 1.4 + */ +public interface Runnable +{ + /** + * This method will be called by whoever wishes to run your class + * implementing Runnable. Note that there are no restrictions on what + * you are allowed to do in the run method, except that you cannot + * throw a checked exception. + */ + void run(); +} diff --git a/libjava/classpath/java/lang/Runtime.java b/libjava/classpath/java/lang/Runtime.java new file mode 100644 index 0000000..64ca5d9 --- /dev/null +++ b/libjava/classpath/java/lang/Runtime.java @@ -0,0 +1,796 @@ +/* Runtime.java -- access to the VM process + Copyright (C) 1998, 2002, 2003, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +import gnu.classpath.SystemProperties; +import gnu.classpath.VMStackWalker; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * Runtime represents the Virtual Machine. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Jeroen Frijters + */ +// No idea why this class isn't final, since you can't build a subclass! +public class Runtime +{ + /** + * The library path, to search when loading libraries. We can also safely use + * this as a lock for synchronization. + */ + private final String[] libpath; + + /** + * The thread that started the exit sequence. Access to this field must + * be thread-safe; lock on libpath to avoid deadlock with user code. + * runFinalization() may want to look at this to see if ALL + * finalizers should be run, because the virtual machine is about to halt. + */ + private Thread exitSequence; + + /** + * All shutdown hooks. This is initialized lazily, and set to null once all + * shutdown hooks have run. Access to this field must be thread-safe; lock + * on libpath to avoid deadlock with user code. + */ + private Set shutdownHooks; + + /** + * The one and only runtime instance. + */ + private static final Runtime current = new Runtime(); + + /** + * Not instantiable by a user, this should only create one instance. + */ + private Runtime() + { + if (current != null) + throw new InternalError("Attempt to recreate Runtime"); + + // If used by underlying VM this contains the directories where Classpath's own + // native libraries are located. + String bootPath = SystemProperties.getProperty("gnu.classpath.boot.library.path", ""); + + // If properly set by the user this contains the directories where the application's + // native libraries are located. On operating systems where a LD_LIBRARY_PATH environment + // variable is available a VM should preset java.library.path with value of this + // variable. + String path = SystemProperties.getProperty("java.library.path", "."); + String pathSep = SystemProperties.getProperty("path.separator", ":"); + String fileSep = SystemProperties.getProperty("file.separator", "/"); + + StringTokenizer t1 = new StringTokenizer(bootPath, pathSep); + StringTokenizer t2 = new StringTokenizer(path, pathSep); + libpath = new String[t1.countTokens() + t2.countTokens()]; + + int i = 0; + while(t1.hasMoreTokens()) { + String prefix = t1.nextToken(); + if (! prefix.endsWith(fileSep)) + prefix += fileSep; + + libpath[i] = prefix; + i++; + } + + while(t2.hasMoreTokens()) { + String prefix = t2.nextToken(); + if (! prefix.endsWith(fileSep)) + prefix += fileSep; + + libpath[i] = prefix; + i++; + } + } + + /** + * Get the current Runtime object for this JVM. This is necessary to access + * the many instance methods of this class. + * + * @return the current Runtime object + */ + public static Runtime getRuntime() + { + return current; + } + + /** + * Exit the Java runtime. This method will either throw a SecurityException + * or it will never return. The status code is returned to the system; often + * a non-zero status code indicates an abnormal exit. Of course, there is a + * security check, checkExit(status). + * + *

    First, all shutdown hooks are run, in unspecified order, and + * concurrently. Next, if finalization on exit has been enabled, all pending + * finalizers are run. Finally, the system calls halt.

    + * + *

    If this is run a second time after shutdown has already started, there + * are two actions. If shutdown hooks are still executing, it blocks + * indefinitely. Otherwise, if the status is nonzero it halts immediately; + * if it is zero, it blocks indefinitely. This is typically called by + * System.exit.

    + * + * @param status the status to exit with + * @throws SecurityException if permission is denied + * @see #addShutdownHook(Thread) + * @see #runFinalizersOnExit(boolean) + * @see #runFinalization() + * @see #halt(int) + */ + public void exit(int status) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExit(status); + + if (runShutdownHooks()) + halt(status); + + // Someone else already called runShutdownHooks(). + // Make sure we are not/no longer in the shutdownHooks set. + // And wait till the thread that is calling runShutdownHooks() finishes. + synchronized (libpath) + { + if (shutdownHooks != null) + { + shutdownHooks.remove(Thread.currentThread()); + // Interrupt the exit sequence thread, in case it was waiting + // inside a join on our thread. + exitSequence.interrupt(); + // Shutdown hooks are still running, so we clear status to + // make sure we don't halt. + status = 0; + } + } + + // If exit() is called again after the shutdown hooks have run, but + // while finalization for exit is going on and the status is non-zero + // we halt immediately. + if (status != 0) + halt(status); + + while (true) + try + { + exitSequence.join(); + } + catch (InterruptedException e) + { + // Ignore, we've suspended indefinitely to let all shutdown + // hooks complete, and to let any non-zero exits through, because + // this is a duplicate call to exit(0). + } + } + + /** + * On first invocation, run all the shutdown hooks and return true. + * Any subsequent invocations will simply return false. + * Note that it is package accessible so that VMRuntime can call it + * when VM exit is not triggered by a call to Runtime.exit(). + * + * @return was the current thread the first one to call this method? + */ + boolean runShutdownHooks() + { + boolean first = false; + synchronized (libpath) // Synch on libpath, not this, to avoid deadlock. + { + if (exitSequence == null) + { + first = true; + exitSequence = Thread.currentThread(); + if (shutdownHooks != null) + { + Iterator i = shutdownHooks.iterator(); + while (i.hasNext()) // Start all shutdown hooks. + try + { + ((Thread) i.next()).start(); + } + catch (IllegalThreadStateException e) + { + i.remove(); + } + } + } + } + if (first) + { + if (shutdownHooks != null) + { + // Check progress of all shutdown hooks. As a hook completes, + // remove it from the set. If a hook calls exit, it removes + // itself from the set, then waits indefinitely on the + // exitSequence thread. Once the set is empty, set it to null to + // signal all finalizer threads that halt may be called. + while (true) + { + Thread[] hooks; + synchronized (libpath) + { + hooks = new Thread[shutdownHooks.size()]; + shutdownHooks.toArray(hooks); + } + if (hooks.length == 0) + break; + for (int i = 0; i < hooks.length; i++) + { + try + { + synchronized (libpath) + { + if (!shutdownHooks.contains(hooks[i])) + continue; + } + hooks[i].join(); + synchronized (libpath) + { + shutdownHooks.remove(hooks[i]); + } + } + catch (InterruptedException x) + { + // continue waiting on the next thread + } + } + } + synchronized (libpath) + { + shutdownHooks = null; + } + } + // Run finalization on all finalizable objects (even if they are + // still reachable). + VMRuntime.runFinalizationForExit(); + } + return first; + } + + /** + * Register a new shutdown hook. This is invoked when the program exits + * normally (because all non-daemon threads ended, or because + * System.exit was invoked), or when the user terminates + * the virtual machine (such as by typing ^C, or logging off). There is + * a security check to add hooks, + * RuntimePermission("shutdownHooks"). + * + *

    The hook must be an initialized, but unstarted Thread. The threads + * are run concurrently, and started in an arbitrary order; and user + * threads or daemons may still be running. Once shutdown hooks have + * started, they must all complete, or else you must use halt, + * to actually finish the shutdown sequence. Attempts to modify hooks + * after shutdown has started result in IllegalStateExceptions.

    + * + *

    It is imperative that you code shutdown hooks defensively, as you + * do not want to deadlock, and have no idea what other hooks will be + * running concurrently. It is also a good idea to finish quickly, as the + * virtual machine really wants to shut down!

    + * + *

    There are no guarantees that such hooks will run, as there are ways + * to forcibly kill a process. But in such a drastic case, shutdown hooks + * would do little for you in the first place.

    + * + * @param hook an initialized, unstarted Thread + * @throws IllegalArgumentException if the hook is already registered or run + * @throws IllegalStateException if the virtual machine is already in + * the shutdown sequence + * @throws SecurityException if permission is denied + * @since 1.3 + * @see #removeShutdownHook(Thread) + * @see #exit(int) + * @see #halt(int) + */ + public void addShutdownHook(Thread hook) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkPermission(new RuntimePermission("shutdownHooks")); + if (hook.isAlive() || hook.getThreadGroup() == null) + throw new IllegalArgumentException("The hook thread " + hook + " must not have been already run or started"); + synchronized (libpath) + { + if (exitSequence != null) + throw new IllegalStateException("The Virtual Machine is exiting. It is not possible anymore to add any hooks"); + if (shutdownHooks == null) + { + VMRuntime.enableShutdownHooks(); + shutdownHooks = new HashSet(); // Lazy initialization. + } + if (! shutdownHooks.add(hook)) + throw new IllegalArgumentException(hook.toString() + " had already been inserted"); + } + } + + /** + * De-register a shutdown hook. As when you registered it, there is a + * security check to remove hooks, + * RuntimePermission("shutdownHooks"). + * + * @param hook the hook to remove + * @return true if the hook was successfully removed, false if it was not + * registered in the first place + * @throws IllegalStateException if the virtual machine is already in + * the shutdown sequence + * @throws SecurityException if permission is denied + * @since 1.3 + * @see #addShutdownHook(Thread) + * @see #exit(int) + * @see #halt(int) + */ + public boolean removeShutdownHook(Thread hook) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkPermission(new RuntimePermission("shutdownHooks")); + synchronized (libpath) + { + if (exitSequence != null) + throw new IllegalStateException(); + if (shutdownHooks != null) + return shutdownHooks.remove(hook); + } + return false; + } + + /** + * Forcibly terminate the virtual machine. This call never returns. It is + * much more severe than exit, as it bypasses all shutdown + * hooks and initializers. Use caution in calling this! Of course, there is + * a security check, checkExit(status). + * + * @param status the status to exit with + * @throws SecurityException if permission is denied + * @since 1.3 + * @see #exit(int) + * @see #addShutdownHook(Thread) + */ + public void halt(int status) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExit(status); + VMRuntime.exit(status); + } + + /** + * Tell the VM to run the finalize() method on every single Object before + * it exits. Note that the JVM may still exit abnormally and not perform + * this, so you still don't have a guarantee. And besides that, this is + * inherently unsafe in multi-threaded code, as it may result in deadlock + * as multiple threads compete to manipulate objects. This value defaults to + * false. There is a security check, checkExit(0). + * + * @param finalizeOnExit whether to finalize all Objects on exit + * @throws SecurityException if permission is denied + * @see #exit(int) + * @see #gc() + * @since 1.1 + * @deprecated never rely on finalizers to do a clean, thread-safe, + * mop-up from your code + */ + public static void runFinalizersOnExit(boolean finalizeOnExit) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExit(0); + VMRuntime.runFinalizersOnExit(finalizeOnExit); + } + + /** + * Create a new subprocess with the specified command line. Calls + * exec(cmdline, null, null). A security check is performed, + * checkExec. + * + * @param cmdline the command to call + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmdline is null + * @throws IndexOutOfBoundsException if cmdline is "" + */ + public Process exec(String cmdline) throws IOException + { + return exec(cmdline, null, null); + } + + /** + * Create a new subprocess with the specified command line and environment. + * If the environment is null, the process inherits the environment of + * this process. Calls exec(cmdline, env, null). A security + * check is performed, checkExec. + * + * @param cmdline the command to call + * @param env the environment to use, in the format name=value + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmdline is null, or env has null entries + * @throws IndexOutOfBoundsException if cmdline is "" + */ + public Process exec(String cmdline, String[] env) throws IOException + { + return exec(cmdline, env, null); + } + + /** + * Create a new subprocess with the specified command line, environment, and + * working directory. If the environment is null, the process inherits the + * environment of this process. If the directory is null, the process uses + * the current working directory. This splits cmdline into an array, using + * the default StringTokenizer, then calls + * exec(cmdArray, env, dir). A security check is performed, + * checkExec. + * + * @param cmdline the command to call + * @param env the environment to use, in the format name=value + * @param dir the working directory to use + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmdline is null, or env has null entries + * @throws IndexOutOfBoundsException if cmdline is "" + * @since 1.3 + */ + public Process exec(String cmdline, String[] env, File dir) + throws IOException + { + StringTokenizer t = new StringTokenizer(cmdline); + String[] cmd = new String[t.countTokens()]; + for (int i = 0; i < cmd.length; i++) + cmd[i] = t.nextToken(); + return exec(cmd, env, dir); + } + + /** + * Create a new subprocess with the specified command line, already + * tokenized. Calls exec(cmd, null, null). A security check + * is performed, checkExec. + * + * @param cmd the command to call + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmd is null, or has null entries + * @throws IndexOutOfBoundsException if cmd is length 0 + */ + public Process exec(String[] cmd) throws IOException + { + return exec(cmd, null, null); + } + + /** + * Create a new subprocess with the specified command line, already + * tokenized, and specified environment. If the environment is null, the + * process inherits the environment of this process. Calls + * exec(cmd, env, null). A security check is performed, + * checkExec. + * + * @param cmd the command to call + * @param env the environment to use, in the format name=value + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmd is null, or cmd or env has null + * entries + * @throws IndexOutOfBoundsException if cmd is length 0 + */ + public Process exec(String[] cmd, String[] env) throws IOException + { + return exec(cmd, env, null); + } + + /** + * Create a new subprocess with the specified command line, already + * tokenized, and the specified environment and working directory. If the + * environment is null, the process inherits the environment of this + * process. If the directory is null, the process uses the current working + * directory. A security check is performed, checkExec. + * + * @param cmd the command to call + * @param env the environment to use, in the format name=value + * @param dir the working directory to use + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmd is null, or cmd or env has null + * entries + * @throws IndexOutOfBoundsException if cmd is length 0 + * @since 1.3 + */ + public Process exec(String[] cmd, String[] env, File dir) + throws IOException + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExec(cmd[0]); + return VMRuntime.exec(cmd, env, dir); + } + + /** + * Returns the number of available processors currently available to the + * virtual machine. This number may change over time; so a multi-processor + * program want to poll this to determine maximal resource usage. + * + * @return the number of processors available, at least 1 + */ + public int availableProcessors() + { + return VMRuntime.availableProcessors(); + } + + /** + * Find out how much memory is still free for allocating Objects on the heap. + * + * @return the number of bytes of free memory for more Objects + */ + public long freeMemory() + { + return VMRuntime.freeMemory(); + } + + /** + * Find out how much memory total is available on the heap for allocating + * Objects. + * + * @return the total number of bytes of memory for Objects + */ + public long totalMemory() + { + return VMRuntime.totalMemory(); + } + + /** + * Returns the maximum amount of memory the virtual machine can attempt to + * use. This may be Long.MAX_VALUE if there is no inherent + * limit (or if you really do have a 8 exabyte memory!). + * + * @return the maximum number of bytes the virtual machine will attempt + * to allocate + */ + public long maxMemory() + { + return VMRuntime.maxMemory(); + } + + /** + * Run the garbage collector. This method is more of a suggestion than + * anything. All this method guarantees is that the garbage collector will + * have "done its best" by the time it returns. Notice that garbage + * collection takes place even without calling this method. + */ + public void gc() + { + VMRuntime.gc(); + } + + /** + * Run finalization on all Objects that are waiting to be finalized. Again, + * a suggestion, though a stronger one than {@link #gc()}. This calls the + * finalize method of all objects waiting to be collected. + * + * @see #finalize() + */ + public void runFinalization() + { + VMRuntime.runFinalization(); + } + + /** + * Tell the VM to trace every bytecode instruction that executes (print out + * a trace of it). No guarantees are made as to where it will be printed, + * and the VM is allowed to ignore this request. + * + * @param on whether to turn instruction tracing on + */ + public void traceInstructions(boolean on) + { + VMRuntime.traceInstructions(on); + } + + /** + * Tell the VM to trace every method call that executes (print out a trace + * of it). No guarantees are made as to where it will be printed, and the + * VM is allowed to ignore this request. + * + * @param on whether to turn method tracing on + */ + public void traceMethodCalls(boolean on) + { + VMRuntime.traceMethodCalls(on); + } + + /** + * Load a native library using the system-dependent filename. This is similar + * to loadLibrary, except the only name mangling done is inserting "_g" + * before the final ".so" if the VM was invoked by the name "java_g". There + * may be a security check, of checkLink. + * + *

    + * The library is loaded using the class loader associated with the + * class associated with the invoking method. + * + * @param filename the file to load + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the library is not found + */ + public void load(String filename) + { + load(filename, VMStackWalker.getCallingClassLoader()); + } + + /** + * Same as load(String) but using the given loader. + * + * @param filename the file to load + * @param loader class loader, or null for the boot loader + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the library is not found + */ + void load(String filename, ClassLoader loader) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkLink(filename); + if (loadLib(filename, loader) == 0) + throw new UnsatisfiedLinkError("Could not load library " + filename); + } + + /** + * Do a security check on the filename and then load the native library. + * + * @param filename the file to load + * @param loader class loader, or null for the boot loader + * @return 0 on failure, nonzero on success + * @throws SecurityException if file read permission is denied + */ + private static int loadLib(String filename, ClassLoader loader) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkRead(filename); + return VMRuntime.nativeLoad(filename, loader); + } + + /** + * Load a native library using a system-independent "short name" for the + * library. It will be transformed to a correct filename in a + * system-dependent manner (for example, in Windows, "mylib" will be turned + * into "mylib.dll"). This is done as follows: if the context that called + * load has a ClassLoader cl, then cl.findLibrary(libpath) is + * used to convert the name. If that result was null, or there was no class + * loader, this searches each directory of the system property + * java.library.path for a file named + * System.mapLibraryName(libname). There may be a security + * check, of checkLink. + * + *

    Note: Besides java.library.path a VM may chose to search + * for native libraries in a path that is specified by the + * gnu.classpath.boot.library.path system property. However + * this is for internal usage or development of GNU Classpath only. + * A Java application must not load a non-system library by changing + * this property otherwise it will break compatibility.

    + * + *

    + * The library is loaded using the class loader associated with the + * class associated with the invoking method. + * + * @param libname the library to load + * + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the library is not found + * + * @see System#mapLibraryName(String) + * @see ClassLoader#findLibrary(String) + */ + public void loadLibrary(String libname) + { + loadLibrary(libname, VMStackWalker.getCallingClassLoader()); + } + + /** + * Same as loadLibrary(String) but using the given loader. + * + * @param libname the library to load + * @param loader class loader, or null for the boot loader + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the library is not found + */ + void loadLibrary(String libname, ClassLoader loader) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkLink(libname); + String filename; + if (loader != null && (filename = loader.findLibrary(libname)) != null) + { + if (loadLib(filename, loader) != 0) + return; + } + else + { + filename = VMRuntime.mapLibraryName(libname); + for (int i = 0; i < libpath.length; i++) + if (loadLib(libpath[i] + filename, loader) != 0) + return; + } + throw new UnsatisfiedLinkError("Native library `" + libname + + "' not found (as file `" + filename + "') in gnu.classpath.boot.library.path and java.library.path"); + } + + /** + * Return a localized version of this InputStream, meaning all characters + * are localized before they come out the other end. + * + * @param in the stream to localize + * @return the localized stream + * @deprecated InputStreamReader is the preferred way to read + * local encodings + * @XXX This implementation does not localize, yet. + */ + public InputStream getLocalizedInputStream(InputStream in) + { + return in; + } + + /** + * Return a localized version of this OutputStream, meaning all characters + * are localized before they are sent to the other end. + * + * @param out the stream to localize + * @return the localized stream + * @deprecated OutputStreamWriter is the preferred way to write + * local encodings + * @XXX This implementation does not localize, yet. + */ + public OutputStream getLocalizedOutputStream(OutputStream out) + { + return out; + } +} // class Runtime diff --git a/libjava/classpath/java/lang/RuntimeException.java b/libjava/classpath/java/lang/RuntimeException.java new file mode 100644 index 0000000..72cf087 --- /dev/null +++ b/libjava/classpath/java/lang/RuntimeException.java @@ -0,0 +1,102 @@ +/* RuntimeException.java -- root of all unchecked exceptions + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * All exceptions which are subclasses of RuntimeException + * can be thrown at any time during the execution of a Java virtual machine. + * Methods which throw these exceptions are not required to declare them + * in their throws clause. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class RuntimeException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -7034897190745766939L; + + /** + * Create an exception without a message. The cause remains uninitialized. + * + * @see #initCause(Throwable) + */ + public RuntimeException() + { + } + + /** + * Create an exception with a message. The cause remains uninitialized. + * + * @param s the message string + * @see #initCause(Throwable) + */ + public RuntimeException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message string + * @param cause the cause of this exception + * @since 1.4 + */ + public RuntimeException(String s, Throwable cause) + { + super(s, cause); + } + + /** + * Create an exception with the given cause, and a message of + * cause == null ? null : cause.toString(). + * + * @param cause the cause of this exception + * @since 1.4 + */ + public RuntimeException(Throwable cause) + { + super(cause); + } +} diff --git a/libjava/classpath/java/lang/RuntimePermission.java b/libjava/classpath/java/lang/RuntimePermission.java new file mode 100644 index 0000000..ca33307 --- /dev/null +++ b/libjava/classpath/java/lang/RuntimePermission.java @@ -0,0 +1,208 @@ +/* RuntimePermission.java -- permission for a secure runtime action + Copyright (C) 1998, 2000, 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 java.lang; + +import java.security.BasicPermission; + +/** + * A RuntimePermission contains a permission name, but no + * actions list. This means you either have the permission or you don't. + * + * Permission names have the follow the hierarchial property naming + * convention. In addition, an asterisk may appear at the end of a + * name if following a period or by itself. + * + * + * + * + * + *
    Valid namesInvalid names
    "accessClassInPackage.*","*""**", "*x", "*.a"
    + *
    + * + * The following table provides a list of all the possible RuntimePermission + * permission names with a description of what that permission allows.
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Permission NamePermission AllowsRisks + *
    createClassLoadercreation of a class loadera class loader can load rogue classes which bypass all security + * permissions
    getClassLoaderretrieval of the class loader for the calling classrogue code could load classes not otherwise available
    setContextClassLoaderallows the setting of the context class loader used by a threadrogue code could change the context class loader needed by system + * threads
    setSecurityManagerallows the application to replace the security managerthe new manager may be less restrictive, so that rogue code can + * bypass existing security checks
    createSecurityManagerallows the application to create a new security managerrogue code can use the new security manager to discover information + * about the execution stack
    exitVMallows the application to halt the virtual machinerogue code can mount a denial-of-service attack by killing the + * virtual machine
    shutdownHooksallows registration and modification of shutdown hooksrogue code can add a hook that interferes with clean + * virtual machine shutdown
    setFactoryallows the application to set the socket factory for socket, + * server socket, stream handler, or RMI socket factory.rogue code can create a rogue network object which mangles or + * intercepts data
    setIOallows the application to set System.out, System.in, and + * System.errrogue code could sniff user input and intercept or mangle + * output
    modifyThreadallows the application to modify any thread in the virtual machine + * using any of the methods stop, resume, + * suspend, setPriority, and + * setName of classs Threadrogue code could adversely modify system or user threads
    stopThreadallows the application to stop any thread it has + * access to in the systemrogue code can stop arbitrary threads
    modifyThreadGroupallows the application to modify thread groups using any of the + * methods destroy, resume, + * setDaemon, setMaxPriority, + * stop, and suspend of the class + * ThreadGrouprogue code can mount a denial-of-service attack by changing run + * priorities
    getProtectionDomainretrieve a class's ProtectionDomainrogue code can gain information about the security policy, to + * prepare a better attack
    readFileDescriptorread a file descriptorrogue code can read sensitive information
    writeFileDescriptorwrite a file descriptorrogue code can write files, including viruses, and can modify the + * virtual machine binary; if not just fill up the disk
    loadLibrary.library namedynamic linking of the named librarynative code can bypass many security checks of pure Java
    accessClassInPackage.package nameaccess to a package via a ClassLoaderrogue code can access classes not normally available
    defineClassInPackage.package namedefine a class inside a given packagerogue code can install rogue classes, including in trusted packages + * like java.security or java.lang
    accessDeclaredMembersaccess declared class members via reflectionrogue code can discover information, invoke methods, or modify fields + * that are not otherwise available
    queuePrintJobinitiate a print jobrogue code could make a hard copy of sensitive information, or + * simply waste paper
    + * + * @author Brian Jones + * @author Eric Blake (ebb9@email.byu.edu) + * @see BasicPermission + * @see Permission + * @see SecurityManager + * @since 1.2 + * @status updated to 1.4 + */ +public final class RuntimePermission extends BasicPermission +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 7399184964622342223L; + + /** + * Create a new permission with the specified name. + * + * @param permissionName the name of the granted permission + * @throws NullPointerException if name is null + * @throws IllegalArgumentException thrown if name is empty or invalid + */ + public RuntimePermission(String permissionName) + { + super(permissionName); + } + + /** + * Create a new permission with the specified name. The actions argument + * is ignored, as runtime permissions have no actions. + * + * @param permissionName the name of the granted permission + * @param actions ignored + * @throws NullPointerException if name is null + * @throws IllegalArgumentException thrown if name is empty or invalid + */ + public RuntimePermission(String permissionName, String actions) + { + super(permissionName); + } +} diff --git a/libjava/classpath/java/lang/SecurityException.java b/libjava/classpath/java/lang/SecurityException.java new file mode 100644 index 0000000..a95d797 --- /dev/null +++ b/libjava/classpath/java/lang/SecurityException.java @@ -0,0 +1,74 @@ +/* SecurityException.java -- thrown to indicate a security violation + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * The security manager will throw this exception to indicate a security + * violation. This can occur any time an operation is attempted which is + * deemed unsafe by the current security policies. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @see SecurityManager + * @status updated to 1.4 + */ +public class SecurityException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 6878364983674394167L; + + /** + * Create an exception without a message. + */ + public SecurityException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public SecurityException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/SecurityManager.java b/libjava/classpath/java/lang/SecurityManager.java new file mode 100644 index 0000000..ef9e759 --- /dev/null +++ b/libjava/classpath/java/lang/SecurityManager.java @@ -0,0 +1,1062 @@ +/* SecurityManager.java -- security checks for privileged actions + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +import gnu.classpath.VMStackWalker; + +import java.awt.AWTPermission; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FilePermission; +import java.lang.reflect.Member; +import java.net.InetAddress; +import java.net.SocketPermission; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.AllPermission; +import java.security.Permission; +import java.security.PrivilegedAction; +import java.security.Security; +import java.security.SecurityPermission; +import java.util.PropertyPermission; +import java.util.StringTokenizer; + +/** + * SecurityManager is a class you can extend to create your own Java + * security policy. By default, there is no SecurityManager installed in + * 1.1, which means that all things are permitted to all people. The security + * manager, if set, is consulted before doing anything with potentially + * dangerous results, and throws a SecurityException if the + * action is forbidden. + * + *

    A typical check is as follows, just before the dangerous operation:
    + *

    + * SecurityManager sm = System.getSecurityManager();
    + * if (sm != null)
    + *   sm.checkABC(argument, ...);
    + * 
    + * Note that this is thread-safe, by caching the security manager in a local + * variable rather than risking a NullPointerException if the mangager is + * changed between the check for null and before the permission check. + * + *

    The special method checkPermission is a catchall, and + * the default implementation calls + * AccessController.checkPermission. In fact, all the other + * methods default to calling checkPermission. + * + *

    Sometimes, the security check needs to happen from a different context, + * such as when called from a worker thread. In such cases, use + * getSecurityContext to take a snapshot that can be passed + * to the worker thread:
    + *

    + * Object context = null;
    + * SecurityManager sm = System.getSecurityManager();
    + * if (sm != null)
    + *   context = sm.getSecurityContext(); // defaults to an AccessControlContext
    + * // now, in worker thread
    + * if (sm != null)
    + *   sm.checkPermission(permission, context);
    + * 
    + * + *

    Permissions fall into these categories: File, Socket, Net, Security, + * Runtime, Property, AWT, Reflect, and Serializable. Each of these + * permissions have a property naming convention, that follows a hierarchical + * naming convention, to make it easy to grant or deny several permissions + * at once. Some permissions also take a list of permitted actions, such + * as "read" or "write", to fine-tune control even more. The permission + * java.security.AllPermission grants all permissions. + * + *

    The default methods in this class deny all things to all people. You + * must explicitly grant permission for anything you want to be legal when + * subclassing this class. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @see ClassLoader + * @see SecurityException + * @see #checkTopLevelWindow(Object) + * @see System#getSecurityManager() + * @see System#setSecurityManager(SecurityManager) + * @see AccessController + * @see AccessControlContext + * @see AccessControlException + * @see Permission + * @see BasicPermission + * @see java.io.FilePermission + * @see java.net.SocketPermission + * @see java.util.PropertyPermission + * @see RuntimePermission + * @see java.awt.AWTPermission + * @see Policy + * @see SecurityPermission + * @see ProtectionDomain + * @since 1.0 + * @status still missing 1.4 functionality + */ +public class SecurityManager +{ + /** + * The current security manager. This is located here instead of in + * System, to avoid security problems, as well as bootstrap issues. + * Make sure to access it in a thread-safe manner; it is package visible + * to avoid overhead in java.lang. + */ + static volatile SecurityManager current; + + /** + * Tells whether or not the SecurityManager is currently performing a + * security check. + * @deprecated Use {@link #checkPermission(Permission)} instead. + */ + protected boolean inCheck; + + /** + * Construct a new security manager. There may be a security check, of + * RuntimePermission("createSecurityManager"). + * + * @throws SecurityException if permission is denied + */ + public SecurityManager() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("createSecurityManager")); + } + + /** + * Tells whether or not the SecurityManager is currently performing a + * security check. + * + * @return true if the SecurityManager is in a security check + * @see #inCheck + * @deprecated use {@link #checkPermission(Permission)} instead + */ + public boolean getInCheck() + { + return inCheck; + } + + /** + * Get a list of all the classes currently executing methods on the Java + * stack. getClassContext()[0] is the currently executing method (ie. the + * class that CALLED getClassContext, not SecurityManager). + * + * @return an array of classes on the Java execution stack + */ + protected Class[] getClassContext() + { + Class[] stack1 = VMStackWalker.getClassContext(); + Class[] stack2 = new Class[stack1.length - 1]; + System.arraycopy(stack1, 1, stack2, 0, stack1.length - 1); + return stack2; + } + + /** + * Find the ClassLoader of the first non-system class on the execution + * stack. A non-system class is one whose ClassLoader is not equal to + * {@link ClassLoader#getSystemClassLoader()} or its ancestors. This + * will return null in three cases: + * + *

      + *
    • All methods on the stack are from system classes
    • + *
    • All methods on the stack up to the first "privileged" caller, as + * created by {@link AccessController.doPrivileged(PrivilegedAction)}, + * are from system classes
    • + *
    • A check of java.security.AllPermission succeeds.
    • + *
    + * + * @return the most recent non-system ClassLoader on the execution stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected ClassLoader currentClassLoader() + { + Class cl = currentLoadedClass(); + return cl != null ? cl.getClassLoader() : null; + } + + /** + * Find the first non-system class on the execution stack. A non-system + * class is one whose ClassLoader is not equal to + * {@link ClassLoader#getSystemClassLoader()} or its ancestors. This + * will return null in three cases: + * + *
      + *
    • All methods on the stack are from system classes
    • + *
    • All methods on the stack up to the first "privileged" caller, as + * created by {@link AccessController.doPrivileged(PrivilegedAction)}, + * are from system classes
    • + *
    • A check of java.security.AllPermission succeeds.
    • + *
    + * + * @return the most recent non-system Class on the execution stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected Class currentLoadedClass() + { + int i = classLoaderDepth(); + return i >= 0 ? getClassContext()[i] : null; + } + + /** + * Get the depth of a particular class on the execution stack. + * + * @param className the fully-qualified name to search for + * @return the index of the class on the stack, or -1 + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected int classDepth(String className) + { + Class[] c = getClassContext(); + for (int i = 0; i < c.length; i++) + if (className.equals(c[i].getName())) + return i; + return -1; + } + + /** + * Get the depth on the execution stack of the most recent non-system class. + * A non-system class is one whose ClassLoader is not equal to + * {@link ClassLoader#getSystemClassLoader()} or its ancestors. This + * will return -1 in three cases: + * + *
      + *
    • All methods on the stack are from system classes
    • + *
    • All methods on the stack up to the first "privileged" caller, as + * created by {@link AccessController.doPrivileged(PrivilegedAction)}, + * are from system classes
    • + *
    • A check of java.security.AllPermission succeeds.
    • + *
    + * + * @return the index of the most recent non-system Class on the stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected int classLoaderDepth() + { + try + { + checkPermission(new AllPermission()); + } + catch (SecurityException e) + { + Class[] c = getClassContext(); + for (int i = 0; i < c.length; i++) + if (c[i].getClassLoader() != null) + // XXX Check if c[i] is AccessController, or a system class. + return i; + } + return -1; + } + + /** + * Tell whether the specified class is on the execution stack. + * + * @param className the fully-qualified name of the class to find + * @return whether the specified class is on the execution stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected boolean inClass(String className) + { + return classDepth(className) != -1; + } + + /** + * Tell whether there is a class loaded with an explicit ClassLoader on + * the stack. + * + * @return whether a class with an explicit ClassLoader is on the stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected boolean inClassLoader() + { + return classLoaderDepth() != -1; + } + + /** + * Get an implementation-dependent Object that contains enough information + * about the current environment to be able to perform standard security + * checks later. This is used by trusted methods that need to verify that + * their callers have sufficient access to perform certain operations. + * + *

    Currently the only methods that use this are checkRead() and + * checkConnect(). The default implementation returns an + * AccessControlContext. + * + * @return a security context + * @see #checkConnect(String, int, Object) + * @see #checkRead(String, Object) + * @see AccessControlContext + * @see AccessController#getContext() + */ + public Object getSecurityContext() + { + return AccessController.getContext(); + } + + /** + * Check if the current thread is allowed to perform an operation that + * requires the specified Permission. This defaults to + * AccessController.checkPermission. + * + * @param perm the Permission required + * @throws SecurityException if permission is denied + * @throws NullPointerException if perm is null + * @since 1.2 + */ + public void checkPermission(Permission perm) + { + AccessController.checkPermission(perm); + } + + /** + * Check if the current thread is allowed to perform an operation that + * requires the specified Permission. This is done in a + * context previously returned by getSecurityContext(). The + * default implementation expects context to be an AccessControlContext, + * and it calls AccessControlContext.checkPermission(perm). + * + * @param perm the Permission required + * @param context a security context + * @throws SecurityException if permission is denied, or if context is + * not an AccessControlContext + * @throws NullPointerException if perm is null + * @see #getSecurityContext() + * @see AccessControlContext#checkPermission(Permission) + * @since 1.2 + */ + public void checkPermission(Permission perm, Object context) + { + if (! (context instanceof AccessControlContext)) + throw new SecurityException("Missing context"); + ((AccessControlContext) context).checkPermission(perm); + } + + /** + * Check if the current thread is allowed to create a ClassLoader. This + * method is called from ClassLoader.ClassLoader(), and checks + * RuntimePermission("createClassLoader"). If you override + * this, you should call super.checkCreateClassLoader() rather + * than throwing an exception. + * + * @throws SecurityException if permission is denied + * @see ClassLoader#ClassLoader() + */ + public void checkCreateClassLoader() + { + checkPermission(new RuntimePermission("createClassLoader")); + } + + /** + * Check if the current thread is allowed to modify another Thread. This is + * called by Thread.stop(), suspend(), resume(), interrupt(), destroy(), + * setPriority(), setName(), and setDaemon(). The default implementation + * checks RuntimePermission("modifyThread") on system threads + * (ie. threads in ThreadGroup with a null parent), and returns silently on + * other threads. + * + *

    If you override this, you must do two things. First, call + * super.checkAccess(t), to make sure you are not relaxing + * requirements. Second, if the calling thread has + * RuntimePermission("modifyThread"), return silently, so that + * core classes (the Classpath library!) can modify any thread. + * + * @param thread the other Thread to check + * @throws SecurityException if permission is denied + * @throws NullPointerException if thread is null + * @see Thread#stop() + * @see Thread#suspend() + * @see Thread#resume() + * @see Thread#setPriority(int) + * @see Thread#setName(String) + * @see Thread#setDaemon(boolean) + */ + public void checkAccess(Thread thread) + { + if (thread.getThreadGroup() != null + && thread.getThreadGroup().getParent() != null) + checkPermission(new RuntimePermission("modifyThread")); + } + + /** + * Check if the current thread is allowed to modify a ThreadGroup. This is + * called by Thread.Thread() (to add a thread to the ThreadGroup), + * ThreadGroup.ThreadGroup() (to add this ThreadGroup to a parent), + * ThreadGroup.stop(), suspend(), resume(), interrupt(), destroy(), + * setDaemon(), and setMaxPriority(). The default implementation + * checks RuntimePermission("modifyThread") on the system group + * (ie. the one with a null parent), and returns silently on other groups. + * + *

    If you override this, you must do two things. First, call + * super.checkAccess(t), to make sure you are not relaxing + * requirements. Second, if the calling thread has + * RuntimePermission("modifyThreadGroup"), return silently, + * so that core classes (the Classpath library!) can modify any thread. + * + * @param g the ThreadGroup to check + * @throws SecurityException if permission is denied + * @throws NullPointerException if g is null + * @see Thread#Thread() + * @see ThreadGroup#ThreadGroup() + * @see ThreadGroup#stop() + * @see ThreadGroup#suspend() + * @see ThreadGroup#resume() + * @see ThreadGroup#interrupt() + * @see ThreadGroup#setDaemon(boolean) + * @see ThreadGroup#setMaxPriority(int) + */ + public void checkAccess(ThreadGroup g) + { + if (g.getParent() != null) + checkPermission(new RuntimePermission("modifyThreadGroup")); + } + + /** + * Check if the current thread is allowed to exit the JVM with the given + * status. This method is called from Runtime.exit() and Runtime.halt(). + * The default implementation checks + * RuntimePermission("exitVM"). If you override this, call + * super.checkExit rather than throwing an exception. + * + * @param status the status to exit with + * @throws SecurityException if permission is denied + * @see Runtime#exit(int) + * @see Runtime#halt(int) + */ + public void checkExit(int status) + { + checkPermission(new RuntimePermission("exitVM")); + } + + /** + * Check if the current thread is allowed to execute the given program. This + * method is called from Runtime.exec(). If the name is an absolute path, + * the default implementation checks + * FilePermission(program, "execute"), otherwise it checks + * FilePermission("<<ALL FILES>>", "execute"). If + * you override this, call super.checkExec rather than + * throwing an exception. + * + * @param program the name of the program to exec + * @throws SecurityException if permission is denied + * @throws NullPointerException if program is null + * @see Runtime#exec(String[], String[], File) + */ + public void checkExec(String program) + { + if (! program.equals(new File(program).getAbsolutePath())) + program = "<>"; + checkPermission(new FilePermission(program, "execute")); + } + + /** + * Check if the current thread is allowed to link in the given native + * library. This method is called from Runtime.load() (and hence, by + * loadLibrary() as well). The default implementation checks + * RuntimePermission("loadLibrary." + filename). If you + * override this, call super.checkLink rather than throwing + * an exception. + * + * @param filename the full name of the library to load + * @throws SecurityException if permission is denied + * @throws NullPointerException if filename is null + * @see Runtime#load(String) + */ + public void checkLink(String filename) + { + // Use the toString() hack to do the null check. + checkPermission(new RuntimePermission("loadLibrary." + + filename.toString())); + } + + /** + * Check if the current thread is allowed to read the given file using the + * FileDescriptor. This method is called from + * FileInputStream.FileInputStream(). The default implementation checks + * RuntimePermission("readFileDescriptor"). If you override + * this, call super.checkRead rather than throwing an + * exception. + * + * @param desc the FileDescriptor representing the file to access + * @throws SecurityException if permission is denied + * @throws NullPointerException if desc is null + * @see FileInputStream#FileInputStream(FileDescriptor) + */ + public void checkRead(FileDescriptor desc) + { + if (desc == null) + throw new NullPointerException(); + checkPermission(new RuntimePermission("readFileDescriptor")); + } + + /** + * Check if the current thread is allowed to read the given file. This + * method is called from FileInputStream.FileInputStream(), + * RandomAccessFile.RandomAccessFile(), File.exists(), canRead(), isFile(), + * isDirectory(), lastModified(), length() and list(). The default + * implementation checks FilePermission(filename, "read"). If + * you override this, call super.checkRead rather than + * throwing an exception. + * + * @param filename the full name of the file to access + * @throws SecurityException if permission is denied + * @throws NullPointerException if filename is null + * @see File + * @see FileInputStream#FileInputStream(String) + * @see RandomAccessFile#RandomAccessFile(String) + */ + public void checkRead(String filename) + { + checkPermission(new FilePermission(filename, "read")); + } + + /** + * Check if the current thread is allowed to read the given file. using the + * given security context. The context must be a result of a previous call + * to getSecurityContext(). The default implementation checks + * AccessControlContext.checkPermission(new FilePermission(filename, + * "read")). If you override this, call super.checkRead + * rather than throwing an exception. + * + * @param filename the full name of the file to access + * @param context the context to determine access for + * @throws SecurityException if permission is denied, or if context is + * not an AccessControlContext + * @throws NullPointerException if filename is null + * @see #getSecurityContext() + * @see AccessControlContext#checkPermission(Permission) + */ + public void checkRead(String filename, Object context) + { + if (! (context instanceof AccessControlContext)) + throw new SecurityException("Missing context"); + AccessControlContext ac = (AccessControlContext) context; + ac.checkPermission(new FilePermission(filename, "read")); + } + + /** + * Check if the current thread is allowed to write the given file using the + * FileDescriptor. This method is called from + * FileOutputStream.FileOutputStream(). The default implementation checks + * RuntimePermission("writeFileDescriptor"). If you override + * this, call super.checkWrite rather than throwing an + * exception. + * + * @param desc the FileDescriptor representing the file to access + * @throws SecurityException if permission is denied + * @throws NullPointerException if desc is null + * @see FileOutputStream#FileOutputStream(FileDescriptor) + */ + public void checkWrite(FileDescriptor desc) + { + if (desc == null) + throw new NullPointerException(); + checkPermission(new RuntimePermission("writeFileDescriptor")); + } + + /** + * Check if the current thread is allowed to write the given file. This + * method is called from FileOutputStream.FileOutputStream(), + * RandomAccessFile.RandomAccessFile(), File.canWrite(), mkdir(), and + * renameTo(). The default implementation checks + * FilePermission(filename, "write"). If you override this, + * call super.checkWrite rather than throwing an exception. + * + * @param filename the full name of the file to access + * @throws SecurityException if permission is denied + * @throws NullPointerException if filename is null + * @see File + * @see File#canWrite() + * @see File#mkdir() + * @see File#renameTo() + * @see FileOutputStream#FileOutputStream(String) + * @see RandomAccessFile#RandomAccessFile(String) + */ + public void checkWrite(String filename) + { + checkPermission(new FilePermission(filename, "write")); + } + + /** + * Check if the current thread is allowed to delete the given file. This + * method is called from File.delete(). The default implementation checks + * FilePermission(filename, "delete"). If you override this, + * call super.checkDelete rather than throwing an exception. + * + * @param filename the full name of the file to delete + * @throws SecurityException if permission is denied + * @throws NullPointerException if filename is null + * @see File#delete() + */ + public void checkDelete(String filename) + { + checkPermission(new FilePermission(filename, "delete")); + } + + /** + * Check if the current thread is allowed to connect to a given host on a + * given port. This method is called from Socket.Socket(). A port number + * of -1 indicates the caller is attempting to determine an IP address, so + * the default implementation checks + * SocketPermission(host, "resolve"). Otherwise, the default + * implementation checks + * SocketPermission(host + ":" + port, "connect"). If you + * override this, call super.checkConnect rather than throwing + * an exception. + * + * @param host the host to connect to + * @param port the port to connect on + * @throws SecurityException if permission is denied + * @throws NullPointerException if host is null + * @see Socket#Socket() + */ + public void checkConnect(String host, int port) + { + if (port == -1) + checkPermission(new SocketPermission(host, "resolve")); + else + // Use the toString() hack to do the null check. + checkPermission(new SocketPermission(host.toString() + ":" + port, + "connect")); + } + + /** + * Check if the current thread is allowed to connect to a given host on a + * given port, using the given security context. The context must be a + * result of a previous call to getSecurityContext. A port + * number of -1 indicates the caller is attempting to determine an IP + * address, so the default implementation checks + * AccessControlContext.checkPermission(new SocketPermission(host, + * "resolve")). Otherwise, the default implementation checks + * AccessControlContext.checkPermission(new SocketPermission(host + * + ":" + port, "connect")). If you override this, call + * super.checkConnect rather than throwing an exception. + * + * @param host the host to connect to + * @param port the port to connect on + * @param context the context to determine access for + * + * @throws SecurityException if permission is denied, or if context is + * not an AccessControlContext + * @throws NullPointerException if host is null + * + * @see #getSecurityContext() + * @see AccessControlContext#checkPermission(Permission) + */ + public void checkConnect(String host, int port, Object context) + { + if (! (context instanceof AccessControlContext)) + throw new SecurityException("Missing context"); + AccessControlContext ac = (AccessControlContext) context; + if (port == -1) + ac.checkPermission(new SocketPermission(host, "resolve")); + else + // Use the toString() hack to do the null check. + ac.checkPermission(new SocketPermission(host.toString() + ":" + port, + "connect")); + } + + /** + * Check if the current thread is allowed to listen to a specific port for + * data. This method is called by ServerSocket.ServerSocket(). The default + * implementation checks + * SocketPermission("localhost:" + (port == 0 ? "1024-" : "" + port), + * "listen"). If you override this, call + * super.checkListen rather than throwing an exception. + * + * @param port the port to listen on + * @throws SecurityException if permission is denied + * @see ServerSocket#ServerSocket(int) + */ + public void checkListen(int port) + { + checkPermission(new SocketPermission("localhost:" + + (port == 0 ? "1024-" : "" +port), + "listen")); + } + + /** + * Check if the current thread is allowed to accept a connection from a + * particular host on a particular port. This method is called by + * ServerSocket.implAccept(). The default implementation checks + * SocketPermission(host + ":" + port, "accept"). If you + * override this, call super.checkAccept rather than throwing + * an exception. + * + * @param host the host which wishes to connect + * @param port the port the connection will be on + * @throws SecurityException if permission is denied + * @throws NullPointerException if host is null + * @see ServerSocket#accept() + */ + public void checkAccept(String host, int port) + { + // Use the toString() hack to do the null check. + checkPermission(new SocketPermission(host.toString() + ":" + port, + "accept")); + } + + /** + * Check if the current thread is allowed to read and write multicast to + * a particular address. The default implementation checks + * SocketPermission(addr.getHostAddress(), "accept,connect"). + * If you override this, call super.checkMulticast rather than + * throwing an exception. + * + * @param addr the address to multicast to + * @throws SecurityException if permission is denied + * @throws NullPointerException if host is null + * @since 1.1 + */ + public void checkMulticast(InetAddress addr) + { + checkPermission(new SocketPermission(addr.getHostAddress(), + "accept,connect")); + } + + /** + *Check if the current thread is allowed to read and write multicast to + * a particular address with a particular ttl (time-to-live) value. The + * default implementation ignores ttl, and checks + * SocketPermission(addr.getHostAddress(), "accept,connect"). + * If you override this, call super.checkMulticast rather than + * throwing an exception. + * + * @param addr the address to multicast to + * @param ttl value in use for multicast send + * @throws SecurityException if permission is denied + * @throws NullPointerException if host is null + * @since 1.1 + * @deprecated use {@link #checkPermission(Permission)} instead + */ + public void checkMulticast(InetAddress addr, byte ttl) + { + checkPermission(new SocketPermission(addr.getHostAddress(), + "accept,connect")); + } + + /** + * Check if the current thread is allowed to read or write all the system + * properties at once. This method is called by System.getProperties() + * and setProperties(). The default implementation checks + * PropertyPermission("*", "read,write"). If you override + * this, call super.checkPropertiesAccess rather than + * throwing an exception. + * + * @throws SecurityException if permission is denied + * @see System#getProperties() + * @see System#setProperties(Properties) + */ + public void checkPropertiesAccess() + { + checkPermission(new PropertyPermission("*", "read,write")); + } + + /** + * Check if the current thread is allowed to read a particular system + * property (writes are checked directly via checkPermission). This method + * is called by System.getProperty() and setProperty(). The default + * implementation checks PropertyPermission(key, "read"). If + * you override this, call super.checkPropertyAccess rather + * than throwing an exception. + * + * @param key the key of the property to check + * + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + * + * @see System#getProperty(String) + */ + public void checkPropertyAccess(String key) + { + checkPermission(new PropertyPermission(key, "read")); + } + + /** + * Check if the current thread is allowed to create a top-level window. If + * it is not, the operation should still go through, but some sort of + * nonremovable warning should be placed on the window to show that it + * is untrusted. This method is called by Window.Window(). The default + * implementation checks + * AWTPermission("showWindowWithoutWarningBanner"), and returns + * true if no exception was thrown. If you override this, use + * return super.checkTopLevelWindow rather than returning + * false. + * + * @param window the window to create + * @return true if there is permission to show the window without warning + * @throws NullPointerException if window is null + * @see Window#Window(Frame) + */ + public boolean checkTopLevelWindow(Object window) + { + if (window == null) + throw new NullPointerException(); + try + { + checkPermission(new AWTPermission("showWindowWithoutWarningBanner")); + return true; + } + catch (SecurityException e) + { + return false; + } + } + + /** + * Check if the current thread is allowed to create a print job. This + * method is called by Toolkit.getPrintJob(). The default implementation + * checks RuntimePermission("queuePrintJob"). If you override + * this, call super.checkPrintJobAccess rather than throwing + * an exception. + * + * @throws SecurityException if permission is denied + * @see Toolkit#getPrintJob(Frame, String, Properties) + * @since 1.1 + */ + public void checkPrintJobAccess() + { + checkPermission(new RuntimePermission("queuePrintJob")); + } + + /** + * Check if the current thread is allowed to use the system clipboard. This + * method is called by Toolkit.getSystemClipboard(). The default + * implementation checks AWTPermission("accessClipboard"). If + * you override this, call super.checkSystemClipboardAccess + * rather than throwing an exception. + * + * @throws SecurityException if permission is denied + * @see Toolkit#getSystemClipboard() + * @since 1.1 + */ + public void checkSystemClipboardAccess() + { + checkPermission(new AWTPermission("accessClipboard")); + } + + /** + * Check if the current thread is allowed to use the AWT event queue. This + * method is called by Toolkit.getSystemEventQueue(). The default + * implementation checks AWTPermission("accessEventQueue"). + * you override this, call super.checkAwtEventQueueAccess + * rather than throwing an exception. + * + * @throws SecurityException if permission is denied + * @see Toolkit#getSystemEventQueue() + * @since 1.1 + */ + public void checkAwtEventQueueAccess() + { + checkPermission(new AWTPermission("accessEventQueue")); + } + + /** + * Check if the current thread is allowed to access the specified package + * at all. This method is called by ClassLoader.loadClass() in user-created + * ClassLoaders. The default implementation gets a list of all restricted + * packages, via Security.getProperty("package.access"). Then, + * if packageName starts with or equals any restricted package, it checks + * RuntimePermission("accessClassInPackage." + packageName). + * If you override this, you should call + * super.checkPackageAccess before doing anything else. + * + * @param packageName the package name to check access to + * @throws SecurityException if permission is denied + * @throws NullPointerException if packageName is null + * @see ClassLoader#loadClass(String, boolean) + * @see Security#getProperty(String) + */ + public void checkPackageAccess(String packageName) + { + checkPackageList(packageName, "package.access", "accessClassInPackage."); + } + + /** + * Check if the current thread is allowed to define a class into the + * specified package. This method is called by ClassLoader.loadClass() in + * user-created ClassLoaders. The default implementation gets a list of all + * restricted packages, via + * Security.getProperty("package.definition"). Then, if + * packageName starts with or equals any restricted package, it checks + * RuntimePermission("defineClassInPackage." + packageName). + * If you override this, you should call + * super.checkPackageDefinition before doing anything else. + * + * @param packageName the package name to check access to + * @throws SecurityException if permission is denied + * @throws NullPointerException if packageName is null + * @see ClassLoader#loadClass(String, boolean) + * @see Security#getProperty(String) + */ + public void checkPackageDefinition(String packageName) + { + checkPackageList(packageName, "package.definition", "defineClassInPackage."); + } + + /** + * Check if the current thread is allowed to set the current socket factory. + * This method is called by Socket.setSocketImplFactory(), + * ServerSocket.setSocketFactory(), and URL.setURLStreamHandlerFactory(). + * The default implementation checks + * RuntimePermission("setFactory"). If you override this, call + * super.checkSetFactory rather than throwing an exception. + * + * @throws SecurityException if permission is denied + * @see Socket#setSocketImplFactory(SocketImplFactory) + * @see ServerSocket#setSocketFactory(SocketImplFactory) + * @see URL#setURLStreamHandlerFactory(URLStreamHandlerFactory) + */ + public void checkSetFactory() + { + checkPermission(new RuntimePermission("setFactory")); + } + + /** + * Check if the current thread is allowed to get certain types of Methods, + * Fields and Constructors from a Class object. This method is called by + * Class.getMethod[s](), Class.getField[s](), Class.getConstructor[s], + * Class.getDeclaredMethod[s](), Class.getDeclaredField[s](), and + * Class.getDeclaredConstructor[s](). The default implementation allows + * PUBLIC access, and access to classes defined by the same classloader as + * the code performing the reflection. Otherwise, it checks + * RuntimePermission("accessDeclaredMembers"). If you override + * this, do not call super.checkMemberAccess, as this would + * mess up the stack depth check that determines the ClassLoader requesting + * the access. + * + * @param c the Class to check + * @param memberType either DECLARED or PUBLIC + * @throws SecurityException if permission is denied, including when + * memberType is not DECLARED or PUBLIC + * @throws NullPointerException if c is null + * @see Class + * @see Member#DECLARED + * @see Member#PUBLIC + * @since 1.1 + */ + public void checkMemberAccess(Class c, int memberType) + { + if (c == null) + throw new NullPointerException(); + if (memberType == Member.PUBLIC) + return; + // XXX Allow access to classes created by same classloader before next + // check. + checkPermission(new RuntimePermission("accessDeclaredMembers")); + } + + /** + * Test whether a particular security action may be taken. The default + * implementation checks SecurityPermission(action). If you + * override this, call super.checkSecurityAccess rather than + * throwing an exception. + * + * @param action the desired action to take + * @throws SecurityException if permission is denied + * @throws NullPointerException if action is null + * @throws IllegalArgumentException if action is "" + * @since 1.1 + */ + public void checkSecurityAccess(String action) + { + checkPermission(new SecurityPermission(action)); + } + + /** + * Get the ThreadGroup that a new Thread should belong to by default. Called + * by Thread.Thread(). The default implementation returns the current + * ThreadGroup of the current Thread. Spec Note: it is not + * clear whether the new Thread is guaranteed to pass the + * checkAccessThreadGroup() test when using this ThreadGroup, but I presume + * so. + * + * @return the ThreadGroup to put the new Thread into + * @since 1.1 + */ + public ThreadGroup getThreadGroup() + { + return Thread.currentThread().getThreadGroup(); + } + + /** + * Helper that checks a comma-separated list of restricted packages, from + * Security.getProperty("package.definition"), for the given + * package access permission. If packageName starts with or equals any + * restricted package, it checks + * RuntimePermission(permission + packageName). + * + * @param packageName the package name to check access to + * @param restriction "package.access" or "package.definition" + * @param permission the base permission, including the '.' + * @throws SecurityException if permission is denied + * @throws NullPointerException if packageName is null + * @see #checkPackageAccess(String) + * @see #checkPackageDefinition(String) + */ + void checkPackageList(String packageName, final String restriction, + String permission) + { + if (packageName == null) + throw new NullPointerException(); + + String list = (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return Security.getProperty(restriction); + } + }); + + if (list == null || list.equals("")) + return; + + String packageNamePlusDot = packageName + "."; + + StringTokenizer st = new StringTokenizer(list, ","); + while (st.hasMoreTokens()) + { + if (packageNamePlusDot.startsWith(st.nextToken())) + { + Permission p = new RuntimePermission(permission + packageName); + checkPermission(p); + return; + } + } + } +} diff --git a/libjava/classpath/java/lang/Short.java b/libjava/classpath/java/lang/Short.java new file mode 100644 index 0000000..fbeea91 --- /dev/null +++ b/libjava/classpath/java/lang/Short.java @@ -0,0 +1,353 @@ +/* Short.java -- object wrapper for short + Copyright (C) 1998, 2001, 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 java.lang; + +/** + * Instances of class Short represent primitive + * short values. + * + * Additionally, this class provides various helper functions and variables + * related to shorts. + * + * @author Paul Fisher + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public final class Short extends Number implements Comparable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 7515723908773894738L; + + /** + * The minimum value a short can represent is -32768 (or + * -215). + */ + public static final short MIN_VALUE = -32768; + + /** + * The minimum value a short can represent is 32767 (or + * 215). + */ + public static final short MAX_VALUE = 32767; + + /** + * The primitive type short is represented by this + * Class object. + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass('S'); + + /** + * The immutable value of this Short. + * + * @serial the wrapped short + */ + private final short value; + + /** + * Create a Short object representing the value of the + * short argument. + * + * @param value the value to use + */ + public Short(short value) + { + this.value = value; + } + + /** + * Create a Short object representing the value of the + * argument after conversion to a short. + * + * @param s the string to convert + * @throws NumberFormatException if the String cannot be parsed + */ + public Short(String s) + { + value = parseShort(s, 10); + } + + /** + * Converts the short to a String and assumes + * a radix of 10. + * + * @param s the short to convert to String + * @return the String representation of the argument + */ + public static String toString(short s) + { + return String.valueOf(s); + } + + /** + * Converts the specified String into a short. + * This function assumes a radix of 10. + * + * @param s the String to convert + * @return the short value of s + * @throws NumberFormatException if s cannot be parsed as a + * short + */ + public static short parseShort(String s) + { + return parseShort(s, 10); + } + + /** + * Converts the specified String into a short + * using the specified radix (base). The string must not be null + * or empty. It may begin with an optional '-', which will negate the answer, + * provided that there are also valid digits. Each digit is parsed as if by + * Character.digit(d, radix), and must be in the range + * 0 to radix - 1. Finally, the result must be + * within MIN_VALUE to MAX_VALUE, inclusive. + * Unlike Double.parseDouble, you may not have a leading '+'. + * + * @param s the String to convert + * @param radix the radix (base) to use in the conversion + * @return the String argument converted to short + * @throws NumberFormatException if s cannot be parsed as a + * short + */ + public static short parseShort(String s, int radix) + { + int i = Integer.parseInt(s, radix, false); + if ((short) i != i) + throw new NumberFormatException(); + return (short) i; + } + + /** + * Creates a new Short object using the String + * and specified radix (base). + * + * @param s the String to convert + * @param radix the radix (base) to convert with + * @return the new Short + * @throws NumberFormatException if s cannot be parsed as a + * short + * @see #parseShort(String, int) + */ + public static Short valueOf(String s, int radix) + { + return new Short(parseShort(s, radix)); + } + + /** + * Creates a new Short object using the String, + * assuming a radix of 10. + * + * @param s the String to convert + * @return the new Short + * @throws NumberFormatException if s cannot be parsed as a + * short + * @see #Short(String) + * @see #parseShort(String) + */ + public static Short valueOf(String s) + { + return new Short(parseShort(s, 10)); + } + + /** + * Convert the specified String into a Short. + * The String may represent decimal, hexadecimal, or + * octal numbers. + * + *

    The extended BNF grammar is as follows:
    + *

    +   * DecodableString:
    +   *      ( [ - ] DecimalNumber )
    +   *    | ( [ - ] ( 0x | 0X
    +   *              | # ) HexDigit { HexDigit } )
    +   *    | ( [ - ] 0 { OctalDigit } )
    +   * DecimalNumber:
    +   *        DecimalDigit except '0' { DecimalDigit }
    +   * DecimalDigit:
    +   *        Character.digit(d, 10) has value 0 to 9
    +   * OctalDigit:
    +   *        Character.digit(d, 8) has value 0 to 7
    +   * DecimalDigit:
    +   *        Character.digit(d, 16) has value 0 to 15
    +   * 
    + * Finally, the value must be in the range MIN_VALUE to + * MAX_VALUE, or an exception is thrown. + * + * @param s the String to interpret + * @return the value of the String as a Short + * @throws NumberFormatException if s cannot be parsed as a + * short + * @throws NullPointerException if s is null + * @see Integer#decode(String) + */ + public static Short decode(String s) + { + int i = Integer.parseInt(s, 10, true); + if ((short) i != i) + throw new NumberFormatException(); + return new Short((short) i); + } + + /** + * Return the value of this Short as a byte. + * + * @return the byte value + */ + public byte byteValue() + { + return (byte) value; + } + + /** + * Return the value of this Short. + * + * @return the short value + */ + public short shortValue() + { + return value; + } + + /** + * Return the value of this Short as an int. + * + * @return the int value + */ + public int intValue() + { + return value; + } + + /** + * Return the value of this Short as a long. + * + * @return the long value + */ + public long longValue() + { + return value; + } + + /** + * Return the value of this Short as a float. + * + * @return the float value + */ + public float floatValue() + { + return value; + } + + /** + * Return the value of this Short as a double. + * + * @return the double value + */ + public double doubleValue() + { + return value; + } + + /** + * Converts the Short value to a String and + * assumes a radix of 10. + * + * @return the String representation of this Short + */ + public String toString() + { + return String.valueOf(value); + } + + /** + * Return a hashcode representing this Object. Short's hash + * code is simply its value. + * + * @return this Object's hash code + */ + public int hashCode() + { + return value; + } + + /** + * Returns true if obj is an instance of + * Short and represents the same short value. + * + * @param obj the object to compare + * @return whether these Objects are semantically equal + */ + public boolean equals(Object obj) + { + return obj instanceof Short && value == ((Short) obj).value; + } + + /** + * Compare two Shorts numerically by comparing their short + * values. The result is positive if the first is greater, negative if the + * second is greater, and 0 if the two are equal. + * + * @param s the Short to compare + * @return the comparison + * @since 1.2 + */ + public int compareTo(Short s) + { + return value - s.value; + } + + /** + * Behaves like compareTo(Short) unless the Object + * is not a Short. + * + * @param o the object to compare + * @return the comparison + * @throws ClassCastException if the argument is not a Short + * @see #compareTo(Short) + * @see Comparable + * @since 1.2 + */ + public int compareTo(Object o) + { + return compareTo((Short)o); + } +} diff --git a/libjava/classpath/java/lang/StackOverflowError.java b/libjava/classpath/java/lang/StackOverflowError.java new file mode 100644 index 0000000..5188ddd --- /dev/null +++ b/libjava/classpath/java/lang/StackOverflowError.java @@ -0,0 +1,72 @@ +/* StackOverflowError.java -- thrown when the stack depth is exceeded + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * A StackOverflowError is thrown when the execution stack + * overflow occurs. This often occurs when a method enters infinit recursion. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class StackOverflowError extends VirtualMachineError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 8609175038441759607L; + + /** + * Create an error without a message. + */ + public StackOverflowError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public StackOverflowError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/StackTraceElement.java b/libjava/classpath/java/lang/StackTraceElement.java new file mode 100644 index 0000000..6dd4d85 --- /dev/null +++ b/libjava/classpath/java/lang/StackTraceElement.java @@ -0,0 +1,259 @@ +/* StackTraceElement.java -- One function call or call stack element + Copyright (C) 2001, 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 java.lang; + +import java.io.Serializable; + +/** + * One function call or stack trace element. Gives information about + * the execution point such as the source file name, the line number, + * the fully qualified class name, the method name and whether this method + * is native, if this information is known. + * + * @author Mark Wielaard (mark@klomp.org) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public final class StackTraceElement implements Serializable +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 6992337162326171013L; + + /** + * The name of the file, null if unknown. + * + * @serial the source code filename, if known + */ + private final String fileName; + + /** + * The line number in the file, negative if unknown. + * + * @serial the source code line number, if known + */ + private final int lineNumber; + + /** + * The fully qualified class name, null if unknown. + * + * @serial the enclosing class, if known + */ + private final String declaringClass; + + /** + * The method name in the class, null if unknown. + * + * @serial the enclosing method, if known + */ + private final String methodName; + + /** Whether the method is native. */ + private final transient boolean isNative; + + /** + * A package local constructor for the StackTraceElement class, to be + * called by the Virtual Machine as part of Throwable.fillInStackTrace. + * There are no public constructors defined for this class. Creation + * of new elements is implementation specific. + * + * @param fileName the name of the file, null if unknown + * @param lineNumber the line in the file, negative if unknown + * @param className the fully qualified name of the class, null if unknown + * @param methodName the name of the method, null if unknown + * @param isNative true if native, false otherwise + */ + StackTraceElement(String fileName, int lineNumber, String className, + String methodName, boolean isNative) + { + this.fileName = fileName; + this.lineNumber = lineNumber; + this.declaringClass = className; + this.methodName = methodName; + this.isNative = isNative; + } + + /** + * Returns the name of the file, or null if unknown. This is usually + * obtained from the SourceFile attribute of the class file + * format, if present. + * + * @return the file name + */ + public String getFileName() + { + return fileName; + } + + /** + * Returns the line number in the file, or a negative number if unknown. + * This is usually obtained from the LineNumberTable attribute + * of the method in the class file format, if present. + * + * @return the line number + */ + public int getLineNumber() + { + return lineNumber; + } + + /** + * Returns the fully qualified class name, or null if unknown. + * + * @return the class name + */ + public String getClassName() + { + return declaringClass; + } + + /** + * Returns the method name in the class, or null if unknown. If the + * execution point is in a constructor, the name is + * <init>; if the execution point is in the class + * initializer, the name is <clinit>. + * + * @return the method name + */ + public String getMethodName() + { + return methodName; + } + + /** + * Returns true if the method is native, or false if it is not or unknown. + * + * @return whether the method is native + */ + public boolean isNativeMethod() + { + return isNative; + } + + /** + * Returns a string representation of this stack trace element. The + * returned String is implementation specific. This implementation + * returns the following String: "[class][.][method]([file][:line])". + * If the fully qualified class name or the method is unknown it is + * omitted including the point seperator. If the source file name is + * unknown it is replaced by "Unknown Source" if the method is not native + * or by "Native Method" if the method is native. If the line number + * is unknown it and the colon are omitted. + * + * @return a string representation of this execution point + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + if (declaringClass != null) + { + sb.append(declaringClass); + if (methodName != null) + sb.append('.'); + } + if (methodName != null) + sb.append(methodName); + sb.append(" ("); + if (fileName != null) + sb.append(fileName); + else + sb.append(isNative ? "Native Method" : "Unknown Source"); + if (lineNumber >= 0) + sb.append(':').append(lineNumber); + sb.append(')'); + return sb.toString(); + } + + /** + * Returns true if the given object is also a StackTraceElement and all + * attributes, except the native flag, are equal (either the same attribute + * between the two elments are null, or both satisfy Object.equals). + * + * @param o the object to compare + * @return true if the two are equal + */ + public boolean equals(Object o) + { + if (! (o instanceof StackTraceElement)) + return false; + StackTraceElement e = (StackTraceElement) o; + return equals(fileName, e.fileName) + && lineNumber == e.lineNumber + && equals(declaringClass, e.declaringClass) + && equals(methodName, e.methodName); + } + + /** + * Returns the hashCode of this StackTraceElement. This implementation + * computes the hashcode by xor-ing the hashcode of all attributes except + * the native flag. + * + * @return the hashcode + */ + public int hashCode() + { + return hashCode(fileName) ^ lineNumber ^ hashCode(declaringClass) + ^ hashCode(methodName); + } + + /** + * Compare two objects according to Collection semantics. + * + * @param o1 the first object + * @param o2 the second object + * @return o1 == null ? o2 == null : o1.equals(o2) + */ + private static boolean equals(Object o1, Object o2) + { + return o1 == null ? o2 == null : o1.equals(o2); + } + + /** + * Hash an object according to Collection semantics. + * + * @param o the object to hash + * @return o1 == null ? 0 : o1.hashCode() + */ + private static int hashCode(Object o) + { + return o == null ? 0 : o.hashCode(); + } +} diff --git a/libjava/classpath/java/lang/StrictMath.java b/libjava/classpath/java/lang/StrictMath.java new file mode 100644 index 0000000..32bd354 --- /dev/null +++ b/libjava/classpath/java/lang/StrictMath.java @@ -0,0 +1,1844 @@ +/* java.lang.StrictMath -- common mathematical functions, strict Java + Copyright (C) 1998, 2001, 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. */ + +/* + * Some of the algorithms in this class are in the public domain, as part + * of fdlibm (freely-distributable math library), available at + * http://www.netlib.org/fdlibm/, and carry the following copyright: + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +package java.lang; + +import gnu.classpath.Configuration; + +import java.util.Random; + +/** + * Helper class containing useful mathematical functions and constants. + * This class mirrors {@link Math}, but is 100% portable, because it uses + * no native methods whatsoever. Also, these algorithms are all accurate + * to less than 1 ulp, and execute in strictfp mode, while + * Math is allowed to vary in its results for some functions. Unfortunately, + * this usually means StrictMath has less efficiency and speed, as Math can + * use native methods. + * + *

    The source of the various algorithms used is the fdlibm library, at:
    + * http://www.netlib.org/fdlibm/ + * + * Note that angles are specified in radians. Conversion functions are + * provided for your convenience. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + */ +public final strictfp class StrictMath +{ + /** + * StrictMath is non-instantiable. + */ + private StrictMath() + { + } + + /** + * A random number generator, initialized on first use. + * + * @see #random() + */ + private static Random rand; + + /** + * The most accurate approximation to the mathematical constant e: + * 2.718281828459045. Used in natural log and exp. + * + * @see #log(double) + * @see #exp(double) + */ + public static final double E + = 2.718281828459045; // Long bits 0x4005bf0z8b145769L. + + /** + * The most accurate approximation to the mathematical constant pi: + * 3.141592653589793. This is the ratio of a circle's diameter + * to its circumference. + */ + public static final double PI + = 3.141592653589793; // Long bits 0x400921fb54442d18L. + + /** + * Take the absolute value of the argument. (Absolute value means make + * it positive.) + * + *

    Note that the the largest negative value (Integer.MIN_VALUE) cannot + * be made positive. In this case, because of the rules of negation in + * a computer, MIN_VALUE is what will be returned. + * This is a negative value. You have been warned. + * + * @param i the number to take the absolute value of + * @return the absolute value + * @see Integer#MIN_VALUE + */ + public static int abs(int i) + { + return (i < 0) ? -i : i; + } + + /** + * Take the absolute value of the argument. (Absolute value means make + * it positive.) + * + *

    Note that the the largest negative value (Long.MIN_VALUE) cannot + * be made positive. In this case, because of the rules of negation in + * a computer, MIN_VALUE is what will be returned. + * This is a negative value. You have been warned. + * + * @param l the number to take the absolute value of + * @return the absolute value + * @see Long#MIN_VALUE + */ + public static long abs(long l) + { + return (l < 0) ? -l : l; + } + + /** + * Take the absolute value of the argument. (Absolute value means make + * it positive.) + * + * @param f the number to take the absolute value of + * @return the absolute value + */ + public static float abs(float f) + { + return (f <= 0) ? 0 - f : f; + } + + /** + * Take the absolute value of the argument. (Absolute value means make + * it positive.) + * + * @param d the number to take the absolute value of + * @return the absolute value + */ + public static double abs(double d) + { + return (d <= 0) ? 0 - d : d; + } + + /** + * Return whichever argument is smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static int min(int a, int b) + { + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static long min(long a, long b) + { + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, -0 is always smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static float min(float a, float b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; < will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return -(-a - b); + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, -0 is always smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static double min(double a, double b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; < will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return -(-a - b); + return (a < b) ? a : b; + } + + /** + * Return whichever argument is larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static int max(int a, int b) + { + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static long max(long a, long b) + { + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, 0 is always larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static float max(float a, float b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; > will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return a - -b; + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, 0 is always larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static double max(double a, double b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; > will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return a - -b; + return (a > b) ? a : b; + } + + /** + * The trigonometric function sin. The sine of NaN or infinity is + * NaN, and the sine of 0 retains its sign. + * + * @param a the angle (in radians) + * @return sin(a) + */ + public static double sin(double a) + { + if (a == Double.NEGATIVE_INFINITY || ! (a < Double.POSITIVE_INFINITY)) + return Double.NaN; + + if (abs(a) <= PI / 4) + return sin(a, 0); + + // Argument reduction needed. + double[] y = new double[2]; + int n = remPiOver2(a, y); + switch (n & 3) + { + case 0: + return sin(y[0], y[1]); + case 1: + return cos(y[0], y[1]); + case 2: + return -sin(y[0], y[1]); + default: + return -cos(y[0], y[1]); + } + } + + /** + * The trigonometric function cos. The cosine of NaN or infinity is + * NaN. + * + * @param a the angle (in radians). + * @return cos(a). + */ + public static double cos(double a) + { + if (a == Double.NEGATIVE_INFINITY || ! (a < Double.POSITIVE_INFINITY)) + return Double.NaN; + + if (abs(a) <= PI / 4) + return cos(a, 0); + + // Argument reduction needed. + double[] y = new double[2]; + int n = remPiOver2(a, y); + switch (n & 3) + { + case 0: + return cos(y[0], y[1]); + case 1: + return -sin(y[0], y[1]); + case 2: + return -cos(y[0], y[1]); + default: + return sin(y[0], y[1]); + } + } + + /** + * The trigonometric function tan. The tangent of NaN or infinity + * is NaN, and the tangent of 0 retains its sign. + * + * @param a the angle (in radians) + * @return tan(a) + */ + public static double tan(double a) + { + if (a == Double.NEGATIVE_INFINITY || ! (a < Double.POSITIVE_INFINITY)) + return Double.NaN; + + if (abs(a) <= PI / 4) + return tan(a, 0, false); + + // Argument reduction needed. + double[] y = new double[2]; + int n = remPiOver2(a, y); + return tan(y[0], y[1], (n & 1) == 1); + } + + /** + * The trigonometric function arcsin. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN; and the arcsine of + * 0 retains its sign. + * + * @param x the sin to turn back into an angle + * @return arcsin(x) + */ + public static double asin(double x) + { + boolean negative = x < 0; + if (negative) + x = -x; + if (! (x <= 1)) + return Double.NaN; + if (x == 1) + return negative ? -PI / 2 : PI / 2; + if (x < 0.5) + { + if (x < 1 / TWO_27) + return negative ? -x : x; + double t = x * x; + double p = t * (PS0 + t * (PS1 + t * (PS2 + t * (PS3 + t + * (PS4 + t * PS5))))); + double q = 1 + t * (QS1 + t * (QS2 + t * (QS3 + t * QS4))); + return negative ? -x - x * (p / q) : x + x * (p / q); + } + double w = 1 - x; // 1>|x|>=0.5. + double t = w * 0.5; + double p = t * (PS0 + t * (PS1 + t * (PS2 + t * (PS3 + t + * (PS4 + t * PS5))))); + double q = 1 + t * (QS1 + t * (QS2 + t * (QS3 + t * QS4))); + double s = sqrt(t); + if (x >= 0.975) + { + w = p / q; + t = PI / 2 - (2 * (s + s * w) - PI_L / 2); + } + else + { + w = (float) s; + double c = (t - w * w) / (s + w); + p = 2 * s * (p / q) - (PI_L / 2 - 2 * c); + q = PI / 4 - 2 * w; + t = PI / 4 - (p - q); + } + return negative ? -t : t; + } + + /** + * The trigonometric function arccos. The range of angles returned + * is 0 to pi radians (0 to 180 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN. + * + * @param x the cos to turn back into an angle + * @return arccos(x) + */ + public static double acos(double x) + { + boolean negative = x < 0; + if (negative) + x = -x; + if (! (x <= 1)) + return Double.NaN; + if (x == 1) + return negative ? PI : 0; + if (x < 0.5) + { + if (x < 1 / TWO_57) + return PI / 2; + double z = x * x; + double p = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z + * (PS4 + z * PS5))))); + double q = 1 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); + double r = x - (PI_L / 2 - x * (p / q)); + return negative ? PI / 2 + r : PI / 2 - r; + } + if (negative) // x<=-0.5. + { + double z = (1 + x) * 0.5; + double p = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z + * (PS4 + z * PS5))))); + double q = 1 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); + double s = sqrt(z); + double w = p / q * s - PI_L / 2; + return PI - 2 * (s + w); + } + double z = (1 - x) * 0.5; // x>0.5. + double s = sqrt(z); + double df = (float) s; + double c = (z - df * df) / (s + df); + double p = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z + * (PS4 + z * PS5))))); + double q = 1 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); + double w = p / q * s + c; + return 2 * (df + w); + } + + /** + * The trigonometric function arcsin. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN, the + * result is NaN; and the arctangent of 0 retains its sign. + * + * @param x the tan to turn back into an angle + * @return arcsin(x) + * @see #atan2(double, double) + */ + public static double atan(double x) + { + double lo; + double hi; + boolean negative = x < 0; + if (negative) + x = -x; + if (x >= TWO_66) + return negative ? -PI / 2 : PI / 2; + if (! (x >= 0.4375)) // |x|<7/16, or NaN. + { + if (! (x >= 1 / TWO_29)) // Small, or NaN. + return negative ? -x : x; + lo = hi = 0; + } + else if (x < 1.1875) + { + if (x < 0.6875) // 7/16<=|x|<11/16. + { + x = (2 * x - 1) / (2 + x); + hi = ATAN_0_5H; + lo = ATAN_0_5L; + } + else // 11/16<=|x|<19/16. + { + x = (x - 1) / (x + 1); + hi = PI / 4; + lo = PI_L / 4; + } + } + else if (x < 2.4375) // 19/16<=|x|<39/16. + { + x = (x - 1.5) / (1 + 1.5 * x); + hi = ATAN_1_5H; + lo = ATAN_1_5L; + } + else // 39/16<=|x|<2**66. + { + x = -1 / x; + hi = PI / 2; + lo = PI_L / 2; + } + + // Break sum from i=0 to 10 ATi*z**(i+1) into odd and even poly. + double z = x * x; + double w = z * z; + double s1 = z * (AT0 + w * (AT2 + w * (AT4 + w * (AT6 + w + * (AT8 + w * AT10))))); + double s2 = w * (AT1 + w * (AT3 + w * (AT5 + w * (AT7 + w * AT9)))); + if (hi == 0) + return negative ? x * (s1 + s2) - x : x - x * (s1 + s2); + z = hi - ((x * (s1 + s2) - lo) - x); + return negative ? -z : z; + } + + /** + * A special version of the trigonometric function arctan, for + * converting rectangular coordinates (x, y) to polar + * (r, theta). This computes the arctangent of x/y in the range + * of -pi to pi radians (-180 to 180 degrees). Special cases:

      + *
    • If either argument is NaN, the result is NaN.
    • + *
    • If the first argument is positive zero and the second argument is + * positive, or the first argument is positive and finite and the second + * argument is positive infinity, then the result is positive zero.
    • + *
    • If the first argument is negative zero and the second argument is + * positive, or the first argument is negative and finite and the second + * argument is positive infinity, then the result is negative zero.
    • + *
    • If the first argument is positive zero and the second argument is + * negative, or the first argument is positive and finite and the second + * argument is negative infinity, then the result is the double value + * closest to pi.
    • + *
    • If the first argument is negative zero and the second argument is + * negative, or the first argument is negative and finite and the second + * argument is negative infinity, then the result is the double value + * closest to -pi.
    • + *
    • If the first argument is positive and the second argument is + * positive zero or negative zero, or the first argument is positive + * infinity and the second argument is finite, then the result is the + * double value closest to pi/2.
    • + *
    • If the first argument is negative and the second argument is + * positive zero or negative zero, or the first argument is negative + * infinity and the second argument is finite, then the result is the + * double value closest to -pi/2.
    • + *
    • If both arguments are positive infinity, then the result is the + * double value closest to pi/4.
    • + *
    • If the first argument is positive infinity and the second argument + * is negative infinity, then the result is the double value closest to + * 3*pi/4.
    • + *
    • If the first argument is negative infinity and the second argument + * is positive infinity, then the result is the double value closest to + * -pi/4.
    • + *
    • If both arguments are negative infinity, then the result is the + * double value closest to -3*pi/4.
    • + * + *

    This returns theta, the angle of the point. To get r, albeit + * slightly inaccurately, use sqrt(x*x+y*y). + * + * @param y the y position + * @param x the x position + * @return theta in the conversion of (x, y) to (r, theta) + * @see #atan(double) + */ + public static double atan2(double y, double x) + { + if (x != x || y != y) + return Double.NaN; + if (x == 1) + return atan(y); + if (x == Double.POSITIVE_INFINITY) + { + if (y == Double.POSITIVE_INFINITY) + return PI / 4; + if (y == Double.NEGATIVE_INFINITY) + return -PI / 4; + return 0 * y; + } + if (x == Double.NEGATIVE_INFINITY) + { + if (y == Double.POSITIVE_INFINITY) + return 3 * PI / 4; + if (y == Double.NEGATIVE_INFINITY) + return -3 * PI / 4; + return (1 / (0 * y) == Double.POSITIVE_INFINITY) ? PI : -PI; + } + if (y == 0) + { + if (1 / (0 * x) == Double.POSITIVE_INFINITY) + return y; + return (1 / y == Double.POSITIVE_INFINITY) ? PI : -PI; + } + if (y == Double.POSITIVE_INFINITY || y == Double.NEGATIVE_INFINITY + || x == 0) + return y < 0 ? -PI / 2 : PI / 2; + + double z = abs(y / x); // Safe to do y/x. + if (z > TWO_60) + z = PI / 2 + 0.5 * PI_L; + else if (x < 0 && z < 1 / TWO_60) + z = 0; + else + z = atan(z); + if (x > 0) + return y > 0 ? z : -z; + return y > 0 ? PI - (z - PI_L) : z - PI_L - PI; + } + + /** + * Take ea. The opposite of log(). If the + * argument is NaN, the result is NaN; if the argument is positive infinity, + * the result is positive infinity; and if the argument is negative + * infinity, the result is positive zero. + * + * @param x the number to raise to the power + * @return the number raised to the power of e + * @see #log(double) + * @see #pow(double, double) + */ + public static double exp(double x) + { + if (x != x) + return x; + if (x > EXP_LIMIT_H) + return Double.POSITIVE_INFINITY; + if (x < EXP_LIMIT_L) + return 0; + + // Argument reduction. + double hi; + double lo; + int k; + double t = abs(x); + if (t > 0.5 * LN2) + { + if (t < 1.5 * LN2) + { + hi = t - LN2_H; + lo = LN2_L; + k = 1; + } + else + { + k = (int) (INV_LN2 * t + 0.5); + hi = t - k * LN2_H; + lo = k * LN2_L; + } + if (x < 0) + { + hi = -hi; + lo = -lo; + k = -k; + } + x = hi - lo; + } + else if (t < 1 / TWO_28) + return 1; + else + lo = hi = k = 0; + + // Now x is in primary range. + t = x * x; + double c = x - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + if (k == 0) + return 1 - (x * c / (c - 2) - x); + double y = 1 - (lo - x * c / (2 - c) - hi); + return scale(y, k); + } + + /** + * Take ln(a) (the natural log). The opposite of exp(). If the + * argument is NaN or negative, the result is NaN; if the argument is + * positive infinity, the result is positive infinity; and if the argument + * is either zero, the result is negative infinity. + * + *

    Note that the way to get logb(a) is to do this: + * ln(a) / ln(b). + * + * @param x the number to take the natural log of + * @return the natural log of a + * @see #exp(double) + */ + public static double log(double x) + { + if (x == 0) + return Double.NEGATIVE_INFINITY; + if (x < 0) + return Double.NaN; + if (! (x < Double.POSITIVE_INFINITY)) + return x; + + // Normalize x. + long bits = Double.doubleToLongBits(x); + int exp = (int) (bits >> 52); + if (exp == 0) // Subnormal x. + { + x *= TWO_54; + bits = Double.doubleToLongBits(x); + exp = (int) (bits >> 52) - 54; + } + exp -= 1023; // Unbias exponent. + bits = (bits & 0x000fffffffffffffL) | 0x3ff0000000000000L; + x = Double.longBitsToDouble(bits); + if (x >= SQRT_2) + { + x *= 0.5; + exp++; + } + x--; + if (abs(x) < 1 / TWO_20) + { + if (x == 0) + return exp * LN2_H + exp * LN2_L; + double r = x * x * (0.5 - 1 / 3.0 * x); + if (exp == 0) + return x - r; + return exp * LN2_H - ((r - exp * LN2_L) - x); + } + double s = x / (2 + x); + double z = s * s; + double w = z * z; + double t1 = w * (LG2 + w * (LG4 + w * LG6)); + double t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + double r = t2 + t1; + if (bits >= 0x3ff6174a00000000L && bits < 0x3ff6b85200000000L) + { + double h = 0.5 * x * x; // Need more accuracy for x near sqrt(2). + if (exp == 0) + return x - (h - s * (h + r)); + return exp * LN2_H - ((h - (s * (h + r) + exp * LN2_L)) - x); + } + if (exp == 0) + return x - s * (x - r); + return exp * LN2_H - ((s * (x - r) - exp * LN2_L) - x); + } + + /** + * Take a square root. If the argument is NaN or negative, the result is + * NaN; if the argument is positive infinity, the result is positive + * infinity; and if the result is either zero, the result is the same. + * + *

    For other roots, use pow(x, 1/rootNumber). + * + * @param x the numeric argument + * @return the square root of the argument + * @see #pow(double, double) + */ + public static double sqrt(double x) + { + if (x < 0) + return Double.NaN; + if (x == 0 || ! (x < Double.POSITIVE_INFINITY)) + return x; + + // Normalize x. + long bits = Double.doubleToLongBits(x); + int exp = (int) (bits >> 52); + if (exp == 0) // Subnormal x. + { + x *= TWO_54; + bits = Double.doubleToLongBits(x); + exp = (int) (bits >> 52) - 54; + } + exp -= 1023; // Unbias exponent. + bits = (bits & 0x000fffffffffffffL) | 0x0010000000000000L; + if ((exp & 1) == 1) // Odd exp, double x to make it even. + bits <<= 1; + exp >>= 1; + + // Generate sqrt(x) bit by bit. + bits <<= 1; + long q = 0; + long s = 0; + long r = 0x0020000000000000L; // Move r right to left. + while (r != 0) + { + long t = s + r; + if (t <= bits) + { + s = t + r; + bits -= t; + q += r; + } + bits <<= 1; + r >>= 1; + } + + // Use floating add to round correctly. + if (bits != 0) + q += q & 1; + return Double.longBitsToDouble((q >> 1) + ((exp + 1022L) << 52)); + } + + /** + * Raise a number to a power. Special cases:

      + *
    • If the second argument is positive or negative zero, then the result + * is 1.0.
    • + *
    • If the second argument is 1.0, then the result is the same as the + * first argument.
    • + *
    • If the second argument is NaN, then the result is NaN.
    • + *
    • If the first argument is NaN and the second argument is nonzero, + * then the result is NaN.
    • + *
    • If the absolute value of the first argument is greater than 1 and + * the second argument is positive infinity, or the absolute value of the + * first argument is less than 1 and the second argument is negative + * infinity, then the result is positive infinity.
    • + *
    • If the absolute value of the first argument is greater than 1 and + * the second argument is negative infinity, or the absolute value of the + * first argument is less than 1 and the second argument is positive + * infinity, then the result is positive zero.
    • + *
    • If the absolute value of the first argument equals 1 and the second + * argument is infinite, then the result is NaN.
    • + *
    • If the first argument is positive zero and the second argument is + * greater than zero, or the first argument is positive infinity and the + * second argument is less than zero, then the result is positive zero.
    • + *
    • If the first argument is positive zero and the second argument is + * less than zero, or the first argument is positive infinity and the + * second argument is greater than zero, then the result is positive + * infinity.
    • + *
    • If the first argument is negative zero and the second argument is + * greater than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is less than zero but not a + * finite odd integer, then the result is positive zero.
    • + *
    • If the first argument is negative zero and the second argument is a + * positive finite odd integer, or the first argument is negative infinity + * and the second argument is a negative finite odd integer, then the result + * is negative zero.
    • + *
    • If the first argument is negative zero and the second argument is + * less than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is greater than zero but not a + * finite odd integer, then the result is positive infinity.
    • + *
    • If the first argument is negative zero and the second argument is a + * negative finite odd integer, or the first argument is negative infinity + * and the second argument is a positive finite odd integer, then the result + * is negative infinity.
    • + *
    • If the first argument is less than zero and the second argument is a + * finite even integer, then the result is equal to the result of raising + * the absolute value of the first argument to the power of the second + * argument.
    • + *
    • If the first argument is less than zero and the second argument is a + * finite odd integer, then the result is equal to the negative of the + * result of raising the absolute value of the first argument to the power + * of the second argument.
    • + *
    • If the first argument is finite and less than zero and the second + * argument is finite and not an integer, then the result is NaN.
    • + *
    • If both arguments are integers, then the result is exactly equal to + * the mathematical result of raising the first argument to the power of + * the second argument if that result can in fact be represented exactly as + * a double value.
    • + * + *

    (In the foregoing descriptions, a floating-point value is + * considered to be an integer if and only if it is a fixed point of the + * method {@link #ceil(double)} or, equivalently, a fixed point of the + * method {@link #floor(double)}. A value is a fixed point of a one-argument + * method if and only if the result of applying the method to the value is + * equal to the value.) + * + * @param x the number to raise + * @param y the power to raise it to + * @return xy + */ + public static double pow(double x, double y) + { + // Special cases first. + if (y == 0) + return 1; + if (y == 1) + return x; + if (y == -1) + return 1 / x; + if (x != x || y != y) + return Double.NaN; + + // When x < 0, yisint tells if y is not an integer (0), even(1), + // or odd (2). + int yisint = 0; + if (x < 0 && floor(y) == y) + yisint = (y % 2 == 0) ? 2 : 1; + double ax = abs(x); + double ay = abs(y); + + // More special cases, of y. + if (ay == Double.POSITIVE_INFINITY) + { + if (ax == 1) + return Double.NaN; + if (ax > 1) + return y > 0 ? y : 0; + return y < 0 ? -y : 0; + } + if (y == 2) + return x * x; + if (y == 0.5) + return sqrt(x); + + // More special cases, of x. + if (x == 0 || ax == Double.POSITIVE_INFINITY || ax == 1) + { + if (y < 0) + ax = 1 / ax; + if (x < 0) + { + if (x == -1 && yisint == 0) + ax = Double.NaN; + else if (yisint == 1) + ax = -ax; + } + return ax; + } + if (x < 0 && yisint == 0) + return Double.NaN; + + // Now we can start! + double t; + double t1; + double t2; + double u; + double v; + double w; + if (ay > TWO_31) + { + if (ay > TWO_64) // Automatic over/underflow. + return ((ax < 1) ? y < 0 : y > 0) ? Double.POSITIVE_INFINITY : 0; + // Over/underflow if x is not close to one. + if (ax < 0.9999995231628418) + return y < 0 ? Double.POSITIVE_INFINITY : 0; + if (ax >= 1.0000009536743164) + return y > 0 ? Double.POSITIVE_INFINITY : 0; + // Now |1-x| is <= 2**-20, sufficient to compute + // log(x) by x-x^2/2+x^3/3-x^4/4. + t = x - 1; + w = t * t * (0.5 - t * (1 / 3.0 - t * 0.25)); + u = INV_LN2_H * t; + v = t * INV_LN2_L - w * INV_LN2; + t1 = (float) (u + v); + t2 = v - (t1 - u); + } + else + { + long bits = Double.doubleToLongBits(ax); + int exp = (int) (bits >> 52); + if (exp == 0) // Subnormal x. + { + ax *= TWO_54; + bits = Double.doubleToLongBits(ax); + exp = (int) (bits >> 52) - 54; + } + exp -= 1023; // Unbias exponent. + ax = Double.longBitsToDouble((bits & 0x000fffffffffffffL) + | 0x3ff0000000000000L); + boolean k; + if (ax < SQRT_1_5) // |x|= 1024) // Detect overflow. + { + if (z > 1024 || p_l + OVT > z - p_h) + return negative ? Double.NEGATIVE_INFINITY + : Double.POSITIVE_INFINITY; + } + else if (z <= -1075) // Detect underflow. + { + if (z < -1075 || p_l <= z - p_h) + return negative ? -0.0 : 0; + } + + // Compute 2**(p_h+p_l). + int n = round((float) z); + p_h -= n; + t = (float) (p_l + p_h); + u = t * LN2_H; + v = (p_l - (t - p_h)) * LN2 + t * LN2_L; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + double r = (z * t1) / (t1 - 2) - (w + z * w); + z = scale(1 - (r - z), n); + return negative ? -z : z; + } + + /** + * Get the IEEE 754 floating point remainder on two numbers. This is the + * value of x - y * n, where n is the closest + * double to x / y (ties go to the even n); for a zero + * remainder, the sign is that of x. If either argument is NaN, + * the first argument is infinite, or the second argument is zero, the result + * is NaN; if x is finite but y is infinite, the result is x. + * + * @param x the dividend (the top half) + * @param y the divisor (the bottom half) + * @return the IEEE 754-defined floating point remainder of x/y + * @see #rint(double) + */ + public static double IEEEremainder(double x, double y) + { + // Purge off exception values. + if (x == Double.NEGATIVE_INFINITY || ! (x < Double.POSITIVE_INFINITY) + || y == 0 || y != y) + return Double.NaN; + + boolean negative = x < 0; + x = abs(x); + y = abs(y); + if (x == y || x == 0) + return 0 * x; // Get correct sign. + + // Achieve x < 2y, then take first shot at remainder. + if (y < TWO_1023) + x %= y + y; + + // Now adjust x to get correct precision. + if (y < 4 / TWO_1023) + { + if (x + x > y) + { + x -= y; + if (x + x >= y) + x -= y; + } + } + else + { + y *= 0.5; + if (x > y) + { + x -= y; + if (x >= y) + x -= y; + } + } + return negative ? -x : x; + } + + /** + * Take the nearest integer that is that is greater than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same; if the argument is between -1 and 0, the result is negative zero. + * Note that Math.ceil(x) == -Math.floor(-x). + * + * @param a the value to act upon + * @return the nearest integer >= a + */ + public static double ceil(double a) + { + return -floor(-a); + } + + /** + * Take the nearest integer that is that is less than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same. Note that Math.ceil(x) == -Math.floor(-x). + * + * @param a the value to act upon + * @return the nearest integer <= a + */ + public static double floor(double a) + { + double x = abs(a); + if (! (x < TWO_52) || (long) a == a) + return a; // No fraction bits; includes NaN and infinity. + if (x < 1) + return a >= 0 ? 0 * a : -1; // Worry about signed zero. + return a < 0 ? (long) a - 1.0 : (long) a; // Cast to long truncates. + } + + /** + * Take the nearest integer to the argument. If it is exactly between + * two integers, the even integer is taken. If the argument is NaN, + * infinite, or zero, the result is the same. + * + * @param a the value to act upon + * @return the nearest integer to a + */ + public static double rint(double a) + { + double x = abs(a); + if (! (x < TWO_52)) + return a; // No fraction bits; includes NaN and infinity. + if (x <= 0.5) + return 0 * a; // Worry about signed zero. + if (x % 2 <= 0.5) + return (long) a; // Catch round down to even. + return (long) (a + (a < 0 ? -0.5 : 0.5)); // Cast to long truncates. + } + + /** + * Take the nearest integer to the argument. This is equivalent to + * (int) Math.floor(f + 0.5f). If the argument is NaN, the + * result is 0; otherwise if the argument is outside the range of int, the + * result will be Integer.MIN_VALUE or Integer.MAX_VALUE, as appropriate. + * + * @param f the argument to round + * @return the nearest integer to the argument + * @see Integer#MIN_VALUE + * @see Integer#MAX_VALUE + */ + public static int round(float f) + { + return (int) floor(f + 0.5f); + } + + /** + * Take the nearest long to the argument. This is equivalent to + * (long) Math.floor(d + 0.5). If the argument is NaN, the + * result is 0; otherwise if the argument is outside the range of long, the + * result will be Long.MIN_VALUE or Long.MAX_VALUE, as appropriate. + * + * @param d the argument to round + * @return the nearest long to the argument + * @see Long#MIN_VALUE + * @see Long#MAX_VALUE + */ + public static long round(double d) + { + return (long) floor(d + 0.5); + } + + /** + * Get a random number. This behaves like Random.nextDouble(), seeded by + * System.currentTimeMillis() when first called. In other words, the number + * is from a pseudorandom sequence, and lies in the range [+0.0, 1.0). + * This random sequence is only used by this method, and is threadsafe, + * although you may want your own random number generator if it is shared + * among threads. + * + * @return a random number + * @see Random#nextDouble() + * @see System#currentTimeMillis() + */ + public static synchronized double random() + { + if (rand == null) + rand = new Random(); + return rand.nextDouble(); + } + + /** + * Convert from degrees to radians. The formula for this is + * radians = degrees * (pi/180); however it is not always exact given the + * limitations of floating point numbers. + * + * @param degrees an angle in degrees + * @return the angle in radians + */ + public static double toRadians(double degrees) + { + return (degrees * PI) / 180; + } + + /** + * Convert from radians to degrees. The formula for this is + * degrees = radians * (180/pi); however it is not always exact given the + * limitations of floating point numbers. + * + * @param rads an angle in radians + * @return the angle in degrees + */ + public static double toDegrees(double rads) + { + return (rads * 180) / PI; + } + + /** + * Constants for scaling and comparing doubles by powers of 2. The compiler + * must automatically inline constructs like (1/TWO_54), so we don't list + * negative powers of two here. + */ + private static final double + TWO_16 = 0x10000, // Long bits 0x40f0000000000000L. + TWO_20 = 0x100000, // Long bits 0x4130000000000000L. + TWO_24 = 0x1000000, // Long bits 0x4170000000000000L. + TWO_27 = 0x8000000, // Long bits 0x41a0000000000000L. + TWO_28 = 0x10000000, // Long bits 0x41b0000000000000L. + TWO_29 = 0x20000000, // Long bits 0x41c0000000000000L. + TWO_31 = 0x80000000L, // Long bits 0x41e0000000000000L. + TWO_49 = 0x2000000000000L, // Long bits 0x4300000000000000L. + TWO_52 = 0x10000000000000L, // Long bits 0x4330000000000000L. + TWO_54 = 0x40000000000000L, // Long bits 0x4350000000000000L. + TWO_57 = 0x200000000000000L, // Long bits 0x4380000000000000L. + TWO_60 = 0x1000000000000000L, // Long bits 0x43b0000000000000L. + TWO_64 = 1.8446744073709552e19, // Long bits 0x43f0000000000000L. + TWO_66 = 7.378697629483821e19, // Long bits 0x4410000000000000L. + TWO_1023 = 8.98846567431158e307; // Long bits 0x7fe0000000000000L. + + /** + * Super precision for 2/pi in 24-bit chunks, for use in + * {@link #remPiOver2()}. + */ + private static final int TWO_OVER_PI[] = { + 0xa2f983, 0x6e4e44, 0x1529fc, 0x2757d1, 0xf534dd, 0xc0db62, + 0x95993c, 0x439041, 0xfe5163, 0xabdebb, 0xc561b7, 0x246e3a, + 0x424dd2, 0xe00649, 0x2eea09, 0xd1921c, 0xfe1deb, 0x1cb129, + 0xa73ee8, 0x8235f5, 0x2ebb44, 0x84e99c, 0x7026b4, 0x5f7e41, + 0x3991d6, 0x398353, 0x39f49c, 0x845f8b, 0xbdf928, 0x3b1ff8, + 0x97ffde, 0x05980f, 0xef2f11, 0x8b5a0a, 0x6d1f6d, 0x367ecf, + 0x27cb09, 0xb74f46, 0x3f669e, 0x5fea2d, 0x7527ba, 0xc7ebe5, + 0xf17b3d, 0x0739f7, 0x8a5292, 0xea6bfb, 0x5fb11f, 0x8d5d08, + 0x560330, 0x46fc7b, 0x6babf0, 0xcfbc20, 0x9af436, 0x1da9e3, + 0x91615e, 0xe61b08, 0x659985, 0x5f14a0, 0x68408d, 0xffd880, + 0x4d7327, 0x310606, 0x1556ca, 0x73a8c9, 0x60e27b, 0xc08c6b, + }; + + /** + * Super precision for pi/2 in 24-bit chunks, for use in + * {@link #remPiOver2()}. + */ + private static final double PI_OVER_TWO[] = { + 1.570796251296997, // Long bits 0x3ff921fb40000000L. + 7.549789415861596e-8, // Long bits 0x3e74442d00000000L. + 5.390302529957765e-15, // Long bits 0x3cf8469880000000L. + 3.282003415807913e-22, // Long bits 0x3b78cc5160000000L. + 1.270655753080676e-29, // Long bits 0x39f01b8380000000L. + 1.2293330898111133e-36, // Long bits 0x387a252040000000L. + 2.7337005381646456e-44, // Long bits 0x36e3822280000000L. + 2.1674168387780482e-51, // Long bits 0x3569f31d00000000L. + }; + + /** + * More constants related to pi, used in {@link #remPiOver2()} and + * elsewhere. + */ + private static final double + PI_L = 1.2246467991473532e-16, // Long bits 0x3ca1a62633145c07L. + PIO2_1 = 1.5707963267341256, // Long bits 0x3ff921fb54400000L. + PIO2_1L = 6.077100506506192e-11, // Long bits 0x3dd0b4611a626331L. + PIO2_2 = 6.077100506303966e-11, // Long bits 0x3dd0b4611a600000L. + PIO2_2L = 2.0222662487959506e-21, // Long bits 0x3ba3198a2e037073L. + PIO2_3 = 2.0222662487111665e-21, // Long bits 0x3ba3198a2e000000L. + PIO2_3L = 8.4784276603689e-32; // Long bits 0x397b839a252049c1L. + + /** + * Natural log and square root constants, for calculation of + * {@link #exp(double)}, {@link #log(double)} and + * {@link #power(double, double)}. CP is 2/(3*ln(2)). + */ + private static final double + SQRT_1_5 = 1.224744871391589, // Long bits 0x3ff3988e1409212eL. + SQRT_2 = 1.4142135623730951, // Long bits 0x3ff6a09e667f3bcdL. + SQRT_3 = 1.7320508075688772, // Long bits 0x3ffbb67ae8584caaL. + EXP_LIMIT_H = 709.782712893384, // Long bits 0x40862e42fefa39efL. + EXP_LIMIT_L = -745.1332191019411, // Long bits 0xc0874910d52d3051L. + CP = 0.9617966939259756, // Long bits 0x3feec709dc3a03fdL. + CP_H = 0.9617967009544373, // Long bits 0x3feec709e0000000L. + CP_L = -7.028461650952758e-9, // Long bits 0xbe3e2fe0145b01f5L. + LN2 = 0.6931471805599453, // Long bits 0x3fe62e42fefa39efL. + LN2_H = 0.6931471803691238, // Long bits 0x3fe62e42fee00000L. + LN2_L = 1.9082149292705877e-10, // Long bits 0x3dea39ef35793c76L. + INV_LN2 = 1.4426950408889634, // Long bits 0x3ff71547652b82feL. + INV_LN2_H = 1.4426950216293335, // Long bits 0x3ff7154760000000L. + INV_LN2_L = 1.9259629911266175e-8; // Long bits 0x3e54ae0bf85ddf44L. + + /** + * Constants for computing {@link #log(double)}. + */ + private static final double + LG1 = 0.6666666666666735, // Long bits 0x3fe5555555555593L. + LG2 = 0.3999999999940942, // Long bits 0x3fd999999997fa04L. + LG3 = 0.2857142874366239, // Long bits 0x3fd2492494229359L. + LG4 = 0.22222198432149784, // Long bits 0x3fcc71c51d8e78afL. + LG5 = 0.1818357216161805, // Long bits 0x3fc7466496cb03deL. + LG6 = 0.15313837699209373, // Long bits 0x3fc39a09d078c69fL. + LG7 = 0.14798198605116586; // Long bits 0x3fc2f112df3e5244L. + + /** + * Constants for computing {@link #pow(double, double)}. L and P are + * coefficients for series; OVT is -(1024-log2(ovfl+.5ulp)); and DP is ???. + * The P coefficients also calculate {@link #exp(double)}. + */ + private static final double + L1 = 0.5999999999999946, // Long bits 0x3fe3333333333303L. + L2 = 0.4285714285785502, // Long bits 0x3fdb6db6db6fabffL. + L3 = 0.33333332981837743, // Long bits 0x3fd55555518f264dL. + L4 = 0.272728123808534, // Long bits 0x3fd17460a91d4101L. + L5 = 0.23066074577556175, // Long bits 0x3fcd864a93c9db65L. + L6 = 0.20697501780033842, // Long bits 0x3fca7e284a454eefL. + P1 = 0.16666666666666602, // Long bits 0x3fc555555555553eL. + P2 = -2.7777777777015593e-3, // Long bits 0xbf66c16c16bebd93L. + P3 = 6.613756321437934e-5, // Long bits 0x3f11566aaf25de2cL. + P4 = -1.6533902205465252e-6, // Long bits 0xbebbbd41c5d26bf1L. + P5 = 4.1381367970572385e-8, // Long bits 0x3e66376972bea4d0L. + DP_H = 0.5849624872207642, // Long bits 0x3fe2b80340000000L. + DP_L = 1.350039202129749e-8, // Long bits 0x3e4cfdeb43cfd006L. + OVT = 8.008566259537294e-17; // Long bits 0x3c971547652b82feL. + + /** + * Coefficients for computing {@link #sin(double)}. + */ + private static final double + S1 = -0.16666666666666632, // Long bits 0xbfc5555555555549L. + S2 = 8.33333333332249e-3, // Long bits 0x3f8111111110f8a6L. + S3 = -1.984126982985795e-4, // Long bits 0xbf2a01a019c161d5L. + S4 = 2.7557313707070068e-6, // Long bits 0x3ec71de357b1fe7dL. + S5 = -2.5050760253406863e-8, // Long bits 0xbe5ae5e68a2b9cebL. + S6 = 1.58969099521155e-10; // Long bits 0x3de5d93a5acfd57cL. + + /** + * Coefficients for computing {@link #cos(double)}. + */ + private static final double + C1 = 0.0416666666666666, // Long bits 0x3fa555555555554cL. + C2 = -1.388888888887411e-3, // Long bits 0xbf56c16c16c15177L. + C3 = 2.480158728947673e-5, // Long bits 0x3efa01a019cb1590L. + C4 = -2.7557314351390663e-7, // Long bits 0xbe927e4f809c52adL. + C5 = 2.087572321298175e-9, // Long bits 0x3e21ee9ebdb4b1c4L. + C6 = -1.1359647557788195e-11; // Long bits 0xbda8fae9be8838d4L. + + /** + * Coefficients for computing {@link #tan(double)}. + */ + private static final double + T0 = 0.3333333333333341, // Long bits 0x3fd5555555555563L. + T1 = 0.13333333333320124, // Long bits 0x3fc111111110fe7aL. + T2 = 0.05396825397622605, // Long bits 0x3faba1ba1bb341feL. + T3 = 0.021869488294859542, // Long bits 0x3f9664f48406d637L. + T4 = 8.8632398235993e-3, // Long bits 0x3f8226e3e96e8493L. + T5 = 3.5920791075913124e-3, // Long bits 0x3f6d6d22c9560328L. + T6 = 1.4562094543252903e-3, // Long bits 0x3f57dbc8fee08315L. + T7 = 5.880412408202641e-4, // Long bits 0x3f4344d8f2f26501L. + T8 = 2.464631348184699e-4, // Long bits 0x3f3026f71a8d1068L. + T9 = 7.817944429395571e-5, // Long bits 0x3f147e88a03792a6L. + T10 = 7.140724913826082e-5, // Long bits 0x3f12b80f32f0a7e9L. + T11 = -1.8558637485527546e-5, // Long bits 0xbef375cbdb605373L. + T12 = 2.590730518636337e-5; // Long bits 0x3efb2a7074bf7ad4L. + + /** + * Coefficients for computing {@link #asin(double)} and + * {@link #acos(double)}. + */ + private static final double + PS0 = 0.16666666666666666, // Long bits 0x3fc5555555555555L. + PS1 = -0.3255658186224009, // Long bits 0xbfd4d61203eb6f7dL. + PS2 = 0.20121253213486293, // Long bits 0x3fc9c1550e884455L. + PS3 = -0.04005553450067941, // Long bits 0xbfa48228b5688f3bL. + PS4 = 7.915349942898145e-4, // Long bits 0x3f49efe07501b288L. + PS5 = 3.479331075960212e-5, // Long bits 0x3f023de10dfdf709L. + QS1 = -2.403394911734414, // Long bits 0xc0033a271c8a2d4bL. + QS2 = 2.0209457602335057, // Long bits 0x40002ae59c598ac8L. + QS3 = -0.6882839716054533, // Long bits 0xbfe6066c1b8d0159L. + QS4 = 0.07703815055590194; // Long bits 0x3fb3b8c5b12e9282L. + + /** + * Coefficients for computing {@link #atan(double)}. + */ + private static final double + ATAN_0_5H = 0.4636476090008061, // Long bits 0x3fddac670561bb4fL. + ATAN_0_5L = 2.2698777452961687e-17, // Long bits 0x3c7a2b7f222f65e2L. + ATAN_1_5H = 0.982793723247329, // Long bits 0x3fef730bd281f69bL. + ATAN_1_5L = 1.3903311031230998e-17, // Long bits 0x3c7007887af0cbbdL. + AT0 = 0.3333333333333293, // Long bits 0x3fd555555555550dL. + AT1 = -0.19999999999876483, // Long bits 0xbfc999999998ebc4L. + AT2 = 0.14285714272503466, // Long bits 0x3fc24924920083ffL. + AT3 = -0.11111110405462356, // Long bits 0xbfbc71c6fe231671L. + AT4 = 0.09090887133436507, // Long bits 0x3fb745cdc54c206eL. + AT5 = -0.0769187620504483, // Long bits 0xbfb3b0f2af749a6dL. + AT6 = 0.06661073137387531, // Long bits 0x3fb10d66a0d03d51L. + AT7 = -0.058335701337905735, // Long bits 0xbfadde2d52defd9aL. + AT8 = 0.049768779946159324, // Long bits 0x3fa97b4b24760debL. + AT9 = -0.036531572744216916, // Long bits 0xbfa2b4442c6a6c2fL. + AT10 = 0.016285820115365782; // Long bits 0x3f90ad3ae322da11L. + + /** + * Helper function for reducing an angle to a multiple of pi/2 within + * [-pi/4, pi/4]. + * + * @param x the angle; not infinity or NaN, and outside pi/4 + * @param y an array of 2 doubles modified to hold the remander x % pi/2 + * @return the quadrant of the result, mod 4: 0: [-pi/4, pi/4], + * 1: [pi/4, 3*pi/4], 2: [3*pi/4, 5*pi/4], 3: [-3*pi/4, -pi/4] + */ + private static int remPiOver2(double x, double[] y) + { + boolean negative = x < 0; + x = abs(x); + double z; + int n; + if (Configuration.DEBUG && (x <= PI / 4 || x != x + || x == Double.POSITIVE_INFINITY)) + throw new InternalError("Assertion failure"); + if (x < 3 * PI / 4) // If |x| is small. + { + z = x - PIO2_1; + if ((float) x != (float) (PI / 2)) // 33+53 bit pi is good enough. + { + y[0] = z - PIO2_1L; + y[1] = z - y[0] - PIO2_1L; + } + else // Near pi/2, use 33+33+53 bit pi. + { + z -= PIO2_2; + y[0] = z - PIO2_2L; + y[1] = z - y[0] - PIO2_2L; + } + n = 1; + } + else if (x <= TWO_20 * PI / 2) // Medium size. + { + n = (int) (2 / PI * x + 0.5); + z = x - n * PIO2_1; + double w = n * PIO2_1L; // First round good to 85 bits. + y[0] = z - w; + if (n >= 32 || (float) x == (float) (w)) + { + if (x / y[0] >= TWO_16) // Second iteration, good to 118 bits. + { + double t = z; + w = n * PIO2_2; + z = t - w; + w = n * PIO2_2L - (t - z - w); + y[0] = z - w; + if (x / y[0] >= TWO_49) // Third iteration, 151 bits accuracy. + { + t = z; + w = n * PIO2_3; + z = t - w; + w = n * PIO2_3L - (t - z - w); + y[0] = z - w; + } + } + } + y[1] = z - y[0] - w; + } + else + { + // All other (large) arguments. + int e0 = (int) (Double.doubleToLongBits(x) >> 52) - 1046; + z = scale(x, -e0); // e0 = ilogb(z) - 23. + double[] tx = new double[3]; + for (int i = 0; i < 2; i++) + { + tx[i] = (int) z; + z = (z - tx[i]) * TWO_24; + } + tx[2] = z; + int nx = 2; + while (tx[nx] == 0) + nx--; + n = remPiOver2(tx, y, e0, nx); + } + if (negative) + { + y[0] = -y[0]; + y[1] = -y[1]; + return -n; + } + return n; + } + + /** + * Helper function for reducing an angle to a multiple of pi/2 within + * [-pi/4, pi/4]. + * + * @param x the positive angle, broken into 24-bit chunks + * @param y an array of 2 doubles modified to hold the remander x % pi/2 + * @param e0 the exponent of x[0] + * @param nx the last index used in x + * @return the quadrant of the result, mod 4: 0: [-pi/4, pi/4], + * 1: [pi/4, 3*pi/4], 2: [3*pi/4, 5*pi/4], 3: [-3*pi/4, -pi/4] + */ + private static int remPiOver2(double[] x, double[] y, int e0, int nx) + { + int i; + int ih; + int n; + double fw; + double z; + int[] iq = new int[20]; + double[] f = new double[20]; + double[] q = new double[20]; + boolean recompute = false; + + // Initialize jk, jz, jv, q0; note that 3>q0. + int jk = 4; + int jz = jk; + int jv = max((e0 - 3) / 24, 0); + int q0 = e0 - 24 * (jv + 1); + + // Set up f[0] to f[nx+jk] where f[nx+jk] = TWO_OVER_PI[jv+jk]. + int j = jv - nx; + int m = nx + jk; + for (i = 0; i <= m; i++, j++) + f[i] = (j < 0) ? 0 : TWO_OVER_PI[j]; + + // Compute q[0],q[1],...q[jk]. + for (i = 0; i <= jk; i++) + { + for (j = 0, fw = 0; j <= nx; j++) + fw += x[j] * f[nx + i - j]; + q[i] = fw; + } + + do + { + // Distill q[] into iq[] reversingly. + for (i = 0, j = jz, z = q[jz]; j > 0; i++, j--) + { + fw = (int) (1 / TWO_24 * z); + iq[i] = (int) (z - TWO_24 * fw); + z = q[j - 1] + fw; + } + + // Compute n. + z = scale(z, q0); + z -= 8 * floor(z * 0.125); // Trim off integer >= 8. + n = (int) z; + z -= n; + ih = 0; + if (q0 > 0) // Need iq[jz-1] to determine n. + { + i = iq[jz - 1] >> (24 - q0); + n += i; + iq[jz - 1] -= i << (24 - q0); + ih = iq[jz - 1] >> (23 - q0); + } + else if (q0 == 0) + ih = iq[jz - 1] >> 23; + else if (z >= 0.5) + ih = 2; + + if (ih > 0) // If q > 0.5. + { + n += 1; + int carry = 0; + for (i = 0; i < jz; i++) // Compute 1-q. + { + j = iq[i]; + if (carry == 0) + { + if (j != 0) + { + carry = 1; + iq[i] = 0x1000000 - j; + } + } + else + iq[i] = 0xffffff - j; + } + switch (q0) + { + case 1: // Rare case: chance is 1 in 12 for non-default. + iq[jz - 1] &= 0x7fffff; + break; + case 2: + iq[jz - 1] &= 0x3fffff; + } + if (ih == 2) + { + z = 1 - z; + if (carry != 0) + z -= scale(1, q0); + } + } + + // Check if recomputation is needed. + if (z == 0) + { + j = 0; + for (i = jz - 1; i >= jk; i--) + j |= iq[i]; + if (j == 0) // Need recomputation. + { + int k; + for (k = 1; iq[jk - k] == 0; k++); // k = no. of terms needed. + + for (i = jz + 1; i <= jz + k; i++) // Add q[jz+1] to q[jz+k]. + { + f[nx + i] = TWO_OVER_PI[jv + i]; + for (j = 0, fw = 0; j <= nx; j++) + fw += x[j] * f[nx + i - j]; + q[i] = fw; + } + jz += k; + recompute = true; + } + } + } + while (recompute); + + // Chop off zero terms. + if (z == 0) + { + jz--; + q0 -= 24; + while (iq[jz] == 0) + { + jz--; + q0 -= 24; + } + } + else // Break z into 24-bit if necessary. + { + z = scale(z, -q0); + if (z >= TWO_24) + { + fw = (int) (1 / TWO_24 * z); + iq[jz] = (int) (z - TWO_24 * fw); + jz++; + q0 += 24; + iq[jz] = (int) fw; + } + else + iq[jz] = (int) z; + } + + // Convert integer "bit" chunk to floating-point value. + fw = scale(1, q0); + for (i = jz; i >= 0; i--) + { + q[i] = fw * iq[i]; + fw *= 1 / TWO_24; + } + + // Compute PI_OVER_TWO[0,...,jk]*q[jz,...,0]. + double[] fq = new double[20]; + for (i = jz; i >= 0; i--) + { + fw = 0; + for (int k = 0; k <= jk && k <= jz - i; k++) + fw += PI_OVER_TWO[k] * q[i + k]; + fq[jz - i] = fw; + } + + // Compress fq[] into y[]. + fw = 0; + for (i = jz; i >= 0; i--) + fw += fq[i]; + y[0] = (ih == 0) ? fw : -fw; + fw = fq[0] - fw; + for (i = 1; i <= jz; i++) + fw += fq[i]; + y[1] = (ih == 0) ? fw : -fw; + return n; + } + + /** + * Helper method for scaling a double by a power of 2. + * + * @param x the double + * @param n the scale; |n| < 2048 + * @return x * 2**n + */ + private static double scale(double x, int n) + { + if (Configuration.DEBUG && abs(n) >= 2048) + throw new InternalError("Assertion failure"); + if (x == 0 || x == Double.NEGATIVE_INFINITY + || ! (x < Double.POSITIVE_INFINITY) || n == 0) + return x; + long bits = Double.doubleToLongBits(x); + int exp = (int) (bits >> 52) & 0x7ff; + if (exp == 0) // Subnormal x. + { + x *= TWO_54; + exp = ((int) (Double.doubleToLongBits(x) >> 52) & 0x7ff) - 54; + } + exp += n; + if (exp > 0x7fe) // Overflow. + return Double.POSITIVE_INFINITY * x; + if (exp > 0) // Normal. + return Double.longBitsToDouble((bits & 0x800fffffffffffffL) + | ((long) exp << 52)); + if (exp <= -54) + return 0 * x; // Underflow. + exp += 54; // Subnormal result. + x = Double.longBitsToDouble((bits & 0x800fffffffffffffL) + | ((long) exp << 52)); + return x * (1 / TWO_54); + } + + /** + * Helper trig function; computes sin in range [-pi/4, pi/4]. + * + * @param x angle within about pi/4 + * @param y tail of x, created by remPiOver2 + * @return sin(x+y) + */ + private static double sin(double x, double y) + { + if (Configuration.DEBUG && abs(x + y) > 0.7854) + throw new InternalError("Assertion failure"); + if (abs(x) < 1 / TWO_27) + return x; // If |x| ~< 2**-27, already know answer. + + double z = x * x; + double v = z * x; + double r = S2 + z * (S3 + z * (S4 + z * (S5 + z * S6))); + if (y == 0) + return x + v * (S1 + z * r); + return x - ((z * (0.5 * y - v * r) - y) - v * S1); + } + + /** + * Helper trig function; computes cos in range [-pi/4, pi/4]. + * + * @param x angle within about pi/4 + * @param y tail of x, created by remPiOver2 + * @return cos(x+y) + */ + private static double cos(double x, double y) + { + if (Configuration.DEBUG && abs(x + y) > 0.7854) + throw new InternalError("Assertion failure"); + x = abs(x); + if (x < 1 / TWO_27) + return 1; // If |x| ~< 2**-27, already know answer. + + double z = x * x; + double r = z * (C1 + z * (C2 + z * (C3 + z * (C4 + z * (C5 + z * C6))))); + + if (x < 0.3) + return 1 - (0.5 * z - (z * r - x * y)); + + double qx = (x > 0.78125) ? 0.28125 : (x * 0.25); + return 1 - qx - ((0.5 * z - qx) - (z * r - x * y)); + } + + /** + * Helper trig function; computes tan in range [-pi/4, pi/4]. + * + * @param x angle within about pi/4 + * @param y tail of x, created by remPiOver2 + * @param invert true iff -1/tan should be returned instead + * @return tan(x+y) + */ + private static double tan(double x, double y, boolean invert) + { + // PI/2 is irrational, so no double is a perfect multiple of it. + if (Configuration.DEBUG && (abs(x + y) > 0.7854 || (x == 0 && invert))) + throw new InternalError("Assertion failure"); + boolean negative = x < 0; + if (negative) + { + x = -x; + y = -y; + } + if (x < 1 / TWO_28) // If |x| ~< 2**-28, already know answer. + return (negative ? -1 : 1) * (invert ? -1 / x : x); + + double z; + double w; + boolean large = x >= 0.6744; + if (large) + { + z = PI / 4 - x; + w = PI_L / 4 - y; + x = z + w; + y = 0; + } + z = x * x; + w = z * z; + // Break x**5*(T1+x**2*T2+...) into + // x**5(T1+x**4*T3+...+x**20*T11) + // + x**5(x**2*(T2+x**4*T4+...+x**22*T12)). + double r = T1 + w * (T3 + w * (T5 + w * (T7 + w * (T9 + w * T11)))); + double v = z * (T2 + w * (T4 + w * (T6 + w * (T8 + w * (T10 + w * T12))))); + double s = z * x; + r = y + z * (s * (r + v) + y); + r += T0 * s; + w = x + r; + if (large) + { + v = invert ? -1 : 1; + return (negative ? -1 : 1) * (v - 2 * (x - (w * w / (w + v) - r))); + } + if (! invert) + return w; + + // Compute -1.0/(x+r) accurately. + z = (float) w; + v = r - (z - x); + double a = -1 / w; + double t = (float) a; + return t + a * (1 + t * z + t * v); + } +} diff --git a/libjava/classpath/java/lang/String.java b/libjava/classpath/java/lang/String.java new file mode 100644 index 0000000..b4db850 --- /dev/null +++ b/libjava/classpath/java/lang/String.java @@ -0,0 +1,1750 @@ +/* String.java -- immutable character sequences; the object of string literals + Copyright (C) 1998, 1999, 2000, 2001, 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 java.lang; + +import gnu.java.lang.CharData; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.text.Collator; +import java.util.Comparator; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Strings represent an immutable set of characters. All String literals + * are instances of this class, and two string literals with the same contents + * refer to the same String object. + * + *

    This class also includes a number of methods for manipulating the + * contents of strings (of course, creating a new object if there are any + * changes, as String is immutable). Case mapping relies on Unicode 3.0.0 + * standards, where some character sequences have a different number of + * characters in the uppercase version than the lower case. + * + *

    Strings are special, in that they are the only object with an overloaded + * operator. When you use '+' with at least one String argument, both + * arguments have String conversion performed on them, and another String (not + * guaranteed to be unique) results. + * + *

    String is special-cased when doing data serialization - rather than + * listing the fields of this class, a String object is converted to a string + * literal in the object stream. + * + * @author Paul N. Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @author Per Bothner (bothner@cygnus.com) + * @since 1.0 + * @status updated to 1.4; but could use better data sharing via offset field + */ +public final class String implements Serializable, Comparable, CharSequence +{ + // WARNING: String is a CORE class in the bootstrap cycle. See the comments + // in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * This is probably not necessary because this class is special cased already + * but it will avoid showing up as a discrepancy when comparing SUIDs. + */ + private static final long serialVersionUID = -6849794470754667710L; + + /** + * Stores unicode multi-character uppercase expansion table. + * @see #toUpperCase(char) + * @see CharData#UPPER_EXPAND + */ + private static final char[] upperExpand + = zeroBasedStringValue(CharData.UPPER_EXPAND); + + /** + * Stores unicode multi-character uppercase special casing table. + * @see #upperCaseExpansion(char) + * @see CharData#UPPER_SPECIAL + */ + private static final char[] upperSpecial + = zeroBasedStringValue(CharData.UPPER_SPECIAL); + + /** + * Characters which make up the String. + * Package access is granted for use by StringBuffer. + */ + final char[] value; + + /** + * Holds the number of characters in value. This number is generally + * the same as value.length, but can be smaller because substrings and + * StringBuffers can share arrays. Package visible for use by trusted code. + */ + final int count; + + /** + * Caches the result of hashCode(). If this value is zero, the hashcode + * is considered uncached (even if 0 is the correct hash value). + */ + private int cachedHashCode; + + /** + * Holds the starting position for characters in value[]. Since + * substring()'s are common, the use of offset allows the operation + * to perform in O(1). Package access is granted for use by StringBuffer. + */ + final int offset; + + /** + * An implementation for {@link CASE_INSENSITIVE_ORDER}. + * This must be {@link Serializable}. The class name is dictated by + * compatibility with Sun's JDK. + */ + private static final class CaseInsensitiveComparator + implements Comparator, Serializable + { + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = 8575799808933029326L; + + /** + * The default private constructor generates unnecessary overhead. + */ + CaseInsensitiveComparator() {} + + /** + * Compares to Strings, using + * String.compareToIgnoreCase(String). + * + * @param o1 the first string + * @param o2 the second string + * @return < 0, 0, or > 0 depending on the case-insensitive + * comparison of the two strings. + * @throws NullPointerException if either argument is null + * @throws ClassCastException if either argument is not a String + * @see #compareToIgnoreCase(String) + */ + public int compare(Object o1, Object o2) + { + return ((String) o1).compareToIgnoreCase((String) o2); + } + } // class CaseInsensitiveComparator + + /** + * A Comparator that uses String.compareToIgnoreCase(String). + * This comparator is {@link Serializable}. Note that it ignores Locale, + * for that, you want a Collator. + * + * @see Collator#compare(String, String) + * @since 1.2 + */ + public static final Comparator CASE_INSENSITIVE_ORDER + = new CaseInsensitiveComparator(); + + /** + * Creates an empty String (length 0). Unless you really need a new object, + * consider using "" instead. + */ + public String() + { + value = "".value; + offset = 0; + count = 0; + } + + /** + * Copies the contents of a String to a new String. Since Strings are + * immutable, only a shallow copy is performed. + * + * @param str String to copy + * @throws NullPointerException if value is null + */ + public String(String str) + { + value = str.value; + offset = str.offset; + count = str.count; + cachedHashCode = str.cachedHashCode; + } + + /** + * Creates a new String using the character sequence of the char array. + * Subsequent changes to data do not affect the String. + * + * @param data char array to copy + * @throws NullPointerException if data is null + */ + public String(char[] data) + { + this(data, 0, data.length, false); + } + + /** + * Creates a new String using the character sequence of a subarray of + * characters. The string starts at offset, and copies count chars. + * Subsequent changes to data do not affect the String. + * + * @param data char array to copy + * @param offset position (base 0) to start copying out of data + * @param count the number of characters from data to copy + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count > data.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public String(char[] data, int offset, int count) + { + this(data, offset, count, false); + } + + /** + * Creates a new String using an 8-bit array of integer values, starting at + * an offset, and copying up to the count. Each character c, using + * corresponding byte b, is created in the new String as if by performing: + * + *

    +   * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff))
    +   * 
    + * + * @param ascii array of integer values + * @param hibyte top byte of each Unicode character + * @param offset position (base 0) to start copying out of ascii + * @param count the number of characters from ascii to copy + * @throws NullPointerException if ascii is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count > ascii.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #String(byte[]) + * @see #String(byte[], String) + * @see #String(byte[], int, int) + * @see #String(byte[], int, int, String) + * @deprecated use {@link #String(byte[], int, int, String)} to perform + * correct encoding + */ + public String(byte[] ascii, int hibyte, int offset, int count) + { + if (offset < 0 || count < 0 || offset + count > ascii.length) + throw new StringIndexOutOfBoundsException(); + value = new char[count]; + this.offset = 0; + this.count = count; + hibyte <<= 8; + offset += count; + while (--count >= 0) + value[count] = (char) (hibyte | (ascii[--offset] & 0xff)); + } + + /** + * Creates a new String using an 8-bit array of integer values. Each + * character c, using corresponding byte b, is created in the new String + * as if by performing: + * + *
    +   * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff))
    +   * 
    + * + * @param ascii array of integer values + * @param hibyte top byte of each Unicode character + * @throws NullPointerException if ascii is null + * @see #String(byte[]) + * @see #String(byte[], String) + * @see #String(byte[], int, int) + * @see #String(byte[], int, int, String) + * @see #String(byte[], int, int, int) + * @deprecated use {@link #String(byte[], String)} to perform + * correct encoding + */ + public String(byte[] ascii, int hibyte) + { + this(ascii, hibyte, 0, ascii.length); + } + + /** + * Creates a new String using the portion of the byte array starting at the + * offset and ending at offset + count. Uses the specified encoding type + * to decode the byte array, so the resulting string may be longer or + * shorter than the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, + * see {@link java.nio.charset.Charset}. The behavior is not specified if + * the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @param offset the offset to start at + * @param count the number of bytes in the array to use + * @param encoding the name of the encoding to use + * @throws NullPointerException if data or encoding is null + * @throws IndexOutOfBoundsException if offset or count is incorrect + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @throws UnsupportedEncodingException if encoding is not found + * @throws Error if the decoding fails + * @since 1.1 + */ + public String(byte[] data, int offset, int count, String encoding) + throws UnsupportedEncodingException + { + if (offset < 0 || count < 0 || offset + count > data.length) + throw new StringIndexOutOfBoundsException(); + try + { + CharsetDecoder csd = Charset.forName(encoding).newDecoder(); + csd.onMalformedInput(CodingErrorAction.REPLACE); + csd.onUnmappableCharacter(CodingErrorAction.REPLACE); + CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count)); + if(cbuf.hasArray()) + { + value = cbuf.array(); + this.offset = cbuf.position(); + this.count = cbuf.remaining(); + } else { + // Doubt this will happen. But just in case. + value = new char[cbuf.remaining()]; + cbuf.get(value); + this.offset = 0; + this.count = value.length; + } + } catch(CharacterCodingException e){ + throw new UnsupportedEncodingException("Encoding: "+encoding+ + " not found."); + } catch(IllegalCharsetNameException e){ + throw new UnsupportedEncodingException("Encoding: "+encoding+ + " not found."); + } catch(UnsupportedCharsetException e){ + throw new UnsupportedEncodingException("Encoding: "+encoding+ + " not found."); + } + } + + /** + * Creates a new String using the byte array. Uses the specified encoding + * type to decode the byte array, so the resulting string may be longer or + * shorter than the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, + * see {@link java.nio.charset.Charset}. The behavior is not specified if + * the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @param encoding the name of the encoding to use + * @throws NullPointerException if data or encoding is null + * @throws UnsupportedEncodingException if encoding is not found + * @throws Error if the decoding fails + * @see #String(byte[], int, int, String) + * @since 1.1 + */ + public String(byte[] data, String encoding) + throws UnsupportedEncodingException + { + this(data, 0, data.length, encoding); + } + + /** + * Creates a new String using the portion of the byte array starting at the + * offset and ending at offset + count. Uses the encoding of the platform's + * default charset, so the resulting string may be longer or shorter than + * the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}. The behavior is not specified + * if the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @param offset the offset to start at + * @param count the number of bytes in the array to use + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if offset or count is incorrect + * @throws Error if the decoding fails + * @see #String(byte[], int, int, String) + * @since 1.1 + */ + public String(byte[] data, int offset, int count) + { + if (offset < 0 || count < 0 || offset + count > data.length) + throw new StringIndexOutOfBoundsException(); + int o, c; + char[] v; + String encoding; + try + { + encoding = System.getProperty("file.encoding"); + CharsetDecoder csd = Charset.forName(encoding).newDecoder(); + csd.onMalformedInput(CodingErrorAction.REPLACE); + csd.onUnmappableCharacter(CodingErrorAction.REPLACE); + CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count)); + if(cbuf.hasArray()) + { + v = cbuf.array(); + o = cbuf.position(); + c = cbuf.remaining(); + } else { + // Doubt this will happen. But just in case. + v = new char[cbuf.remaining()]; + cbuf.get(v); + o = 0; + c = v.length; + } + } catch(Exception ex){ + // If anything goes wrong (System property not set, + // NIO provider not available, etc) + // Default to the 'safe' encoding ISO8859_1 + v = new char[count]; + o = 0; + c = count; + for (int i=0;i data.length) + throw new StringIndexOutOfBoundsException(); + if (dont_copy) + { + value = data; + this.offset = offset; + } + else + { + value = new char[count]; + VMSystem.arraycopy(data, offset, value, 0, count); + this.offset = 0; + } + this.count = count; + } + + /** + * Returns the number of characters contained in this String. + * + * @return the length of this String + */ + public int length() + { + return count; + } + + /** + * Returns the character located at the specified index within this String. + * + * @param index position of character to return (base 0) + * @return character located at position index + * @throws IndexOutOfBoundsException if index < 0 || index >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public char charAt(int index) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + return value[offset + index]; + } + + /** + * Copies characters from this String starting at a specified start index, + * ending at a specified stop index, to a character array starting at + * a specified destination begin index. + * + * @param srcBegin index to begin copying characters from this String + * @param srcEnd index after the last character to be copied from this String + * @param dst character array which this String is copied into + * @param dstBegin index to start writing characters into dst + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if any indices are out of bounds + * (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dst problems cause an + * ArrayIndexOutOfBoundsException) + */ + public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) + { + if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) + throw new StringIndexOutOfBoundsException(); + VMSystem.arraycopy(value, srcBegin + offset, + dst, dstBegin, srcEnd - srcBegin); + } + + /** + * Copies the low byte of each character from this String starting at a + * specified start index, ending at a specified stop index, to a byte array + * starting at a specified destination begin index. + * + * @param srcBegin index to being copying characters from this String + * @param srcEnd index after the last character to be copied from this String + * @param dst byte array which each low byte of this String is copied into + * @param dstBegin index to start writing characters into dst + * @throws NullPointerException if dst is null and copy length is non-zero + * @throws IndexOutOfBoundsException if any indices are out of bounds + * (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dst problems cause an + * ArrayIndexOutOfBoundsException) + * @see #getBytes() + * @see #getBytes(String) + * @deprecated use {@link #getBytes()}, which uses a char to byte encoder + */ + public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) + { + if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) + throw new StringIndexOutOfBoundsException(); + int i = srcEnd - srcBegin; + srcBegin += offset; + while (--i >= 0) + dst[dstBegin++] = (byte) value[srcBegin++]; + } + + /** + * Converts the Unicode characters in this String to a byte array. Uses the + * specified encoding method, so the result may be longer or shorter than + * the String. For more encoding control, use + * {@link java.nio.charset.CharsetEncoder}, and for valid character sets, + * see {@link java.nio.charset.Charset}. Unsupported characters get + * replaced by an encoding specific byte. + * + * @param enc encoding name + * @return the resulting byte array + * @throws NullPointerException if enc is null + * @throws UnsupportedEncodingException if encoding is not supported + * @since 1.1 + */ + public byte[] getBytes(String enc) throws UnsupportedEncodingException + { + try + { + CharsetEncoder cse = Charset.forName(enc).newEncoder(); + cse.onMalformedInput(CodingErrorAction.REPLACE); + cse.onUnmappableCharacter(CodingErrorAction.REPLACE); + ByteBuffer bbuf = cse.encode(CharBuffer.wrap(value, offset, count)); + if(bbuf.hasArray()) + return bbuf.array(); + + // Doubt this will happen. But just in case. + byte[] bytes = new byte[bbuf.remaining()]; + bbuf.get(bytes); + return bytes; + + } catch(IllegalCharsetNameException e){ + throw new UnsupportedEncodingException("Encoding: "+enc+ + " not found."); + } catch(UnsupportedCharsetException e){ + throw new UnsupportedEncodingException("Encoding: "+enc+ + " not found."); + } catch(CharacterCodingException e){ + // XXX - Ignore coding exceptions? They shouldn't really happen. + return null; + } + } + + /** + * Converts the Unicode characters in this String to a byte array. Uses the + * encoding of the platform's default charset, so the result may be longer + * or shorter than the String. For more encoding control, use + * {@link java.nio.charset.CharsetEncoder}. Unsupported characters get + * replaced by an encoding specific byte. + * + * @return the resulting byte array, or null on a problem + * @since 1.1 + */ + public byte[] getBytes() + { + try + { + return getBytes(System.getProperty("file.encoding")); + } catch(Exception e) { + // XXX - Throw an error here? + // For now, default to the 'safe' encoding. + byte[] bytes = new byte[count]; + for(int i=0;i= 0) + if (value[x++] != str2.value[y++]) + return false; + return true; + } + + /** + * Compares the given StringBuffer to this String. This is true if the + * StringBuffer has the same content as this String at this moment. + * + * @param buffer the StringBuffer to compare to + * @return true if StringBuffer has the same character sequence + * @throws NullPointerException if the given StringBuffer is null + * @since 1.4 + */ + public boolean contentEquals(StringBuffer buffer) + { + synchronized (buffer) + { + if (count != buffer.count) + return false; + if (value == buffer.value) + return true; // Possible if shared. + int i = count; + int x = offset + count; + while (--i >= 0) + if (value[--x] != buffer.value[i]) + return false; + return true; + } + } + + /** + * Compares a String to this String, ignoring case. This does not handle + * multi-character capitalization exceptions; instead the comparison is + * made on a character-by-character basis, and is true if:
      + *
    • c1 == c2
    • + *
    • Character.toUpperCase(c1) + * == Character.toUpperCase(c2)
    • + *
    • Character.toLowerCase(c1) + * == Character.toLowerCase(c2)
    • + *
    + * + * @param anotherString String to compare to this String + * @return true if anotherString is equal, ignoring case + * @see #equals(Object) + * @see Character#toUpperCase(char) + * @see Character#toLowerCase(char) + */ + public boolean equalsIgnoreCase(String anotherString) + { + if (anotherString == null || count != anotherString.count) + return false; + int i = count; + int x = offset; + int y = anotherString.offset; + while (--i >= 0) + { + char c1 = value[x++]; + char c2 = anotherString.value[y++]; + // Note that checking c1 != c2 is redundant, but avoids method calls. + if (c1 != c2 + && Character.toUpperCase(c1) != Character.toUpperCase(c2) + && Character.toLowerCase(c1) != Character.toLowerCase(c2)) + return false; + } + return true; + } + + /** + * Compares this String and another String (case sensitive, + * lexicographically). The result is less than 0 if this string sorts + * before the other, 0 if they are equal, and greater than 0 otherwise. + * After any common starting sequence is skipped, the result is + * this.charAt(k) - anotherString.charAt(k) if both strings + * have characters remaining, or + * this.length() - anotherString.length() if one string is + * a subsequence of the other. + * + * @param anotherString the String to compare against + * @return the comparison + * @throws NullPointerException if anotherString is null + */ + public int compareTo(String anotherString) + { + int i = Math.min(count, anotherString.count); + int x = offset; + int y = anotherString.offset; + while (--i >= 0) + { + int result = value[x++] - anotherString.value[y++]; + if (result != 0) + return result; + } + return count - anotherString.count; + } + + /** + * Behaves like compareTo(java.lang.String) unless the Object + * is not a String. Then it throws a + * ClassCastException. + * + * @param o the object to compare against + * @return the comparison + * @throws NullPointerException if o is null + * @throws ClassCastException if o is not a String + * @since 1.2 + */ + public int compareTo(Object o) + { + return compareTo((String) o); + } + + /** + * Compares this String and another String (case insensitive). This + * comparison is similar to equalsIgnoreCase, in that it ignores + * locale and multi-characater capitalization, and compares characters + * after performing + * Character.toLowerCase(Character.toUpperCase(c)) on each + * character of the string. This is unsatisfactory for locale-based + * comparison, in which case you should use {@link java.text.Collator}. + * + * @param str the string to compare against + * @return the comparison + * @see Collator#compare(String, String) + * @since 1.2 + */ + public int compareToIgnoreCase(String str) + { + int i = Math.min(count, str.count); + int x = offset; + int y = str.offset; + while (--i >= 0) + { + int result = Character.toLowerCase(Character.toUpperCase(value[x++])) + - Character.toLowerCase(Character.toUpperCase(str.value[y++])); + if (result != 0) + return result; + } + return count - str.count; + } + + /** + * Predicate which determines if this String matches another String + * starting at a specified offset for each String and continuing + * for a specified length. Indices out of bounds are harmless, and give + * a false result. + * + * @param toffset index to start comparison at for this String + * @param other String to compare region to this String + * @param ooffset index to start comparison at for other + * @param len number of characters to compare + * @return true if regions match (case sensitive) + * @throws NullPointerException if other is null + */ + public boolean regionMatches(int toffset, String other, int ooffset, int len) + { + return regionMatches(false, toffset, other, ooffset, len); + } + + /** + * Predicate which determines if this String matches another String + * starting at a specified offset for each String and continuing + * for a specified length, optionally ignoring case. Indices out of bounds + * are harmless, and give a false result. Case comparisons are based on + * Character.toLowerCase() and + * Character.toUpperCase(), not on multi-character + * capitalization expansions. + * + * @param ignoreCase true if case should be ignored in comparision + * @param toffset index to start comparison at for this String + * @param other String to compare region to this String + * @param ooffset index to start comparison at for other + * @param len number of characters to compare + * @return true if regions match, false otherwise + * @throws NullPointerException if other is null + */ + public boolean regionMatches(boolean ignoreCase, int toffset, + String other, int ooffset, int len) + { + if (toffset < 0 || ooffset < 0 || toffset + len > count + || ooffset + len > other.count) + return false; + toffset += offset; + ooffset += other.offset; + while (--len >= 0) + { + char c1 = value[toffset++]; + char c2 = other.value[ooffset++]; + // Note that checking c1 != c2 is redundant when ignoreCase is true, + // but it avoids method calls. + if (c1 != c2 + && (! ignoreCase + || (Character.toLowerCase(c1) != Character.toLowerCase(c2) + && (Character.toUpperCase(c1) + != Character.toUpperCase(c2))))) + return false; + } + return true; + } + + /** + * Predicate which determines if this String contains the given prefix, + * beginning comparison at toffset. The result is false if toffset is + * negative or greater than this.length(), otherwise it is the same as + * this.substring(toffset).startsWith(prefix). + * + * @param prefix String to compare + * @param toffset offset for this String where comparison starts + * @return true if this String starts with prefix + * @throws NullPointerException if prefix is null + * @see #regionMatches(boolean, int, String, int, int) + */ + public boolean startsWith(String prefix, int toffset) + { + return regionMatches(false, toffset, prefix, 0, prefix.count); + } + + /** + * Predicate which determines if this String starts with a given prefix. + * If the prefix is an empty String, true is returned. + * + * @param prefix String to compare + * @return true if this String starts with the prefix + * @throws NullPointerException if prefix is null + * @see #startsWith(String, int) + */ + public boolean startsWith(String prefix) + { + return regionMatches(false, 0, prefix, 0, prefix.count); + } + + /** + * Predicate which determines if this String ends with a given suffix. + * If the suffix is an empty String, true is returned. + * + * @param suffix String to compare + * @return true if this String ends with the suffix + * @throws NullPointerException if suffix is null + * @see #regionMatches(boolean, int, String, int, int) + */ + public boolean endsWith(String suffix) + { + return regionMatches(false, count - suffix.count, suffix, 0, suffix.count); + } + + /** + * Computes the hashcode for this String. This is done with int arithmetic, + * where ** represents exponentiation, by this formula:
    + * s[0]*31**(n-1) + s[1]*31**(n-2) + ... + s[n-1]. + * + * @return hashcode value of this String + */ + public int hashCode() + { + if (cachedHashCode != 0) + return cachedHashCode; + + // Compute the hash code using a local variable to be reentrant. + int hashCode = 0; + int limit = count + offset; + for (int i = offset; i < limit; i++) + hashCode = hashCode * 31 + value[i]; + return cachedHashCode = hashCode; + } + + /** + * Finds the first instance of a character in this String. + * + * @param ch character to find + * @return location (base 0) of the character, or -1 if not found + */ + public int indexOf(int ch) + { + return indexOf(ch, 0); + } + + /** + * Finds the first instance of a character in this String, 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, -1 is returned. + * + * @param ch character to find + * @param fromIndex index to start the search + * @return location (base 0) of the character, or -1 if not found + */ + public int indexOf(int ch, int fromIndex) + { + if ((char) ch != ch) + return -1; + if (fromIndex < 0) + fromIndex = 0; + int i = fromIndex + offset; + for ( ; fromIndex < count; fromIndex++) + if (value[i++] == ch) + return fromIndex; + return -1; + } + + /** + * Finds the last instance of a character in this String. + * + * @param ch character to find + * @return location (base 0) of the character, or -1 if not found + */ + public int lastIndexOf(int ch) + { + return lastIndexOf(ch, count - 1); + } + + /** + * Finds the last instance of a character in this String, 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, -1 is returned. + * + * @param ch character to find + * @param fromIndex index to start the search + * @return location (base 0) of the character, or -1 if not found + */ + public int lastIndexOf(int ch, int fromIndex) + { + if ((char) ch != ch) + return -1; + if (fromIndex >= count) + fromIndex = count - 1; + int i = fromIndex + offset; + for ( ; fromIndex >= 0; fromIndex--) + if (value[i--] == ch) + return fromIndex; + return -1; + } + + /** + * Finds the first instance of a String in this String. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int indexOf(String str) + { + return indexOf(str, 0); + } + + /** + * Finds the first instance of a String in this String, 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, -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 + */ + public int indexOf(String str, int fromIndex) + { + if (fromIndex < 0) + fromIndex = 0; + int limit = count - str.count; + for ( ; fromIndex <= limit; fromIndex++) + if (regionMatches(fromIndex, str, 0, str.count)) + return fromIndex; + return -1; + } + + /** + * Finds the last instance of a String in this String. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int lastIndexOf(String str) + { + return lastIndexOf(str, count - str.count); + } + + /** + * Finds the last instance of a String in this String, 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, -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 + */ + public int lastIndexOf(String str, int fromIndex) + { + fromIndex = Math.min(fromIndex, count - str.count); + for ( ; fromIndex >= 0; fromIndex--) + if (regionMatches(fromIndex, str, 0, str.count)) + return fromIndex; + return -1; + } + + /** + * Creates a substring of this String, starting at a specified index + * and ending at the end of this String. + * + * @param begin index to start substring (base 0) + * @return new String which is a substring of this String + * @throws IndexOutOfBoundsException if begin < 0 || begin > length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public String substring(int begin) + { + return substring(begin, count); + } + + /** + * Creates a substring of this String, starting at a specified index + * and ending at one character before a specified index. + * + * @param beginIndex index to start substring (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this String + * @throws IndexOutOfBoundsException if begin < 0 || end > length() + * || begin > end (while unspecified, this is a + * StringIndexOutOfBoundsException) + */ + public String substring(int beginIndex, int endIndex) + { + if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) + throw new StringIndexOutOfBoundsException(); + if (beginIndex == 0 && endIndex == count) + return this; + int len = endIndex - beginIndex; + // Package constructor avoids an array copy. + return new String(value, beginIndex + offset, len, + (len << 2) >= value.length); + } + + /** + * Creates a substring of this String, starting at a specified index + * and ending at one character before a specified index. This behaves like + * substring(begin, end). + * + * @param begin index to start substring (inclusive, base 0) + * @param end index to end at (exclusive) + * @return new String which is a substring of this String + * @throws IndexOutOfBoundsException if begin < 0 || end > length() + * || begin > end + * @since 1.4 + */ + public CharSequence subSequence(int begin, int end) + { + return substring(begin, end); + } + + /** + * Concatenates a String to this String. This results in a new string unless + * one of the two originals is "". + * + * @param str String to append to this String + * @return newly concatenated String + * @throws NullPointerException if str is null + */ + public String concat(String str) + { + if (str.count == 0) + return this; + if (count == 0) + return str; + char[] newStr = new char[count + str.count]; + VMSystem.arraycopy(value, offset, newStr, 0, count); + VMSystem.arraycopy(str.value, str.offset, newStr, count, str.count); + // Package constructor avoids an array copy. + return new String(newStr, 0, newStr.length, true); + } + + /** + * Replaces every instance of a character in this String with a new + * character. If no replacements occur, this is returned. + * + * @param oldChar the old character to replace + * @param newChar the new character + * @return new String with all instances of oldChar replaced with newChar + */ + public String replace(char oldChar, char newChar) + { + if (oldChar == newChar) + return this; + int i = count; + int x = offset - 1; + while (--i >= 0) + if (value[++x] == oldChar) + break; + if (i < 0) + return this; + char[] newStr = (char[]) value.clone(); + newStr[x] = newChar; + while (--i >= 0) + if (value[++x] == oldChar) + newStr[x] = newChar; + // Package constructor avoids an array copy. + return new String(newStr, offset, count, true); + } + + /** + * Test if this String matches a regular expression. This is shorthand for + * {@link Pattern}.matches(regex, this). + * + * @param regex the pattern to match + * @return true if the pattern matches + * @throws NullPointerException if regex is null + * @throws PatternSyntaxException if regex is invalid + * @see Pattern#matches(String, CharSequence) + * @since 1.4 + */ + public boolean matches(String regex) + { + return Pattern.matches(regex, this); + } + + /** + * Replaces the first substring match of the regular expression with a + * given replacement. This is shorthand for {@link Pattern} + * .compile(regex).matcher(this).replaceFirst(replacement). + * + * @param regex the pattern to match + * @param replacement the replacement string + * @return the modified string + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #replaceAll(String, String) + * @see Pattern#compile(String) + * @see Pattern#matcher(CharSequence) + * @see Matcher#replaceFirst(String) + * @since 1.4 + */ + public String replaceFirst(String regex, String replacement) + { + return Pattern.compile(regex).matcher(this).replaceFirst(replacement); + } + + /** + * Replaces all matching substrings of the regular expression with a + * given replacement. This is shorthand for {@link Pattern} + * .compile(regex).matcher(this).replaceAll(replacement). + * + * @param regex the pattern to match + * @param replacement the replacement string + * @return the modified string + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #replaceFirst(String, String) + * @see Pattern#compile(String) + * @see Pattern#matcher(CharSequence) + * @see Matcher#replaceAll(String) + * @since 1.4 + */ + public String replaceAll(String regex, String replacement) + { + return Pattern.compile(regex).matcher(this).replaceAll(replacement); + } + + /** + * Split this string around the matches of a regular expression. Each + * element of the returned array is the largest block of characters not + * terminated by the regular expression, in the order the matches are found. + * + *

    The limit affects the length of the array. If it is positive, the + * array will contain at most n elements (n - 1 pattern matches). If + * negative, the array length is unlimited, but there can be trailing empty + * entries. if 0, the array length is unlimited, and trailing empty entries + * are discarded. + * + *

    For example, splitting "boo:and:foo" yields:
    + * + * + * + * + * + * + * + * + *
    Regex Limit Result
    ":" 2 { "boo", "and:foo" }
    ":" t { "boo", "and", "foo" }
    ":" -2 { "boo", "and", "foo" }
    "o" 5 { "b", "", ":and:f", "", "" }
    "o" -2 { "b", "", ":and:f", "", "" }
    "o" 0 { "b", "", ":and:f" }
    + * + *

    This is shorthand for + * {@link Pattern}.compile(regex).split(this, limit). + * + * @param regex the pattern to match + * @param limit the limit threshold + * @return the array of split strings + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see Pattern#compile(String) + * @see Pattern#split(CharSequence, int) + * @since 1.4 + */ + public String[] split(String regex, int limit) + { + return Pattern.compile(regex).split(this, limit); + } + + /** + * Split this string around the matches of a regular expression. Each + * element of the returned array is the largest block of characters not + * terminated by the regular expression, in the order the matches are found. + * The array length is unlimited, and trailing empty entries are discarded, + * as though calling split(regex, 0). + * + * @param regex the pattern to match + * @return the array of split strings + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #split(String, int) + * @see Pattern#compile(String) + * @see Pattern#split(CharSequence, int) + * @since 1.4 + */ + public String[] split(String regex) + { + return Pattern.compile(regex).split(this, 0); + } + + /** + * Lowercases this String according to a particular locale. This uses + * Unicode's special case mappings, as applied to the given Locale, so the + * resulting string may be a different length. + * + * @param loc locale to use + * @return new lowercased String, or this if no characters were lowercased + * @throws NullPointerException if loc is null + * @see #toUpperCase(Locale) + * @since 1.1 + */ + public String toLowerCase(Locale loc) + { + // First, see if the current string is already lower case. + boolean turkish = "tr".equals(loc.getLanguage()); + int i = count; + int x = offset - 1; + while (--i >= 0) + { + char ch = value[++x]; + if ((turkish && ch == '\u0049') + || ch != Character.toLowerCase(ch)) + break; + } + if (i < 0) + return this; + + // Now we perform the conversion. Fortunately, there are no multi-character + // lowercase expansions in Unicode 3.0.0. + char[] newStr = (char[]) value.clone(); + do + { + char ch = value[x]; + // Hardcoded special case. + newStr[x++] = (turkish && ch == '\u0049') ? '\u0131' + : Character.toLowerCase(ch); + } + while (--i >= 0); + // Package constructor avoids an array copy. + return new String(newStr, offset, count, true); + } + + /** + * Lowercases this String. This uses Unicode's special case mappings, as + * applied to the platform's default Locale, so the resulting string may + * be a different length. + * + * @return new lowercased String, or this if no characters were lowercased + * @see #toLowerCase(Locale) + * @see #toUpperCase() + */ + public String toLowerCase() + { + return toLowerCase(Locale.getDefault()); + } + + /** + * Uppercases this String according to a particular locale. This uses + * Unicode's special case mappings, as applied to the given Locale, so the + * resulting string may be a different length. + * + * @param loc locale to use + * @return new uppercased String, or this if no characters were uppercased + * @throws NullPointerException if loc is null + * @see #toLowerCase(Locale) + * @since 1.1 + */ + public String toUpperCase(Locale loc) + { + // First, see how many characters we have to grow by, as well as if the + // current string is already upper case. + boolean turkish = "tr".equals(loc.getLanguage()); + int expand = 0; + boolean unchanged = true; + int i = count; + int x = i + offset; + while (--i >= 0) + { + char ch = value[--x]; + expand += upperCaseExpansion(ch); + unchanged = (unchanged && expand == 0 + && ! (turkish && ch == '\u0069') + && ch == Character.toUpperCase(ch)); + } + if (unchanged) + return this; + + // Now we perform the conversion. + i = count; + if (expand == 0) + { + char[] newStr = (char[]) value.clone(); + while (--i >= 0) + { + char ch = value[x]; + // Hardcoded special case. + newStr[x++] = (turkish && ch == '\u0069') ? '\u0130' + : Character.toUpperCase(ch); + } + // Package constructor avoids an array copy. + return new String(newStr, offset, count, true); + } + + // Expansion is necessary. + char[] newStr = new char[count + expand]; + int j = 0; + while (--i >= 0) + { + char ch = value[x++]; + // Hardcoded special case. + if (turkish && ch == '\u0069') + { + newStr[j++] = '\u0130'; + continue; + } + expand = upperCaseExpansion(ch); + if (expand > 0) + { + int index = upperCaseIndex(ch); + while (expand-- >= 0) + newStr[j++] = upperExpand[index++]; + } + else + newStr[j++] = Character.toUpperCase(ch); + } + // Package constructor avoids an array copy. + return new String(newStr, 0, newStr.length, true); + } + + /** + * Uppercases this String. This uses Unicode's special case mappings, as + * applied to the platform's default Locale, so the resulting string may + * be a different length. + * + * @return new uppercased String, or this if no characters were uppercased + * @see #toUpperCase(Locale) + * @see #toLowerCase() + */ + public String toUpperCase() + { + return toUpperCase(Locale.getDefault()); + } + + /** + * Trims all characters less than or equal to '\u0020' + * (' ') from the beginning and end of this String. This + * includes many, but not all, ASCII control characters, and all + * {@link Character#isWhitespace(char)}. + * + * @return new trimmed String, or this if nothing trimmed + */ + public String trim() + { + int limit = count + offset; + if (count == 0 || (value[offset] > '\u0020' + && value[limit - 1] > '\u0020')) + return this; + int begin = offset; + do + if (begin == limit) + return ""; + while (value[begin++] <= '\u0020'); + int end = limit; + while (value[--end] <= '\u0020'); + return substring(begin - offset - 1, end - offset + 1); + } + + /** + * Returns this, as it is already a String! + * + * @return this + */ + public String toString() + { + return this; + } + + /** + * Copies the contents of this String into a character array. Subsequent + * changes to the array do not affect the String. + * + * @return character array copying the String + */ + public char[] toCharArray() + { + if (count == value.length) + return (char[]) value.clone(); + + char[] copy = new char[count]; + VMSystem.arraycopy(value, offset, copy, 0, count); + return copy; + } + + /** + * Returns a String representation of an Object. This is "null" if the + * object is null, otherwise it is obj.toString() (which + * can be null). + * + * @param obj the Object + * @return the string conversion of obj + */ + public static String valueOf(Object obj) + { + return obj == null ? "null" : obj.toString(); + } + + /** + * Returns a String representation of a character array. Subsequent + * changes to the array do not affect the String. + * + * @param data the character array + * @return a String containing the same character sequence as data + * @throws NullPointerException if data is null + * @see #valueOf(char[], int, int) + * @see #String(char[]) + */ + public static String valueOf(char[] data) + { + return valueOf (data, 0, data.length); + } + + /** + * Returns a String representing the character sequence of the char array, + * starting at the specified offset, and copying chars up to the specified + * count. Subsequent changes to the array do not affect the String. + * + * @param data character array + * @param offset position (base 0) to start copying out of data + * @param count the number of characters from data to copy + * @return String containing the chars from data[offset..offset+count] + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count > data.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #String(char[], int, int) + */ + public static String valueOf(char[] data, int offset, int count) + { + return new String(data, offset, count, false); + } + + /** + * Returns a String representing the character sequence of the char array, + * starting at the specified offset, and copying chars up to the specified + * count. Subsequent changes to the array do not affect the String. + * + * @param data character array + * @param offset position (base 0) to start copying out of data + * @param count the number of characters from data to copy + * @return String containing the chars from data[offset..offset+count] + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count > data.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #String(char[], int, int) + */ + public static String copyValueOf(char[] data, int offset, int count) + { + return new String(data, offset, count, false); + } + + /** + * Returns a String representation of a character array. Subsequent + * changes to the array do not affect the String. + * + * @param data the character array + * @return a String containing the same character sequence as data + * @throws NullPointerException if data is null + * @see #copyValueOf(char[], int, int) + * @see #String(char[]) + */ + public static String copyValueOf(char[] data) + { + return copyValueOf (data, 0, data.length); + } + + /** + * Returns a String representing a boolean. + * + * @param b the boolean + * @return "true" if b is true, else "false" + */ + public static String valueOf(boolean b) + { + return b ? "true" : "false"; + } + + /** + * Returns a String representing a character. + * + * @param c the character + * @return String containing the single character c + */ + public static String valueOf(char c) + { + // Package constructor avoids an array copy. + return new String(new char[] { c }, 0, 1, true); + } + + /** + * Returns a String representing an integer. + * + * @param i the integer + * @return String containing the integer in base 10 + * @see Integer#toString(int) + */ + public static String valueOf(int i) + { + // See Integer to understand why we call the two-arg variant. + return Integer.toString(i, 10); + } + + /** + * Returns a String representing a long. + * + * @param l the long + * @return String containing the long in base 10 + * @see Long#toString(long) + */ + public static String valueOf(long l) + { + return Long.toString(l); + } + + /** + * Returns a String representing a float. + * + * @param f the float + * @return String containing the float + * @see Float#toString(float) + */ + public static String valueOf(float f) + { + return Float.toString(f); + } + + /** + * Returns a String representing a double. + * + * @param d the double + * @return String containing the double + * @see Double#toString(double) + */ + public static String valueOf(double d) + { + return Double.toString(d); + } + + /** + * If two Strings are considered equal, by the equals() method, + * then intern() will return the same String instance. ie. + * if (s1.equals(s2)) then (s1.intern() == s2.intern()). + * All string literals and string-valued constant expressions + * are already interned. + * + * @return the interned String + */ + public String intern() + { + return VMString.intern(this); + } + + /** + * Helper function used to detect which characters have a multi-character + * uppercase expansion. Note that this is only used in locations which + * track one-to-many capitalization (java.lang.Character does not do this). + * As of Unicode 3.0.0, the result is limited in the range 0 to 2, as the + * longest uppercase expansion is three characters (a growth of 2 from the + * lowercase character). + * + * @param ch the char to check + * @return the number of characters to add when converting to uppercase + * @see CharData#DIRECTION + * @see CharData#UPPER_SPECIAL + * @see #toUpperCase(Locale) + */ + private static int upperCaseExpansion(char ch) + { + return Character.direction[Character.readChar(ch) >> 7] & 3; + } + + /** + * Helper function used to locate the offset in upperExpand given a + * character with a multi-character expansion. The binary search is + * optimized under the assumption that this method will only be called on + * characters which exist in upperSpecial. + * + * @param ch the char to check + * @return the index where its expansion begins + * @see CharData#UPPER_SPECIAL + * @see CharData#UPPER_EXPAND + * @see #toUpperCase(Locale) + */ + private static int upperCaseIndex(char ch) + { + // Simple binary search for the correct character. + int low = 0; + int hi = upperSpecial.length - 2; + int mid = ((low + hi) >> 2) << 1; + char c = upperSpecial[mid]; + while (ch != c) + { + if (ch < c) + hi = mid - 2; + else + low = mid + 2; + mid = ((low + hi) >> 2) << 1; + c = upperSpecial[mid]; + } + return upperSpecial[mid + 1]; + } + + /** + * Returns the value array of the given string if it is zero based or a + * copy of it that is zero based (stripping offset and making length equal + * to count). Used for accessing the char[]s of gnu.java.lang.CharData. + * Package private for use in Character. + */ + static char[] zeroBasedStringValue(String s) + { + char[] value; + + if (s.offset == 0 && s.count == s.value.length) + value = s.value; + else + { + int count = s.count; + value = new char[count]; + VMSystem.arraycopy(s.value, s.offset, value, 0, count); + } + + return value; + } +} diff --git a/libjava/classpath/java/lang/StringBuffer.java b/libjava/classpath/java/lang/StringBuffer.java new file mode 100644 index 0000000..94dec48 --- /dev/null +++ b/libjava/classpath/java/lang/StringBuffer.java @@ -0,0 +1,931 @@ +/* StringBuffer.java -- Growable strings + 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 java.lang; + +import java.io.Serializable; + +/** + * StringBuffer represents a changeable String. + * It provides the operations required to modify the + * StringBuffer, including insert, replace, delete, append, + * and reverse. It is thread-safe; meaning that all modifications to a buffer + * are in synchronized methods. + * + *

    StringBuffers are variable-length in nature, so even if + * you initialize them to a certain size, they can still grow larger than + * that. Capacity indicates the number of characters the + * StringBuffer can have in it before it has to grow (growing + * the char array is an expensive operation involving new). + * + *

    Incidentally, compilers often implement the String operator "+" + * by using a StringBuffer operation:
    + * a + b
    + * is the same as
    + * new StringBuffer().append(a).append(b).toString(). + * + *

    Classpath's StringBuffer is capable of sharing memory with Strings for + * efficiency. This will help when a StringBuffer is converted to a String + * and the StringBuffer is not changed after that (quite common when performing + * string concatenation). + * + * @author Paul Fisher + * @author John Keiser + * @author Tom Tromey + * @author Eric Blake (ebb9@email.byu.edu) + * @see String + * @since 1.0 + * @status updated to 1.4 + */ +public final class StringBuffer implements Serializable, CharSequence +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3388685877147921107L; + + /** + * 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 + */ + int count; + + /** + * The buffer. Note that this has permissions set this way so that String + * can get the value. + * + * @serial the buffer + */ + char[] value; + + /** + * True if the buffer is shared with another object (StringBuffer or + * String); this means the buffer must be copied before writing to it again. + * Note that this has permissions set this way so that String can get the + * value. + * + * @serial whether the buffer is shared + */ + boolean shared; + + /** + * The default capacity of a buffer. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * Create a new StringBuffer with default capacity 16. + */ + public StringBuffer() + { + this(DEFAULT_CAPACITY); + } + + /** + * Create an empty StringBuffer with the specified initial + * capacity. + * + * @param capacity the initial capacity + * @throws NegativeArraySizeException if capacity is negative + */ + public StringBuffer(int capacity) + { + value = new char[capacity]; + } + + /** + * Create a new StringBuffer with the characters in the + * specified String. Initial capacity will be the size of the + * String plus 16. + * + * @param str the String to convert + * @throws NullPointerException if str is null + */ + public StringBuffer(String str) + { + // Unfortunately, because the size is 16 larger, we cannot share. + count = str.count; + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Get the length of the String this StringBuffer + * would create. Not to be confused with the capacity of the + * StringBuffer. + * + * @return the length of this StringBuffer + * @see #capacity() + * @see #setLength(int) + */ + public synchronized int length() + { + return count; + } + + /** + * Get the total number of characters this StringBuffer can + * support before it must be grown. Not to be confused with length. + * + * @return the capacity of this StringBuffer + * @see #length() + * @see #ensureCapacity(int) + */ + public synchronized int capacity() + { + return value.length; + } + + /** + * Increase the capacity of this StringBuffer. This will + * ensure that an expensive growing operation will not occur until + * minimumCapacity is reached. The buffer is grown to the + * larger of minimumCapacity and + * capacity() * 2 + 2, if it is not already large enough. + * + * @param minimumCapacity the new capacity + * @see #capacity() + */ + public synchronized void ensureCapacity(int minimumCapacity) + { + ensureCapacity_unsynchronized(minimumCapacity); + } + + /** + * 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 synchronized void setLength(int newLength) + { + if (newLength < 0) + throw new StringIndexOutOfBoundsException(newLength); + + int valueLength = value.length; + + /* Always call ensureCapacity_unsynchronized in order to preserve + copy-on-write semantics. */ + ensureCapacity_unsynchronized(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 synchronized char charAt(int index) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + return value[index]; + } + + /** + * 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 synchronized void getChars(int srcOffset, int srcEnd, + char[] dst, int dstOffset) + { + if (srcOffset < 0 || srcEnd > count || srcEnd < srcOffset) + throw new StringIndexOutOfBoundsException(); + VMSystem.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 synchronized void setCharAt(int index, char ch) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity_unsynchronized(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 StringBuffer append(Object obj) + { + return append(obj == null ? "null" : obj.toString()); + } + + /** + * 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 synchronized StringBuffer append(String str) + { + if (str == null) + str = "null"; + int len = str.count; + ensureCapacity_unsynchronized(count + len); + str.getChars(0, len, value, count); + count += len; + return this; + } + + /** + * Append the StringBuffer value of the argument to this + * StringBuffer. This behaves the same as + * append((Object) stringBuffer), except it is more efficient. + * + * @param stringBuffer the StringBuffer to convert and append + * @return this StringBuffer + * @see #append(Object) + * @since 1.4 + */ + public synchronized StringBuffer append(StringBuffer stringBuffer) + { + if (stringBuffer == null) + return append("null"); + synchronized (stringBuffer) + { + int len = stringBuffer.count; + ensureCapacity_unsynchronized(count + len); + VMSystem.arraycopy(stringBuffer.value, 0, value, count, len); + 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 StringBuffer 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 synchronized StringBuffer append(char[] data, int offset, int count) + { + if (offset < 0 || count < 0 || offset > data.length - count) + throw new StringIndexOutOfBoundsException(); + ensureCapacity_unsynchronized(this.count + count); + VMSystem.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 StringBuffer append(boolean bool) + { + return append(bool ? "true" : "false"); + } + + /** + * Append the char to this StringBuffer. + * + * @param ch the char to append + * @return this StringBuffer + */ + public synchronized StringBuffer append(char ch) + { + ensureCapacity_unsynchronized(count + 1); + value[count++] = ch; + 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 StringBuffer 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 StringBuffer 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 StringBuffer 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 StringBuffer append(double dnum) + { + return append(Double.toString(dnum)); + } + + /** + * 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 synchronized StringBuffer delete(int start, int end) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + if (end > count) + end = count; + // This will unshare if required. + ensureCapacity_unsynchronized(count); + if (count - end != 0) + VMSystem.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 StringBuffer 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 synchronized StringBuffer replace(int start, int end, String str) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + + int len = str.count; + // Calculate the difference in 'count' after the replace. + int delta = len - (end > count ? count : end) + start; + ensureCapacity_unsynchronized(count + delta); + + if (delta != 0 && end < count) + VMSystem.arraycopy(value, end, value, end + delta, count - end); + + str.getChars(0, len, value, start); + count += delta; + return this; + } + + /** + * Creates a substring of this StringBuffer, starting at a specified index + * and ending at the end of this StringBuffer. + * + * @param beginIndex index to start substring (base 0) + * @return new String which is a substring of this StringBuffer + * @throws StringIndexOutOfBoundsException if beginIndex is out of bounds + * @see #substring(int, int) + * @since 1.2 + */ + public String substring(int beginIndex) + { + return substring(beginIndex, count); + } + + /** + * Creates a substring of this StringBuffer, 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 StringBuffer + * @throws IndexOutOfBoundsException if beginIndex or endIndex is out of + * bounds + * @see #substring(int, int) + * @since 1.4 + */ + public CharSequence subSequence(int beginIndex, int endIndex) + { + return substring(beginIndex, endIndex); + } + + /** + * Creates a substring of this StringBuffer, 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 StringBuffer + * @throws StringIndexOutOfBoundsException if beginIndex or endIndex is out + * of bounds + * @since 1.2 + */ + public synchronized String substring(int beginIndex, int endIndex) + { + int len = endIndex - beginIndex; + if (beginIndex < 0 || endIndex > count || endIndex < beginIndex) + throw new StringIndexOutOfBoundsException(); + if (len == 0) + return ""; + // Don't copy unless substring is smaller than 1/4 of the buffer. + boolean share_buffer = ((len << 2) >= value.length); + if (share_buffer) + this.shared = true; + // Package constructor avoids an array copy. + return new String(value, beginIndex, len, share_buffer); + } + + /** + * 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 synchronized StringBuffer 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_unsynchronized(count + len); + VMSystem.arraycopy(value, offset, value, offset + len, count - offset); + VMSystem.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 StringBuffer 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 synchronized StringBuffer insert(int offset, String str) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + if (str == null) + str = "null"; + int len = str.count; + ensureCapacity_unsynchronized(count + len); + VMSystem.arraycopy(value, offset, value, offset + len, count - offset); + str.getChars(0, len, value, offset); + 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 StringBuffer 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 StringBuffer 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 synchronized StringBuffer insert(int offset, char ch) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + ensureCapacity_unsynchronized(count + 1); + VMSystem.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 StringBuffer 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 StringBuffer 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 StringBuffer 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 StringBuffer insert(int offset, double dnum) + { + return insert(offset, Double.toString(dnum)); + } + + /** + * Finds the first 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 #indexOf(String, int) + * @since 1.4 + */ + 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 synchronized int indexOf(String str, int fromIndex) + { + if (fromIndex < 0) + fromIndex = 0; + int limit = count - str.count; + for ( ; fromIndex <= limit; fromIndex++) + if (regionMatches(fromIndex, str)) + 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.count); + } + + /** + * 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 synchronized int lastIndexOf(String str, int fromIndex) + { + fromIndex = Math.min(fromIndex, count - str.count); + for ( ; fromIndex >= 0; fromIndex--) + if (regionMatches(fromIndex, str)) + 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 synchronized StringBuffer reverse() + { + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity_unsynchronized(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; + } + + /** + * Convert this StringBuffer to a String. The + * String is composed of the characters currently in this StringBuffer. Note + * that the result is a copy, and that future modifications to this buffer + * do not affect the String. + * + * @return the characters in this StringBuffer + */ + public String toString() + { + // The string will set this.shared = true. + return new String(this); + } + + /** + * An unsynchronized version of ensureCapacity, used internally to avoid + * the cost of a second lock on the same object. This also has the side + * effect of duplicating the array, if it was shared (to form copy-on-write + * semantics). + * + * @param minimumCapacity the minimum capacity + * @see #ensureCapacity(int) + */ + private void ensureCapacity_unsynchronized(int minimumCapacity) + { + if (shared || minimumCapacity > value.length) + { + // We don't want to make a larger vector when `shared' is + // set. If we do, then setLength becomes very inefficient + // when repeatedly reusing a StringBuffer in a loop. + int max = (minimumCapacity > value.length + ? value.length * 2 + 2 + : value.length); + minimumCapacity = (minimumCapacity < max ? max : minimumCapacity); + char[] nb = new char[minimumCapacity]; + VMSystem.arraycopy(value, 0, nb, 0, count); + value = nb; + shared = false; + } + } + + /** + * Predicate which determines if a substring of this matches another String + * starting at a specified offset for each String and continuing for a + * specified length. This is more efficient than creating a String to call + * indexOf on. + * + * @param toffset index to start comparison at for this String + * @param other non-null String to compare to region of this + * @return true if regions match, false otherwise + * @see #indexOf(String, int) + * @see #lastIndexOf(String, int) + * @see String#regionMatches(boolean, int, String, int, int) + */ + private boolean regionMatches(int toffset, String other) + { + int len = other.count; + int index = other.offset; + while (--len >= 0) + if (value[toffset++] != other.value[index++]) + return false; + return true; + } +} diff --git a/libjava/classpath/java/lang/StringBuilder.java b/libjava/classpath/java/lang/StringBuilder.java new file mode 100644 index 0000000..b54c8ef --- /dev/null +++ b/libjava/classpath/java/lang/StringBuilder.java @@ -0,0 +1,944 @@ +/* StringBuilder.java -- Unsynchronized growable strings + 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 java.lang; + +import java.io.Serializable; + +/** + * StringBuilder represents a changeable String. + * It provides the operations required to modify the + * StringBuilder, including insert, replace, delete, append, + * and reverse. It like StringBuffer, but is not + * synchronized. It is ideal for use when it is known that the + * object will only be used from a single thread. + * + *

    StringBuilders are variable-length in nature, so even if + * you initialize them to a certain size, they can still grow larger than + * that. Capacity indicates the number of characters the + * StringBuilder can have in it before it has to grow (growing + * the char array is an expensive operation involving new). + * + *

    Incidentally, compilers often implement the String operator "+" + * by using a StringBuilder operation:
    + * a + b
    + * is the same as
    + * new StringBuilder().append(a).append(b).toString(). + * + *

    Classpath's StringBuilder is capable of sharing memory with Strings for + * efficiency. This will help when a StringBuilder is converted to a String + * and the StringBuilder is not changed after that (quite common when + * performing string concatenation). + * + * @author Paul Fisher + * @author John Keiser + * @author Tom Tromey + * @author Eric Blake (ebb9@email.byu.edu) + * @see String + * @see StringBuffer + * + * @since 1.5 + */ +// FIX15: Implement Appendable when co-variant methods are available +public final class StringBuilder + implements Serializable, CharSequence +{ + // Implementation note: if you change this class, you usually will + // want to change StringBuffer as well. + + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 4383685877147921099L; + + /** + * 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 + */ + int count; + + /** + * The buffer. Note that this has permissions set this way so that String + * can get the value. + * + * @serial the buffer + */ + char[] value; + + /** + * The default capacity of a buffer. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * Create a new StringBuilder with default capacity 16. + */ + public StringBuilder() + { + this(DEFAULT_CAPACITY); + } + + /** + * Create an empty StringBuilder with the specified initial + * capacity. + * + * @param capacity the initial capacity + * @throws NegativeArraySizeException if capacity is negative + */ + public StringBuilder(int capacity) + { + value = new char[capacity]; + } + + /** + * Create a new StringBuilder with the characters in the + * specified String. Initial capacity will be the size of the + * String plus 16. + * + * @param str the String to convert + * @throws NullPointerException if str is null + */ + public StringBuilder(String str) + { + // Unfortunately, because the size is 16 larger, we cannot share. + count = str.count; + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new StringBuilder with the characters in the + * specified CharSequence. Initial capacity will be the + * length of the sequence plus 16; if the sequence reports a length + * less than or equal to 0, then the initial capacity will be 16. + * + * @param seq the initializing CharSequence + * @throws NullPointerException if str is null + */ + public StringBuilder(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); + } + + /** + * 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; + } + + /** + * Get the total number of characters this StringBuilder can + * support before it must be grown. Not to be confused with length. + * + * @return the capacity of this StringBuilder + * @see #length() + * @see #ensureCapacity(int) + */ + public int capacity() + { + return value.length; + } + + /** + * Increase the capacity of this StringBuilder. This will + * ensure that an expensive growing operation will not occur until + * minimumCapacity is reached. The buffer is grown to the + * larger of minimumCapacity and + * capacity() * 2 + 2, if it is not already large enough. + * + * @param minimumCapacity the new capacity + * @see #capacity() + */ + public void ensureCapacity(int minimumCapacity) + { + if (minimumCapacity > value.length) + { + int max = value.length * 2 + 2; + minimumCapacity = (minimumCapacity < max ? max : minimumCapacity); + char[] nb = new char[minimumCapacity]; + System.arraycopy(value, 0, nb, 0, count); + value = nb; + } + } + + /** + * Set the length of this StringBuilder. 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. */ + ensureCapacity(newLength); + + if (newLength < valueLength) + { + /* If the StringBuilder'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 StringBuilder'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 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 + * StringBuilder. Uses String.valueOf() to convert + * to String. + * + * @param obj the Object to convert and append + * @return this StringBuilder + * @see String#valueOf(Object) + * @see #append(String) + */ + public StringBuilder append(Object obj) + { + return append(obj == null ? "null" : obj.toString()); + } + + /** + * Append the String to this StringBuilder. If + * str is null, the String "null" is appended. + * + * @param str the String to append + * @return this StringBuilder + */ + public StringBuilder append(String str) + { + if (str == null) + str = "null"; + int len = str.count; + 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 StringBuilder append(StringBuffer stringBuffer) + { + if (stringBuffer == null) + return append("null"); + synchronized (stringBuffer) + { + int len = stringBuffer.count; + ensureCapacity(count + len); + System.arraycopy(stringBuffer.value, 0, value, count, len); + count += len; + } + return this; + } + + /** + * Append the char array to this StringBuilder. + * 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 StringBuilder + * @throws NullPointerException if str is null + * @see #append(char[], int, int) + */ + public StringBuilder append(char[] data) + { + return append(data, 0, data.length); + } + + /** + * Append part of the char array to this + * StringBuilder. 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 StringBuilder + * @throws NullPointerException if str is null + * @throws IndexOutOfBoundsException if offset or count is out of range + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public StringBuilder 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 + * StringBuilder. Uses String.valueOf() to convert + * to String. + * + * @param bool the boolean to convert and append + * @return this StringBuilder + * @see String#valueOf(boolean) + */ + public StringBuilder append(boolean bool) + { + return append(bool ? "true" : "false"); + } + + /** + * Append the char to this StringBuilder. + * + * @param ch the char to append + * @return this StringBuilder + */ + public StringBuilder 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 StringBuilder + */ + public StringBuilder 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 StringBuilder + */ + public StringBuilder 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 + * StringBuilder. Uses String.valueOf() to convert + * to String. + * + * @param inum the int to convert and append + * @return this StringBuilder + * @see String#valueOf(int) + */ + // This is native in libgcj, for efficiency. + public StringBuilder append(int inum) + { + return append(String.valueOf(inum)); + } + + /** + * Append the String value of the argument to this + * StringBuilder. Uses String.valueOf() to convert + * to String. + * + * @param lnum the long to convert and append + * @return this StringBuilder + * @see String#valueOf(long) + */ + public StringBuilder append(long lnum) + { + return append(Long.toString(lnum, 10)); + } + + /** + * Append the String value of the argument to this + * StringBuilder. Uses String.valueOf() to convert + * to String. + * + * @param fnum the float to convert and append + * @return this StringBuilder + * @see String#valueOf(float) + */ + public StringBuilder append(float fnum) + { + return append(Float.toString(fnum)); + } + + /** + * Append the String value of the argument to this + * StringBuilder. Uses String.valueOf() to convert + * to String. + * + * @param dnum the double to convert and append + * @return this StringBuilder + * @see String#valueOf(double) + */ + public StringBuilder append(double dnum) + { + return append(Double.toString(dnum)); + } + + /** + * Delete characters from this StringBuilder. + * 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 StringBuilder + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + */ + public StringBuilder delete(int start, int end) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + if (end > count) + end = count; + // This will unshare if required. + ensureCapacity(count); + if (count - end != 0) + System.arraycopy(value, end, value, start, count - end); + count -= end - start; + return this; + } + + /** + * Delete a character from this StringBuilder. + * + * @param index the index of the character to delete + * @return this StringBuilder + * @throws StringIndexOutOfBoundsException if index is out of bounds + */ + public StringBuilder 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 StringBuilder, 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 StringBuilder + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @throws NullPointerException if str is null + */ + public StringBuilder replace(int start, int end, String str) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + + int len = str.count; + // 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; + } + + /** + * Creates a substring of this StringBuilder, 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 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 StringBuilder, 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) + { + int len = endIndex - beginIndex; + if (beginIndex < 0 || endIndex > count || endIndex < beginIndex) + throw new StringIndexOutOfBoundsException(); + if (len == 0) + return ""; + return new String(value, beginIndex, len); + } + + /** + * Insert a subarray of the char[] argument into this + * StringBuilder. + * + * @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 StringBuilder + * @throws NullPointerException if str is null + * @throws StringIndexOutOfBoundsException if any index is out of bounds + */ + public StringBuilder 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 + * StringBuilder. 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 StringBuilder + * @exception StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(Object) + */ + public StringBuilder insert(int offset, Object obj) + { + return insert(offset, obj == null ? "null" : obj.toString()); + } + + /** + * Insert the String argument into this + * StringBuilder. 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 StringBuilder + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public StringBuilder insert(int offset, String str) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + if (str == null) + str = "null"; + int len = str.count; + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + str.getChars(0, len, value, offset); + count += len; + return this; + } + + /** + * Insert the char[] argument into this + * StringBuilder. + * + * @param offset the place to insert in this buffer + * @param data the char[] to insert + * @return this StringBuilder + * @throws NullPointerException if data is null + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see #insert(int, char[], int, int) + */ + public StringBuilder insert(int offset, char[] data) + { + return insert(offset, data, 0, data.length); + } + + /** + * Insert the String value of the argument into this + * StringBuilder. 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 StringBuilder + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(boolean) + */ + public StringBuilder insert(int offset, boolean bool) + { + return insert(offset, bool ? "true" : "false"); + } + + /** + * Insert the char argument into this StringBuilder. + * + * @param offset the place to insert in this buffer + * @param ch the char to insert + * @return this StringBuilder + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public StringBuilder 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 + * StringBuilder. 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 StringBuilder + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(int) + */ + public StringBuilder insert(int offset, int inum) + { + return insert(offset, String.valueOf(inum)); + } + + /** + * Insert the String value of the argument into this + * StringBuilder. 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 StringBuilder + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(long) + */ + public StringBuilder insert(int offset, long lnum) + { + return insert(offset, Long.toString(lnum, 10)); + } + + /** + * Insert the String value of the argument into this + * StringBuilder. 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 StringBuilder + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(float) + */ + public StringBuilder insert(int offset, float fnum) + { + return insert(offset, Float.toString(fnum)); + } + + /** + * Insert the String value of the argument into this + * StringBuilder. 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 StringBuilder + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(double) + */ + public StringBuilder 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 StringBuilder, 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 + */ + public int indexOf(String str, int fromIndex) + { + if (fromIndex < 0) + fromIndex = 0; + int limit = count - str.count; + for ( ; fromIndex <= limit; fromIndex++) + if (regionMatches(fromIndex, str)) + return fromIndex; + return -1; + } + + /** + * Finds the last 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 #lastIndexOf(String, int) + */ + public int lastIndexOf(String str) + { + return lastIndexOf(str, count - str.count); + } + + /** + * Finds the last instance of a String in this StringBuilder, 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 + */ + public int lastIndexOf(String str, int fromIndex) + { + fromIndex = Math.min(fromIndex, count - str.count); + for ( ; fromIndex >= 0; fromIndex--) + if (regionMatches(fromIndex, str)) + return fromIndex; + return -1; + } + + /** + * Reverse the characters in this StringBuilder. The same sequence of + * characters exists, but in the reverse index ordering. + * + * @return this StringBuilder + */ + public StringBuilder 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; + } + + /** + * Convert this StringBuilder to a String. The + * String is composed of the characters currently in this StringBuilder. Note + * that the result is a copy, and that future modifications to this buffer + * do not affect the String. + * + * @return the characters in this StringBuilder + */ + public String toString() + { + return new String(this); + } + + /** + * Predicate which determines if a substring of this matches another String + * starting at a specified offset for each String and continuing for a + * specified length. This is more efficient than creating a String to call + * indexOf on. + * + * @param toffset index to start comparison at for this String + * @param other non-null String to compare to region of this + * @return true if regions match, false otherwise + * @see #indexOf(String, int) + * @see #lastIndexOf(String, int) + * @see String#regionMatches(boolean, int, String, int, int) + */ + private boolean regionMatches(int toffset, String other) + { + int len = other.count; + int index = other.offset; + while (--len >= 0) + if (value[toffset++] != other.value[index++]) + return false; + return true; + } +} diff --git a/libjava/classpath/java/lang/StringIndexOutOfBoundsException.java b/libjava/classpath/java/lang/StringIndexOutOfBoundsException.java new file mode 100644 index 0000000..ebc4a04 --- /dev/null +++ b/libjava/classpath/java/lang/StringIndexOutOfBoundsException.java @@ -0,0 +1,85 @@ +/* StringIndexOutOfBoundsException.java -- thrown to indicate attempt to + exceed string bounds + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * This exception can be thrown to indicate an attempt to access an index + * which is out of bounds of a String. Any negative integer, and a positive + * integer greater than or equal to the size of the string, is an index + * which would be out of bounds. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class StringIndexOutOfBoundsException extends IndexOutOfBoundsException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -6762910422159637258L; + + /** + * Create an exception without a message. + */ + public StringIndexOutOfBoundsException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public StringIndexOutOfBoundsException(String s) + { + super(s); + } + + /** + * Create an exception noting the illegal index. + * + * @param index the invalid index + */ + public StringIndexOutOfBoundsException(int index) + { + super("String index out of range: " + index); + } +} diff --git a/libjava/classpath/java/lang/System.java b/libjava/classpath/java/lang/System.java new file mode 100644 index 0000000..e466d3b --- /dev/null +++ b/libjava/classpath/java/lang/System.java @@ -0,0 +1,528 @@ +/* System.java -- useful methods to interface with the system + 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 java.lang; + +import gnu.classpath.SystemProperties; +import gnu.classpath.VMStackWalker; + +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Properties; +import java.util.PropertyPermission; + +/** + * System represents system-wide resources; things that represent the + * general environment. As such, all methods are static. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status still missing 1.4 functionality + */ +public final class System +{ + // WARNING: System is a CORE class in the bootstrap cycle. See the comments + // in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * The standard InputStream. This is assigned at startup and starts its + * life perfectly valid. Although it is marked final, you can change it + * using {@link #setIn(InputStream)} through some hefty VM magic. + * + *

    This corresponds to the C stdin and C++ cin variables, which + * typically input from the keyboard, but may be used to pipe input from + * other processes or files. That should all be transparent to you, + * however. + */ + public static final InputStream in = VMSystem.makeStandardInputStream(); + + /** + * The standard output PrintStream. This is assigned at startup and + * starts its life perfectly valid. Although it is marked final, you can + * change it using {@link #setOut(PrintStream)} through some hefty VM magic. + * + *

    This corresponds to the C stdout and C++ cout variables, which + * typically output normal messages to the screen, but may be used to pipe + * output to other processes or files. That should all be transparent to + * you, however. + */ + public static final PrintStream out = VMSystem.makeStandardOutputStream(); + + /** + * The standard output PrintStream. This is assigned at startup and + * starts its life perfectly valid. Although it is marked final, you can + * change it using {@link #setErr(PrintStream)} through some hefty VM magic. + * + *

    This corresponds to the C stderr and C++ cerr variables, which + * typically output error messages to the screen, but may be used to pipe + * output to other processes or files. That should all be transparent to + * you, however. + */ + public static final PrintStream err = VMSystem.makeStandardErrorStream(); + + /** + * This class is uninstantiable. + */ + private System() + { + } + + /** + * Set {@link #in} to a new InputStream. This uses some VM magic to change + * a "final" variable, so naturally there is a security check, + * RuntimePermission("setIO"). + * + * @param in the new InputStream + * @throws SecurityException if permission is denied + * @since 1.1 + */ + public static void setIn(InputStream in) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setIO")); + VMSystem.setIn(in); + } + + /** + * Set {@link #out} to a new PrintStream. This uses some VM magic to change + * a "final" variable, so naturally there is a security check, + * RuntimePermission("setIO"). + * + * @param out the new PrintStream + * @throws SecurityException if permission is denied + * @since 1.1 + */ + public static void setOut(PrintStream out) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setIO")); + + VMSystem.setOut(out); + } + + /** + * Set {@link #err} to a new PrintStream. This uses some VM magic to change + * a "final" variable, so naturally there is a security check, + * RuntimePermission("setIO"). + * + * @param err the new PrintStream + * @throws SecurityException if permission is denied + * @since 1.1 + */ + public static void setErr(PrintStream err) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setIO")); + VMSystem.setErr(err); + } + + /** + * Set the current SecurityManager. If a security manager already exists, + * then RuntimePermission("setSecurityManager") is checked + * first. Since this permission is denied by the default security manager, + * setting the security manager is often an irreversible action. + * + * Spec Note: Don't ask me, I didn't write it. It looks + * pretty vulnerable; whoever gets to the gate first gets to set the policy. + * There is probably some way to set the original security manager as a + * command line argument to the VM, but I don't know it. + * + * @param sm the new SecurityManager + * @throws SecurityException if permission is denied + */ + public static synchronized void setSecurityManager(SecurityManager sm) + { + // Implementation note: the field lives in SecurityManager because of + // bootstrap initialization issues. This method is synchronized so that + // no other thread changes it to null before this thread makes the change. + if (SecurityManager.current != null) + SecurityManager.current.checkPermission + (new RuntimePermission("setSecurityManager")); + SecurityManager.current = sm; + } + + /** + * Get the current SecurityManager. If the SecurityManager has not been + * set yet, then this method returns null. + * + * @return the current SecurityManager, or null + */ + public static SecurityManager getSecurityManager() + { + return SecurityManager.current; + } + + /** + * Get the current time, measured in the number of milliseconds from the + * beginning of Jan. 1, 1970. This is gathered from the system clock, with + * any attendant incorrectness (it may be timezone dependent). + * + * @return the current time + * @see java.util.Date + */ + public static long currentTimeMillis() + { + return VMSystem.currentTimeMillis(); + } + + /** + * Copy one array onto another from src[srcStart] ... + * src[srcStart+len-1] to dest[destStart] ... + * dest[destStart+len-1]. First, the arguments are validated: + * neither array may be null, they must be of compatible types, and the + * start and length must fit within both arrays. Then the copying starts, + * and proceeds through increasing slots. If src and dest are the same + * array, this will appear to copy the data to a temporary location first. + * An ArrayStoreException in the middle of copying will leave earlier + * elements copied, but later elements unchanged. + * + * @param src the array to copy elements from + * @param srcStart the starting position in src + * @param dest the array to copy elements to + * @param destStart the starting position in dest + * @param len the number of elements to copy + * @throws NullPointerException if src or dest is null + * @throws ArrayStoreException if src or dest is not an array, if they are + * not compatible array types, or if an incompatible runtime type + * is stored in dest + * @throws IndexOutOfBoundsException if len is negative, or if the start or + * end copy position in either array is out of bounds + */ + public static void arraycopy(Object src, int srcStart, + Object dest, int destStart, int len) + { + VMSystem.arraycopy(src, srcStart, dest, destStart, len); + } + + /** + * Get a hash code computed by the VM for the Object. This hash code will + * be the same as Object's hashCode() method. It is usually some + * convolution of the pointer to the Object internal to the VM. It + * follows standard hash code rules, in that it will remain the same for a + * given Object for the lifetime of that Object. + * + * @param o the Object to get the hash code for + * @return the VM-dependent hash code for this Object + * @since 1.1 + */ + public static int identityHashCode(Object o) + { + return VMSystem.identityHashCode(o); + } + + /** + * Get all the system properties at once. A security check may be performed, + * checkPropertiesAccess. Note that a security manager may + * allow getting a single property, but not the entire group. + * + *

    The required properties include: + *

    + *
    java.version
    Java version number
    + *
    java.vendor
    Java vendor specific string
    + *
    java.vendor.url
    Java vendor URL
    + *
    java.home
    Java installation directory
    + *
    java.vm.specification.version
    VM Spec version
    + *
    java.vm.specification.vendor
    VM Spec vendor
    + *
    java.vm.specification.name
    VM Spec name
    + *
    java.vm.version
    VM implementation version
    + *
    java.vm.vendor
    VM implementation vendor
    + *
    java.vm.name
    VM implementation name
    + *
    java.specification.version
    Java Runtime Environment version
    + *
    java.specification.vendor
    Java Runtime Environment vendor
    + *
    java.specification.name
    Java Runtime Environment name
    + *
    java.class.version
    Java class version number
    + *
    java.class.path
    Java classpath
    + *
    java.library.path
    Path for finding Java libraries
    + *
    java.io.tmpdir
    Default temp file path
    + *
    java.compiler
    Name of JIT to use
    + *
    java.ext.dirs
    Java extension path
    + *
    os.name
    Operating System Name
    + *
    os.arch
    Operating System Architecture
    + *
    os.version
    Operating System Version
    + *
    file.separator
    File separator ("/" on Unix)
    + *
    path.separator
    Path separator (":" on Unix)
    + *
    line.separator
    Line separator ("\n" on Unix)
    + *
    user.name
    User account name
    + *
    user.home
    User home directory
    + *
    user.dir
    User's current working directory
    + *
    + * + * In addition, gnu defines several other properties, where ? stands for + * each character in '0' through '9': + *
    + *
    gnu.classpath.home
    Path to the classpath libraries.
    + *
    gnu.classpath.version
    Version of the classpath libraries.
    + *
    gnu.classpath.vm.shortname
    Succinct version of the VM name; + * used for finding property files in file system
    + *
    gnu.classpath.home.url
    Base URL; used for finding + * property files in file system
    + *
    gnu.cpu.endian
    big or little
    + *
    gnu.java.io.encoding_scheme_alias.iso-8859-?
    8859_?
    + *
    gnu.java.io.encoding_scheme_alias.iso8859_?
    8859_?
    + *
    gnu.java.io.encoding_scheme_alias.iso-latin-_?
    8859_?
    + *
    gnu.java.io.encoding_scheme_alias.latin?
    8859_?
    + *
    gnu.java.io.encoding_scheme_alias.utf-8
    UTF8
    + *
    + * + * @return the system properties, will never be null + * @throws SecurityException if permission is denied + */ + public static Properties getProperties() + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertiesAccess(); + return SystemProperties.getProperties(); + } + + /** + * Set all the system properties at once. A security check may be performed, + * checkPropertiesAccess. Note that a security manager may + * allow setting a single property, but not the entire group. An argument + * of null resets the properties to the startup default. + * + * @param properties the new set of system properties + * @throws SecurityException if permission is denied + */ + public static void setProperties(Properties properties) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertiesAccess(); + SystemProperties.setProperties(properties); + } + + /** + * Get a single system property by name. A security check may be performed, + * checkPropertyAccess(key). + * + * @param key the name of the system property to get + * @return the property, or null if not found + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + */ + public static String getProperty(String key) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertyAccess(key); + else if (key.length() == 0) + throw new IllegalArgumentException("key can't be empty"); + return SystemProperties.getProperty(key); + } + + /** + * Get a single system property by name. A security check may be performed, + * checkPropertyAccess(key). + * + * @param key the name of the system property to get + * @param def the default + * @return the property, or def if not found + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + */ + public static String getProperty(String key, String def) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertyAccess(key); + return SystemProperties.getProperty(key, def); + } + + /** + * Set a single system property by name. A security check may be performed, + * checkPropertyAccess(key, "write"). + * + * @param key the name of the system property to set + * @param value the new value + * @return the previous value, or null + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + * @since 1.2 + */ + public static String setProperty(String key, String value) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new PropertyPermission(key, "write")); + return SystemProperties.setProperty(key, value); + } + + /** + * Gets the value of an environment variable. + * + * @param name the name of the environment variable + * @return the string value of the variable or null when the + * environment variable is not defined. + * @throws NullPointerException + * @throws SecurityException if permission is denied + * @since 1.5 + * @specnote This method was deprecated in some JDK releases, but + * was restored in 1.5. + */ + public static String getenv(String name) + { + if (name == null) + throw new NullPointerException(); + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("getenv." + name)); + return VMSystem.getenv(name); + } + + /** + * Terminate the Virtual Machine. This just calls + * Runtime.getRuntime().exit(status), and never returns. + * Obviously, a security check is in order, checkExit. + * + * @param status the exit status; by convention non-zero is abnormal + * @throws SecurityException if permission is denied + * @see Runtime#exit(int) + */ + public static void exit(int status) + { + Runtime.getRuntime().exit(status); + } + + /** + * Calls the garbage collector. This is only a hint, and it is up to the + * implementation what this hint suggests, but it usually causes a + * best-effort attempt to reclaim unused memory from discarded objects. + * This calls Runtime.getRuntime().gc(). + * + * @see Runtime#gc() + */ + public static void gc() + { + Runtime.getRuntime().gc(); + } + + /** + * Runs object finalization on pending objects. This is only a hint, and + * it is up to the implementation what this hint suggests, but it usually + * causes a best-effort attempt to run finalizers on all objects ready + * to be reclaimed. This calls + * Runtime.getRuntime().runFinalization(). + * + * @see Runtime#runFinalization() + */ + public static void runFinalization() + { + Runtime.getRuntime().runFinalization(); + } + + /** + * Tell the Runtime whether to run finalization before exiting the + * JVM. This is inherently unsafe in multi-threaded applications, + * since it can force initialization on objects which are still in use + * by live threads, leading to deadlock; therefore this is disabled by + * default. There may be a security check, checkExit(0). This + * calls Runtime.runFinalizersOnExit(). + * + * @param finalizeOnExit whether to run finalizers on exit + * @throws SecurityException if permission is denied + * @see Runtime#runFinalizersOnExit() + * @since 1.1 + * @deprecated never rely on finalizers to do a clean, thread-safe, + * mop-up from your code + */ + public static void runFinalizersOnExit(boolean finalizeOnExit) + { + Runtime.runFinalizersOnExit(finalizeOnExit); + } + + /** + * Load a code file using its explicit system-dependent filename. A security + * check may be performed, checkLink. This just calls + * Runtime.getRuntime().load(filename). + * + *

    + * The library is loaded using the class loader associated with the + * class associated with the invoking method. + * + * @param filename the code file to load + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the file cannot be loaded + * @see Runtime#load(String) + */ + public static void load(String filename) + { + Runtime.getRuntime().load(filename, VMStackWalker.getCallingClassLoader()); + } + + /** + * Load a library using its explicit system-dependent filename. A security + * check may be performed, checkLink. This just calls + * Runtime.getRuntime().load(filename). + * + *

    + * The library is loaded using the class loader associated with the + * class associated with the invoking method. + * + * @param libname the library file to load + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the file cannot be loaded + * @see Runtime#load(String) + */ + public static void loadLibrary(String libname) + { + Runtime.getRuntime().loadLibrary(libname, + VMStackWalker.getCallingClassLoader()); + } + + /** + * Convert a library name to its platform-specific variant. + * + * @param libname the library name, as used in loadLibrary + * @return the platform-specific mangling of the name + * @since 1.2 + */ + public static String mapLibraryName(String libname) + { + return VMRuntime.mapLibraryName(libname); + } + +} // class System diff --git a/libjava/classpath/java/lang/Thread.java b/libjava/classpath/java/lang/Thread.java new file mode 100644 index 0000000..37ca630 --- /dev/null +++ b/libjava/classpath/java/lang/Thread.java @@ -0,0 +1,999 @@ +/* Thread -- an independent thread of executable code + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 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 java.lang; + +import java.util.Map; +import java.util.WeakHashMap; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete to version 1.4, with caveats. We do not + * implement the deprecated (and dangerous) stop, suspend, and resume + * methods. Security implementation is not complete. + */ + +/** + * Thread represents a single thread of execution in the VM. When an + * application VM starts up, it creates a non-daemon Thread which calls the + * main() method of a particular class. There may be other Threads running, + * such as the garbage collection thread. + * + *

    Threads have names to identify them. These names are not necessarily + * unique. Every Thread has a priority, as well, which tells the VM which + * Threads should get more running time. New threads inherit the priority + * and daemon status of the parent thread, by default. + * + *

    There are two methods of creating a Thread: you may subclass Thread and + * implement the run() method, at which point you may start the + * Thread by calling its start() method, or you may implement + * Runnable in the class you want to use and then call new + * Thread(your_obj).start(). + * + *

    The virtual machine runs until all non-daemon threads have died (either + * by returning from the run() method as invoked by start(), or by throwing + * an uncaught exception); or until System.exit is called with + * adequate permissions. + * + *

    It is unclear at what point a Thread should be added to a ThreadGroup, + * and at what point it should be removed. Should it be inserted when it + * starts, or when it is created? Should it be removed when it is suspended + * or interrupted? The only thing that is clear is that the Thread should be + * removed when it is stopped. + * + * @author Tom Tromey + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @see Runnable + * @see Runtime#exit(int) + * @see #run() + * @see #start() + * @see ThreadLocal + * @since 1.0 + * @status updated to 1.4 + */ +public class Thread implements Runnable +{ + /** The minimum priority for a Thread. */ + public static final int MIN_PRIORITY = 1; + + /** The priority a Thread gets by default. */ + public static final int NORM_PRIORITY = 5; + + /** The maximum priority for a Thread. */ + public static final int MAX_PRIORITY = 10; + + /** The underlying VM thread, only set when the thread is actually running. + */ + volatile VMThread vmThread; + + /** + * The group this thread belongs to. This is set to null by + * ThreadGroup.removeThread when the thread dies. + */ + volatile ThreadGroup group; + + /** The object to run(), null if this is the target. */ + final Runnable runnable; + + /** The thread name, non-null. */ + volatile String name; + + /** Whether the thread is a daemon. */ + volatile boolean daemon; + + /** The thread priority, 1 to 10. */ + volatile int priority; + + /** Native thread stack size. 0 = use default */ + private long stacksize; + + /** Was the thread stopped before it was started? */ + Throwable stillborn; + + /** The context classloader for this Thread. */ + private ClassLoader contextClassLoader; + + /** The next thread number to use. */ + private static int numAnonymousThreadsCreated; + + /** Thread local storage. Package accessible for use by + * InheritableThreadLocal. + */ + WeakHashMap locals; + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, null, + * gname), where gname is + * a newly generated name. Automatically generated names are of the + * form "Thread-"+n, where n is an integer. + *

    + * Threads created this way must have overridden their + * run() method to actually do anything. An example + * illustrating this method being used follows: + *

    +   *     import java.lang.*;
    +   *
    +   *     class plain01 implements Runnable {
    +   *         String name;
    +   *         plain01() {
    +   *             name = null;
    +   *         }
    +   *         plain01(String s) {
    +   *             name = s;
    +   *         }
    +   *         public void run() {
    +   *             if (name == null)
    +   *                 System.out.println("A new thread created");
    +   *             else
    +   *                 System.out.println("A new thread with name " + name +
    +   *                                    " created");
    +   *         }
    +   *     }
    +   *     class threadtest01 {
    +   *         public static void main(String args[] ) {
    +   *             int failed = 0 ;
    +   *
    +   *             Thread t1 = new Thread();
    +   *             if (t1 != null)
    +   *                 System.out.println("new Thread() succeed");
    +   *             else {
    +   *                 System.out.println("new Thread() failed");
    +   *                 failed++;
    +   *             }
    +   *         }
    +   *     }
    +   * 
    + * + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread() + { + this(null, (Runnable) null); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, target, + * gname), where gname is + * a newly generated name. Automatically generated names are of the + * form "Thread-"+n, where n is an integer. + * + * @param target the object whose run method is called. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread(Runnable target) + { + this(null, target); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, null, name). + * + * @param name the name of the new thread. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread(String name) + { + this(null, null, name, 0); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(group, target, + * gname), where gname is + * a newly generated name. Automatically generated names are of the + * form "Thread-"+n, where n is an integer. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @see #Thread(ThreadGroup, Runnable, String) + */ + public Thread(ThreadGroup group, Runnable target) + { + this(group, target, "Thread-" + ++numAnonymousThreadsCreated, 0); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(group, null, name) + * + * @param group the group to put the Thread into + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @see #Thread(ThreadGroup, Runnable, String) + */ + public Thread(ThreadGroup group, String name) + { + this(group, null, name, 0); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, target, name). + * + * @param target the Runnable object to execute + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @see #Thread(ThreadGroup, Runnable, String) + */ + public Thread(Runnable target, String name) + { + this(null, target, name, 0); + } + + /** + * Allocate a new Thread object, with the specified ThreadGroup and name, and + * using the specified Runnable object's run() method to + * execute. If the Runnable object is null, this (which is + * a Runnable) is used instead. + * + *

    If the ThreadGroup is null, the security manager is checked. If a + * manager exists and returns a non-null object for + * getThreadGroup, that group is used; otherwise the group + * of the creating thread is used. Note that the security manager calls + * checkAccess if the ThreadGroup is not null. + * + *

    The new Thread will inherit its creator's priority and daemon status. + * These can be changed with setPriority and + * setDaemon. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @see Runnable#run() + * @see #run() + * @see #setDaemon(boolean) + * @see #setPriority(int) + * @see SecurityManager#checkAccess(ThreadGroup) + * @see ThreadGroup#checkAccess() + */ + public Thread(ThreadGroup group, Runnable target, String name) + { + this(group, target, name, 0); + } + + /** + * Allocate a new Thread object, as if by + * Thread(group, null, name), and give it the specified stack + * size, in bytes. The stack size is highly platform independent, + * and the virtual machine is free to round up or down, or ignore it + * completely. A higher value might let you go longer before a + * StackOverflowError, while a lower value might let you go + * longer before an OutOfMemoryError. Or, it may do absolutely + * nothing! So be careful, and expect to need to tune this value if your + * virtual machine even supports it. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @param size the stack size, in bytes; 0 to be ignored + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @since 1.4 + */ + public Thread(ThreadGroup group, Runnable target, String name, long size) + { + // Bypass System.getSecurityManager, for bootstrap efficiency. + SecurityManager sm = SecurityManager.current; + Thread current = currentThread(); + if (group == null) + { + if (sm != null) + group = sm.getThreadGroup(); + if (group == null) + group = current.group; + } + else if (sm != null) + sm.checkAccess(group); + + this.group = group; + // Use toString hack to detect null. + this.name = name.toString(); + this.runnable = target; + this.stacksize = size; + + priority = current.priority; + daemon = current.daemon; + contextClassLoader = current.contextClassLoader; + + group.addThread(this); + InheritableThreadLocal.newChildThread(this); + } + + /** + * Used by the VM to create thread objects for threads started outside + * of Java. Note: caller is responsible for adding the thread to + * a group and InheritableThreadLocal. + * + * @param vmThread the native thread + * @param name the thread name or null to use the default naming scheme + * @param priority current priority + * @param daemon is the thread a background thread? + */ + Thread(VMThread vmThread, String name, int priority, boolean daemon) + { + this.vmThread = vmThread; + this.runnable = null; + if (name == null) + name = "Thread-" + ++numAnonymousThreadsCreated; + this.name = name; + this.priority = priority; + this.daemon = daemon; + this.contextClassLoader = ClassLoader.getSystemClassLoader(); + } + + /** + * Get the number of active threads in the current Thread's ThreadGroup. + * This implementation calls + * currentThread().getThreadGroup().activeCount(). + * + * @return the number of active threads in the current ThreadGroup + * @see ThreadGroup#activeCount() + */ + public static int activeCount() + { + return currentThread().group.activeCount(); + } + + /** + * Check whether the current Thread is allowed to modify this Thread. This + * passes the check on to SecurityManager.checkAccess(this). + * + * @throws SecurityException if the current Thread cannot modify this Thread + * @see SecurityManager#checkAccess(Thread) + */ + public final void checkAccess() + { + // Bypass System.getSecurityManager, for bootstrap efficiency. + SecurityManager sm = SecurityManager.current; + if (sm != null) + sm.checkAccess(this); + } + + /** + * Count the number of stack frames in this Thread. The Thread in question + * must be suspended when this occurs. + * + * @return the number of stack frames in this Thread + * @throws IllegalThreadStateException if this Thread is not suspended + * @deprecated pointless, since suspend is deprecated + */ + public int countStackFrames() + { + VMThread t = vmThread; + if (t == null || group == null) + throw new IllegalThreadStateException(); + + return t.countStackFrames(); + } + + /** + * Get the currently executing Thread. In the situation that the + * currently running thread was created by native code and doesn't + * have an associated Thread object yet, a new Thread object is + * constructed and associated with the native thread. + * + * @return the currently executing Thread + */ + public static Thread currentThread() + { + return VMThread.currentThread(); + } + + /** + * Originally intended to destroy this thread, this method was never + * implemented by Sun, and is hence a no-op. + */ + public void destroy() + { + throw new NoSuchMethodError(); + } + + /** + * Print a stack trace of the current thread to stderr using the same + * format as Throwable's printStackTrace() method. + * + * @see Throwable#printStackTrace() + */ + public static void dumpStack() + { + new Throwable().printStackTrace(); + } + + /** + * Copy every active thread in the current Thread's ThreadGroup into the + * array. Extra threads are silently ignored. This implementation calls + * getThreadGroup().enumerate(array), which may have a + * security check, checkAccess(group). + * + * @param array the array to place the Threads into + * @return the number of Threads placed into the array + * @throws NullPointerException if array is null + * @throws SecurityException if you cannot access the ThreadGroup + * @see ThreadGroup#enumerate(Thread[]) + * @see #activeCount() + * @see SecurityManager#checkAccess(ThreadGroup) + */ + public static int enumerate(Thread[] array) + { + return currentThread().group.enumerate(array); + } + + /** + * Get this Thread's name. + * + * @return this Thread's name + */ + public final String getName() + { + VMThread t = vmThread; + return t == null ? name : t.getName(); + } + + /** + * Get this Thread's priority. + * + * @return the Thread's priority + */ + public final synchronized int getPriority() + { + VMThread t = vmThread; + return t == null ? priority : t.getPriority(); + } + + /** + * Get the ThreadGroup this Thread belongs to. If the thread has died, this + * returns null. + * + * @return this Thread's ThreadGroup + */ + public final ThreadGroup getThreadGroup() + { + return group; + } + + /** + * Checks whether the current thread holds the monitor on a given object. + * This allows you to do assert Thread.holdsLock(obj). + * + * @param obj the object to test lock ownership on. + * @return true if the current thread is currently synchronized on obj + * @throws NullPointerException if obj is null + * @since 1.4 + */ + public static boolean holdsLock(Object obj) + { + return VMThread.holdsLock(obj); + } + + /** + * Interrupt this Thread. First, there is a security check, + * checkAccess. Then, depending on the current state of the + * thread, various actions take place: + * + *

    If the thread is waiting because of {@link #wait()}, + * {@link #sleep(long)}, or {@link #join()}, its interrupt status + * will be cleared, and an InterruptedException will be thrown. Notice that + * this case is only possible if an external thread called interrupt(). + * + *

    If the thread is blocked in an interruptible I/O operation, in + * {@link java.nio.channels.InterruptibleChannel}, the interrupt + * status will be set, and ClosedByInterruptException will be thrown. + * + *

    If the thread is blocked on a {@link java.nio.channels.Selector}, the + * interrupt status will be set, and the selection will return, with + * a possible non-zero value, as though by the wakeup() method. + * + *

    Otherwise, the interrupt status will be set. + * + * @throws SecurityException if you cannot modify this Thread + */ + public synchronized void interrupt() + { + checkAccess(); + VMThread t = vmThread; + if (t != null) + t.interrupt(); + } + + /** + * Determine whether the current Thread has been interrupted, and clear + * the interrupted status in the process. + * + * @return whether the current Thread has been interrupted + * @see #isInterrupted() + */ + public static boolean interrupted() + { + return VMThread.interrupted(); + } + + /** + * Determine whether the given Thread has been interrupted, but leave + * the interrupted status alone in the process. + * + * @return whether the Thread has been interrupted + * @see #interrupted() + */ + public boolean isInterrupted() + { + VMThread t = vmThread; + return t != null && t.isInterrupted(); + } + + /** + * Determine whether this Thread is alive. A thread which is alive has + * started and not yet died. + * + * @return whether this Thread is alive + */ + public final boolean isAlive() + { + return vmThread != null && group != null; + } + + /** + * Tell whether this is a daemon Thread or not. + * + * @return whether this is a daemon Thread or not + * @see #setDaemon(boolean) + */ + public final boolean isDaemon() + { + VMThread t = vmThread; + return t == null ? daemon : t.isDaemon(); + } + + /** + * Wait forever for the Thread in question to die. + * + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared + */ + public final void join() throws InterruptedException + { + join(0, 0); + } + + /** + * Wait the specified amount of time for the Thread in question to die. + * + * @param ms the number of milliseconds to wait, or 0 for forever + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared + */ + public final void join(long ms) throws InterruptedException + { + join(ms, 0); + } + + /** + * Wait the specified amount of time for the Thread in question to die. + * + *

    Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do + * not offer that fine a grain of timing resolution. Besides, there is + * no guarantee that this thread can start up immediately when time expires, + * because some other thread may be active. So don't expect real-time + * performance. + * + * @param ms the number of milliseconds to wait, or 0 for forever + * @param ns the number of extra nanoseconds to sleep (0-999999) + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared + * @throws IllegalArgumentException if ns is invalid + */ + public final void join(long ms, int ns) throws InterruptedException + { + if(ms < 0 || ns < 0 || ns > 999999) + throw new IllegalArgumentException(); + + VMThread t = vmThread; + if(t != null) + t.join(ms, ns); + } + + /** + * Resume this Thread. If the thread is not suspended, this method does + * nothing. To mirror suspend(), there may be a security check: + * checkAccess. + * + * @throws SecurityException if you cannot resume the Thread + * @see #checkAccess() + * @see #suspend() + * @deprecated pointless, since suspend is deprecated + */ + public final synchronized void resume() + { + checkAccess(); + VMThread t = vmThread; + if (t != null) + t.resume(); + } + + /** + * The method of Thread that will be run if there is no Runnable object + * associated with the Thread. Thread's implementation does nothing at all. + * + * @see #start() + * @see #Thread(ThreadGroup, Runnable, String) + */ + public void run() + { + if (runnable != null) + runnable.run(); + } + + /** + * Set the daemon status of this Thread. If this is a daemon Thread, then + * the VM may exit even if it is still running. This may only be called + * before the Thread starts running. There may be a security check, + * checkAccess. + * + * @param daemon whether this should be a daemon thread or not + * @throws SecurityException if you cannot modify this Thread + * @throws IllegalThreadStateException if the Thread is active + * @see #isDaemon() + * @see #checkAccess() + */ + public final synchronized void setDaemon(boolean daemon) + { + if (vmThread != null) + throw new IllegalThreadStateException(); + checkAccess(); + this.daemon = daemon; + } + + /** + * Returns the context classloader of this Thread. The context + * classloader can be used by code that want to load classes depending + * on the current thread. Normally classes are loaded depending on + * the classloader of the current class. There may be a security check + * for RuntimePermission("getClassLoader") if the caller's + * class loader is not null or an ancestor of this thread's context class + * loader. + * + * @return the context class loader + * @throws SecurityException when permission is denied + * @see setContextClassLoader(ClassLoader) + * @since 1.2 + */ + public synchronized ClassLoader getContextClassLoader() + { + // Bypass System.getSecurityManager, for bootstrap efficiency. + SecurityManager sm = SecurityManager.current; + if (sm != null) + // XXX Don't check this if the caller's class loader is an ancestor. + sm.checkPermission(new RuntimePermission("getClassLoader")); + return contextClassLoader; + } + + /** + * Sets the context classloader for this Thread. When not explicitly set, + * the context classloader for a thread is the same as the context + * classloader of the thread that created this thread. The first thread has + * as context classloader the system classloader. There may be a security + * check for RuntimePermission("setContextClassLoader"). + * + * @param classloader the new context class loader + * @throws SecurityException when permission is denied + * @see getContextClassLoader() + * @since 1.2 + */ + public synchronized void setContextClassLoader(ClassLoader classloader) + { + SecurityManager sm = SecurityManager.current; + if (sm != null) + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + this.contextClassLoader = classloader; + } + + /** + * Set this Thread's name. There may be a security check, + * checkAccess. + * + * @param name the new name for this Thread + * @throws NullPointerException if name is null + * @throws SecurityException if you cannot modify this Thread + */ + public final synchronized void setName(String name) + { + checkAccess(); + // The Class Libraries book says ``threadName cannot be null''. I + // take this to mean NullPointerException. + if (name == null) + throw new NullPointerException(); + VMThread t = vmThread; + if (t != null) + t.setName(name); + else + this.name = name; + } + + /** + * Yield to another thread. The Thread will not lose any locks it holds + * during this time. There are no guarantees which thread will be + * next to run, and it could even be this one, but most VMs will choose + * the highest priority thread that has been waiting longest. + */ + public static void yield() + { + VMThread.yield(); + } + + /** + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. + * + * @param ms the number of milliseconds to sleep. + * @throws InterruptedException if the Thread is (or was) interrupted; + * it's interrupted status will be cleared + * @throws IllegalArgumentException if ms is negative + * @see #interrupt() + */ + public static void sleep(long ms) throws InterruptedException + { + sleep(ms, 0); + } + + /** + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. + *

    + * Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs + * do not offer that fine a grain of timing resolution. When ms is + * zero and ns is non-zero the Thread will sleep for at least one + * milli second. There is no guarantee that this thread can start up + * immediately when time expires, because some other thread may be + * active. So don't expect real-time performance. + * + * @param ms the number of milliseconds to sleep + * @param ns the number of extra nanoseconds to sleep (0-999999) + * @throws InterruptedException if the Thread is (or was) interrupted; + * it's interrupted status will be cleared + * @throws IllegalArgumentException if ms or ns is negative + * or ns is larger than 999999. + * @see #interrupt() + */ + public static void sleep(long ms, int ns) throws InterruptedException + { + + // Check parameters + if (ms < 0 || ns < 0 || ns > 999999) + throw new IllegalArgumentException(); + + // Really sleep + VMThread.sleep(ms, ns); + } + + /** + * Start this Thread, calling the run() method of the Runnable this Thread + * was created with, or else the run() method of the Thread itself. This + * is the only way to start a new thread; calling run by yourself will just + * stay in the same thread. The virtual machine will remove the thread from + * its thread group when the run() method completes. + * + * @throws IllegalThreadStateException if the thread has already started + * @see #run() + */ + public synchronized void start() + { + if (vmThread != null || group == null) + throw new IllegalThreadStateException(); + + VMThread.create(this, stacksize); + } + + /** + * Cause this Thread to stop abnormally because of the throw of a ThreadDeath + * error. If you stop a Thread that has not yet started, it will stop + * immediately when it is actually started. + * + *

    This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * checkAccess(this), plus another one if the current thread + * is not this: RuntimePermission("stopThread"). If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. + * + * @throws SecurityException if you cannot stop the Thread + * @see #interrupt() + * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) + * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use + */ + public final void stop() + { + stop(new ThreadDeath()); + } + + /** + * Cause this Thread to stop abnormally and throw the specified exception. + * If you stop a Thread that has not yet started, the stop is ignored + * (contrary to what the JDK documentation says). + * WARNINGThis bypasses Java security, and can throw a checked + * exception which the call stack is unprepared to handle. Do not abuse + * this power. + * + *

    This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * checkAccess(this), plus another one if the current thread + * is not this: RuntimePermission("stopThread"). If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. + * + * @param t the Throwable to throw when the Thread dies + * @throws SecurityException if you cannot stop the Thread + * @throws NullPointerException in the calling thread, if t is null + * @see #interrupt() + * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) + * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use + */ + public final synchronized void stop(Throwable t) + { + if (t == null) + throw new NullPointerException(); + // Bypass System.getSecurityManager, for bootstrap efficiency. + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + sm.checkAccess(this); + if (this != currentThread()) + sm.checkPermission(new RuntimePermission("stopThread")); + } + VMThread vt = vmThread; + if (vt != null) + vt.stop(t); + else + stillborn = t; + } + + /** + * Suspend this Thread. It will not come back, ever, unless it is resumed. + * + *

    This is inherently unsafe, as the suspended thread still holds locks, + * and can potentially deadlock your program. Hence, there is a security + * check: checkAccess. + * + * @throws SecurityException if you cannot suspend the Thread + * @see #checkAccess() + * @see #resume() + * @deprecated unsafe operation, try not to use + */ + public final synchronized void suspend() + { + checkAccess(); + VMThread t = vmThread; + if (t != null) + t.suspend(); + } + + /** + * Set this Thread's priority. There may be a security check, + * checkAccess, then the priority is set to the smaller of + * priority and the ThreadGroup maximum priority. + * + * @param priority the new priority for this Thread + * @throws IllegalArgumentException if priority exceeds MIN_PRIORITY or + * MAX_PRIORITY + * @throws SecurityException if you cannot modify this Thread + * @see #getPriority() + * @see #checkAccess() + * @see ThreadGroup#getMaxPriority() + * @see #MIN_PRIORITY + * @see #MAX_PRIORITY + */ + public final synchronized void setPriority(int priority) + { + checkAccess(); + if (priority < MIN_PRIORITY || priority > MAX_PRIORITY) + throw new IllegalArgumentException("Invalid thread priority value " + + priority + "."); + priority = Math.min(priority, group.getMaxPriority()); + VMThread t = vmThread; + if (t != null) + t.setPriority(priority); + else + this.priority = priority; + } + + /** + * Returns a string representation of this thread, including the + * thread's name, priority, and thread group. + * + * @return a human-readable String representing this Thread + */ + public String toString() + { + return ("Thread[" + name + "," + priority + "," + + (group == null ? "" : group.getName()) + "]"); + } + + /** + * Clean up code, called by VMThread when thread dies. + */ + synchronized void die() + { + group.removeThread(this); + vmThread = null; + locals = null; + } + + /** + * Returns the map used by ThreadLocal to store the thread local values. + */ + static Map getThreadLocals() + { + Thread thread = currentThread(); + Map locals = thread.locals; + if (locals == null) + { + locals = thread.locals = new WeakHashMap(); + } + return locals; + } +} diff --git a/libjava/classpath/java/lang/ThreadDeath.java b/libjava/classpath/java/lang/ThreadDeath.java new file mode 100644 index 0000000..c7d88fb --- /dev/null +++ b/libjava/classpath/java/lang/ThreadDeath.java @@ -0,0 +1,68 @@ +/* ThreadDeath.java - special exception registering Thread death + Copyright (C) 1998, 1999, 2000, 2001, 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 java.lang; + +/** + * ThreadDeath is thrown in a thread when someone calls stop() + * on that thread. Important: Make sure you rethrow this exception + * if you catch it. If you don't, the thread will not die. + * + *

    This is an Error rather than an exception, so that normal code will + * not catch it. It is intended for asynchronous cleanup when using the + * deprecated Thread.stop() method. + * + * @author John Keiser + * @author Tom Tromey (tromey@cygnus.com) + * @see Thread#stop() + * @status updated to 1.4 + */ +public class ThreadDeath extends Error +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4417128565033088268L; + + /** + * Create an error without a message. + */ + public ThreadDeath() + { + } +} diff --git a/libjava/classpath/java/lang/ThreadGroup.java b/libjava/classpath/java/lang/ThreadGroup.java new file mode 100644 index 0000000..6e4c27a --- /dev/null +++ b/libjava/classpath/java/lang/ThreadGroup.java @@ -0,0 +1,749 @@ +/* ThreadGroup -- a group of Threads + Copyright (C) 1998, 2000, 2001, 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 java.lang; + +import java.util.Vector; + +/** + * ThreadGroup allows you to group Threads together. There is a hierarchy + * of ThreadGroups, and only the initial ThreadGroup has no parent. A Thread + * may access information about its own ThreadGroup, but not its parents or + * others outside the tree. + * + * @author John Keiser + * @author Tom Tromey + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Thread + * @since 1.0 + * @status updated to 1.4 + */ +public class ThreadGroup +{ + /** The Initial, top-level ThreadGroup. */ + static ThreadGroup root = new ThreadGroup(); + + /** + * This flag is set if an uncaught exception occurs. The runtime should + * check this and exit with an error status if it is set. + */ + static boolean had_uncaught_exception; + + /** The parent thread group. */ + private final ThreadGroup parent; + + /** The group name, non-null. */ + final String name; + + /** The threads in the group. */ + private final Vector threads = new Vector(); + + /** Child thread groups, or null when this group is destroyed. */ + private Vector groups = new Vector(); + + /** If all threads in the group are daemons. */ + private boolean daemon_flag = false; + + /** The maximum group priority. */ + private int maxpri; + + /** + * Hidden constructor to build the root node. + */ + private ThreadGroup() + { + name = "main"; + parent = null; + maxpri = Thread.MAX_PRIORITY; + } + + /** + * Create a new ThreadGroup using the given name and the current thread's + * ThreadGroup as a parent. There may be a security check, + * checkAccess. + * + * @param name the name to use for the ThreadGroup + * @throws SecurityException if the current thread cannot create a group + * @see #checkAccess() + */ + public ThreadGroup(String name) + { + this(Thread.currentThread().group, name); + } + + /** + * Create a new ThreadGroup using the given name and parent group. The new + * group inherits the maximum priority and daemon status of its parent + * group. There may be a security check, checkAccess. + * + * @param name the name to use for the ThreadGroup + * @param parent the ThreadGroup to use as a parent + * @throws NullPointerException if parent is null + * @throws SecurityException if the current thread cannot create a group + * @throws IllegalThreadStateException if the parent is destroyed + * @see #checkAccess() + */ + public ThreadGroup(ThreadGroup parent, String name) + { + parent.checkAccess(); + this.parent = parent; + this.name = name; + maxpri = parent.maxpri; + daemon_flag = parent.daemon_flag; + synchronized (parent) + { + if (parent.groups == null) + throw new IllegalThreadStateException(); + parent.groups.add(this); + } + } + + /** + * Get the name of this ThreadGroup. + * + * @return the name of this ThreadGroup + */ + public final String getName() + { + return name; + } + + /** + * Get the parent of this ThreadGroup. If the parent is not null, there + * may be a security check, checkAccess. + * + * @return the parent of this ThreadGroup + * @throws SecurityException if permission is denied + */ + public final ThreadGroup getParent() + { + if (parent != null) + parent.checkAccess(); + return parent; + } + + /** + * Get the maximum priority of Threads in this ThreadGroup. Threads created + * after this call in this group may not exceed this priority. + * + * @return the maximum priority of Threads in this ThreadGroup + */ + public final int getMaxPriority() + { + return maxpri; + } + + /** + * Tell whether this ThreadGroup is a daemon group. A daemon group will + * be automatically destroyed when its last thread is stopped and + * its last thread group is destroyed. + * + * @return whether this ThreadGroup is a daemon group + */ + public final boolean isDaemon() + { + return daemon_flag; + } + + /** + * Tell whether this ThreadGroup has been destroyed or not. + * + * @return whether this ThreadGroup has been destroyed or not + * @since 1.1 + */ + public synchronized boolean isDestroyed() + { + return groups == null; + } + + /** + * Set whether this ThreadGroup is a daemon group. A daemon group will be + * destroyed when its last thread is stopped and its last thread group is + * destroyed. There may be a security check, checkAccess. + * + * @param daemon whether this ThreadGroup should be a daemon group + * @throws SecurityException if you cannot modify this ThreadGroup + * @see #checkAccess() + */ + public final void setDaemon(boolean daemon) + { + checkAccess(); + daemon_flag = daemon; + } + + /** + * Set the maximum priority for Threads in this ThreadGroup. setMaxPriority + * can only be used to reduce the current maximum. If maxpri is greater + * than the current Maximum of the parent group, the current value is not + * changed. Otherwise, all groups which belong to this have their priority + * adjusted as well. Calling this does not affect threads already in this + * ThreadGroup. There may be a security check, checkAccess. + * + * @param maxpri the new maximum priority for this ThreadGroup + * @throws SecurityException if you cannot modify this ThreadGroup + * @see #getMaxPriority() + * @see #checkAccess() + */ + public final synchronized void setMaxPriority(int maxpri) + { + checkAccess(); + if (maxpri < Thread.MIN_PRIORITY || maxpri > Thread.MAX_PRIORITY) + return; + if (parent != null && maxpri > parent.maxpri) + maxpri = parent.maxpri; + this.maxpri = maxpri; + if (groups == null) + return; + int i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).setMaxPriority(maxpri); + } + + /** + * Check whether this ThreadGroup is an ancestor of the specified + * ThreadGroup, or if they are the same. + * + * @param group the group to test on + * @return whether this ThreadGroup is a parent of the specified group + */ + public final boolean parentOf(ThreadGroup group) + { + while (group != null) + { + if (group == this) + return true; + group = group.parent; + } + return false; + } + + /** + * Find out if the current Thread can modify this ThreadGroup. This passes + * the check on to SecurityManager.checkAccess(this). + * + * @throws SecurityException if the current Thread cannot modify this + * ThreadGroup + * @see SecurityManager#checkAccess(ThreadGroup) + */ + public final void checkAccess() + { + // Bypass System.getSecurityManager, for bootstrap efficiency. + SecurityManager sm = SecurityManager.current; + if (sm != null) + sm.checkAccess(this); + } + + /** + * Return an estimate of the total number of active threads in this + * ThreadGroup and all its descendants. This cannot return an exact number, + * since the status of threads may change after they were counted; but it + * should be pretty close. Based on a JDC bug, + * + * 4089701, we take active to mean isAlive(). + * + * @return count of active threads in this ThreadGroup and its descendants + */ + public int activeCount() + { + int total = 0; + if (groups == null) + return total; + int i = threads.size(); + while (--i >= 0) + if (((Thread) threads.get(i)).isAlive()) + total++; + i = groups.size(); + while (--i >= 0) + total += ((ThreadGroup) groups.get(i)).activeCount(); + return total; + } + + /** + * Copy all of the active Threads from this ThreadGroup and its descendants + * into the specified array. If the array is not big enough to hold all + * the Threads, extra Threads will simply not be copied. There may be a + * security check, checkAccess. + * + * @param array the array to put the threads into + * @return the number of threads put into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if array is null + * @throws ArrayStoreException if a thread does not fit in the array + * @see #activeCount() + * @see #checkAccess() + * @see #enumerate(Thread[], boolean) + */ + public int enumerate(Thread[] array) + { + return enumerate(array, 0, true); + } + + /** + * Copy all of the active Threads from this ThreadGroup and, if desired, + * from its descendants, into the specified array. If the array is not big + * enough to hold all the Threads, extra Threads will simply not be copied. + * There may be a security check, checkAccess. + * + * @param array the array to put the threads into + * @param recurse whether to recurse into descendent ThreadGroups + * @return the number of threads put into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if array is null + * @throws ArrayStoreException if a thread does not fit in the array + * @see #activeCount() + * @see #checkAccess() + */ + public int enumerate(Thread[] array, boolean recurse) + { + return enumerate(array, 0, recurse); + } + + /** + * Get the number of active groups in this ThreadGroup. This group itself + * is not included in the count. A sub-group is active if it has not been + * destroyed. This cannot return an exact number, since the status of + * threads may change after they were counted; but it should be pretty close. + * + * @return the number of active groups in this ThreadGroup + */ + public int activeGroupCount() + { + if (groups == null) + return 0; + int total = groups.size(); + int i = total; + while (--i >= 0) + total += ((ThreadGroup) groups.get(i)).activeGroupCount(); + return total; + } + + /** + * Copy all active ThreadGroups that are descendants of this ThreadGroup + * into the specified array. If the array is not large enough to hold all + * active ThreadGroups, extra ThreadGroups simply will not be copied. There + * may be a security check, checkAccess. + * + * @param array the array to put the ThreadGroups into + * @return the number of ThreadGroups copied into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if array is null + * @throws ArrayStoreException if a group does not fit in the array + * @see #activeCount() + * @see #checkAccess() + * @see #enumerate(ThreadGroup[], boolean) + */ + public int enumerate(ThreadGroup[] array) + { + return enumerate(array, 0, true); + } + + /** + * Copy all active ThreadGroups that are children of this ThreadGroup into + * the specified array, and if desired, also all descendents. If the array + * is not large enough to hold all active ThreadGroups, extra ThreadGroups + * simply will not be copied. There may be a security check, + * checkAccess. + * + * @param array the array to put the ThreadGroups into + * @param recurse whether to recurse into descendent ThreadGroups + * @return the number of ThreadGroups copied into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if array is null + * @throws ArrayStoreException if a group does not fit in the array + * @see #activeCount() + * @see #checkAccess() + */ + public int enumerate(ThreadGroup[] array, boolean recurse) + { + return enumerate(array, 0, recurse); + } + + /** + * Stop all Threads in this ThreadGroup and its descendants. + * + *

    This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * checkAccess(), followed by further checks on each thread + * being stopped. + * + * @throws SecurityException if permission is denied + * @see #checkAccess() + * @see Thread#stop(Throwable) + * @deprecated unsafe operation, try not to use + */ + public final synchronized void stop() + { + checkAccess(); + if (groups == null) + return; + int i = threads.size(); + while (--i >= 0) + ((Thread) threads.get(i)).stop(); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).stop(); + } + + /** + * Interrupt all Threads in this ThreadGroup and its sub-groups. There may + * be a security check, checkAccess. + * + * @throws SecurityException if permission is denied + * @see #checkAccess() + * @see Thread#interrupt() + * @since 1.2 + */ + public final synchronized void interrupt() + { + checkAccess(); + if (groups == null) + return; + int i = threads.size(); + while (--i >= 0) + ((Thread) threads.get(i)).interrupt(); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).interrupt(); + } + + /** + * Suspend all Threads in this ThreadGroup and its descendants. + * + *

    This is inherently unsafe, as suspended threads still hold locks, + * which can lead to deadlock. Hence, there is a security check: + * checkAccess(), followed by further checks on each thread + * being suspended. + * + * @throws SecurityException if permission is denied + * @see #checkAccess() + * @see Thread#suspend() + * @deprecated unsafe operation, try not to use + */ + public final synchronized void suspend() + { + checkAccess(); + if (groups == null) + return; + int i = threads.size(); + while (--i >= 0) + ((Thread) threads.get(i)).suspend(); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).suspend(); + } + + /** + * Resume all suspended Threads in this ThreadGroup and its descendants. + * To mirror suspend(), there is a security check: + * checkAccess(), followed by further checks on each thread + * being resumed. + * + * @throws SecurityException if permission is denied + * @see #checkAccess() + * @see Thread#suspend() + * @deprecated pointless, since suspend is deprecated + */ + public final synchronized void resume() + { + checkAccess(); + if (groups == null) + return; + int i = threads.size(); + while (--i >= 0) + ((Thread) threads.get(i)).resume(); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).resume(); + } + + /** + * Destroy this ThreadGroup. The group must be empty, meaning that all + * threads and sub-groups have completed execution. Daemon groups are + * destroyed automatically. There may be a security check, + * checkAccess. + * + * @throws IllegalThreadStateException if the ThreadGroup is not empty, or + * was previously destroyed + * @throws SecurityException if permission is denied + * @see #checkAccess() + */ + public final synchronized void destroy() + { + checkAccess(); + if (! threads.isEmpty() || groups == null) + throw new IllegalThreadStateException(); + int i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).destroy(); + groups = null; + if (parent != null) + parent.removeGroup(this); + } + + /** + * Print out information about this ThreadGroup to System.out. This is + * meant for debugging purposes. WARNING: This method is not secure, + * and can print the name of threads to standard out even when you cannot + * otherwise get at such threads. + */ + public void list() + { + list(""); + } + + /** + * When a Thread in this ThreadGroup does not catch an exception, the + * virtual machine calls this method. The default implementation simply + * passes the call to the parent; then in top ThreadGroup, it will + * ignore ThreadDeath and print the stack trace of any other throwable. + * Override this method if you want to handle the exception in a different + * manner. + * + * @param thread the thread that exited + * @param t the uncaught throwable + * @throws NullPointerException if t is null + * @see ThreadDeath + * @see System#err + * @see Throwable#printStackTrace() + */ + public void uncaughtException(Thread thread, Throwable t) + { + if (parent != null) + parent.uncaughtException(thread, t); + else if (! (t instanceof ThreadDeath)) + { + if (t == null) + throw new NullPointerException(); + had_uncaught_exception = true; + try + { + if (thread != null) + System.err.print("Exception in thread \"" + thread.name + "\" "); + t.printStackTrace(System.err); + } + catch (Throwable x) + { + // This means that something is badly screwed up with the runtime, + // or perhaps someone overloaded the Throwable.printStackTrace to + // die. In any case, try to deal with it gracefully. + try + { + System.err.println(t); + System.err.println("*** Got " + x + + " while trying to print stack trace."); + } + catch (Throwable x2) + { + // Here, someone may have overloaded t.toString() or + // x.toString() to die. Give up all hope; we can't even chain + // the exception, because the chain would likewise die. + System.err.println("*** Catastrophic failure while handling " + + "uncaught exception."); + throw new InternalError(); + } + } + } + } + + /** + * Originally intended to tell the VM whether it may suspend Threads in + * low memory situations, this method was never implemented by Sun, and + * is hence a no-op. + * + * @param allow whether to allow low-memory thread suspension; ignored + * @return false + * @since 1.1 + * @deprecated pointless, since suspend is deprecated + */ + public boolean allowThreadSuspension(boolean allow) + { + return false; + } + + /** + * Return a human-readable String representing this ThreadGroup. The format + * of the string is:
    + * getClass().getName() + "[name=" + getName() + ",maxpri=" + * + getMaxPriority() + ']'. + * + * @return a human-readable String representing this ThreadGroup + */ + public String toString() + { + return getClass().getName() + "[name=" + name + ",maxpri=" + maxpri + ']'; + } + + /** + * Implements enumerate. + * + * @param list the array to put the threads into + * @param next the next open slot in the array + * @param recurse whether to recurse into descendent ThreadGroups + * @return the number of threads put into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if list is null + * @throws ArrayStoreException if a thread does not fit in the array + * @see #enumerate(Thread[]) + * @see #enumerate(Thread[], boolean) + */ + private int enumerate(Thread[] list, int next, boolean recurse) + { + checkAccess(); + if (groups == null) + return next; + int i = threads.size(); + while (--i >= 0 && next < list.length) + { + Thread t = (Thread) threads.get(i); + if (t.isAlive()) + list[next++] = t; + } + if (recurse) + { + i = groups.size(); + while (--i >= 0 && next < list.length) + { + ThreadGroup g = (ThreadGroup) groups.get(i); + next = g.enumerate(list, next, true); + } + } + return next; + } + + /** + * Implements enumerate. + * + * @param list the array to put the groups into + * @param next the next open slot in the array + * @param recurse whether to recurse into descendent ThreadGroups + * @return the number of groups put into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if list is null + * @throws ArrayStoreException if a group does not fit in the array + * @see #enumerate(ThreadGroup[]) + * @see #enumerate(ThreadGroup[], boolean) + */ + private int enumerate(ThreadGroup[] list, int next, boolean recurse) + { + checkAccess(); + if (groups == null) + return next; + int i = groups.size(); + while (--i >= 0 && next < list.length) + { + ThreadGroup g = (ThreadGroup) groups.get(i); + list[next++] = g; + if (recurse && next != list.length) + next = g.enumerate(list, next, true); + } + return next; + } + + /** + * Implements list. + * + * @param indentation the current level of indentation + * @see #list() + */ + private void list(String indentation) + { + if (groups == null) + return; + System.out.println(indentation + this); + indentation += " "; + int i = threads.size(); + while (--i >= 0) + System.out.println(indentation + threads.get(i)); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).list(indentation); + } + + /** + * Add a thread to the group. Called by Thread constructors. + * + * @param t the thread to add, non-null + * @throws IllegalThreadStateException if the group is destroyed + */ + final synchronized void addThread(Thread t) + { + if (groups == null) + throw new IllegalThreadStateException("ThreadGroup is destroyed"); + threads.add(t); + } + + /** + * Called by the VM to remove a thread that has died. + * + * @param t the thread to remove, non-null + * @XXX A ThreadListener to call this might be nice. + */ + final synchronized void removeThread(Thread t) + { + if (groups == null) + return; + threads.remove(t); + t.group = null; + // Daemon groups are automatically destroyed when all their threads die. + if (daemon_flag && groups.size() == 0 && threads.size() == 0) + { + // We inline destroy to avoid the access check. + groups = null; + if (parent != null) + parent.removeGroup(this); + } + } + + /** + * Called when a group is destroyed, to remove it from its parent. + * + * @param g the destroyed group, non-null + */ + final synchronized void removeGroup(ThreadGroup g) + { + groups.remove(g); + // Daemon groups are automatically destroyed when all their threads die. + if (daemon_flag && groups.size() == 0 && threads.size() == 0) + { + // We inline destroy to avoid the access check. + groups = null; + if (parent != null) + parent.removeGroup(this); + } + } +} // class ThreadGroup diff --git a/libjava/classpath/java/lang/ThreadLocal.java b/libjava/classpath/java/lang/ThreadLocal.java new file mode 100644 index 0000000..0b2b608 --- /dev/null +++ b/libjava/classpath/java/lang/ThreadLocal.java @@ -0,0 +1,171 @@ +/* ThreadLocal -- a variable with a unique value per thread + Copyright (C) 2000, 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 java.lang; + +import java.util.Map; +import java.util.WeakHashMap; + + +/** + * ThreadLocal objects have a different state associated with every + * Thread that accesses them. Every access to the ThreadLocal object + * (through the get() and set() methods) + * only affects the state of the object as seen by the currently + * executing Thread. + * + *

    The first time a ThreadLocal object is accessed on a particular + * Thread, the state for that Thread's copy of the local variable is set by + * executing the method initialValue(). + *

    + * + *

    An example how you can use this: + *

    + * + *
    + * class Connection
    + * {
    + *   private static ThreadLocal owner = new ThreadLocal()
    + *     {
    + *       public Object initialValue()
    + *       {
    + *         return("nobody");
    + *       }
    + *     };
    + * ...
    + * }
    + * 
    + * + *

    Now all instances of connection can see who the owner of the currently + * executing Thread is by calling owner.get(). By default any + * Thread would be associated with 'nobody'. But the Connection object could + * offer a method that changes the owner associated with the Thread on + * which the method was called by calling owner.put("somebody"). + * (Such an owner changing method should then be guarded by security checks.) + *

    + * + *

    When a Thread is garbage collected all references to values of + * the ThreadLocal objects associated with that Thread are removed. + *

    + * + * @author Mark Wielaard (mark@klomp.org) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public class ThreadLocal +{ + /** + * Placeholder to distinguish between uninitialized and null set by the + * user. Do not expose this to the public. Package visible for use by + * InheritableThreadLocal + */ + static final Object NULL = new Object(); + + /** + * Serves as a key for the Thread.locals WeakHashMap. + * We can't use "this", because a subclass may override equals/hashCode + * and we need to use object identity for the map. + */ + final Key key = new Key(); + + class Key + { + ThreadLocal get() + { + return ThreadLocal.this; + } + } + + /** + * Creates a ThreadLocal object without associating any value to it yet. + */ + public ThreadLocal() + { + } + + /** + * Called once per thread on the first invocation of get(), if set() was + * not already called. The default implementation returns null. + * Often, this method is overridden to create the appropriate initial object + * for the current thread's view of the ThreadLocal. + * + * @return the initial value of the variable in this thread + */ + protected Object initialValue() + { + return null; + } + + /** + * Gets the value associated with the ThreadLocal object for the currently + * executing Thread. If this is the first time the current thread has called + * get(), and it has not already called set(), the value is obtained by + * initialValue(). + * + * @return the value of the variable in this thread + */ + public Object get() + { + Map map = Thread.getThreadLocals(); + // Note that we don't have to synchronize, as only this thread will + // ever modify the map. + Object value = map.get(key); + if (value == null) + { + value = initialValue(); + map.put(key, value == null ? NULL : value); + } + return value == NULL ? null : value; + } + + /** + * Sets the value associated with the ThreadLocal object for the currently + * executing Thread. This overrides any existing value associated with the + * current Thread and prevents initialValue() from being + * called if this is the first access to this ThreadLocal in this Thread. + * + * @param value the value to set this thread's view of the variable to + */ + public void set(Object value) + { + Map map = Thread.getThreadLocals(); + // Note that we don't have to synchronize, as only this thread will + // ever modify the map. + map.put(key, value == null ? NULL : value); + } +} diff --git a/libjava/classpath/java/lang/Throwable.java b/libjava/classpath/java/lang/Throwable.java new file mode 100644 index 0000000..c47a14b --- /dev/null +++ b/libjava/classpath/java/lang/Throwable.java @@ -0,0 +1,563 @@ +/* java.lang.Throwable -- Root class for all Exceptions and Errors + 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 java.lang; + +import gnu.classpath.SystemProperties; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; + +/** + * Throwable is the superclass of all exceptions that can be raised. + * + *

    There are two special cases: {@link Error} and {@link RuntimeException}: + * these two classes (and their subclasses) are considered unchecked + * exceptions, and are either frequent enough or catastrophic enough that you + * do not need to declare them in throws clauses. Everything + * else is a checked exception, and is ususally a subclass of + * {@link Exception}; these exceptions have to be handled or declared. + * + *

    Instances of this class are usually created with knowledge of the + * execution context, so that you can get a stack trace of the problem spot + * in the code. Also, since JDK 1.4, Throwables participate in "exception + * chaining." This means that one exception can be caused by another, and + * preserve the information of the original. + * + *

    One reason this is useful is to wrap exceptions to conform to an + * interface. For example, it would be bad design to require all levels + * of a program interface to be aware of the low-level exceptions thrown + * at one level of abstraction. Another example is wrapping a checked + * exception in an unchecked one, to communicate that failure occured + * while still obeying the method throws clause of a superclass. + * + *

    A cause is assigned in one of two ways; but can only be assigned once + * in the lifetime of the Throwable. There are new constructors added to + * several classes in the exception hierarchy that directly initialize the + * cause, or you can use the initCause method. This second + * method is especially useful if the superclass has not been retrofitted + * with new constructors:
    + *

    + * try
    + *   {
    + *     lowLevelOp();
    + *   }
    + * catch (LowLevelException lle)
    + *   {
    + *     throw (HighLevelException) new HighLevelException().initCause(lle);
    + *   }
    + * 
    + * Notice the cast in the above example; without it, your method would need + * a throws clase that declared Throwable, defeating the purpose of chainig + * your exceptions. + * + *

    By convention, exception classes have two constructors: one with no + * arguments, and one that takes a String for a detail message. Further, + * classes which are likely to be used in an exception chain also provide + * a constructor that takes a Throwable, with or without a detail message + * string. + * + *

    Another 1.4 feature is the StackTrace, a means of reflection that + * allows the program to inspect the context of the exception, and which is + * serialized, so that remote procedure calls can correctly pass exceptions. + * + * @author Brian Jones + * @author John Keiser + * @author Mark Wielaard + * @author Tom Tromey + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Throwable implements Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -3042686055658047285L; + + /** + * The detail message. + * + * @serial specific details about the exception, may be null + */ + private final String detailMessage; + + /** + * The cause of the throwable, including null for an unknown or non-chained + * cause. This may only be set once; so the field is set to + * this until initialized. + * + * @serial the cause, or null if unknown, or this if not yet set + * @since 1.4 + */ + private Throwable cause = this; + + /** + * The stack trace, in a serialized form. + * + * @serial the elements of the stack trace; this is non-null, and has + * no null entries + * @since 1.4 + */ + private StackTraceElement[] stackTrace; + + /** + * Instantiate this Throwable with an empty message. The cause remains + * uninitialized. {@link #fillInStackTrace()} will be called to set + * up the stack trace. + */ + public Throwable() + { + this((String) null); + } + + /** + * Instantiate this Throwable with the given message. The cause remains + * uninitialized. {@link #fillInStackTrace()} will be called to set + * up the stack trace. + * + * @param message the message to associate with the Throwable + */ + public Throwable(String message) + { + fillInStackTrace(); + detailMessage = message; + } + + /** + * Instantiate this Throwable with the given message and cause. Note that + * the message is unrelated to the message of the cause. + * {@link #fillInStackTrace()} will be called to set up the stack trace. + * + * @param message the message to associate with the Throwable + * @param cause the cause, may be null + * @since 1.4 + */ + public Throwable(String message, Throwable cause) + { + this(message); + this.cause = cause; + } + + /** + * Instantiate this Throwable with the given cause. The message is then + * built as cause == null ? null : cause.toString(). + * {@link #fillInStackTrace()} will be called to set up the stack trace. + * + * @param cause the cause, may be null + * @since 1.4 + */ + public Throwable(Throwable cause) + { + this(cause == null ? null : cause.toString(), cause); + } + + /** + * Get the message associated with this Throwable. + * + * @return the error message associated with this Throwable, may be null + */ + public String getMessage() + { + return detailMessage; + } + + /** + * Get a localized version of this Throwable's error message. + * This method must be overridden in a subclass of Throwable + * to actually produce locale-specific methods. The Throwable + * implementation just returns getMessage(). + * + * @return a localized version of this error message + * @see #getMessage() + * @since 1.1 + */ + public String getLocalizedMessage() + { + return getMessage(); + } + + /** + * Returns the cause of this exception, or null if the cause is not known + * or non-existant. This cause is initialized by the new constructors, + * or by calling initCause. + * + * @return the cause of this Throwable + * @since 1.4 + */ + public Throwable getCause() + { + return cause == this ? null : cause; + } + + /** + * Initialize the cause of this Throwable. This may only be called once + * during the object lifetime, including implicitly by chaining + * constructors. + * + * @param cause the cause of this Throwable, may be null + * @return this + * @throws IllegalArgumentException if cause is this (a Throwable can't be + * its own cause!) + * @throws IllegalStateException if the cause has already been set + * @since 1.4 + */ + public Throwable initCause(Throwable cause) + { + if (cause == this) + throw new IllegalArgumentException(); + if (this.cause != this) + throw new IllegalStateException(); + this.cause = cause; + return this; + } + + /** + * Get a human-readable representation of this Throwable. The detail message + * is retrieved by getLocalizedMessage(). Then, with a null detail + * message, this string is simply the object's class name; otherwise + * the string is getClass().getName() + ": " + message. + * + * @return a human-readable String represting this Throwable + */ + public String toString() + { + String msg = getLocalizedMessage(); + return getClass().getName() + (msg == null ? "" : ": " + msg); + } + + /** + * Print a stack trace to the standard error stream. This stream is the + * current contents of System.err. The first line of output + * is the result of {@link #toString()}, and the remaining lines represent + * the data created by {@link #fillInStackTrace()}. While the format is + * unspecified, this implementation uses the suggested format, demonstrated + * by this example:
    + *

    +   * public class Junk
    +   * {
    +   *   public static void main(String args[])
    +   *   {
    +   *     try
    +   *       {
    +   *         a();
    +   *       }
    +   *     catch(HighLevelException e)
    +   *       {
    +   *         e.printStackTrace();
    +   *       }
    +   *   }
    +   *   static void a() throws HighLevelException
    +   *   {
    +   *     try
    +   *       {
    +   *         b();
    +   *       }
    +   *     catch(MidLevelException e)
    +   *       {
    +   *         throw new HighLevelException(e);
    +   *       }
    +   *   }
    +   *   static void b() throws MidLevelException
    +   *   {
    +   *     c();
    +   *   }
    +   *   static void c() throws MidLevelException
    +   *   {
    +   *     try
    +   *       {
    +   *         d();
    +   *       }
    +   *     catch(LowLevelException e)
    +   *       {
    +   *         throw new MidLevelException(e);
    +   *       }
    +   *   }
    +   *   static void d() throws LowLevelException
    +   *   {
    +   *     e();
    +   *   }
    +   *   static void e() throws LowLevelException
    +   *   {
    +   *     throw new LowLevelException();
    +   *   }
    +   * }
    +   * class HighLevelException extends Exception
    +   * {
    +   *   HighLevelException(Throwable cause) { super(cause); }
    +   * }
    +   * class MidLevelException extends Exception
    +   * {
    +   *   MidLevelException(Throwable cause)  { super(cause); }
    +   * }
    +   * class LowLevelException extends Exception
    +   * {
    +   * }
    +   * 
    + *

    + *

    +   *  HighLevelException: MidLevelException: LowLevelException
    +   *          at Junk.a(Junk.java:13)
    +   *          at Junk.main(Junk.java:4)
    +   *  Caused by: MidLevelException: LowLevelException
    +   *          at Junk.c(Junk.java:23)
    +   *          at Junk.b(Junk.java:17)
    +   *          at Junk.a(Junk.java:11)
    +   *          ... 1 more
    +   *  Caused by: LowLevelException
    +   *          at Junk.e(Junk.java:30)
    +   *          at Junk.d(Junk.java:27)
    +   *          at Junk.c(Junk.java:21)
    +   *          ... 3 more
    +   * 
    + */ + public void printStackTrace() + { + printStackTrace(System.err); + } + + /** + * Print a stack trace to the specified PrintStream. See + * {@link #printStackTrace()} for the sample format. + * + * @param s the PrintStream to write the trace to + */ + public void printStackTrace(PrintStream s) + { + s.print(stackTraceString()); + } + + /** + * Prints the exception, the detailed message and the stack trace + * associated with this Throwable to the given PrintWriter. + * The actual output written is implemention specific. Use the result of + * getStackTrace() when more precise information is needed. + * + *

    This implementation first prints a line with the result of this + * object's toString() method. + *
    + * Then for all elements given by getStackTrace it prints + * a line containing three spaces, the string "at " and the result of calling + * the toString() method on the StackTraceElement + * object. If getStackTrace() returns an empty array it prints + * a line containing three spaces and the string + * "<<No stacktrace available>>". + *
    + * Then if getCause() doesn't return null it adds a line + * starting with "Caused by: " and the result of calling + * toString() on the cause. + *
    + * Then for every cause (of a cause, etc) the stacktrace is printed the + * same as for the top level Throwable except that as soon + * as all the remaining stack frames of the cause are the same as the + * the last stack frames of the throwable that the cause is wrapped in + * then a line starting with three spaces and the string "... X more" is + * printed, where X is the number of remaining stackframes. + * + * @param pw the PrintWriter to write the trace to + * @since 1.1 + */ + public void printStackTrace (PrintWriter pw) + { + pw.print(stackTraceString()); + } + + /* + * We use inner class to avoid a static initializer in this basic class. + */ + private static class StaticData + { + static final String nl = SystemProperties.getProperty("line.separator"); + } + + // Create whole stack trace in a stringbuffer so we don't have to print + // it line by line. This prevents printing multiple stack traces from + // different threads to get mixed up when written to the same PrintWriter. + private String stackTraceString() + { + StringBuffer sb = new StringBuffer(); + + // Main stacktrace + StackTraceElement[] stack = getStackTrace(); + stackTraceStringBuffer(sb, this.toString(), stack, 0); + + // The cause(s) + Throwable cause = getCause(); + while (cause != null) + { + // Cause start first line + sb.append("Caused by: "); + + // Cause stacktrace + StackTraceElement[] parentStack = stack; + stack = cause.getStackTrace(); + if (parentStack == null || parentStack.length == 0) + stackTraceStringBuffer(sb, cause.toString(), stack, 0); + else + { + int equal = 0; // Count how many of the last stack frames are equal + int frame = stack.length-1; + int parentFrame = parentStack.length-1; + while (frame > 0 && parentFrame > 0) + { + if (stack[frame].equals(parentStack[parentFrame])) + { + equal++; + frame--; + parentFrame--; + } + else + break; + } + stackTraceStringBuffer(sb, cause.toString(), stack, equal); + } + cause = cause.getCause(); + } + + return sb.toString(); + } + + // Adds to the given StringBuffer a line containing the name and + // all stacktrace elements minus the last equal ones. + private static void stackTraceStringBuffer(StringBuffer sb, String name, + StackTraceElement[] stack, int equal) + { + String nl = StaticData.nl; + // (finish) first line + sb.append(name); + sb.append(nl); + + // The stacktrace + if (stack == null || stack.length == 0) + { + sb.append(" <>"); + sb.append(nl); + } + else + { + for (int i = 0; i < stack.length-equal; i++) + { + sb.append(" at "); + sb.append(stack[i] == null ? "<>" : stack[i].toString()); + sb.append(nl); + } + if (equal > 0) + { + sb.append(" ..."); + sb.append(equal); + sb.append(" more"); + sb.append(nl); + } + } + } + + /** + * Fill in the stack trace with the current execution stack. + * + * @return this same throwable + * @see #printStackTrace() + */ + public Throwable fillInStackTrace() + { + vmState = VMThrowable.fillInStackTrace(this); + stackTrace = null; // Should be regenerated when used. + + return this; + } + + /** + * Provides access to the information printed in {@link #printStackTrace()}. + * The array is non-null, with no null entries, although the virtual + * machine is allowed to skip stack frames. If the array is not 0-length, + * then slot 0 holds the information on the stack frame where the Throwable + * was created (or at least where fillInStackTrace() was + * called). + * + * @return an array of stack trace information, as available from the VM + * @since 1.4 + */ + public StackTraceElement[] getStackTrace() + { + if (stackTrace == null) + if (vmState == null) + stackTrace = new StackTraceElement[0]; + else + { + stackTrace = vmState.getStackTrace(this); + vmState = null; // No longer needed + } + + return stackTrace; + } + + /** + * Change the stack trace manually. This method is designed for remote + * procedure calls, which intend to alter the stack trace before or after + * serialization according to the context of the remote call. + *

    + * The contents of the given stacktrace is copied so changes to the + * original array do not change the stack trace elements of this + * throwable. + * + * @param stackTrace the new trace to use + * @throws NullPointerException if stackTrace is null or has null elements + * @since 1.4 + */ + public void setStackTrace(StackTraceElement[] stackTrace) + { + int i = stackTrace.length; + StackTraceElement[] st = new StackTraceElement[i]; + + while (--i >= 0) + { + st[i] = stackTrace[i]; + if (st[i] == null) + throw new NullPointerException("Element " + i + " null"); + } + + this.stackTrace = st; + } + + /** + * VM state when fillInStackTrace was called. + * Used by getStackTrace() to get an array of StackTraceElements. + * Cleared when no longer needed. + */ + private transient VMThrowable vmState; +} diff --git a/libjava/classpath/java/lang/TypeNotPresentException.java b/libjava/classpath/java/lang/TypeNotPresentException.java new file mode 100644 index 0000000..3010c96 --- /dev/null +++ b/libjava/classpath/java/lang/TypeNotPresentException.java @@ -0,0 +1,97 @@ +/* TypeNotPresentException.java -- Thrown when a string-based type is missing + 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 java.lang; + +/** + *

    + * Thrown when a type is accessed using a String-based + * representation, but no definition of the supplied type is found. + * This is effectively an unchecked equivalent of the existing + * ClassNotFound exception. + *

    + *

    + * It may occur due to an attempt to load a missing class, interface or + * annotation, or when an undefined type variable is accessed. + *

    + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see ClassNotFoundException + * @since 1.5 + */ +public class TypeNotPresentException + extends RuntimeException +{ + + /** + * Constructs a TypeNotPresentException for + * the supplied type. The specified cause Throwable + * may be used to provide additional history, with regards to the + * root of the problem. It is perfectly valid for this to be null, + * if the cause of the problem is unknown. + * + * @param typeName the name of the missing type. + * @param cause the cause of this exception, or null if the cause + * is unknown. + */ + public TypeNotPresentException(String typeName, Throwable cause) + { + super("type \"" + typeName + "\" not found", cause); + this.typeName = typeName; + } + + /** + * Returns the name of the missing type. + * + * @return the missing type's name. + */ + public String typeName() + { + return typeName; + } + + /** + * The name of the missing type. + * + * @serial the missing type's name. + */ + // Name fixed by serialization. + private String typeName; + +} diff --git a/libjava/classpath/java/lang/UnknownError.java b/libjava/classpath/java/lang/UnknownError.java new file mode 100644 index 0000000..7b317bd --- /dev/null +++ b/libjava/classpath/java/lang/UnknownError.java @@ -0,0 +1,72 @@ +/* UnknownError.java -- thrown when the VM cannot provide more information + about a catastrophic error + Copyright (C) 1998, 1999, 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 java.lang; + +/** + * An UnknownError is thrown when a serious but unknown + * problem has occurred in the Java Virtual Machine. + * + * @author Brian Jones + * @status updated to 1.4 + */ +public class UnknownError extends VirtualMachineError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 2524784860676771849L; + + /** + * Create an error without a message. + */ + public UnknownError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public UnknownError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/UnsatisfiedLinkError.java b/libjava/classpath/java/lang/UnsatisfiedLinkError.java new file mode 100644 index 0000000..0d513d8 --- /dev/null +++ b/libjava/classpath/java/lang/UnsatisfiedLinkError.java @@ -0,0 +1,74 @@ +/* UnsatisfiedLinkError.java -- thrown when a native method cannot be loaded + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * A UnsatisfiedLinkError is thrown if an appropriate + * native language definition of a method declared native + * cannot be found by the Java Virtual Machine. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @see Runtime + * @status updated to 1.4 + */ +public class UnsatisfiedLinkError extends LinkageError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4019343241616879428L; + + /** + * Create an error without a message. + */ + public UnsatisfiedLinkError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public UnsatisfiedLinkError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/UnsupportedClassVersionError.java b/libjava/classpath/java/lang/UnsupportedClassVersionError.java new file mode 100644 index 0000000..d6974b7 --- /dev/null +++ b/libjava/classpath/java/lang/UnsupportedClassVersionError.java @@ -0,0 +1,74 @@ +/* UnsupportedClassVersionError.java -- thrown when a class file version + exceeds the capability of the virtual machine + 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 java.lang; + +/** + * An UnsupportedClassVersionError is thrown when the + * Java Virtual Machine determines it does not support the major and minor + * version numbers in the class file it is attempting to read. + * + * @author Brian Jones + * @since 1.2 + * @status updated to 1.4 + */ +public class UnsupportedClassVersionError extends ClassFormatError +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -7123279212883497373L; + + /** + * Create an error without a message. + */ + public UnsupportedClassVersionError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public UnsupportedClassVersionError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/UnsupportedOperationException.java b/libjava/classpath/java/lang/UnsupportedOperationException.java new file mode 100644 index 0000000..0387d0e --- /dev/null +++ b/libjava/classpath/java/lang/UnsupportedOperationException.java @@ -0,0 +1,73 @@ +/* UnsupportedOperationException.java -- thrown when an operation is not + supported + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * This exception is thrown by an object when an operation is + * requested of it that it does not support. + * + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.2 + * @status updated to 1.4 + */ +public class UnsupportedOperationException extends RuntimeException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -1242599979055084673L; + + /** + * Create an exception without a message. + */ + public UnsupportedOperationException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public UnsupportedOperationException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/VerifyError.java b/libjava/classpath/java/lang/VerifyError.java new file mode 100644 index 0000000..350ceaa --- /dev/null +++ b/libjava/classpath/java/lang/VerifyError.java @@ -0,0 +1,72 @@ +/* VerifyError.java -- thrown when a class fails verification + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * A VerifyError is thrown if there is a security problem or + * internal inconsistency in a class file as detected by the "verifier." + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public class VerifyError extends LinkageError +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 7001962396098498785L; + + /** + * Create an error without a message. + */ + public VerifyError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public VerifyError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/VirtualMachineError.java b/libjava/classpath/java/lang/VirtualMachineError.java new file mode 100644 index 0000000..3062c4f --- /dev/null +++ b/libjava/classpath/java/lang/VirtualMachineError.java @@ -0,0 +1,73 @@ +/* VirtualMachineError.java -- thrown when the Virtual Machine has a problem + Copyright (C) 1998, 1999, 2001, 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 java.lang; + +/** + * A VirtualMachineError or its subclasses are thrown to + * indicate there is something wrong with the Java Virtual Machine or that + * it does not have the resources needed for it to continue execution. + * + * @author Brian Jones + * @author Tom Tromey (tromey@cygnus.com) + * @status updated to 1.4 + */ +public abstract class VirtualMachineError extends Error +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 4161983926571568670L; + + /** + * Create an error without a message. + */ + public VirtualMachineError() + { + } + + /** + * Create an error with a message. + * + * @param s the message + */ + public VirtualMachineError(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/lang/Void.java b/libjava/classpath/java/lang/Void.java new file mode 100644 index 0000000..1503542 --- /dev/null +++ b/libjava/classpath/java/lang/Void.java @@ -0,0 +1,68 @@ +/* Void.class - defines void.class + Copyright (C) 1998, 1999, 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 java.lang; + + +/** + * Void is a placeholder class so that the variable Void.TYPE + * (also available as void.class) can be supported for + * reflection return types. + * + *

    This class could be Serializable, but that is up to Sun.

    + * + * @author Paul Fisher + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public final class Void +{ + /** + * The return type void is represented by this + * Class object. + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass('V'); + + /** + * Void is non-instantiable. + */ + private Void() + { + } +} diff --git a/libjava/classpath/java/lang/annotation/AnnotationFormatError.java b/libjava/classpath/java/lang/annotation/AnnotationFormatError.java new file mode 100644 index 0000000..40ce3ca --- /dev/null +++ b/libjava/classpath/java/lang/annotation/AnnotationFormatError.java @@ -0,0 +1,104 @@ +/* AnnotationFormatError.java - Thrown when an binary annotation is malformed + Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang.annotation; + +/** + * Thrown when an annotation found in a class file is + * malformed. When the virtual machine finds a class file + * containing annotations, it attempts to parse them. + * This error is thrown if this operation fails. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class AnnotationFormatError extends Error +{ + + /** + * Constructs a new AnnotationFormatError + * using the specified message to give details of the error. + * + * @param message the message to use in the error output. + */ + public AnnotationFormatError(String message) + { + super(message); + } + + /** + *

    + * Constructs a new AnnotationFormatError + * using the specified message to give details of the error. + * The supplied cause Throwable is used to + * provide additional history, with regards to the root + * of the problem. It is perfectly valid for this to be null, if + * the cause is unknown. + *

    + *

    + * Note: if a cause is supplied, the error + * message from this cause is not automatically included in the + * error message given by this error. + *

    + * + * @param message the message to use in the error output + * @param cause the cause of this error, or null if the cause + * is unknown. + */ + public AnnotationFormatError(String message, Throwable cause) + { + super(message, cause); + } + + /** + * Constructs a new AnnotationFormatError using + * the supplied cause Throwable to + * provide additional history, with regards to the root + * of the problem. It is perfectly valid for this to be null, if + * the cause is unknown. If the cause is not null, the error + * message from this cause will also be used as the message + * for this error. + * + * @param cause the cause of the error. + */ + public AnnotationFormatError(Throwable cause) + { + super(cause); + } + +} diff --git a/libjava/classpath/java/lang/annotation/AnnotationTypeMismatchException.java b/libjava/classpath/java/lang/annotation/AnnotationTypeMismatchException.java new file mode 100644 index 0000000..653305d --- /dev/null +++ b/libjava/classpath/java/lang/annotation/AnnotationTypeMismatchException.java @@ -0,0 +1,116 @@ +/* AnnotationTypeMismatchException.java - Thrown when annotation has changed + Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang.annotation; + +import java.lang.reflect.Method; + +/** + * Thrown when accessing an element within an annotation for + * which the type has changed, since compilation or serialization + * took place. The mismatch between the compiled or serialized + * type and the current type causes this exception to be thrown. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class AnnotationTypeMismatchException extends RuntimeException +{ + + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 8125925355765570191L; + + /** + * Constructs an AnnotationTypeMismatchException + * which is due to a mismatched type in the annotation + * element, m. The erroneous type used for the + * data in m is represented by the string, + * type. This string is of an undefined format, + * and may contain the value as well as the type. + * + * @param m the element from the annotation. + * @param type the name of the erroneous type found in m. + */ + public AnnotationTypeMismatchException(Method m, String type) + { + this.element = m; + this.foundType = type; + } + + /** + * Returns the element from the annotation, for which a + * mismatch occurred. + * + * @return the element with the mismatched type. + */ + public Method element() + { + return element; + } + + /** + * Returns the erroneous type used by the element, + * represented as a String. The format + * of this String is not explicitly specified, + * and may contain the value as well as the type. + * + * @return the type found in the element. + */ + public String foundType() + { + return foundType; + } + + // Names are chosen from serialization spec. + /** + * The element from the annotation. + * + * @serial the element with the mismatched type. + */ + private Method element; + + /** + * The erroneous type used by the element. + * + * @serial the type found in the element. + */ + private String foundType; + +} diff --git a/libjava/classpath/java/lang/annotation/package.html b/libjava/classpath/java/lang/annotation/package.html new file mode 100644 index 0000000..ee70daf --- /dev/null +++ b/libjava/classpath/java/lang/annotation/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.lang.annotation + + +

    Classes to handle annotations.

    + + + diff --git a/libjava/classpath/java/lang/class-dependencies.conf b/libjava/classpath/java/lang/class-dependencies.conf new file mode 100644 index 0000000..4fbf75e --- /dev/null +++ b/libjava/classpath/java/lang/class-dependencies.conf @@ -0,0 +1,58 @@ +# This property file contains dependencies of classes, methods, and +# field on other methods or classes. +# +# Syntax: +# +# : [... ] +# +# means that when is included, (... ) must +# be included as well. +# +# and are of the form +# +# +# +# or just +# +# +# +# Within dependencies, variables can be used. A variable is defined as +# follows: +# +# {variable}: value1 value2 ... value +# +# variables can be used on the right side of dependencies as follows: +# +# : com.bla.blu.{variable}.Class.m()V +# +# The use of the variable will expand to dependencies of the form +# +# : com.bla.blu.value1.Class.m()V +# : com.bla.blu.value2.Class.m()V +# ... +# : com.bla.blu.value.Class.m()V +# +# Variables can be redefined when building a system to select the +# required support for features like encodings, protocols, etc. +# +# Hints: +# +# - For methods and fields, the signature is mandatory. For +# specification, please see the Java Virtual Machine Specification by +# SUN. Unlike in the spec, field signatures (types) are in brackets. +# +# - Package names must be separated by '/' (and not '.'). E.g., +# java/lang/Class (this is necessary, because the '.' is used to +# separate method or field names from classes) +# +# - In case refers to a class, only the class itself will be +# included in the resulting binary, NOT necessarily all its methods +# and fields. If you want to refer to all methods and fields, you can +# write class.* as an abbreviation. +# +# - Abbreviations for packages are also possible: my/package/* means all +# methods and fields of all classes in my/package. +# +# - A line with a trailing '\' continues in the next line. + +# end of file diff --git a/libjava/classpath/java/lang/package.html b/libjava/classpath/java/lang/package.html new file mode 100644 index 0000000..715418d --- /dev/null +++ b/libjava/classpath/java/lang/package.html @@ -0,0 +1,48 @@ + + + + +GNU Classpath - java.lang + + +

    Core classes including wrappers for primitive types, classes, packages +and class loaders, representations of the system, processes, threads and +the core exception hierarchy.

    + + + diff --git a/libjava/classpath/java/lang/ref/PhantomReference.java b/libjava/classpath/java/lang/ref/PhantomReference.java new file mode 100644 index 0000000..4d929c2 --- /dev/null +++ b/libjava/classpath/java/lang/ref/PhantomReference.java @@ -0,0 +1,73 @@ +/* java.lang.ref.PhantomReference + Copyright (C) 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 java.lang.ref; + +/** + * A phantom reference is useful, to get notified, when an object got + * finalized. You can't access that object though, since it is + * finalized. This is the reason, why get() always + * returns null. + * + * @author Jochen Hoenicke + */ +public class PhantomReference + extends Reference +{ + /** + * Creates a new phantom reference. + * @param referent the object that should be watched. + * @param q the queue that should be notified, if the referent was + * finalized. This mustn't be null. + * @exception NullPointerException if q is null. + */ + public PhantomReference(Object referent, ReferenceQueue q) + { + super(referent, q); + } + + /** + * Returns the object, this reference refers to. + * @return null, since the refered object may be + * finalized and thus not accessible. + */ + public Object get() + { + return null; + } +} diff --git a/libjava/classpath/java/lang/ref/Reference.java b/libjava/classpath/java/lang/ref/Reference.java new file mode 100644 index 0000000..1ec7243 --- /dev/null +++ b/libjava/classpath/java/lang/ref/Reference.java @@ -0,0 +1,177 @@ +/* java.lang.ref.Reference + Copyright (C) 1999, 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 java.lang.ref; + +/** + * This is the base class of all references. A reference allows + * refering to an object without preventing the garbage collector to + * collect it. The only way to get the referred object is via the + * get()-method. This method will return + * null if the object was collected.
    + * + * A reference may be registered with a queue. When a referred + * element gets collected the reference will be put on the queue, so + * that you will be notified.
    + * + * There are currently three types of references: soft reference, + * weak reference and phantom reference.
    + * + * Soft references will be cleared if the garbage collector is told + * to free some memory and there are no unreferenced or weakly referenced + * objects. It is useful for caches.
    + * + * Weak references will be cleared as soon as the garbage collector + * determines that the refered object is only weakly reachable. They + * are useful as keys in hashtables (see WeakHashtable) as + * you get notified when nobody has the key anymore. + * + * Phantom references don't prevent finalization. If an object is only + * phantom reachable, it will be finalized, and the reference will be + * enqueued, but not cleared. Since you mustn't access an finalized + * object, the get method of a phantom reference will never + * work. It is useful to keep track, when an object is finalized. + * + * @author Jochen Hoenicke + * @see java.util.WeakHashtable + */ +public abstract class Reference +{ + /** + * The underlying object. This field is handled in a special way by + * the garbage collector. + */ + Object referent; + + /** + * The queue this reference is registered on. This is null, if this + * wasn't registered to any queue or reference was already enqueued. + */ + ReferenceQueue queue; + + /** + * Link to the next entry on the queue. If this is null, this + * reference is not enqueued. Otherwise it points to the next + * reference. The last reference on a queue will point to itself + * (not to null, that value is used to mark a not enqueued + * reference). + */ + Reference nextOnQueue; + + /** + * This lock should be taken by the garbage collector, before + * determining reachability. It will prevent the get()-method to + * return the reference so that reachability doesn't change. + */ + static Object lock = new Object(); + + /** + * Creates a new reference that is not registered to any queue. + * Since it is package private, it is not possible to overload this + * class in a different package. + * @param referent the object we refer to. + */ + Reference(Object ref) + { + referent = ref; + } + + /** + * Creates a reference that is registered to a queue. Since this is + * package private, it is not possible to overload this class in a + * different package. + * @param referent the object we refer to. + * @param q the reference queue to register on. + * @exception NullPointerException if q is null. + */ + Reference(Object ref, ReferenceQueue q) + { + if (q == null) + throw new NullPointerException(); + referent = ref; + queue = q; + } + + /** + * Returns the object, this reference refers to. + * @return the object, this reference refers to, or null if the + * reference was cleared. + */ + public Object get() + { + synchronized (lock) + { + return referent; + } + } + + /** + * Clears the reference, so that it doesn't refer to its object + * anymore. For soft and weak references this is called by the + * garbage collector. For phantom references you should call + * this when enqueuing the reference. + */ + public void clear() + { + referent = null; + } + + /** + * Tells if the object is enqueued on a reference queue. + * @return true if it is enqueued, false otherwise. + */ + public boolean isEnqueued() + { + return nextOnQueue != null; + } + + /** + * Enqueue an object on a reference queue. This is normally executed + * by the garbage collector. + */ + public boolean enqueue() + { + if (queue != null && nextOnQueue == null) + { + queue.enqueue(this); + queue = null; + return true; + } + return false; + } +} diff --git a/libjava/classpath/java/lang/ref/ReferenceQueue.java b/libjava/classpath/java/lang/ref/ReferenceQueue.java new file mode 100644 index 0000000..f4729f2 --- /dev/null +++ b/libjava/classpath/java/lang/ref/ReferenceQueue.java @@ -0,0 +1,145 @@ +/* java.lang.ref.ReferenceQueue + Copyright (C) 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 java.lang.ref; + +/** + * This is the queue, where references can enqueue themselve on. Each + * reference may be registered to a queue at initialization time and + * will be appended to the queue, when the enqueue method is called. + * + * The enqueue method may be automatically called by the garbage + * collector if it detects, that the object is only reachable through + * the Reference objects. + * + * @author Jochen Hoenicke + * @see Reference#enqueue() + */ +public class ReferenceQueue +{ + /** + * This is a linked list of references. If this is null, the list is + * empty. Otherwise this points to the first reference on the queue. + * The first reference will point to the next reference via the + * nextOnQueue field. The last reference will point to + * itself (not to null, since nextOnQueue is used to + * determine if a reference is enqueued). + */ + private Reference first; + + /** + * Creates a new empty reference queue. + */ + public ReferenceQueue() + { + } + + /** + * Checks if there is a reference on the queue, returning it + * immediately. The reference will be dequeued. + * + * @return a reference on the queue, if there is one, + * null otherwise. + */ + public synchronized Reference poll() + { + return dequeue(); + } + + /** + * This is called by reference to enqueue itself on this queue. + * @param ref the reference that should be enqueued. + */ + synchronized void enqueue(Reference ref) + { + /* last reference will point to itself */ + ref.nextOnQueue = first == null ? ref : first; + first = ref; + /* this wakes only one remove thread. */ + notify(); + } + + /** + * Remove a reference from the queue, if there is one. + * @return the first element of the queue, or null if there isn't any. + */ + private Reference dequeue() + { + if (first == null) + return null; + + Reference result = first; + first = (first == first.nextOnQueue) ? null : first.nextOnQueue; + result.nextOnQueue = null; + return result; + } + + /** + * Removes a reference from the queue, blocking for timeout + * until a reference is enqueued. + * @param timeout the timeout period in milliseconds, 0 means + * wait forever. + * @return the reference removed from the queue, or + * null if timeout period expired. + * @exception InterruptedException if the wait was interrupted. + */ + public synchronized Reference remove(long timeout) + throws InterruptedException + { + if (first == null) + { + wait(timeout); + } + + return dequeue(); + } + + + /** + * Removes a reference from the queue, blocking until a reference is + * enqueued. + * + * @return the reference removed from the queue. + * @exception InterruptedException if the wait was interrupted. + */ + public Reference remove() + throws InterruptedException + { + return remove(0L); + } +} diff --git a/libjava/classpath/java/lang/ref/SoftReference.java b/libjava/classpath/java/lang/ref/SoftReference.java new file mode 100644 index 0000000..97395ea --- /dev/null +++ b/libjava/classpath/java/lang/ref/SoftReference.java @@ -0,0 +1,84 @@ +/* java.lang.ref.SoftReference + Copyright (C) 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 java.lang.ref; + +/** + * A soft reference will be cleared, if the object is only softly + * reachable and the garbage collection needs more memory. The garbage + * collection will use an intelligent strategy to determine which soft + * references it should clear. This makes a soft reference ideal for + * caches.
    + * + * @author Jochen Hoenicke + */ +public class SoftReference + extends Reference +{ + /** + * Create a new soft reference, that is not registered to any queue. + * @param referent the object we refer to. + */ + public SoftReference(Object referent) + { + super(referent); + } + + /** + * Create a new soft reference. + * @param referent the object we refer to. + * @param q the reference queue to register on. + * @exception NullPointerException if q is null. + */ + public SoftReference(Object referent, ReferenceQueue q) + { + super(referent, q); + } + + /** + * Returns the object, this reference refers to. + * @return the object, this reference refers to, or null if the + * reference was cleared. + */ + public Object get() + { + /* Why is this overloaded??? + * Maybe for a kind of LRU strategy. */ + return super.get(); + } +} diff --git a/libjava/classpath/java/lang/ref/WeakReference.java b/libjava/classpath/java/lang/ref/WeakReference.java new file mode 100644 index 0000000..9f758ca --- /dev/null +++ b/libjava/classpath/java/lang/ref/WeakReference.java @@ -0,0 +1,79 @@ +/* java.lang.ref.WeakReference + Copyright (C) 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 java.lang.ref; + +/** + * A weak reference will be cleared, if the object is only weakly + * reachable. It is useful for lookup tables, where you aren't + * interested in an entry, if the key isn't reachable anymore. + * WeakHashtable is a complete implementation of such a + * table.
    + * + * It is also useful to make objects unique: You create a set of weak + * references to those objects, and when you create a new object you + * look in this set, if the object already exists and return it. If + * an object is not referenced anymore, the reference will + * automatically cleared, and you may remove it from the set.
    + * + * @author Jochen Hoenicke + * @see java.util.WeakHashtable + */ +public class WeakReference + extends Reference +{ + /** + * Create a new weak reference, that is not registered to any queue. + * @param referent the object we refer to. + */ + public WeakReference(Object referent) + { + super(referent); + } + + /** + * Create a new weak reference. + * @param referent the object we refer to. + * @param q the reference queue to register on. + * @exception NullPointerException if q is null. + */ + public WeakReference(Object referent, ReferenceQueue q) + { + super(referent, q); + } +} diff --git a/libjava/classpath/java/lang/ref/package.html b/libjava/classpath/java/lang/ref/package.html new file mode 100644 index 0000000..d3d1762 --- /dev/null +++ b/libjava/classpath/java/lang/ref/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.lang.ref + + +

    Low level manipulation and monitoring of object references.

    + + + diff --git a/libjava/classpath/java/lang/reflect/AccessibleObject.java b/libjava/classpath/java/lang/reflect/AccessibleObject.java new file mode 100644 index 0000000..24418c9 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/AccessibleObject.java @@ -0,0 +1,159 @@ +/* java.lang.reflect.AccessibleObject + Copyright (C) 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +/** + * This class is the superclass of various reflection classes, and + * allows sufficiently trusted code to bypass normal restrictions to + * do necessary things like invoke private methods outside of the + * class during Serialization. If you don't have a good reason + * to mess with this, don't try. Fortunately, there are adequate + * security checks before you can set a reflection object as accessible. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Field + * @see Constructor + * @see Method + * @see ReflectPermission + * @since 1.2 + * @status updated to 1.4 + */ +public class AccessibleObject +{ + /** + * True if this object is marked accessible, which means the reflected + * object bypasses normal security checks. + */ + // default visibility for use by inherited classes + boolean flag = false; + + /** + * Only the three reflection classes that extend this can create an + * accessible object. This is not serializable for security reasons. + */ + protected AccessibleObject() + { + } + + /** + * Return the accessibility status of this object. + * + * @return true if this object bypasses security checks + */ + public boolean isAccessible() + { + return flag; + } + + /** + * Convenience method to set the flag on a number of objects with a single + * security check. If a security manager exists, it is checked for + * ReflectPermission("suppressAccessChecks").

    + * + * It is forbidden to set the accessibility flag to true on any constructor + * for java.lang.Class. This will result in a SecurityException. If the + * SecurityException is thrown for any of the passed AccessibleObjects, + * the accessibility flag will be set on AccessibleObjects in the array prior + * to the one which resulted in the exception. + * + * @param array the array of accessible objects + * @param flag the desired state of accessibility, true to bypass security + * @throws NullPointerException if array is null + * @throws SecurityException if the request is denied + * @see SecurityManager#checkPermission(java.security.Permission) + * @see RuntimePermission + */ + public static void setAccessible(AccessibleObject[] array, boolean flag) + { + checkPermission(); + for (int i = 0; i < array.length; i++) + array[i].secureSetAccessible(flag); + } + + /** + * Sets the accessibility flag for this reflection object. If a security + * manager exists, it is checked for + * ReflectPermission("suppressAccessChecks").

    + * + * It is forbidden to set the accessibility flag to true on any constructor for + * java.lang.Class. This will result in a SecurityException. + * + * @param flag the desired state of accessibility, true to bypass security + * @throws NullPointerException if array is null + * @throws SecurityException if the request is denied + * @see SecurityManager#checkPermission(java.security.Permission) + * @see RuntimePermission + */ + public void setAccessible(boolean flag) + { + checkPermission(); + secureSetAccessible(flag); + } + + /** + * Performs the specified security check, for + * ReflectPermission("suppressAccessChecks"). + * + * @throws SecurityException if permission is denied + */ + private static void checkPermission() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new ReflectPermission("suppressAccessChecks")); + } + + /** + * Performs the actual accessibility change, this must always be invoked + * after calling checkPermission. + * + * @param flag the desired status + * @throws SecurityException if flag is true and this is a constructor + * for java.lang.Class. + */ + private void secureSetAccessible(boolean flag) + { + if (flag && + (this instanceof Constructor + && ((Constructor) this).getDeclaringClass() == Class.class)) + throw new SecurityException("Cannot make object accessible: " + this); + this.flag = flag; + } +} diff --git a/libjava/classpath/java/lang/reflect/Array.java b/libjava/classpath/java/lang/reflect/Array.java new file mode 100644 index 0000000..35c77da --- /dev/null +++ b/libjava/classpath/java/lang/reflect/Array.java @@ -0,0 +1,675 @@ +/* java.lang.reflect.Array - manipulate arrays by reflection + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +import gnu.classpath.Configuration; + +/** + * Array holds static helper functions that allow you to create and + * manipulate arrays by reflection. Operations know how to perform widening + * conversions, but throw {@link IllegalArgumentException} if you attempt + * a narrowing conversion. Also, when accessing primitive arrays, this + * class performs object wrapping and unwrapping as necessary.

    + * + * Note: This class returns and accepts types as Classes, even + * primitive types; there are Class types defined that represent each + * different primitive type. They are java.lang.Boolean.TYPE, + * java.lang.Byte.TYPE,, also available as boolean.class, + * byte.class, etc. These are not to be confused with the + * classes java.lang.Boolean, java.lang.Byte, etc., which are + * real classes. Note also that the shorthand Object[].class + * is a convenient way to get array Classes.

    + * + * Performance note: This class performs best when it does not have + * to convert primitive types. The further along the chain it has to convert, + * the worse performance will be. You're best off using the array as whatever + * type it already is, and then converting the result. You will do even + * worse if you do this and use the generic set() function. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Per Bothner (bothner@cygnus.com) + * @see java.lang.Boolean#TYPE + * @see java.lang.Byte#TYPE + * @see java.lang.Short#TYPE + * @see java.lang.Character#TYPE + * @see java.lang.Integer#TYPE + * @see java.lang.Long#TYPE + * @see java.lang.Float#TYPE + * @see java.lang.Double#TYPE + * @since 1.1 + * @status updated to 1.4 + */ +public final class Array +{ + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javalangreflect"); + } + } + + /** + * This class is uninstantiable. + */ + private Array() + { + } + + /** + * Creates a new single-dimensioned array. + * @param componentType the type of the array to create + * @param length the length of the array to create + * @return the created array, cast to an Object + * @throws NullPointerException if componentType is null + * @throws IllegalArgumentException if componentType is + * Void.TYPE + * @throws NegativeArraySizeException when length is less than 0 + * @throws OutOfMemoryError if memory allocation fails + */ + public static Object newInstance(Class componentType, int length) + { + if (! componentType.isPrimitive()) + return createObjectArray(componentType, length); + if (componentType == boolean.class) + return new boolean[length]; + if (componentType == byte.class) + return new byte[length]; + if (componentType == char.class) + return new char[length]; + if (componentType == short.class) + return new short[length]; + if (componentType == int.class) + return new int[length]; + if (componentType == long.class) + return new long[length]; + if (componentType == float.class) + return new float[length]; + if (componentType == double.class) + return new double[length]; + // assert componentType == void.class + throw new IllegalArgumentException(); + } + + /** + * Creates a new multi-dimensioned array. The new array has the same + * component type as the argument class, and the number of dimensions + * in the new array is the sum of the dimensions of the argument class + * and the length of the argument dimensions. Virtual Machine limitations + * forbid too many dimensions (usually 255 is the maximum); but even + * 50 dimensions of 2 elements in each dimension would exceed your memory + * long beforehand! + * + * @param componentType the type of the array to create. + * @param dimensions the dimensions of the array to create. Each element + * in dimensions makes another dimension of the new + * array. Thus, Array.newInstance(java.lang.Boolean, + * new int[]{1,2,3}) is the same as + * new java.lang.Boolean[1][2][3] + * @return the created array, cast to an Object + * @throws NullPointerException if componentType or dimension is null + * @throws IllegalArgumentException if the the size of + * dimensions is 0 or exceeds the maximum number of + * array dimensions in the VM; or if componentType is Void.TYPE + * @throws NegativeArraySizeException when any of the dimensions is less + * than 0 + * @throws OutOfMemoryError if memory allocation fails + */ + public static Object newInstance(Class componentType, int[] dimensions) + { + if (dimensions.length <= 0) + throw new IllegalArgumentException ("Empty dimensions array."); + return createMultiArray(componentType, dimensions, + dimensions.length - 1); + } + + /** + * Gets the array length. + * @param array the array + * @return the length of the array + * @throws IllegalArgumentException if array is not an array + * @throws NullPointerException if array is null + */ + public static int getLength(Object array) + { + if (array instanceof Object[]) + return ((Object[]) array).length; + if (array instanceof boolean[]) + return ((boolean[]) array).length; + if (array instanceof byte[]) + return ((byte[]) array). length; + if (array instanceof char[]) + return ((char[]) array).length; + if (array instanceof short[]) + return ((short[]) array).length; + if (array instanceof int[]) + return ((int[]) array).length; + if (array instanceof long[]) + return ((long[]) array).length; + if (array instanceof float[]) + return ((float[]) array).length; + if (array instanceof double[]) + return ((double[]) array).length; + if (array == null) + throw new NullPointerException(); + throw new IllegalArgumentException(); + } + + /** + * Gets an element of an array. Primitive elements will be wrapped in + * the corresponding class type. + * + * @param array the array to access + * @param index the array index to access + * @return the element at array[index] + * @throws IllegalArgumentException if array is not an array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #getBoolean(Object, int) + * @see #getByte(Object, int) + * @see #getChar(Object, int) + * @see #getShort(Object, int) + * @see #getInt(Object, int) + * @see #getLong(Object, int) + * @see #getFloat(Object, int) + * @see #getDouble(Object, int) + */ + public static Object get(Object array, int index) + { + if (array instanceof Object[]) + return ((Object[]) array)[index]; + if (array instanceof boolean[]) + return ((boolean[]) array)[index] ? Boolean.TRUE : Boolean.FALSE; + if (array instanceof byte[]) + return new Byte(((byte[]) array)[index]); + if (array instanceof char[]) + return new Character(((char[]) array)[index]); + if (array instanceof short[]) + return new Short(((short[]) array)[index]); + if (array instanceof int[]) + return new Integer(((int[]) array)[index]); + if (array instanceof long[]) + return new Long(((long[]) array)[index]); + if (array instanceof float[]) + return new Float(((float[]) array)[index]); + if (array instanceof double[]) + return new Double(((double[]) array)[index]); + if (array == null) + throw new NullPointerException(); + throw new IllegalArgumentException(); + } + + /** + * Gets an element of a boolean array. + * + * @param array the array to access + * @param index the array index to access + * @return the boolean element at array[index] + * @throws IllegalArgumentException if array is not a boolean + * array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #get(Object, int) + */ + public static boolean getBoolean(Object array, int index) + { + if (array instanceof boolean[]) + return ((boolean[]) array)[index]; + if (array == null) + throw new NullPointerException(); + throw new IllegalArgumentException(); + } + + /** + * Gets an element of a byte array. + * + * @param array the array to access + * @param index the array index to access + * @return the byte element at array[index] + * @throws IllegalArgumentException if array is not a byte + * array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #get(Object, int) + */ + public static byte getByte(Object array, int index) + { + if (array instanceof byte[]) + return ((byte[]) array)[index]; + if (array == null) + throw new NullPointerException(); + throw new IllegalArgumentException(); + } + + /** + * Gets an element of a char array. + * + * @param array the array to access + * @param index the array index to access + * @return the char element at array[index] + * @throws IllegalArgumentException if array is not a char + * array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #get(Object, int) + */ + public static char getChar(Object array, int index) + { + if (array instanceof char[]) + return ((char[]) array)[index]; + if (array == null) + throw new NullPointerException(); + throw new IllegalArgumentException(); + } + + /** + * Gets an element of a short array. + * + * @param array the array to access + * @param index the array index to access + * @return the short element at array[index] + * @throws IllegalArgumentException if array is not a byte + * or char array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #get(Object, int) + */ + public static short getShort(Object array, int index) + { + if (array instanceof short[]) + return ((short[]) array)[index]; + return getByte(array, index); + } + + /** + * Gets an element of an int array. + * + * @param array the array to access + * @param index the array index to access + * @return the int element at array[index] + * @throws IllegalArgumentException if array is not a byte, + * char, short, or int array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #get(Object, int) + */ + public static int getInt(Object array, int index) + { + if (array instanceof int[]) + return ((int[]) array)[index]; + if (array instanceof char[]) + return ((char[]) array)[index]; + return getShort(array, index); + } + + /** + * Gets an element of a long array. + * + * @param array the array to access + * @param index the array index to access + * @return the long element at array[index] + * @throws IllegalArgumentException if array is not a byte, + * char, short, int, or long array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #get(Object, int) + */ + public static long getLong(Object array, int index) + { + if (array instanceof long[]) + return ((long[]) array)[index]; + return getInt(array, index); + } + + /** + * Gets an element of a float array. + * + * @param array the array to access + * @param index the array index to access + * @return the float element at array[index] + * @throws IllegalArgumentException if array is not a byte, + * char, short, int, long, or float array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #get(Object, int) + */ + public static float getFloat(Object array, int index) + { + if (array instanceof float[]) + return ((float[]) array)[index]; + return getLong(array, index); + } + + /** + * Gets an element of a double array. + * + * @param array the array to access + * @param index the array index to access + * @return the double element at array[index] + * @throws IllegalArgumentException if array is not a byte, + * char, short, int, long, float, or double array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #get(Object, int) + */ + public static double getDouble(Object array, int index) + { + if (array instanceof double[]) + return ((double[]) array)[index]; + return getFloat(array, index); + } + + /** + * Sets an element of an array. If the array is primitive, then the new + * value is unwrapped and widened. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if array is not an array, + * or the array is primitive and unwrapping value fails, or the + * value is not assignable to the array component type + * @throws NullPointerException if array is null, or if array is primitive + * and value is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #setBoolean(Object, int, boolean) + * @see #setByte(Object, int, byte) + * @see #setChar(Object, int, char) + * @see #setShort(Object, int, short) + * @see #setInt(Object, int, int) + * @see #setLong(Object, int, long) + * @see #setFloat(Object, int, float) + * @see #setDouble(Object, int, double) + */ + public static void set(Object array, int index, Object value) + { + if (array instanceof Object[]) + { + // Too bad the API won't let us throw the easier ArrayStoreException! + if (value != null + && ! array.getClass().getComponentType().isInstance(value)) + throw new IllegalArgumentException(); + ((Object[]) array)[index] = value; + } + else if (value instanceof Byte) + setByte(array, index, ((Byte) value).byteValue()); + else if (value instanceof Short) + setShort(array, index, ((Short) value).shortValue()); + else if (value instanceof Integer) + setInt(array, index, ((Integer) value).intValue()); + else if (value instanceof Long) + setLong(array, index, ((Long) value).longValue()); + else if (value instanceof Float) + setFloat(array, index, ((Float) value).floatValue()); + else if (value instanceof Double) + setDouble(array, index, ((Double) value).doubleValue()); + else if (value instanceof Character) + setChar(array, index, ((Character) value).charValue()); + else if (value instanceof Boolean) + setBoolean(array, index, ((Boolean) value).booleanValue()); + else if (array == null) + throw new NullPointerException(); + else + throw new IllegalArgumentException(); + } + + /** + * Sets an element of a boolean array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if array is not a boolean + * array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #set(Object, int, Object) + */ + public static void setBoolean(Object array, int index, boolean value) + { + if (array instanceof boolean[]) + ((boolean[]) array)[index] = value; + else if (array == null) + throw new NullPointerException(); + else + throw new IllegalArgumentException(); + } + + /** + * Sets an element of a byte array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if array is not a byte, + * short, int, long, float, or double array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #set(Object, int, Object) + */ + public static void setByte(Object array, int index, byte value) + { + if (array instanceof byte[]) + ((byte[]) array)[index] = value; + else + setShort(array, index, value); + } + + /** + * Sets an element of a char array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if array is not a char, + * int, long, float, or double array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #set(Object, int, Object) + */ + public static void setChar(Object array, int index, char value) + { + if (array instanceof char[]) + ((char[]) array)[index] = value; + else + setInt(array, index, value); + } + + /** + * Sets an element of a short array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if array is not a short, + * int, long, float, or double array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #set(Object, int, Object) + */ + public static void setShort(Object array, int index, short value) + { + if (array instanceof short[]) + ((short[]) array)[index] = value; + else + setInt(array, index, value); + } + + /** + * Sets an element of an int array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if array is not an int, + * long, float, or double array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #set(Object, int, Object) + */ + public static void setInt(Object array, int index, int value) + { + if (array instanceof int[]) + ((int[]) array)[index] = value; + else + setLong(array, index, value); + } + + /** + * Sets an element of a long array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if array is not a long, + * float, or double array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #set(Object, int, Object) + */ + public static void setLong(Object array, int index, long value) + { + if (array instanceof long[]) + ((long[]) array)[index] = value; + else + setFloat(array, index, value); + } + + /** + * Sets an element of a float array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if array is not a float + * or double array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #set(Object, int, Object) + */ + public static void setFloat(Object array, int index, float value) + { + if (array instanceof float[]) + ((float[]) array)[index] = value; + else + setDouble(array, index, value); + } + + /** + * Sets an element of a double array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if array is not a double + * array + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if index is out of + * bounds + * @see #set(Object, int, Object) + */ + public static void setDouble(Object array, int index, double value) + { + if (array instanceof double[]) + ((double[]) array)[index] = value; + else if (array == null) + throw new NullPointerException(); + else + throw new IllegalArgumentException(); + } + + /** + * Dynamically and recursively create a multi-dimensioned array of objects. + * + * @param type guaranteed to be a valid object type + * @param dimensions the dimensions of the array + * @param index index of the current dimension to build + * @return the new multi-dimensioned array + * @throws NegativeArraySizeException if any entry of dimensions is negative + * @throws OutOfMemoryError if memory allocation fails + */ + // This would be faster if implemented natively, using the multianewarray + // bytecode instead of this recursive call + private static Object createMultiArray(Class type, int[] dimensions, + int index) + { + if (index == 0) + return newInstance(type, dimensions[0]); + + Object toAdd = createMultiArray(type, dimensions, index - 1); + Class thisType = toAdd.getClass(); + Object[] retval + = (Object[]) createObjectArray(thisType, dimensions[index]); + if (dimensions[index] > 0) + retval[0] = toAdd; + int i = dimensions[index]; + while (--i > 0) + retval[i] = createMultiArray(type, dimensions, index - 1); + return retval; + } + + /** + * Dynamically create an array of objects. + * + * @param type guaranteed to be a valid object type + * @param dim the length of the array + * @return the new array + * @throws NegativeArraySizeException if dim is negative + * @throws OutOfMemoryError if memory allocation fails + */ + private static native Object createObjectArray(Class type, int dim); +} diff --git a/libjava/classpath/java/lang/reflect/GenericArrayType.java b/libjava/classpath/java/lang/reflect/GenericArrayType.java new file mode 100644 index 0000000..8dc33a7 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/GenericArrayType.java @@ -0,0 +1,61 @@ +/* GenericArrayType.java - Represent an array type with a generic component + 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 java.lang.reflect; + +/** + * Represents the type of an array's components, which may be + * either a parameterized type or a type variable. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface GenericArrayType + extends Type +{ + + /** + * Returns the Type of the components within the array. + * + * @return a Type instance representing the type of + * the array's components. + */ + Type getGenericComponentType(); + +} diff --git a/libjava/classpath/java/lang/reflect/GenericSignatureFormatError.java b/libjava/classpath/java/lang/reflect/GenericSignatureFormatError.java new file mode 100644 index 0000000..ab6928d --- /dev/null +++ b/libjava/classpath/java/lang/reflect/GenericSignatureFormatError.java @@ -0,0 +1,62 @@ +/* GenericSignatureFormatError.java - Thrown when a signature is malformed. + 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 java.lang.reflect; + +/** + * Thrown on encountering a syntactically malformed signature in + * a reflective method. During reflection, the generic type signature + * of a type, method or constructor may be interpreted by the virtual + * machine. This error is thrown if this operation fails. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class GenericSignatureFormatError + extends ClassFormatError +{ + + /** + * Constructs a new GenericSignatureFormatError. + */ + public GenericSignatureFormatError() + { + } + +} diff --git a/libjava/classpath/java/lang/reflect/InvocationHandler.java b/libjava/classpath/java/lang/reflect/InvocationHandler.java new file mode 100644 index 0000000..208e621 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/InvocationHandler.java @@ -0,0 +1,137 @@ +/* java.lang.reflect.InvocationHandler - dynamically executes methods in + proxy instances + 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 java.lang.reflect; + +/** + * This interface defines an invocation handler. Suppose you are using + * reflection, and found a method that requires that its parameter + * be an object of a given interface. You want to call this method, + * but have no idea what classes implement that interface. So, you can + * create a {@link Proxy} instance, a convenient way to dynamically + * generate a class that meets all the necessary properties of that + * interface. But in order for the proxy instance to do any good, it + * needs to know what to do when interface methods are invoked! So, + * this interface is basically a cool wrapper that provides runtime + * code generation needed by proxy instances. + * + *

    While this interface was designed for use by Proxy, it will also + * work on any object in general.

    + * + *

    Hints for implementing this class:

    + * + *
      + *
    • Don't forget that Object.equals, Object.hashCode, and + * Object.toString will call this handler. In particular, + * a naive call to proxy.equals, proxy.hashCode, or proxy.toString + * will put you in an infinite loop. And remember that string + * concatenation also invokes toString.
    • + *
    • Obey the contract of the Method object you are handling, or + * the proxy instance will be forced to throw a + * {@link NullPointerException}, {@link ClassCastException}, + * or {@link UndeclaredThrowableException}.
    • + *
    • Be prepared to wrap/unwrap primitives as necessary.
    • + *
    • The Method object may be owned by a different interface than + * what was actually used as the qualifying type of the method + * invocation in the Java source code. This means that it might + * not always be safe to throw an exception listed as belonging + * to the method's throws clause.
    • + *
    + * + *

    For a fun time, create an InvocationHandler that handles the + * methods of a proxy instance of the InvocationHandler interface!

    + * + * @see Proxy + * @see UndeclaredThrowableException + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ +public interface InvocationHandler +{ + /** + * When a method is invoked on a proxy instance, it is wrapped and + * this method is called instead, so that you may decide at runtime + * how the original method should behave. + * + * @param proxy the instance that the wrapped method should be + * invoked on. When this method is called by a Proxy object, + * `proxy' will be an instance of {@link Proxy}, and oddly enough, + * Proxy.getInvocationHandler(proxy) will return + * this! + * @param method the reflected method to invoke on the proxy. + * When this method is called by a Proxy object, 'method' + * will be the reflection object owned by the declaring + * class or interface, which may be a supertype of the + * interfaces the proxy directly implements. + * @param args the arguments passed to the original method, or + * null if the method takes no arguments. + * (But also be prepared to handle a 0-length array). + * Arguments of primitive type, such as boolean + * or int, are wrapped in the appropriate + * class such as {@link Boolean} or {@link Integer}. + * @return whatever is necessary to return from the wrapped method. + * If the wrapped method is void, the proxy + * instance will ignore it. If the wrapped method returns + * a primitive, this must be the correct wrapper type whose value + * is exactly assignable to the appropriate type (no widening + * will be performed); a null object in this case causes a + * {@link NullPointerException}. In all remaining cases, if + * the returned object is not assignment compatible to the + * declared type of the original method, the proxy instance + * will generate a {@link ClassCastException}. + * @throws Throwable this interface is listed as throwing anything, + * but the implementation should only throw unchecked + * exceptions and exceptions listed in the throws clause of + * all methods being overridden by the proxy instance. If + * something is thrown that is not compatible with the throws + * clause of all overridden methods, the proxy instance will + * wrap the exception in an UndeclaredThrowableException. + * Note that an exception listed in the throws clause of the + * `method' parameter might not be declared in additional + * interfaces also implemented by the proxy object. + * + * @see Proxy + * @see UndeclaredThrowableException + */ + Object invoke(Object proxy, Method method, Object[] args) + throws Throwable; + +} diff --git a/libjava/classpath/java/lang/reflect/InvocationTargetException.java b/libjava/classpath/java/lang/reflect/InvocationTargetException.java new file mode 100644 index 0000000..af79d3a --- /dev/null +++ b/libjava/classpath/java/lang/reflect/InvocationTargetException.java @@ -0,0 +1,123 @@ +/* InvocationTargetException.java -- Wrapper exception for reflection + Copyright (C) 1998, 1999, 2000, 2001, 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 java.lang.reflect; + +/** + * InvocationTargetException is sort of a way to "wrap" whatever exception + * comes up when a method or constructor is called via Reflection. As of + * JDK 1.4, it was retrofitted to match the exception chaining of all other + * exceptions, but getTargetException() still works. + * + * @author John Keiser + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Method#invoke(Object,Object[]) + * @see Constructor#newInstance(Object[]) + * @since 1.1 + * @status updated to 1.4 + */ +public class InvocationTargetException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 4085088731926701167L; + + /** + * The chained exception. This field is only around for serial compatibility. + * + * @serial the chained exception + */ + private final Throwable target; + + /** + * Construct an exception with null as the cause. The cause is initialized + * to null. + */ + protected InvocationTargetException() + { + this(null, null); + } + + /** + * Create an InvocationTargetException using another + * exception. + * + * @param targetException the exception to wrap + */ + public InvocationTargetException(Throwable targetException) + { + this(targetException, null); + } + + /** + * Create an InvocationTargetException using another + * exception and an error message. + * + * @param targetException the exception to wrap + * @param err an extra reason for the exception-throwing + */ + public InvocationTargetException(Throwable targetException, String err) + { + super(err, targetException); + target = targetException; + } + + /** + * Get the wrapped (targeted) exception. + * + * @return the targeted exception + * @see #getCause() + */ + public Throwable getTargetException() + { + return target; + } + + /** + * Returns the cause of this exception (which may be null). + * + * @return the cause + * @since 1.4 + */ + public Throwable getCause() + { + return target; + } +} diff --git a/libjava/classpath/java/lang/reflect/Member.java b/libjava/classpath/java/lang/reflect/Member.java new file mode 100644 index 0000000..9983b27 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/Member.java @@ -0,0 +1,100 @@ +/* java.lang.reflect.Member - common query methods in reflection + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +/** + * Member is an interface that represents any member of a class (field or + * method) or a constructor. You can get information about the declaring + * class, name or modifiers of the member with this interface. + * + * @author John Keiser + * @author Per Bothner (bothner@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Class + * @see Field + * @see Method + * @see Constructor + * @since 1.1 + * @status updated to 1.4 + */ +public interface Member +{ + /** + * Represents all members, whether public, private, protected or + * package-protected, but only which are declared in this class. + * Used in SecurityManager.checkMemberAccess() to determine the + * type of members to access. + * @see SecurityManager#checkMemberAccess() + */ + int DECLARED = 1; + + /** + * Represents public members only, but includes all inherited members. + * Used in SecurityManager.checkMemberAccess() to determine the type of + * members to access. + * @see SecurityManager#checkMemberAccess() + */ + int PUBLIC = 0; + + /** + * Gets the class that declared this member. This is not the class where + * this method was called, or even the class where this Member object + * came to life, but the class that declares the member this represents. + * + * @return the class that declared this member + */ + Class getDeclaringClass(); + + /** + * Gets the simple name of this member. This will be a valid Java + * identifier, with no qualification. + * + * @return the name of this member + */ + String getName(); + + /** + * Gets the modifiers this member uses. Use the Modifier + * class to interpret the values. + * + * @return an integer representing the modifiers to this Member + * @see Modifier + */ + int getModifiers(); +} diff --git a/libjava/classpath/java/lang/reflect/Modifier.java b/libjava/classpath/java/lang/reflect/Modifier.java new file mode 100644 index 0000000..efc88c9 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/Modifier.java @@ -0,0 +1,332 @@ +/* java.lang.reflect.Modifier + Copyright (C) 1998, 1999, 2001, 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 java.lang.reflect; + +/** + * Modifier is a helper class with static methods to determine whether an + * int returned from getModifiers() represents static, public, protected, + * native, final, etc... and provides an additional method to print + * out all of the modifiers in an int in order. + *

    + * The methods in this class use the bitmask values in the VM spec to + * determine the modifiers of an int. This means that a VM must return a + * standard mask, conformant with the VM spec. I don't know if this is how + * Sun does it, but I'm willing to bet money that it is. + * + * @author John Keiser + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Member#getModifiers() + * @see Method#getModifiers() + * @see Field#getModifiers() + * @see Constructor#getModifiers() + * @see Class#getModifiers() + * @since 1.1 + */ +public class Modifier +{ + /** This constructor really shouldn't be here ... there are no + * instance methods or variables of this class, so instantiation is + * worthless. However, this function is in the 1.1 spec, so it is added + * for completeness. + */ + public Modifier() + { + } + + /** + * Public: accessible from any other class. + */ + public static final int PUBLIC = 0x0001; + + /** + * Private: accessible only from the same enclosing class. + */ + public static final int PRIVATE = 0x0002; + + /** + * Protected: accessible only to subclasses, or within the package. + */ + public static final int PROTECTED = 0x0004; + + /** + * Static:

      + *
    • Class: no enclosing instance for nested class.
    • + *
    • Field or Method: can be accessed or invoked without an + * instance of the declaring class.
    • + *
    + */ + public static final int STATIC = 0x0008; + + /** + * Final:
      + *
    • Class: no subclasses allowed.
    • + *
    • Field: cannot be changed.
    • + *
    • Method: cannot be overriden.
    • + *
    + */ + public static final int FINAL = 0x0010; + + /** + * Synchronized: Method: lock the class while calling this method. + */ + public static final int SYNCHRONIZED = 0x0020; + + /** + * Volatile: Field: cannot be cached. + */ + public static final int VOLATILE = 0x0040; + + /** + * Transient: Field: not serialized or deserialized. + */ + public static final int TRANSIENT = 0x0080; + + /** + * Native: Method: use JNI to call this method. + */ + public static final int NATIVE = 0x0100; + + /** + * Interface: Class: is an interface. + */ + public static final int INTERFACE = 0x0200; + + /** + * Abstract:
      + *
    • Class: may not be instantiated.
    • + *
    • Method: may not be called.
    • + *
    + */ + public static final int ABSTRACT = 0x0400; + + /** + * Strictfp: Method: expressions are FP-strict.

    + * Also used as a modifier for classes, to mean that all initializers + * and constructors are FP-strict, but does not show up in + * Class.getModifiers. + */ + public static final int STRICT = 0x0800; + + + /** + * Super - treat invokespecial as polymorphic so that super.foo() works + * according to the JLS. This is a reuse of the synchronized constant + * to patch a hole in JDK 1.0. *shudder*. + */ + static final int SUPER = 0x0020; + + /** + * All the flags, only used by code in this package. + */ + static final int ALL_FLAGS = 0xfff; + + /** + * Check whether the given modifier is abstract. + * @param mod the modifier. + * @return true if abstract, false otherwise. + */ + public static boolean isAbstract(int mod) + { + return (mod & ABSTRACT) != 0; + } + + /** + * Check whether the given modifier is final. + * @param mod the modifier. + * @return true if final, false otherwise. + */ + public static boolean isFinal(int mod) + { + return (mod & FINAL) != 0; + } + + /** + * Check whether the given modifier is an interface. + * @param mod the modifier. + * @return true if an interface, false otherwise. + */ + public static boolean isInterface(int mod) + { + return (mod & INTERFACE) != 0; + } + + /** + * Check whether the given modifier is native. + * @param mod the modifier. + * @return true if native, false otherwise. + */ + public static boolean isNative(int mod) + { + return (mod & NATIVE) != 0; + } + + /** + * Check whether the given modifier is private. + * @param mod the modifier. + * @return true if private, false otherwise. + */ + public static boolean isPrivate(int mod) + { + return (mod & PRIVATE) != 0; + } + + /** + * Check whether the given modifier is protected. + * @param mod the modifier. + * @return true if protected, false otherwise. + */ + public static boolean isProtected(int mod) + { + return (mod & PROTECTED) != 0; + } + + /** + * Check whether the given modifier is public. + * @param mod the modifier. + * @return true if public, false otherwise. + */ + public static boolean isPublic(int mod) + { + return (mod & PUBLIC) != 0; + } + + /** + * Check whether the given modifier is static. + * @param mod the modifier. + * @return true if static, false otherwise. + */ + public static boolean isStatic(int mod) + { + return (mod & STATIC) != 0; + } + + /** + * Check whether the given modifier is strictfp. + * @param mod the modifier. + * @return true if strictfp, false otherwise. + */ + public static boolean isStrict(int mod) + { + return (mod & STRICT) != 0; + } + + /** + * Check whether the given modifier is synchronized. + * @param mod the modifier. + * @return true if synchronized, false otherwise. + */ + public static boolean isSynchronized(int mod) + { + return (mod & SYNCHRONIZED) != 0; + } + + /** + * Check whether the given modifier is transient. + * @param mod the modifier. + * @return true if transient, false otherwise. + */ + public static boolean isTransient(int mod) + { + return (mod & TRANSIENT) != 0; + } + + /** + * Check whether the given modifier is volatile. + * @param mod the modifier. + * @return true if volatile, false otherwise. + */ + public static boolean isVolatile(int mod) + { + return (mod & VOLATILE) != 0; + } + + /** + * Get a string representation of all the modifiers represented by the + * given int. The keywords are printed in this order: + * <public|protected|private> abstract static final transient + * volatile synchronized native strictfp interface. + * + * @param mod the modifier. + * @return the String representing the modifiers. + */ + public static String toString(int mod) + { + return toString(mod, new StringBuffer()).toString(); + } + + /** + * Package helper method that can take a StringBuffer. + * @param mod the modifier + * @param r the StringBuffer to which the String representation is appended + * @return r, with information appended + */ + static StringBuffer toString(int mod, StringBuffer r) + { + if (isPublic(mod)) + r.append("public "); + if (isProtected(mod)) + r.append("protected "); + if (isPrivate(mod)) + r.append("private "); + if (isAbstract(mod)) + r.append("abstract "); + if (isStatic(mod)) + r.append("static "); + if (isFinal(mod)) + r.append("final "); + if (isTransient(mod)) + r.append("transient "); + if (isVolatile(mod)) + r.append("volatile "); + if (isSynchronized(mod)) + r.append("synchronized "); + if (isNative(mod)) + r.append("native "); + if (isStrict(mod)) + r.append("strictfp "); + if (isInterface(mod)) + r.append("interface "); + + // Trim trailing space. + if ((mod & ALL_FLAGS) != 0) + r.setLength(r.length() - 1); + return r; + } +} diff --git a/libjava/classpath/java/lang/reflect/ParameterizedType.java b/libjava/classpath/java/lang/reflect/ParameterizedType.java new file mode 100644 index 0000000..61081c9 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/ParameterizedType.java @@ -0,0 +1,122 @@ +/* ParameterizedType.java -- Represents parameterized types e.g. List + 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 java.lang.reflect; + +/** + *

    + * Represents a type which is parameterized over one or more other + * types. For example, List<Integer> is a parameterized + * type, with List parameterized over the type + * Integer. + *

    + *

    + * Instances of this classes are created as needed, during reflection. + * On creating a parameterized type, p, the + * GenericTypeDeclaration corresponding to p + * is created and resolved. Each type argument of p + * is then created recursively; details of this process are availble + * in the documentation of TypeVariable. This creation + * process only happens once; repetition has no effect. + *

    + *

    + * Implementors of this interface must implement an appropriate + * equals() method. This method should equate any + * two instances of the implementing class that have the same + * GenericTypeDeclaration and Type + * parameters. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see GenericTypeDeclaration + * @see TypeVariable + * @since 1.5 + */ +public interface ParameterizedType + extends Type +{ + + /** + *

    + * Returns an array of Type objects, which gives + * the parameters of this type. + *

    + *

    + * Note: the returned array may be empty. This + * occurs if the supposed ParameterizedType is simply + * a normal type wrapped inside a parameterized type. + *

    + * + * @return an array of Types, representing the arguments + * of this type. + * @throws TypeNotPresentException if any of the types referred to by + * the parameters of this type do not actually exist. + * @throws MalformedParameterizedTypeException if any of the types + * refer to a type which can not be instantiated. + */ + Type[] getActualTypeArguments(); + + /** + * Returns the type of which this type is a member. For example, + * in Top<String>.Bottom<Integer>, + * Bottom<Integer> is a member of + * Top<String>, and so the latter is returned + * by this method. Calling this method on top-level types (such as + * Top<String>) returns null. + * + * @return the type which owns this type. + * @throws TypeNotPresentException if the owner type referred to by + * this type do not actually exist. + * @throws MalformedParameterizedTypeException if the owner type + * referred to by this type can not be instantiated. + */ + Type getOwnerType(); + + /** + * Returns a version of this type without parameters, which corresponds + * to the class or interface which declared the type. For example, + * the raw type corresponding to List<Double> + * is List, which was declared by the List + * class. + * + * @return the raw variant of this type (i.e. the type without + * parameters). + */ + Type getRawType(); + +} diff --git a/libjava/classpath/java/lang/reflect/Proxy.java b/libjava/classpath/java/lang/reflect/Proxy.java new file mode 100644 index 0000000..dc1ac87 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/Proxy.java @@ -0,0 +1,1615 @@ +/* Proxy.java -- build a proxy class that implements reflected interfaces + Copyright (C) 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 java.lang.reflect; + +import gnu.classpath.Configuration; +import gnu.java.lang.reflect.TypeSignature; + +import java.io.Serializable; +import java.security.ProtectionDomain; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * This class allows you to dynamically create an instance of any (or + * even multiple) interfaces by reflection, and decide at runtime + * how that instance will behave by giving it an appropriate + * {@link InvocationHandler}. Proxy classes serialize specially, so + * that the proxy object can be reused between VMs, without requiring + * a persistent copy of the generated class code. + * + *

    Creation

    + * To create a proxy for some interface Foo: + * + *
    + *   InvocationHandler handler = new MyInvocationHandler(...);
    + *   Class proxyClass = Proxy.getProxyClass(
    + *       Foo.class.getClassLoader(), new Class[] { Foo.class });
    + *   Foo f = (Foo) proxyClass
    + *       .getConstructor(new Class[] { InvocationHandler.class })
    + *       .newInstance(new Object[] { handler });
    + * 
    + * or more simply: + *
    + *   Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
    + *                                        new Class[] { Foo.class },
    + *                                        handler);
    + * 
    + * + *

    Dynamic Proxy Classes

    + * A dynamic proxy class is created at runtime, and has the following + * properties: + *
      + *
    • The class is public and final, + * and is neither abstract nor an inner class.
    • + *
    • The class has no canonical name (there is no formula you can use + * to determine or generate its name), but begins with the + * sequence "$Proxy". Abuse this knowledge at your own peril. + * (For now, '$' in user identifiers is legal, but it may not + * be that way forever. You weren't using '$' in your + * identifiers, were you?)
    • + *
    • The class extends Proxy, and explicitly implements all the + * interfaces specified at creation, in order (this is important + * for determining how method invocation is resolved). Note that + * a proxy class implements {@link Serializable}, at least + * implicitly, since Proxy does, but true serial behavior + * depends on using a serializable invocation handler as well.
    • + *
    • If at least one interface is non-public, the proxy class + * will be in the same package. Otherwise, the package is + * unspecified. This will work even if the package is sealed + * from user-generated classes, because Proxy classes are + * generated by a trusted source. Meanwhile, the proxy class + * belongs to the classloader you designated.
    • + *
    • Reflection works as expected: {@link Class#getInterfaces()} and + * {@link Class#getMethods()} work as they do on normal classes.
    • + *
    • The method {@link #isProxyClass()} will distinguish between + * true proxy classes and user extensions of this class. It only + * returns true for classes created by {@link #getProxyClass}.
    • + *
    • The {@link ProtectionDomain} of a proxy class is the same as for + * bootstrap classes, such as Object or Proxy, since it is created by + * a trusted source. This protection domain will typically be granted + * {@link java.security.AllPermission}. But this is not a security + * risk, since there are adequate permissions on reflection, which is + * the only way to create an instance of the proxy class.
    • + *
    • The proxy class contains a single constructor, which takes as + * its only argument an {@link InvocationHandler}. The method + * {@link #newInstance} is shorthand to do the necessary + * reflection.
    • + *
    + * + *

    Proxy Instances

    + * A proxy instance is an instance of a proxy class. It has the + * following properties, many of which follow from the properties of a + * proxy class listed above: + *
      + *
    • For a proxy class with Foo listed as one of its interfaces, the + * expression proxy instanceof Foo will return true, + * and the expression (Foo) proxy will succeed without + * a {@link ClassCastException}.
    • + *
    • Each proxy instance has an invocation handler, which can be + * accessed by {@link #getInvocationHandler(Object)}. Any call + * to an interface method, including {@link Object#hashcode()}, + * {@link Object#equals(Object)}, or {@link Object#toString()}, + * but excluding the public final methods of Object, will be + * encoded and passed to the {@link InvocationHandler#invoke} + * method of this handler.
    • + *
    + * + *

    Inheritance Issues

    + * A proxy class may inherit a method from more than one interface. + * The order in which interfaces are listed matters, because it determines + * which reflected {@link Method} object will be passed to the invocation + * handler. This means that the dynamically generated class cannot + * determine through which interface a method is being invoked.

    + * + * In short, if a method is declared in Object (namely, hashCode, + * equals, or toString), then Object will be used; otherwise, the + * leftmost interface that inherits or declares a method will be used, + * even if it has a more permissive throws clause than what the proxy + * class is allowed. Thus, in the invocation handler, it is not always + * safe to assume that every class listed in the throws clause of the + * passed Method object can safely be thrown; fortunately, the Proxy + * instance is robust enough to wrap all illegal checked exceptions in + * {@link UndeclaredThrowableException}. + * + * @see InvocationHandler + * @see UndeclaredThrowableException + * @see Class + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4, except for the use of ProtectionDomain + */ +public class Proxy implements Serializable +{ + /** + * Compatible with JDK 1.3+. + */ + private static final long serialVersionUID = -2222568056686623797L; + + /** + * Map of ProxyType to proxy class. + * + * @XXX This prevents proxy classes from being garbage collected. + * java.util.WeakHashSet is not appropriate, because that collects the + * keys, but we are interested in collecting the elements. + */ + private static final Map proxyClasses = new HashMap(); + + /** + * The invocation handler for this proxy instance. For Proxy, this + * field is unused, but it appears here in order to be serialized in all + * proxy classes. + * + * NOTE: This implementation is more secure for proxy classes + * than what Sun specifies. Sun does not require h to be immutable, but + * this means you could change h after the fact by reflection. However, + * by making h immutable, we may break non-proxy classes which extend + * Proxy. + * @serial invocation handler associated with this proxy instance + */ + protected InvocationHandler h; + + /** + * Constructs a new Proxy from a subclass (usually a proxy class), + * with the specified invocation handler. + * + * NOTE: This throws a NullPointerException if you attempt + * to create a proxy instance with a null handler using reflection. + * This behavior is not yet specified by Sun; see Sun Bug 4487672. + * + * @param handler the invocation handler, may be null if the subclass + * is not a proxy class + * @throws NullPointerException if handler is null and this is a proxy + * instance + */ + protected Proxy(InvocationHandler handler) + { + if (handler == null && isProxyClass(getClass())) + throw new NullPointerException("invalid handler"); + h = handler; + } + + /** + * Returns the proxy {@link Class} for the given ClassLoader and array + * of interfaces, dynamically generating it if necessary. + * + *

    There are several restrictions on this method, the violation of + * which will result in an IllegalArgumentException or + * NullPointerException:

    + * + *
      + *
    • All objects in `interfaces' must represent distinct interfaces. + * Classes, primitive types, null, and duplicates are forbidden.
    • + *
    • The interfaces must be visible in the specified ClassLoader. + * In other words, for each interface i: + * Class.forName(i.getName(), false, loader) == i + * must be true.
    • + *
    • All non-public interfaces (if any) must reside in the same + * package, or the proxy class would be non-instantiable. If + * there are no non-public interfaces, the package of the proxy + * class is unspecified.
    • + *
    • All interfaces must be compatible - if two declare a method + * with the same name and parameters, the return type must be + * the same and the throws clause of the proxy class will be + * the maximal subset of subclasses of the throws clauses for + * each method that is overridden.
    • + *
    • VM constraints limit the number of interfaces a proxy class + * may directly implement (however, the indirect inheritance + * of {@link Serializable} does not count against this limit). + * Even though most VMs can theoretically have 65535 + * superinterfaces for a class, the actual limit is smaller + * because a class's constant pool is limited to 65535 entries, + * and not all entries can be interfaces.
    • + *
    + * + *

    Note that different orders of interfaces produce distinct classes.

    + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param interfaces the array of interfaces the proxy class implements, + * may be empty, but not null + * @return the Class object of the proxy class + * @throws IllegalArgumentException if the constraints above were + * violated, except for problems with null + * @throws NullPointerException if `interfaces' is null or contains + * a null entry + */ + // synchronized so that we aren't trying to build the same class + // simultaneously in two threads + public static synchronized Class getProxyClass(ClassLoader loader, + Class[] interfaces) + { + interfaces = (Class[]) interfaces.clone(); + ProxyType pt = new ProxyType(loader, interfaces); + Class clazz = (Class) proxyClasses.get(pt); + if (clazz == null) + { + if (Configuration.HAVE_NATIVE_GET_PROXY_CLASS) + clazz = getProxyClass0(loader, interfaces); + else + { + ProxyData data = (Configuration.HAVE_NATIVE_GET_PROXY_DATA + ? getProxyData0(loader, interfaces) + : ProxyData.getProxyData(pt)); + + clazz = (Configuration.HAVE_NATIVE_GENERATE_PROXY_CLASS + ? generateProxyClass0(loader, data) + : new ClassFactory(data).generate(loader)); + } + + Object check = proxyClasses.put(pt, clazz); + // assert check == null && clazz != null; + if (check != null || clazz == null) + throw new InternalError(/*"Fatal flaw in getProxyClass"*/); + } + return clazz; + } + + /** + * Combines several methods into one. This is equivalent to: + *
    +   *   Proxy.getProxyClass(loader, interfaces)
    +   *       .getConstructor(new Class[] {InvocationHandler.class})
    +   *       .newInstance(new Object[] {handler});
    +   * 
    + * except that it will not fail with the normal problems caused + * by reflection. It can still fail for the same reasons documented + * in getProxyClass, or if handler is null. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param interfaces the array of interfaces the proxy class implements, + * may be empty, but not null + * @param handler the invocation handler, may not be null + * @return a proxy instance implementing the specified interfaces + * @throws IllegalArgumentException if the constraints for getProxyClass + * were violated, except for problems with null + * @throws NullPointerException if `interfaces' is null or contains + * a null entry, or if handler is null + * @see #getProxyClass(ClassLoader, Class[]) + * @see Class#getConstructor(Class[]) + * @see Constructor#newInstance(Object[]) + */ + public static Object newProxyInstance(ClassLoader loader, + Class[] interfaces, + InvocationHandler handler) + { + try + { + // getProxyClass() and Proxy() throw the necessary exceptions + return getProxyClass(loader, interfaces) + .getConstructor(new Class[] {InvocationHandler.class}) + .newInstance(new Object[] {handler}); + } + catch (RuntimeException e) + { + // Let IllegalArgumentException, NullPointerException escape. + // assert e instanceof IllegalArgumentException + // || e instanceof NullPointerException; + throw e; + } + catch (InvocationTargetException e) + { + // Let wrapped NullPointerException escape. + // assert e.getTargetException() instanceof NullPointerException + throw (NullPointerException) e.getCause(); + } + catch (Exception e) + { + // Covers InstantiationException, IllegalAccessException, + // NoSuchMethodException, none of which should be generated + // if the proxy class was generated correctly. + // assert false; + throw (Error) new InternalError("Unexpected: " + e).initCause(e); + } + } + + /** + * Returns true if and only if the Class object is a dynamically created + * proxy class (created by getProxyClass or by the + * syntactic sugar of newProxyInstance). + * + *

    This check is secure (in other words, it is not simply + * clazz.getSuperclass() == Proxy.class), it will not + * be spoofed by non-proxy classes that extend Proxy. + * + * @param clazz the class to check, must not be null + * @return true if the class represents a proxy class + * @throws NullPointerException if clazz is null + */ + // This is synchronized on the off chance that another thread is + // trying to add a class to the map at the same time we read it. + public static synchronized boolean isProxyClass(Class clazz) + { + if (! Proxy.class.isAssignableFrom(clazz)) + return false; + // This is a linear search, even though we could do an O(1) search + // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()). + return proxyClasses.containsValue(clazz); + } + + /** + * Returns the invocation handler for the given proxy instance.

    + * + * NOTE: We guarantee a non-null result if successful, + * but Sun allows the creation of a proxy instance with a null + * handler. See the comments for {@link #Proxy(InvocationHandler)}. + * + * @param proxy the proxy instance, must not be null + * @return the invocation handler, guaranteed non-null. + * @throws IllegalArgumentException if + * Proxy.isProxyClass(proxy.getClass()) returns false. + * @throws NullPointerException if proxy is null + */ + public static InvocationHandler getInvocationHandler(Object proxy) + { + if (! isProxyClass(proxy.getClass())) + throw new IllegalArgumentException("not a proxy instance"); + return ((Proxy) proxy).h; + } + + /** + * Optional native method to replace (and speed up) the pure Java + * implementation of getProxyClass. Only needed if + * Configuration.HAVE_NATIVE_GET_PROXY_CLASS is true, this does the + * work of both getProxyData0 and generateProxyClass0 with no + * intermediate form in Java. The native code may safely assume that + * this class must be created, and does not already exist. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param interfaces the interfaces the class will extend + * @return the generated proxy class + * @throws IllegalArgumentException if the constraints for getProxyClass + * were violated, except for problems with null + * @throws NullPointerException if `interfaces' is null or contains + * a null entry, or if handler is null + * @see Configuration#HAVE_NATIVE_GET_PROXY_CLASS + * @see #getProxyClass(ClassLoader, Class[]) + * @see #getProxyData0(ClassLoader, Class[]) + * @see #generateProxyClass0(ProxyData) + */ + private static native Class getProxyClass0(ClassLoader loader, + Class[] interfaces); + + /** + * Optional native method to replace (and speed up) the pure Java + * implementation of getProxyData. Only needed if + * Configuration.HAVE_NATIVE_GET_PROXY_DATA is true. The native code + * may safely assume that a new ProxyData object must be created which + * does not duplicate any existing ones. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param interfaces the interfaces the class will extend + * @return all data that is required to make this proxy class + * @throws IllegalArgumentException if the constraints for getProxyClass + * were violated, except for problems with null + * @throws NullPointerException if `interfaces' is null or contains + * a null entry, or if handler is null + * @see Configuration.HAVE_NATIVE_GET_PROXY_DATA + * @see #getProxyClass(ClassLoader, Class[]) + * @see #getProxyClass0(ClassLoader, Class[]) + * @see ProxyType#getProxyData() + */ + private static native ProxyData getProxyData0(ClassLoader loader, + Class[] interfaces); + + /** + * Optional native method to replace (and speed up) the pure Java + * implementation of generateProxyClass. Only needed if + * Configuration.HAVE_NATIVE_GENERATE_PROXY_CLASS is true. The native + * code may safely assume that a new Class must be created, and that + * the ProxyData object does not describe any existing class. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param data the struct of information to convert to a Class. This + * has already been verified for all problems except exceeding + * VM limitations + * @return the newly generated class + * @throws IllegalArgumentException if VM limitations are exceeded + * @see #getProxyClass(ClassLoader, Class[]) + * @see #getProxyClass0(ClassLoader, Class[]) + * @see ProxyData#generateProxyClass(ClassLoader) + */ + private static native Class generateProxyClass0(ClassLoader loader, + ProxyData data); + + /** + * Helper class for mapping unique ClassLoader and interface combinations + * to proxy classes. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class ProxyType + { + /** + * Store the class loader (may be null) + */ + final ClassLoader loader; + + /** + * Store the interfaces (never null, all elements are interfaces) + */ + final Class[] interfaces; + + /** + * Construct the helper object. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param interfaces an array of interfaces + */ + ProxyType(ClassLoader loader, Class[] interfaces) + { + if (loader == null) + loader = ClassLoader.getSystemClassLoader(); + this.loader = loader; + this.interfaces = interfaces; + } + + /** + * Calculates the hash code. + * + * @return a combination of the classloader and interfaces hashcodes. + */ + public int hashCode() + { + //loader is always not null + int hash = loader.hashCode(); + for (int i = 0; i < interfaces.length; i++) + hash = hash * 31 + interfaces[i].hashCode(); + return hash; + } + + // A more comprehensive comparison of two arrays, + // ignore array element order, and + // ignore redundant elements + private static boolean sameTypes(Class arr1[], Class arr2[]) { + if (arr1.length == 1 && arr2.length == 1) { + return arr1[0] == arr2[0]; + } + + // total occurrance of elements of arr1 in arr2 + int total_occ_of_arr1_in_arr2 = 0; + each_type: + for (int i = arr1.length; --i >= 0; ) + { + Class t = arr1[i]; + for (int j = i; --j >= 0; ) + { + if (t == arr1[j]) + { //found duplicate type + continue each_type; + } + } + + // count c(a unique element of arr1)'s + // occurrences in arr2 + int occ_in_arr2 = 0; + for (int j = arr2.length; --j >= 0; ) + { + if (t == arr2[j]) + { + ++occ_in_arr2; + } + } + if (occ_in_arr2 == 0) + { // t does not occur in arr2 + return false; + } + + total_occ_of_arr1_in_arr2 += occ_in_arr2; + } + // now, each element of arr2 must have been visited + return total_occ_of_arr1_in_arr2 == arr2.length; + } + + /** + * Calculates equality. + * + * @param the object to compare to + * @return true if it is a ProxyType with same data + */ + public boolean equals(Object other) + { + ProxyType pt = (ProxyType) other; + if (loader != pt.loader || interfaces.length != pt.interfaces.length) + return false; + return sameTypes(interfaces, pt.interfaces); + } + } // class ProxyType + + /** + * Helper class which allows hashing of a method name and signature + * without worrying about return type, declaring class, or throws clause, + * and which reduces the maximally common throws clause between two methods + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class ProxySignature + { + /** + * The core signatures which all Proxy instances handle. + */ + static final HashMap coreMethods = new HashMap(); + static + { + try + { + ProxySignature sig + = new ProxySignature(Object.class + .getMethod("equals", + new Class[] {Object.class})); + coreMethods.put(sig, sig); + sig = new ProxySignature(Object.class.getMethod("hashCode", null)); + coreMethods.put(sig, sig); + sig = new ProxySignature(Object.class.getMethod("toString", null)); + coreMethods.put(sig, sig); + } + catch (Exception e) + { + // assert false; + throw (Error) new InternalError("Unexpected: " + e).initCause(e); + } + } + + /** + * The underlying Method object, never null + */ + final Method method; + + /** + * The set of compatible thrown exceptions, may be empty + */ + final Set exceptions = new HashSet(); + + /** + * Construct a signature + * + * @param method the Method this signature is based on, never null + */ + ProxySignature(Method method) + { + this.method = method; + Class[] exc = method.getExceptionTypes(); + int i = exc.length; + while (--i >= 0) + { + // discard unchecked exceptions + if (Error.class.isAssignableFrom(exc[i]) + || RuntimeException.class.isAssignableFrom(exc[i])) + continue; + exceptions.add(exc[i]); + } + } + + /** + * Given a method, make sure it's return type is identical + * to this, and adjust this signature's throws clause appropriately + * + * @param other the signature to merge in + * @throws IllegalArgumentException if the return types conflict + */ + void checkCompatibility(ProxySignature other) + { + if (method.getReturnType() != other.method.getReturnType()) + throw new IllegalArgumentException("incompatible return types: " + + method + ", " + other.method); + + // if you can think of a more efficient way than this O(n^2) search, + // implement it! + int size1 = exceptions.size(); + int size2 = other.exceptions.size(); + boolean[] valid1 = new boolean[size1]; + boolean[] valid2 = new boolean[size2]; + Iterator itr = exceptions.iterator(); + int pos = size1; + while (--pos >= 0) + { + Class c1 = (Class) itr.next(); + Iterator itr2 = other.exceptions.iterator(); + int pos2 = size2; + while (--pos2 >= 0) + { + Class c2 = (Class) itr2.next(); + if (c2.isAssignableFrom(c1)) + valid1[pos] = true; + if (c1.isAssignableFrom(c2)) + valid2[pos2] = true; + } + } + pos = size1; + itr = exceptions.iterator(); + while (--pos >= 0) + { + itr.next(); + if (! valid1[pos]) + itr.remove(); + } + pos = size2; + itr = other.exceptions.iterator(); + while (--pos >= 0) + { + itr.next(); + if (! valid2[pos]) + itr.remove(); + } + exceptions.addAll(other.exceptions); + } + + /** + * Calculates the hash code. + * + * @return a combination of name and parameter types + */ + public int hashCode() + { + int hash = method.getName().hashCode(); + Class[] types = method.getParameterTypes(); + for (int i = 0; i < types.length; i++) + hash = hash * 31 + types[i].hashCode(); + return hash; + } + + /** + * Calculates equality. + * + * @param the object to compare to + * @return true if it is a ProxySignature with same data + */ + public boolean equals(Object other) + { + ProxySignature ps = (ProxySignature) other; + Class[] types1 = method.getParameterTypes(); + Class[] types2 = ps.method.getParameterTypes(); + if (! method.getName().equals(ps.method.getName()) + || types1.length != types2.length) + return false; + int i = types1.length; + while (--i >= 0) + if (types1[i] != types2[i]) + return false; + return true; + } + } // class ProxySignature + + /** + * A flat representation of all data needed to generate bytecode/instantiate + * a proxy class. This is basically a struct. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class ProxyData + { + /** + * The package this class is in including the trailing dot + * or an empty string for the unnamed (aka default) package. + */ + String pack; + + /** + * The interfaces this class implements. Non-null, but possibly empty. + */ + Class[] interfaces; + + /** + * The Method objects this class must pass as the second argument to + * invoke (also useful for determining what methods this class has). + * Non-null, non-empty (includes at least Object.hashCode, Object.equals, + * and Object.toString). + */ + Method[] methods; + + /** + * The exceptions that do not need to be wrapped in + * UndeclaredThrowableException. exceptions[i] is the same as, or a + * subset of subclasses, of methods[i].getExceptionTypes(), depending on + * compatible throws clauses with multiple inheritance. It is unspecified + * if these lists include or exclude subclasses of Error and + * RuntimeException, but excluding them is harmless and generates a + * smaller class. + */ + Class[][] exceptions; + + /** + * For unique id's + */ + private static int count; + + /** + * The id of this proxy class + */ + final int id = count++; + + /** + * Construct a ProxyData with uninitialized data members. + */ + ProxyData() + { + } + + /** + * Return the name of a package (including the trailing dot) + * given the name of a class. + * Returns an empty string if no package. We use this in preference to + * using Class.getPackage() to avoid problems with ClassLoaders + * that don't set the package. + */ + private static String getPackage(Class k) + { + String name = k.getName(); + int idx = name.lastIndexOf('.'); + return name.substring(0, idx + 1); + } + + /** + * Verifies that the arguments are legal, and sets up remaining data + * This should only be called when a class must be generated, as + * it is expensive. + * + * @param pt the ProxyType to convert to ProxyData + * @return the flattened, verified ProxyData structure for use in + * class generation + * @throws IllegalArgumentException if `interfaces' contains + * non-interfaces or incompatible combinations, and verify is true + * @throws NullPointerException if interfaces is null or contains null + */ + static ProxyData getProxyData(ProxyType pt) + { + Map method_set = (Map) ProxySignature.coreMethods.clone(); + boolean in_package = false; // true if we encounter non-public interface + + ProxyData data = new ProxyData(); + data.interfaces = pt.interfaces; + + // if interfaces is too large, we croak later on when the constant + // pool overflows + int i = data.interfaces.length; + while (--i >= 0) + { + Class inter = data.interfaces[i]; + if (! inter.isInterface()) + throw new IllegalArgumentException("not an interface: " + inter); + try + { + if (Class.forName(inter.getName(), false, pt.loader) != inter) + throw new IllegalArgumentException("not accessible in " + + "classloader: " + inter); + } + catch (ClassNotFoundException e) + { + throw new IllegalArgumentException("not accessible in " + + "classloader: " + inter); + } + if (! Modifier.isPublic(inter.getModifiers())) + if (in_package) + { + String p = getPackage(inter); + if (! data.pack.equals(p)) + throw new IllegalArgumentException("non-public interfaces " + + "from different " + + "packages"); + } + else + { + in_package = true; + data.pack = getPackage(inter); + } + for (int j = i-1; j >= 0; j--) + if (data.interfaces[j] == inter) + throw new IllegalArgumentException("duplicate interface: " + + inter); + Method[] methods = inter.getMethods(); + int j = methods.length; + while (--j >= 0) + { + ProxySignature sig = new ProxySignature(methods[j]); + ProxySignature old = (ProxySignature) method_set.put(sig, sig); + if (old != null) + sig.checkCompatibility(old); + } + } + + i = method_set.size(); + data.methods = new Method[i]; + data.exceptions = new Class[i][]; + Iterator itr = method_set.values().iterator(); + while (--i >= 0) + { + ProxySignature sig = (ProxySignature) itr.next(); + data.methods[i] = sig.method; + data.exceptions[i] = (Class[]) sig.exceptions + .toArray(new Class[sig.exceptions.size()]); + } + return data; + } + } // class ProxyData + + /** + * Does all the work of building a class. By making this a nested class, + * this code is not loaded in memory if the VM has a native + * implementation instead. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class ClassFactory + { + /** Constants for assisting the compilation */ + private static final byte POOL = 0; + private static final byte FIELD = 1; + private static final byte METHOD = 2; + private static final byte INTERFACE = 3; + private static final String CTOR_SIG + = "(Ljava/lang/reflect/InvocationHandler;)V"; + private static final String INVOKE_SIG = "(Ljava/lang/Object;" + + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"; + + /** Bytecodes for insertion in the class definition byte[] */ + private static final char ACONST_NULL = 1; + private static final char ICONST_0 = 3; + private static final char BIPUSH = 16; + private static final char SIPUSH = 17; + private static final char ILOAD = 21; + private static final char ILOAD_0 = 26; + private static final char ALOAD_0 = 42; + private static final char ALOAD_1 = 43; + private static final char AALOAD = 50; + private static final char AASTORE = 83; + private static final char DUP = 89; + private static final char DUP_X1 = 90; + private static final char SWAP = 95; + private static final char IRETURN = 172; + private static final char LRETURN = 173; + private static final char FRETURN = 174; + private static final char DRETURN = 175; + private static final char ARETURN = 176; + private static final char RETURN = 177; + private static final char GETSTATIC = 178; + private static final char GETFIELD = 180; + private static final char INVOKEVIRTUAL = 182; + private static final char INVOKESPECIAL = 183; + private static final char INVOKESTATIC = 184; + private static final char INVOKEINTERFACE = 185; + private static final char NEW = 187; + private static final char ANEWARRAY = 189; + private static final char ATHROW = 191; + private static final char CHECKCAST = 192; + + // Implementation note: we use StringBuffers to hold the byte data, since + // they automatically grow. However, we only use the low 8 bits of + // every char in the array, so we are using twice the necessary memory + // for the ease StringBuffer provides. + + /** The constant pool. */ + private final StringBuffer pool = new StringBuffer(); + /** The rest of the class data. */ + private final StringBuffer stream = new StringBuffer(); + + /** Map of strings to byte sequences, to minimize size of pool. */ + private final Map poolEntries = new HashMap(); + + /** The VM name of this proxy class. */ + private final String qualName; + + /** + * The Method objects the proxy class refers to when calling the + * invocation handler. + */ + private final Method[] methods; + + /** + * Initializes the buffers with the bytecode contents for a proxy class. + * + * @param data the remainder of the class data + * @throws IllegalArgumentException if anything else goes wrong this + * late in the game; as far as I can tell, this will only happen + * if the constant pool overflows, which is possible even when + * the user doesn't exceed the 65535 interface limit + */ + ClassFactory(ProxyData data) + { + methods = data.methods; + + // magic = 0xcafebabe + // minor_version = 0 + // major_version = 46 + // constant_pool_count: place-holder for now + pool.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0"); + // constant_pool[], filled in as we go + + // access_flags + putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC); + // this_class + qualName = (data.pack + "$Proxy" + data.id); + putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false))); + // super_class + putU2(classInfo("java/lang/reflect/Proxy")); + + // interfaces_count + putU2(data.interfaces.length); + // interfaces[] + for (int i = 0; i < data.interfaces.length; i++) + putU2(classInfo(data.interfaces[i])); + + // Recall that Proxy classes serialize specially, so we do not need + // to worry about a method for this field. Instead, we + // just assign it by reflection after the class is successfully loaded. + // fields_count - private static Method[] m; + putU2(1); + // fields[] + // m.access_flags + putU2(Modifier.PRIVATE | Modifier.STATIC); + // m.name_index + putU2(utf8Info("m")); + // m.descriptor_index + putU2(utf8Info("[Ljava/lang/reflect/Method;")); + // m.attributes_count + putU2(0); + // m.attributes[] + + // methods_count - # handler methods, plus + putU2(methods.length + 1); + // methods[] + // .access_flags + putU2(Modifier.PUBLIC); + // .name_index + putU2(utf8Info("")); + // .descriptor_index + putU2(utf8Info(CTOR_SIG)); + // .attributes_count - only Code is needed + putU2(1); + // .Code.attribute_name_index + putU2(utf8Info("Code")); + // .Code.attribute_length = 18 + // .Code.info: + // $Proxynn(InvocationHandler h) { super(h); } + // .Code.max_stack = 2 + // .Code.max_locals = 2 + // .Code.code_length = 6 + // .Code.code[] + stream.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0 + ALOAD_1 + + INVOKESPECIAL); + putU2(refInfo(METHOD, "java/lang/reflect/Proxy", "", CTOR_SIG)); + // .Code.exception_table_length = 0 + // .Code.exception_table[] + // .Code.attributes_count = 0 + // .Code.attributes[] + stream.append(RETURN + "\0\0\0\0"); + + for (int i = methods.length - 1; i >= 0; i--) + emitMethod(i, data.exceptions[i]); + + // attributes_count + putU2(0); + // attributes[] - empty; omit SourceFile attribute + // XXX should we mark this with a Synthetic attribute? + } + + /** + * Produce the bytecode for a single method. + * + * @param i the index of the method we are building + * @param e the exceptions possible for the method + */ + private void emitMethod(int i, Class[] e) + { + // First, we precalculate the method length and other information. + + Method m = methods[i]; + Class[] paramtypes = m.getParameterTypes(); + int wrap_overhead = 0; // max words taken by wrapped primitive + int param_count = 1; // 1 for this + int code_length = 16; // aload_0, getfield, aload_0, getstatic, const, + // aaload, const/aconst_null, invokeinterface + if (i > 5) + { + if (i > Byte.MAX_VALUE) + code_length += 2; // sipush + else + code_length++; // bipush + } + if (paramtypes.length > 0) + { + code_length += 3; // anewarray + if (paramtypes.length > Byte.MAX_VALUE) + code_length += 2; // sipush + else if (paramtypes.length > 5) + code_length++; // bipush + for (int j = 0; j < paramtypes.length; j++) + { + code_length += 4; // dup, const, load, store + Class type = paramtypes[j]; + if (j > 5) + { + if (j > Byte.MAX_VALUE) + code_length += 2; // sipush + else + code_length++; // bipush + } + if (param_count >= 4) + code_length++; // 2-byte load + param_count++; + if (type.isPrimitive()) + { + code_length += 7; // new, dup, invokespecial + if (type == long.class || type == double.class) + { + wrap_overhead = 3; + param_count++; + } + else if (wrap_overhead < 2) + wrap_overhead = 2; + } + } + } + int end_pc = code_length; + Class ret_type = m.getReturnType(); + if (ret_type == void.class) + code_length++; // return + else if (ret_type.isPrimitive()) + code_length += 7; // cast, invokevirtual, return + else + code_length += 4; // cast, return + int exception_count = 0; + boolean throws_throwable = false; + for (int j = 0; j < e.length; j++) + if (e[j] == Throwable.class) + { + throws_throwable = true; + break; + } + if (! throws_throwable) + { + exception_count = e.length + 3; // Throwable, Error, RuntimeException + code_length += 9; // new, dup_x1, swap, invokespecial, athrow + } + int handler_pc = code_length - 1; + StringBuffer signature = new StringBuffer("("); + for (int j = 0; j < paramtypes.length; j++) + signature.append(TypeSignature.getEncodingOfClass(paramtypes[j])); + signature.append(")").append(TypeSignature.getEncodingOfClass(ret_type)); + + // Now we have enough information to emit the method. + + // handler.access_flags + putU2(Modifier.PUBLIC | Modifier.FINAL); + // handler.name_index + putU2(utf8Info(m.getName())); + // handler.descriptor_index + putU2(utf8Info(signature.toString())); + // handler.attributes_count - Code is necessary, Exceptions possible + putU2(e.length > 0 ? 2 : 1); + + // handler.Code.info: + // type name(args) { + // try { + // return (type) h.invoke(this, methods[i], new Object[] {args}); + // } catch ( e) { + // throw e; + // } catch (Throwable t) { + // throw new UndeclaredThrowableException(t); + // } + // } + // Special cases: + // if arg_n is primitive, wrap it + // if method throws Throwable, try-catch is not needed + // if method returns void, return statement not needed + // if method returns primitive, unwrap it + // save space by sharing code for all the declared handlers + + // handler.Code.attribute_name_index + putU2(utf8Info("Code")); + // handler.Code.attribute_length + putU4(12 + code_length + 8 * exception_count); + // handler.Code.max_stack + putU2(param_count == 1 ? 4 : 7 + wrap_overhead); + // handler.Code.max_locals + putU2(param_count); + // handler.Code.code_length + putU4(code_length); + // handler.Code.code[] + putU1(ALOAD_0); + putU1(GETFIELD); + putU2(refInfo(FIELD, "java/lang/reflect/Proxy", "h", + "Ljava/lang/reflect/InvocationHandler;")); + putU1(ALOAD_0); + putU1(GETSTATIC); + putU2(refInfo(FIELD, TypeSignature.getEncodingOfClass(qualName, false), + "m", "[Ljava/lang/reflect/Method;")); + putConst(i); + putU1(AALOAD); + if (paramtypes.length > 0) + { + putConst(paramtypes.length); + putU1(ANEWARRAY); + putU2(classInfo("java/lang/Object")); + param_count = 1; + for (int j = 0; j < paramtypes.length; j++, param_count++) + { + putU1(DUP); + putConst(j); + if (paramtypes[j].isPrimitive()) + { + putU1(NEW); + putU2(classInfo(wrapper(paramtypes[j]))); + putU1(DUP); + } + putLoad(param_count, paramtypes[j]); + if (paramtypes[j].isPrimitive()) + { + putU1(INVOKESPECIAL); + putU2(refInfo(METHOD, wrapper(paramtypes[j]), "", + '(' + (TypeSignature + .getEncodingOfClass(paramtypes[j]) + + ")V"))); + if (paramtypes[j] == long.class + || paramtypes[j] == double.class) + param_count++; + } + putU1(AASTORE); + } + } + else + putU1(ACONST_NULL); + putU1(INVOKEINTERFACE); + putU2(refInfo(INTERFACE, "java/lang/reflect/InvocationHandler", + "invoke", INVOKE_SIG)); + putU1(4); // InvocationHandler, this, Method, Object[] + putU1(0); + if (ret_type == void.class) + putU1(RETURN); + else if (ret_type.isPrimitive()) + { + putU1(CHECKCAST); + putU2(classInfo(wrapper(ret_type))); + putU1(INVOKEVIRTUAL); + putU2(refInfo(METHOD, wrapper(ret_type), + ret_type.getName() + "Value", + "()" + TypeSignature.getEncodingOfClass(ret_type))); + if (ret_type == long.class) + putU1(LRETURN); + else if (ret_type == float.class) + putU1(FRETURN); + else if (ret_type == double.class) + putU1(DRETURN); + else + putU1(IRETURN); + } + else + { + putU1(CHECKCAST); + putU2(classInfo(ret_type)); + putU1(ARETURN); + } + if (! throws_throwable) + { + putU1(NEW); + putU2(classInfo("java/lang/reflect/UndeclaredThrowableException")); + putU1(DUP_X1); + putU1(SWAP); + putU1(INVOKESPECIAL); + putU2(refInfo(METHOD, + "java/lang/reflect/UndeclaredThrowableException", + "", "(Ljava/lang/Throwable;)V")); + putU1(ATHROW); + } + + // handler.Code.exception_table_length + putU2(exception_count); + // handler.Code.exception_table[] + if (! throws_throwable) + { + // handler.Code.exception_table.start_pc + putU2(0); + // handler.Code.exception_table.end_pc + putU2(end_pc); + // handler.Code.exception_table.handler_pc + putU2(handler_pc); + // handler.Code.exception_table.catch_type + putU2(classInfo("java/lang/Error")); + // handler.Code.exception_table.start_pc + putU2(0); + // handler.Code.exception_table.end_pc + putU2(end_pc); + // handler.Code.exception_table.handler_pc + putU2(handler_pc); + // handler.Code.exception_table.catch_type + putU2(classInfo("java/lang/RuntimeException")); + for (int j = 0; j < e.length; j++) + { + // handler.Code.exception_table.start_pc + putU2(0); + // handler.Code.exception_table.end_pc + putU2(end_pc); + // handler.Code.exception_table.handler_pc + putU2(handler_pc); + // handler.Code.exception_table.catch_type + putU2(classInfo(e[j])); + } + // handler.Code.exception_table.start_pc + putU2(0); + // handler.Code.exception_table.end_pc + putU2(end_pc); + // handler.Code.exception_table.handler_pc - + // -8 for undeclared handler, which falls thru to normal one + putU2(handler_pc - 8); + // handler.Code.exception_table.catch_type + putU2(0); + } + // handler.Code.attributes_count + putU2(0); + // handler.Code.attributes[] + + if (e.length > 0) + { + // handler.Exceptions.attribute_name_index + putU2(utf8Info("Exceptions")); + // handler.Exceptions.attribute_length + putU4(2 * e.length + 2); + // handler.Exceptions.number_of_exceptions + putU2(e.length); + // handler.Exceptions.exception_index_table[] + for (int j = 0; j < e.length; j++) + putU2(classInfo(e[j])); + } + } + + /** + * Creates the Class object that corresponds to the bytecode buffers + * built when this object was constructed. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @return the proxy class Class object + */ + Class generate(ClassLoader loader) + { + byte[] bytecode = new byte[pool.length() + stream.length()]; + // More efficient to bypass calling charAt() repetitively. + char[] c = pool.toString().toCharArray(); + int i = c.length; + while (--i >= 0) + bytecode[i] = (byte) c[i]; + c = stream.toString().toCharArray(); + i = c.length; + int j = bytecode.length; + while (i > 0) + bytecode[--j] = (byte) c[--i]; + + // Patch the constant pool size, which we left at 0 earlier. + int count = poolEntries.size() + 1; + bytecode[8] = (byte) (count >> 8); + bytecode[9] = (byte) count; + + try + { + Class vmClassLoader = Class.forName("java.lang.VMClassLoader"); + Class[] types = {ClassLoader.class, String.class, + byte[].class, int.class, int.class, + ProtectionDomain.class }; + Method m = vmClassLoader.getDeclaredMethod("defineClass", types); + // We can bypass the security check of setAccessible(true), since + // we're in the same package. + m.flag = true; + + Object[] args = {loader, qualName, bytecode, new Integer(0), + new Integer(bytecode.length), + Object.class.getProtectionDomain() }; + Class clazz = (Class) m.invoke(null, args); + + // Finally, initialize the m field of the proxy class, before + // returning it. + Field f = clazz.getDeclaredField("m"); + f.flag = true; + // we can share the array, because it is not publicized + f.set(null, methods); + + return clazz; + } + catch (Exception e) + { + // assert false; + throw (Error) new InternalError("Unexpected: " + e).initCause(e); + } + } + + /** + * Put a single byte on the stream. + * + * @param i the information to add (only lowest 8 bits are used) + */ + private void putU1(int i) + { + stream.append((char) i); + } + + /** + * Put two bytes on the stream. + * + * @param i the information to add (only lowest 16 bits are used) + */ + private void putU2(int i) + { + stream.append((char) (i >> 8)).append((char) i); + } + + /** + * Put four bytes on the stream. + * + * @param i the information to add (treated as unsigned) + */ + private void putU4(int i) + { + stream.append((char) (i >> 24)).append((char) (i >> 16)); + stream.append((char) (i >> 8)).append((char) i); + } + + /** + * Put bytecode to load a constant integer on the stream. This only + * needs to work for values less than Short.MAX_VALUE. + * + * @param i the int to add + */ + private void putConst(int i) + { + if (i >= -1 && i <= 5) + putU1(ICONST_0 + i); + else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) + { + putU1(BIPUSH); + putU1(i); + } + else + { + putU1(SIPUSH); + putU2(i); + } + } + + /** + * Put bytecode to load a given local variable on the stream. + * + * @param i the slot to load + * @param type the base type of the load + */ + private void putLoad(int i, Class type) + { + int offset = 0; + if (type == long.class) + offset = 1; + else if (type == float.class) + offset = 2; + else if (type == double.class) + offset = 3; + else if (! type.isPrimitive()) + offset = 4; + if (i < 4) + putU1(ILOAD_0 + 4 * offset + i); + else + { + putU1(ILOAD + offset); + putU1(i); + } + } + + /** + * Given a primitive type, return its wrapper class name. + * + * @param clazz the primitive type (but not void.class) + * @return the internal form of the wrapper class name + */ + private String wrapper(Class clazz) + { + if (clazz == boolean.class) + return "java/lang/Boolean"; + if (clazz == byte.class) + return "java/lang/Byte"; + if (clazz == short.class) + return "java/lang/Short"; + if (clazz == char.class) + return "java/lang/Character"; + if (clazz == int.class) + return "java/lang/Integer"; + if (clazz == long.class) + return "java/lang/Long"; + if (clazz == float.class) + return "java/lang/Float"; + if (clazz == double.class) + return "java/lang/Double"; + // assert false; + return null; + } + + /** + * Returns the entry of this String in the Constant pool, adding it + * if necessary. + * + * @param str the String to resolve + * @return the index of the String in the constant pool + */ + private char utf8Info(String str) + { + String utf8 = toUtf8(str); + int len = utf8.length(); + return poolIndex("\1" + (char) (len >> 8) + (char) (len & 0xff) + utf8); + } + + /** + * Returns the entry of the appropriate class info structure in the + * Constant pool, adding it if necessary. + * + * @param name the class name, in internal form + * @return the index of the ClassInfo in the constant pool + */ + private char classInfo(String name) + { + char index = utf8Info(name); + char[] c = {7, (char) (index >> 8), (char) (index & 0xff)}; + return poolIndex(new String(c)); + } + + /** + * Returns the entry of the appropriate class info structure in the + * Constant pool, adding it if necessary. + * + * @param clazz the class type + * @return the index of the ClassInfo in the constant pool + */ + private char classInfo(Class clazz) + { + return classInfo(TypeSignature.getEncodingOfClass(clazz.getName(), + false)); + } + + /** + * Returns the entry of the appropriate fieldref, methodref, or + * interfacemethodref info structure in the Constant pool, adding it + * if necessary. + * + * @param structure FIELD, METHOD, or INTERFACE + * @param clazz the class name, in internal form + * @param name the simple reference name + * @param type the type of the reference + * @return the index of the appropriate Info structure in the constant pool + */ + private char refInfo(byte structure, String clazz, String name, + String type) + { + char cindex = classInfo(clazz); + char ntindex = nameAndTypeInfo(name, type); + // relies on FIELD == 1, METHOD == 2, INTERFACE == 3 + char[] c = {(char) (structure + 8), + (char) (cindex >> 8), (char) (cindex & 0xff), + (char) (ntindex >> 8), (char) (ntindex & 0xff)}; + return poolIndex(new String(c)); + } + + /** + * Returns the entry of the appropriate nameAndTyperef info structure + * in the Constant pool, adding it if necessary. + * + * @param name the simple name + * @param type the reference type + * @return the index of the NameAndTypeInfo structure in the constant pool + */ + private char nameAndTypeInfo(String name, String type) + { + char nindex = utf8Info(name); + char tindex = utf8Info(type); + char[] c = {12, (char) (nindex >> 8), (char) (nindex & 0xff), + (char) (tindex >> 8), (char) (tindex & 0xff)}; + return poolIndex(new String(c)); + } + + /** + * Converts a regular string to a UTF8 string, where the upper byte + * of every char is 0, and '\\u0000' is not in the string. This is + * basically to use a String as a fancy byte[], and while it is less + * efficient in memory use, it is easier for hashing. + * + * @param str the original, in straight unicode + * @return a modified string, in UTF8 format in the low bytes + */ + private String toUtf8(String str) + { + final char[] ca = str.toCharArray(); + final int len = ca.length; + + // Avoid object creation, if str is already fits UTF8. + int i; + for (i = 0; i < len; i++) + if (ca[i] == 0 || ca[i] > '\u007f') + break; + if (i == len) + return str; + + final StringBuffer sb = new StringBuffer(str); + sb.setLength(i); + for ( ; i < len; i++) + { + final char c = ca[i]; + if (c > 0 && c <= '\u007f') + sb.append(c); + else if (c <= '\u07ff') // includes '\0' + { + sb.append((char) (0xc0 | (c >> 6))); + sb.append((char) (0x80 | (c & 0x6f))); + } + else + { + sb.append((char) (0xe0 | (c >> 12))); + sb.append((char) (0x80 | ((c >> 6) & 0x6f))); + sb.append((char) (0x80 | (c & 0x6f))); + } + } + return sb.toString(); + } + + /** + * Returns the location of a byte sequence (conveniently wrapped in + * a String with all characters between \u0001 and \u00ff inclusive) + * in the constant pool, adding it if necessary. + * + * @param sequence the byte sequence to look for + * @return the index of the sequence + * @throws IllegalArgumentException if this would make the constant + * pool overflow + */ + private char poolIndex(String sequence) + { + Integer i = (Integer) poolEntries.get(sequence); + if (i == null) + { + // pool starts at index 1 + int size = poolEntries.size() + 1; + if (size >= 65535) + throw new IllegalArgumentException("exceeds VM limitations"); + i = new Integer(size); + poolEntries.put(sequence, i); + pool.append(sequence); + } + return (char) i.intValue(); + } + } // class ClassFactory +} diff --git a/libjava/classpath/java/lang/reflect/README b/libjava/classpath/java/lang/reflect/README new file mode 100644 index 0000000..99ea224 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/README @@ -0,0 +1,4 @@ +README for java.lang.reflect: + +java.lang.reflect is now mostly empty. We've carved out the classes that have +to do with the VM and put them into the VM interface. diff --git a/libjava/classpath/java/lang/reflect/ReflectPermission.java b/libjava/classpath/java/lang/reflect/ReflectPermission.java new file mode 100644 index 0000000..56eccf8 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/ReflectPermission.java @@ -0,0 +1,102 @@ +/* ReflectPermission.java - named permission for reflaction + Copyright (C) 2000, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang.reflect; + +import java.security.BasicPermission; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + */ + +/** + * This class implements permissions for reflection. This is a named + * permission, and the only defined name is suppressAccessChecks, which + * allows suppression of normal Java objects when using reflection. + * + * + * + * + * + * + * + * + * + * + * + * + *
    Permission Target NameWhat Permission AllowsRisk of Allowing Permission
    suppressAccessChecksAbility to access fields, invoke methods, and construct objects + * via reflection, including non-public members in contexts where + * such access is not legal at compile-time.This is dangerous. It exposes possibly confidential information, + * and malicious code could interfere with the internals of the Virtual + * Machine by corrupting private data.
    + * + * @author Tom Tromey (tromey@redhat.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public final class ReflectPermission + extends BasicPermission +{ + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = 7412737110241507485L; + + /** + * Construct a ReflectPermission with the given name. + * + * @param name The permission name + */ + public ReflectPermission(String name) + { + super(name); + } + + /** + * Construct a ReflectPermission with the given name. + * + * @param name The permission name + * @param actions The actions; this is ignored and should be null + */ + public ReflectPermission(String name, String actions) + { + super(name, actions); + } +} diff --git a/libjava/classpath/java/lang/reflect/TODO b/libjava/classpath/java/lang/reflect/TODO new file mode 100755 index 0000000..6514c76 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/TODO @@ -0,0 +1,4 @@ +TODO for java.lang.reflect Java side + +- more tests! +- Java 2 support (waiting on java.lang Java 2 support) diff --git a/libjava/classpath/java/lang/reflect/Type.java b/libjava/classpath/java/lang/reflect/Type.java new file mode 100644 index 0000000..c9ea5bf --- /dev/null +++ b/libjava/classpath/java/lang/reflect/Type.java @@ -0,0 +1,55 @@ +/* Type.java - Superinterface for all types. + 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 java.lang.reflect; + +/** + * Represents any Type within the Java programming + * language. This may be a primitive type (e.g. int, + * an array type (e.g. double[]>/code>), a raw type + * (e.g. Calendar), a parameterized type + * (e.g. List<Boolean>, or a type + * variable (e.g. T extends String). + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface Type +{ +} diff --git a/libjava/classpath/java/lang/reflect/UndeclaredThrowableException.java b/libjava/classpath/java/lang/reflect/UndeclaredThrowableException.java new file mode 100644 index 0000000..6d5a800 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/UndeclaredThrowableException.java @@ -0,0 +1,128 @@ +/* UndeclaredThrowableException.java -- wraps an undeclared checked exception + thrown by a Proxy invocation handler + Copyright (C) 2001, 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 java.lang.reflect; + +/** + * This exception class is thrown by a {@link Proxy} instance if + * the {@link InvocationHandler#invoke(Object, Method, Object[]) invoke} + * method of that instance's InvocationHandler attempts to throw an + * exception that not declared by the throws clauses of all of the + * interface methods that the proxy instance is implementing. + * + *

    When thrown by Proxy, this class will always wrap a checked + * exception, never {@link Error} or {@link RuntimeException}, + * which are unchecked. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Proxy + * @see InvocationHandler + * @since 1.3 + * @status updated to 1.4 + */ +public class UndeclaredThrowableException extends RuntimeException +{ + /** + * Compatible with JDK 1.3+. + */ + private static final long serialVersionUID = 330127114055056639L; + + /** + * The immutable exception that this wraps. This field is redundant + * with {@link Throwable#cause}, but is necessary for serial compatibility. + * + * @serial the chained exception + */ + private final Throwable undeclaredThrowable; + + /** + * Wraps the given checked exception into a RuntimeException, with no + * detail message. {@link Throwable#initCause(Throwable)} will fail + * on this instance. + * + * @param cause the undeclared throwable that caused this exception, + * may be null + */ + public UndeclaredThrowableException(Throwable cause) + { + this(cause, null); + } + + /** + * Wraps the given checked exception into a RuntimeException, with the + * specified detail message. {@link Throwable#initCause(Throwable)} will + * fail on this instance. + * + * @param cause the undeclared throwable that caused this exception, + * may be null + * @param message the message, may be null + */ + public UndeclaredThrowableException(Throwable cause, String message) + { + super(message, cause); + undeclaredThrowable = cause; + } + + /** + * Returns the cause of this exception. If this exception was created + * by a {@link Proxy} instance, it will be a non-null checked + * exception. This method pre-dates exception chaining, and is now + * simply a longer way to call getCause(). + * + * @return the cause of this exception, may be null + * @see #getCause() + */ + public Throwable getUndeclaredThrowable() + { + return undeclaredThrowable; + } + + /** + * Returns the cause of this exception. If this exception was created + * by a {@link Proxy} instance, it will be a non-null checked + * exception. + * + * @return the cause of this exception, may be null + * @since 1.4 + */ + public Throwable getCause() + { + return undeclaredThrowable; + } +} diff --git a/libjava/classpath/java/lang/reflect/WildcardType.java b/libjava/classpath/java/lang/reflect/WildcardType.java new file mode 100644 index 0000000..4f78906 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/WildcardType.java @@ -0,0 +1,115 @@ +/* WildcardType.java -- A wildcard type expression e.g. ? extends String + 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 java.lang.reflect; + +/** + * Represents a wildcard type expression, where the type variable + * is unnamed. The simplest example of this is ?, + * which represents any unbounded type. Another example is + * ? extends Number, which specifies any type + * which is a subclass of Number (Number + * is the upper bound). + *

    + *

    + * ? super String gives the type a less common lower bound, + * which means that the type must be either a String or one + * of its superclasses. This can be useful in working with collections. + * You may want a method to add instances of a class to a collection + * with a more generic type (e.g. adding Strings to + * a list of Objects), but don't want to allow users + * to pass in a collection with a more specific type. + *

    + * + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface WildcardType extends Type +{ + + /** + *

    + * Returns an array of Types, which specify the + * lower bounds of this type. The default lower bound is + * null, which causes this method to return an + * empty array. + *

    + *

    + * In generating the array of Types, each + * ParameterizedType or TypeVariable is + * created, (see the documentation for these classes for details of this + * process), if necessary, while all other types are simply + * resolved. + *

    + * + * @return an array of Type objects, representing + * the wildcard type's lower bounds. + * @throws TypeNotPresentException if any of the types referred to by + * the lower bounds of this type do not actually exist. + * @throws MalformedParameterizedTypeException if any of the types + * refer to a type which can not be instantiated. + */ + Type[] getLowerBounds(); + + /** + *

    + * Returns an array of Types, which specify the + * upper bounds of this type. The default upper bound is + * Object, which causes this method to return an + * array, containing just the Type instance for + * Object. + *

    + *

    + * In generating the array of Types, each + * ParameterizedType or TypeVariable is + * created, (see the documentation for these classes for details of this + * process), if necessary, while all other types are simply + * resolved. + *

    + * + * @return an array of Type objects, representing + * the wildcard type's upper bounds. + * @throws TypeNotPresentException if any of the types referred to by + * the upper bounds of this type do not actually exist. + * @throws MalformedParameterizedTypeException if any of the types + * refer to a type which can not be instantiated. + */ + Type[] getUpperBounds(); + +} diff --git a/libjava/classpath/java/lang/reflect/package.html b/libjava/classpath/java/lang/reflect/package.html new file mode 100644 index 0000000..9f7ed63 --- /dev/null +++ b/libjava/classpath/java/lang/reflect/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - java.lang.reflect + + +

    Runtime inspection and manipulation of object classes, methods, arguments +and fields.

    + + + diff --git a/libjava/classpath/java/math/BigDecimal.java b/libjava/classpath/java/math/BigDecimal.java new file mode 100644 index 0000000..d99be0f --- /dev/null +++ b/libjava/classpath/java/math/BigDecimal.java @@ -0,0 +1,517 @@ +/* java.math.BigDecimal -- Arbitrary precision decimals. + Copyright (C) 1999, 2000, 2001, 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 java.math; + +public class BigDecimal extends Number implements Comparable +{ + private BigInteger intVal; + private int scale; + private static final long serialVersionUID = 6108874887143696463L; + + private static final BigDecimal ZERO = + new BigDecimal (BigInteger.valueOf (0), 0); + + private static final BigDecimal ONE = + new BigDecimal (BigInteger.valueOf (1), 0); + + public static final int ROUND_UP = 0; + public static final int ROUND_DOWN = 1; + public static final int ROUND_CEILING = 2; + public static final int ROUND_FLOOR = 3; + public static final int ROUND_HALF_UP = 4; + public static final int ROUND_HALF_DOWN = 5; + public static final int ROUND_HALF_EVEN = 6; + public static final int ROUND_UNNECESSARY = 7; + + public BigDecimal (BigInteger num) + { + this (num, 0); + } + + public BigDecimal (BigInteger num, int scale) throws NumberFormatException + { + if (scale < 0) + throw new NumberFormatException ("scale of " + scale + " is < 0"); + this.intVal = num; + this.scale = scale; + } + + public BigDecimal (double num) throws NumberFormatException + { + if (Double.isInfinite (num) || Double.isNaN (num)) + throw new NumberFormatException ("invalid argument: " + num); + // Note we can't convert NUM to a String and then use the + // String-based constructor. The BigDecimal documentation makes + // it clear that the two constructors work differently. + + final int mantissaBits = 52; + final int exponentBits = 11; + final long mantMask = (1L << mantissaBits) - 1; + final long expMask = (1L << exponentBits) - 1; + + long bits = Double.doubleToLongBits (num); + long mantissa = bits & mantMask; + long exponent = (bits >>> mantissaBits) & expMask; + boolean denormal = exponent == 0; + // Correct the exponent for the bias. + exponent -= denormal ? 1022 : 1023; + // Now correct the exponent to account for the bits to the right + // of the decimal. + exponent -= mantissaBits; + // Ordinary numbers have an implied leading `1' bit. + if (! denormal) + mantissa |= (1L << mantissaBits); + + // Shave off factors of 10. + while (exponent < 0 && (mantissa & 1) == 0) + { + ++exponent; + mantissa >>= 1; + } + + intVal = BigInteger.valueOf (bits < 0 ? - mantissa : mantissa); + if (exponent < 0) + { + // We have MANTISSA * 2 ^ (EXPONENT). + // Since (1/2)^N == 5^N * 10^-N we can easily convert this + // into a power of 10. + scale = (int) (- exponent); + BigInteger mult = BigInteger.valueOf (5).pow (scale); + intVal = intVal.multiply (mult); + } + else + { + intVal = intVal.shiftLeft ((int) exponent); + scale = 0; + } + } + + public BigDecimal (String num) throws NumberFormatException + { + int len = num.length(); + int start = 0, point = 0; + int dot = -1; + boolean negative = false; + if (num.charAt(0) == '+') + { + ++start; + ++point; + } + else if (num.charAt(0) == '-') + { + ++start; + ++point; + negative = true; + } + + while (point < len) + { + char c = num.charAt (point); + if (c == '.') + { + if (dot >= 0) + throw new NumberFormatException ("multiple `.'s in number"); + dot = point; + } + else if (c == 'e' || c == 'E') + break; + else if (Character.digit (c, 10) < 0) + throw new NumberFormatException ("unrecognized character: " + c); + ++point; + } + + String val; + if (dot >= 0) + { + val = num.substring (start, dot) + num.substring (dot + 1, point); + scale = point - 1 - dot; + } + else + { + val = num.substring (start, point); + scale = 0; + } + if (val.length () == 0) + throw new NumberFormatException ("no digits seen"); + + if (negative) + val = "-" + val; + intVal = new BigInteger (val); + + // Now parse exponent. + if (point < len) + { + point++; + if (num.charAt(point) == '+') + point++; + + if (point >= len ) + throw new NumberFormatException ("no exponent following e or E"); + + try + { + int exp = Integer.parseInt (num.substring (point)); + exp -= scale; + if (signum () == 0) + scale = 0; + else if (exp > 0) + { + intVal = intVal.multiply (BigInteger.valueOf (10).pow (exp)); + scale = 0; + } + else + scale = - exp; + } + catch (NumberFormatException ex) + { + throw new NumberFormatException ("malformed exponent"); + } + } + } + + public static BigDecimal valueOf (long val) + { + return valueOf (val, 0); + } + + public static BigDecimal valueOf (long val, int scale) + throws NumberFormatException + { + if ((scale == 0) && ((int)val == val)) + switch ((int) val) + { + case 0: + return ZERO; + case 1: + return ONE; + } + + return new BigDecimal (BigInteger.valueOf (val), scale); + } + + public BigDecimal add (BigDecimal val) + { + // For addition, need to line up decimals. Note that the movePointRight + // method cannot be used for this as it might return a BigDecimal with + // scale == 0 instead of the scale we need. + BigInteger op1 = intVal; + BigInteger op2 = val.intVal; + if (scale < val.scale) + op1 = op1.multiply (BigInteger.valueOf (10).pow (val.scale - scale)); + else if (scale > val.scale) + op2 = op2.multiply (BigInteger.valueOf (10).pow (scale - val.scale)); + + return new BigDecimal (op1.add (op2), Math.max (scale, val.scale)); + } + + public BigDecimal subtract (BigDecimal val) + { + return this.add(val.negate()); + } + + public BigDecimal multiply (BigDecimal val) + { + return new BigDecimal (intVal.multiply (val.intVal), scale + val.scale); + } + + public BigDecimal divide (BigDecimal val, int roundingMode) + throws ArithmeticException, IllegalArgumentException + { + return divide (val, scale, roundingMode); + } + + public BigDecimal divide(BigDecimal val, int newScale, int roundingMode) + throws ArithmeticException, IllegalArgumentException + { + if (roundingMode < 0 || roundingMode > 7) + throw + new IllegalArgumentException("illegal rounding mode: " + roundingMode); + + if (newScale < 0) + throw new ArithmeticException ("scale is negative: " + newScale); + + if (intVal.signum () == 0) // handle special case of 0.0/0.0 + return newScale == 0 ? ZERO : new BigDecimal (ZERO.intVal, newScale); + + // Ensure that pow gets a non-negative value. + BigInteger valIntVal = val.intVal; + int power = newScale - (scale - val.scale); + if (power < 0) + { + // Effectively increase the scale of val to avoid an + // ArithmeticException for a negative power. + valIntVal = valIntVal.multiply (BigInteger.valueOf (10).pow (-power)); + power = 0; + } + + BigInteger dividend = intVal.multiply (BigInteger.valueOf (10).pow (power)); + + BigInteger parts[] = dividend.divideAndRemainder (valIntVal); + + BigInteger unrounded = parts[0]; + if (parts[1].signum () == 0) // no remainder, no rounding necessary + return new BigDecimal (unrounded, newScale); + + if (roundingMode == ROUND_UNNECESSARY) + throw new ArithmeticException ("newScale is not large enough"); + + int sign = intVal.signum () * valIntVal.signum (); + + if (roundingMode == ROUND_CEILING) + roundingMode = (sign > 0) ? ROUND_UP : ROUND_DOWN; + else if (roundingMode == ROUND_FLOOR) + roundingMode = (sign < 0) ? ROUND_UP : ROUND_DOWN; + else + { + // half is -1 if remainder*2 < positive intValue (*power), 0 if equal, + // 1 if >. This implies that the remainder to round is less than, + // equal to, or greater than half way to the next digit. + BigInteger posRemainder + = parts[1].signum () < 0 ? parts[1].negate() : parts[1]; + valIntVal = valIntVal.signum () < 0 ? valIntVal.negate () : valIntVal; + int half = posRemainder.shiftLeft(1).compareTo(valIntVal); + + switch(roundingMode) + { + case ROUND_HALF_UP: + roundingMode = (half < 0) ? ROUND_DOWN : ROUND_UP; + break; + case ROUND_HALF_DOWN: + roundingMode = (half > 0) ? ROUND_UP : ROUND_DOWN; + break; + case ROUND_HALF_EVEN: + if (half < 0) + roundingMode = ROUND_DOWN; + else if (half > 0) + roundingMode = ROUND_UP; + else if (unrounded.testBit(0)) // odd, then ROUND_HALF_UP + roundingMode = ROUND_UP; + else // even, ROUND_HALF_DOWN + roundingMode = ROUND_DOWN; + break; + } + } + + if (roundingMode == ROUND_UP) + unrounded = unrounded.add (BigInteger.valueOf (sign > 0 ? 1 : -1)); + + // roundingMode == ROUND_DOWN + return new BigDecimal (unrounded, newScale); + } + + public int compareTo (BigDecimal val) + { + if (scale == val.scale) + return intVal.compareTo (val.intVal); + + BigInteger thisParts[] = + intVal.divideAndRemainder (BigInteger.valueOf (10).pow (scale)); + BigInteger valParts[] = + val.intVal.divideAndRemainder (BigInteger.valueOf (10).pow (val.scale)); + + int compare; + if ((compare = thisParts[0].compareTo (valParts[0])) != 0) + return compare; + + // quotients are the same, so compare remainders + + // remove trailing zeros + if (thisParts[1].equals (BigInteger.valueOf (0)) == false) + while (thisParts[1].mod (BigInteger.valueOf (10)).equals + (BigInteger.valueOf (0))) + thisParts[1] = thisParts[1].divide (BigInteger.valueOf (10)); + // again... + if (valParts[1].equals(BigInteger.valueOf (0)) == false) + while (valParts[1].mod (BigInteger.valueOf (10)).equals + (BigInteger.valueOf (0))) + valParts[1] = valParts[1].divide (BigInteger.valueOf (10)); + + // and compare them + return thisParts[1].compareTo (valParts[1]); + } + + public int compareTo (Object val) + { + return(compareTo((BigDecimal)val)); + } + + public boolean equals (Object o) + { + return (o instanceof BigDecimal + && scale == ((BigDecimal) o).scale + && compareTo ((BigDecimal) o) == 0); + } + + public int hashCode() + { + return intValue() ^ scale; + } + + public BigDecimal max (BigDecimal val) + { + switch (compareTo (val)) + { + case 1: + return this; + default: + return val; + } + } + + public BigDecimal min (BigDecimal val) + { + switch (compareTo (val)) + { + case -1: + return this; + default: + return val; + } + } + + public BigDecimal movePointLeft (int n) + { + return (n < 0) ? movePointRight (-n) : new BigDecimal (intVal, scale + n); + } + + public BigDecimal movePointRight (int n) + { + if (n < 0) + return movePointLeft (-n); + + if (scale >= n) + return new BigDecimal (intVal, scale - n); + + return new BigDecimal (intVal.multiply + (BigInteger.valueOf (10).pow (n - scale)), 0); + } + + public int signum () + { + return intVal.signum (); + } + + public int scale () + { + return scale; + } + + public BigInteger unscaledValue() + { + return intVal; + } + + public BigDecimal abs () + { + return new BigDecimal (intVal.abs (), scale); + } + + public BigDecimal negate () + { + return new BigDecimal (intVal.negate (), scale); + } + + public String toString () + { + String bigStr = intVal.toString(); + if (scale == 0) + return bigStr; + + boolean negative = (bigStr.charAt(0) == '-'); + + int point = bigStr.length() - scale - (negative ? 1 : 0); + + StringBuffer sb = new StringBuffer(bigStr.length() + 2 + + (point <= 0 ? (-point + 1) : 0)); + if (point <= 0) + { + if (negative) + sb.append('-'); + sb.append('0').append('.'); + while (point < 0) + { + sb.append('0'); + point++; + } + sb.append(bigStr.substring(negative ? 1 : 0)); + } + else + { + sb.append(bigStr); + sb.insert(point + (negative ? 1 : 0), '.'); + } + return sb.toString(); + } + + public BigInteger toBigInteger () + { + return scale == 0 ? intVal : + intVal.divide (BigInteger.valueOf (10).pow (scale)); + } + + public int intValue () + { + return toBigInteger ().intValue (); + } + + public long longValue () + { + return toBigInteger().longValue(); + } + + public float floatValue() + { + return Float.valueOf(toString()).floatValue(); + } + + public double doubleValue() + { + return Double.valueOf(toString()).doubleValue(); + } + + public BigDecimal setScale (int scale) throws ArithmeticException + { + return setScale (scale, ROUND_UNNECESSARY); + } + + public BigDecimal setScale (int scale, int roundingMode) + throws ArithmeticException, IllegalArgumentException + { + return divide (ONE, scale, roundingMode); + } +} diff --git a/libjava/classpath/java/math/BigInteger.java b/libjava/classpath/java/math/BigInteger.java new file mode 100644 index 0000000..82f550d --- /dev/null +++ b/libjava/classpath/java/math/BigInteger.java @@ -0,0 +1,2230 @@ +/* java.math.BigInteger -- Arbitary precision integers + Copyright (C) 1998, 1999, 2000, 2001, 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 java.math; + +import gnu.java.math.MPN; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Random; + +/** + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998) and + * "Applied Cryptography, Second Edition" by Bruce Schneier (Wiley, 1996). + * + * Based primarily on IntNum.java BitOps.java by Per Bothner (per@bothner.com) + * (found in Kawa 1.6.62). + * + * @author Warren Levy (warrenl@cygnus.com) + * @date December 20, 1999. + * @status believed complete and correct. + */ +public class BigInteger extends Number implements Comparable +{ + /** All integers are stored in 2's-complement form. + * If words == null, the ival is the value of this BigInteger. + * Otherwise, the first ival elements of words make the value + * of this BigInteger, stored in little-endian order, 2's-complement form. */ + private transient int ival; + private transient int[] words; + + // Serialization fields. + private int bitCount = -1; + private int bitLength = -1; + private int firstNonzeroByteNum = -2; + private int lowestSetBit = -2; + private byte[] magnitude; + private int signum; + private static final long serialVersionUID = -8287574255936472291L; + + + /** We pre-allocate integers in the range minFixNum..maxFixNum. */ + private static final int minFixNum = -100; + private static final int maxFixNum = 1024; + private static final int numFixNum = maxFixNum-minFixNum+1; + private static final BigInteger[] smallFixNums = new BigInteger[numFixNum]; + + static { + for (int i = numFixNum; --i >= 0; ) + smallFixNums[i] = new BigInteger(i + minFixNum); + } + + // JDK1.2 + public static final BigInteger ZERO = smallFixNums[-minFixNum]; + + // JDK1.2 + public static final BigInteger ONE = smallFixNums[1 - minFixNum]; + + /* Rounding modes: */ + private static final int FLOOR = 1; + private static final int CEILING = 2; + private static final int TRUNCATE = 3; + private static final int ROUND = 4; + + /** When checking the probability of primes, it is most efficient to + * first check the factoring of small primes, so we'll use this array. + */ + private static final int[] primes = + { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, + 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, + 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251 }; + + /** HAC (Handbook of Applied Cryptography), Alfred Menezes & al. Table 4.4. */ + private static final int[] k = + {100,150,200,250,300,350,400,500,600,800,1250, Integer.MAX_VALUE}; + private static final int[] t = + { 27, 18, 15, 12, 9, 8, 7, 6, 5, 4, 3, 2}; + + private BigInteger() + { + } + + /* Create a new (non-shared) BigInteger, and initialize to an int. */ + private BigInteger(int value) + { + ival = value; + } + + public BigInteger(String val, int radix) + { + BigInteger result = valueOf(val, radix); + this.ival = result.ival; + this.words = result.words; + } + + public BigInteger(String val) + { + this(val, 10); + } + + /* Create a new (non-shared) BigInteger, and initialize from a byte array. */ + public BigInteger(byte[] val) + { + if (val == null || val.length < 1) + throw new NumberFormatException(); + + words = byteArrayToIntArray(val, val[0] < 0 ? -1 : 0); + BigInteger result = make(words, words.length); + this.ival = result.ival; + this.words = result.words; + } + + public BigInteger(int signum, byte[] magnitude) + { + if (magnitude == null || signum > 1 || signum < -1) + throw new NumberFormatException(); + + if (signum == 0) + { + int i; + for (i = magnitude.length - 1; i >= 0 && magnitude[i] == 0; --i) + ; + if (i >= 0) + throw new NumberFormatException(); + return; + } + + // Magnitude is always positive, so don't ever pass a sign of -1. + words = byteArrayToIntArray(magnitude, 0); + BigInteger result = make(words, words.length); + this.ival = result.ival; + this.words = result.words; + + if (signum < 0) + setNegative(); + } + + public BigInteger(int numBits, Random rnd) + { + if (numBits < 0) + throw new IllegalArgumentException(); + + init(numBits, rnd); + } + + private void init(int numBits, Random rnd) + { + int highbits = numBits & 31; + if (highbits > 0) + highbits = rnd.nextInt() >>> (32 - highbits); + int nwords = numBits / 32; + + while (highbits == 0 && nwords > 0) + { + highbits = rnd.nextInt(); + --nwords; + } + if (nwords == 0 && highbits >= 0) + { + ival = highbits; + } + else + { + ival = highbits < 0 ? nwords + 2 : nwords + 1; + words = new int[ival]; + words[nwords] = highbits; + while (--nwords >= 0) + words[nwords] = rnd.nextInt(); + } + } + + public BigInteger(int bitLength, int certainty, Random rnd) + { + this(bitLength, rnd); + + // Keep going until we find a probable prime. + while (true) + { + if (isProbablePrime(certainty)) + return; + + init(bitLength, rnd); + } + } + + /** + * Return a BigInteger that is bitLength bits long with a + * probability < 2^-100 of being composite. + * + * @param bitLength length in bits of resulting number + * @param rnd random number generator to use + * @throws ArithmeticException if bitLength < 2 + * @since 1.4 + */ + public static BigInteger probablePrime(int bitLength, Random rnd) + { + if (bitLength < 2) + throw new ArithmeticException(); + + return new BigInteger(bitLength, 100, rnd); + } + + /** Return a (possibly-shared) BigInteger with a given long value. */ + public static BigInteger valueOf(long val) + { + if (val >= minFixNum && val <= maxFixNum) + return smallFixNums[(int) val - minFixNum]; + int i = (int) val; + if ((long) i == val) + return new BigInteger(i); + BigInteger result = alloc(2); + result.ival = 2; + result.words[0] = i; + result.words[1] = (int)(val >> 32); + return result; + } + + /** Make a canonicalized BigInteger from an array of words. + * The array may be reused (without copying). */ + private static BigInteger make(int[] words, int len) + { + if (words == null) + return valueOf(len); + len = BigInteger.wordsNeeded(words, len); + if (len <= 1) + return len == 0 ? ZERO : valueOf(words[0]); + BigInteger num = new BigInteger(); + num.words = words; + num.ival = len; + return num; + } + + /** Convert a big-endian byte array to a little-endian array of words. */ + private static int[] byteArrayToIntArray(byte[] bytes, int sign) + { + // Determine number of words needed. + int[] words = new int[bytes.length/4 + 1]; + int nwords = words.length; + + // Create a int out of modulo 4 high order bytes. + int bptr = 0; + int word = sign; + for (int i = bytes.length % 4; i > 0; --i, bptr++) + word = (word << 8) | (bytes[bptr] & 0xff); + words[--nwords] = word; + + // Elements remaining in byte[] are a multiple of 4. + while (nwords > 0) + words[--nwords] = bytes[bptr++] << 24 | + (bytes[bptr++] & 0xff) << 16 | + (bytes[bptr++] & 0xff) << 8 | + (bytes[bptr++] & 0xff); + return words; + } + + /** Allocate a new non-shared BigInteger. + * @param nwords number of words to allocate + */ + private static BigInteger alloc(int nwords) + { + BigInteger result = new BigInteger(); + if (nwords > 1) + result.words = new int[nwords]; + return result; + } + + /** Change words.length to nwords. + * We allow words.length to be upto nwords+2 without reallocating. + */ + private void realloc(int nwords) + { + if (nwords == 0) + { + if (words != null) + { + if (ival > 0) + ival = words[0]; + words = null; + } + } + else if (words == null + || words.length < nwords + || words.length > nwords + 2) + { + int[] new_words = new int [nwords]; + if (words == null) + { + new_words[0] = ival; + ival = 1; + } + else + { + if (nwords < ival) + ival = nwords; + System.arraycopy(words, 0, new_words, 0, ival); + } + words = new_words; + } + } + + private boolean isNegative() + { + return (words == null ? ival : words[ival - 1]) < 0; + } + + public int signum() + { + int top = words == null ? ival : words[ival-1]; + if (top == 0 && words == null) + return 0; + return top < 0 ? -1 : 1; + } + + private static int compareTo(BigInteger x, BigInteger y) + { + if (x.words == null && y.words == null) + return x.ival < y.ival ? -1 : x.ival > y.ival ? 1 : 0; + boolean x_negative = x.isNegative(); + boolean y_negative = y.isNegative(); + if (x_negative != y_negative) + return x_negative ? -1 : 1; + int x_len = x.words == null ? 1 : x.ival; + int y_len = y.words == null ? 1 : y.ival; + if (x_len != y_len) + return (x_len > y_len) != x_negative ? 1 : -1; + return MPN.cmp(x.words, y.words, x_len); + } + + // JDK1.2 + public int compareTo(Object obj) + { + if (obj instanceof BigInteger) + return compareTo(this, (BigInteger) obj); + throw new ClassCastException(); + } + + public int compareTo(BigInteger val) + { + return compareTo(this, val); + } + + public BigInteger min(BigInteger val) + { + return compareTo(this, val) < 0 ? this : val; + } + + public BigInteger max(BigInteger val) + { + return compareTo(this, val) > 0 ? this : val; + } + + private boolean isZero() + { + return words == null && ival == 0; + } + + private boolean isOne() + { + return words == null && ival == 1; + } + + /** Calculate how many words are significant in words[0:len-1]. + * Returns the least value x such that x>0 && words[0:x-1]==words[0:len-1], + * when words is viewed as a 2's complement integer. + */ + private static int wordsNeeded(int[] words, int len) + { + int i = len; + if (i > 0) + { + int word = words[--i]; + if (word == -1) + { + while (i > 0 && (word = words[i - 1]) < 0) + { + i--; + if (word != -1) break; + } + } + else + { + while (word == 0 && i > 0 && (word = words[i - 1]) >= 0) i--; + } + } + return i + 1; + } + + private BigInteger canonicalize() + { + if (words != null + && (ival = BigInteger.wordsNeeded(words, ival)) <= 1) + { + if (ival == 1) + ival = words[0]; + words = null; + } + if (words == null && ival >= minFixNum && ival <= maxFixNum) + return smallFixNums[ival - minFixNum]; + return this; + } + + /** Add two ints, yielding a BigInteger. */ + private static BigInteger add(int x, int y) + { + return valueOf((long) x + (long) y); + } + + /** Add a BigInteger and an int, yielding a new BigInteger. */ + private static BigInteger add(BigInteger x, int y) + { + if (x.words == null) + return BigInteger.add(x.ival, y); + BigInteger result = new BigInteger(0); + result.setAdd(x, y); + return result.canonicalize(); + } + + /** Set this to the sum of x and y. + * OK if x==this. */ + private void setAdd(BigInteger x, int y) + { + if (x.words == null) + { + set((long) x.ival + (long) y); + return; + } + int len = x.ival; + realloc(len + 1); + long carry = y; + for (int i = 0; i < len; i++) + { + carry += ((long) x.words[i] & 0xffffffffL); + words[i] = (int) carry; + carry >>= 32; + } + if (x.words[len - 1] < 0) + carry--; + words[len] = (int) carry; + ival = wordsNeeded(words, len + 1); + } + + /** Destructively add an int to this. */ + private void setAdd(int y) + { + setAdd(this, y); + } + + /** Destructively set the value of this to a long. */ + private void set(long y) + { + int i = (int) y; + if ((long) i == y) + { + ival = i; + words = null; + } + else + { + realloc(2); + words[0] = i; + words[1] = (int) (y >> 32); + ival = 2; + } + } + + /** Destructively set the value of this to the given words. + * The words array is reused, not copied. */ + private void set(int[] words, int length) + { + this.ival = length; + this.words = words; + } + + /** Destructively set the value of this to that of y. */ + private void set(BigInteger y) + { + if (y.words == null) + set(y.ival); + else if (this != y) + { + realloc(y.ival); + System.arraycopy(y.words, 0, words, 0, y.ival); + ival = y.ival; + } + } + + /** Add two BigIntegers, yielding their sum as another BigInteger. */ + private static BigInteger add(BigInteger x, BigInteger y, int k) + { + if (x.words == null && y.words == null) + return valueOf((long) k * (long) y.ival + (long) x.ival); + if (k != 1) + { + if (k == -1) + y = BigInteger.neg(y); + else + y = BigInteger.times(y, valueOf(k)); + } + if (x.words == null) + return BigInteger.add(y, x.ival); + if (y.words == null) + return BigInteger.add(x, y.ival); + // Both are big + if (y.ival > x.ival) + { // Swap so x is longer then y. + BigInteger tmp = x; x = y; y = tmp; + } + BigInteger result = alloc(x.ival + 1); + int i = y.ival; + long carry = MPN.add_n(result.words, x.words, y.words, i); + long y_ext = y.words[i - 1] < 0 ? 0xffffffffL : 0; + for (; i < x.ival; i++) + { + carry += ((long) x.words[i] & 0xffffffffL) + y_ext;; + result.words[i] = (int) carry; + carry >>>= 32; + } + if (x.words[i - 1] < 0) + y_ext--; + result.words[i] = (int) (carry + y_ext); + result.ival = i+1; + return result.canonicalize(); + } + + public BigInteger add(BigInteger val) + { + return add(this, val, 1); + } + + public BigInteger subtract(BigInteger val) + { + return add(this, val, -1); + } + + private static BigInteger times(BigInteger x, int y) + { + if (y == 0) + return ZERO; + if (y == 1) + return x; + int[] xwords = x.words; + int xlen = x.ival; + if (xwords == null) + return valueOf((long) xlen * (long) y); + boolean negative; + BigInteger result = BigInteger.alloc(xlen + 1); + if (xwords[xlen - 1] < 0) + { + negative = true; + negate(result.words, xwords, xlen); + xwords = result.words; + } + else + negative = false; + if (y < 0) + { + negative = !negative; + y = -y; + } + result.words[xlen] = MPN.mul_1(result.words, xwords, xlen, y); + result.ival = xlen + 1; + if (negative) + result.setNegative(); + return result.canonicalize(); + } + + private static BigInteger times(BigInteger x, BigInteger y) + { + if (y.words == null) + return times(x, y.ival); + if (x.words == null) + return times(y, x.ival); + boolean negative = false; + int[] xwords; + int[] ywords; + int xlen = x.ival; + int ylen = y.ival; + if (x.isNegative()) + { + negative = true; + xwords = new int[xlen]; + negate(xwords, x.words, xlen); + } + else + { + negative = false; + xwords = x.words; + } + if (y.isNegative()) + { + negative = !negative; + ywords = new int[ylen]; + negate(ywords, y.words, ylen); + } + else + ywords = y.words; + // Swap if x is shorter then y. + if (xlen < ylen) + { + int[] twords = xwords; xwords = ywords; ywords = twords; + int tlen = xlen; xlen = ylen; ylen = tlen; + } + BigInteger result = BigInteger.alloc(xlen+ylen); + MPN.mul(result.words, xwords, xlen, ywords, ylen); + result.ival = xlen+ylen; + if (negative) + result.setNegative(); + return result.canonicalize(); + } + + public BigInteger multiply(BigInteger y) + { + return times(this, y); + } + + private static void divide(long x, long y, + BigInteger quotient, BigInteger remainder, + int rounding_mode) + { + boolean xNegative, yNegative; + if (x < 0) + { + xNegative = true; + if (x == Long.MIN_VALUE) + { + divide(valueOf(x), valueOf(y), + quotient, remainder, rounding_mode); + return; + } + x = -x; + } + else + xNegative = false; + + if (y < 0) + { + yNegative = true; + if (y == Long.MIN_VALUE) + { + if (rounding_mode == TRUNCATE) + { // x != Long.Min_VALUE implies abs(x) < abs(y) + if (quotient != null) + quotient.set(0); + if (remainder != null) + remainder.set(x); + } + else + divide(valueOf(x), valueOf(y), + quotient, remainder, rounding_mode); + return; + } + y = -y; + } + else + yNegative = false; + + long q = x / y; + long r = x % y; + boolean qNegative = xNegative ^ yNegative; + + boolean add_one = false; + if (r != 0) + { + switch (rounding_mode) + { + case TRUNCATE: + break; + case CEILING: + case FLOOR: + if (qNegative == (rounding_mode == FLOOR)) + add_one = true; + break; + case ROUND: + add_one = r > ((y - (q & 1)) >> 1); + break; + } + } + if (quotient != null) + { + if (add_one) + q++; + if (qNegative) + q = -q; + quotient.set(q); + } + if (remainder != null) + { + // The remainder is by definition: X-Q*Y + if (add_one) + { + // Subtract the remainder from Y. + r = y - r; + // In this case, abs(Q*Y) > abs(X). + // So sign(remainder) = -sign(X). + xNegative = ! xNegative; + } + else + { + // If !add_one, then: abs(Q*Y) <= abs(X). + // So sign(remainder) = sign(X). + } + if (xNegative) + r = -r; + remainder.set(r); + } + } + + /** Divide two integers, yielding quotient and remainder. + * @param x the numerator in the division + * @param y the denominator in the division + * @param quotient is set to the quotient of the result (iff quotient!=null) + * @param remainder is set to the remainder of the result + * (iff remainder!=null) + * @param rounding_mode one of FLOOR, CEILING, TRUNCATE, or ROUND. + */ + private static void divide(BigInteger x, BigInteger y, + BigInteger quotient, BigInteger remainder, + int rounding_mode) + { + if ((x.words == null || x.ival <= 2) + && (y.words == null || y.ival <= 2)) + { + long x_l = x.longValue(); + long y_l = y.longValue(); + if (x_l != Long.MIN_VALUE && y_l != Long.MIN_VALUE) + { + divide(x_l, y_l, quotient, remainder, rounding_mode); + return; + } + } + + boolean xNegative = x.isNegative(); + boolean yNegative = y.isNegative(); + boolean qNegative = xNegative ^ yNegative; + + int ylen = y.words == null ? 1 : y.ival; + int[] ywords = new int[ylen]; + y.getAbsolute(ywords); + while (ylen > 1 && ywords[ylen - 1] == 0) ylen--; + + int xlen = x.words == null ? 1 : x.ival; + int[] xwords = new int[xlen+2]; + x.getAbsolute(xwords); + while (xlen > 1 && xwords[xlen-1] == 0) xlen--; + + int qlen, rlen; + + int cmpval = MPN.cmp(xwords, xlen, ywords, ylen); + if (cmpval < 0) // abs(x) < abs(y) + { // quotient = 0; remainder = num. + int[] rwords = xwords; xwords = ywords; ywords = rwords; + rlen = xlen; qlen = 1; xwords[0] = 0; + } + else if (cmpval == 0) // abs(x) == abs(y) + { + xwords[0] = 1; qlen = 1; // quotient = 1 + ywords[0] = 0; rlen = 1; // remainder = 0; + } + else if (ylen == 1) + { + qlen = xlen; + // Need to leave room for a word of leading zeros if dividing by 1 + // and the dividend has the high bit set. It might be safe to + // increment qlen in all cases, but it certainly is only necessary + // in the following case. + if (ywords[0] == 1 && xwords[xlen-1] < 0) + qlen++; + rlen = 1; + ywords[0] = MPN.divmod_1(xwords, xwords, xlen, ywords[0]); + } + else // abs(x) > abs(y) + { + // Normalize the denominator, i.e. make its most significant bit set by + // shifting it normalization_steps bits to the left. Also shift the + // numerator the same number of steps (to keep the quotient the same!). + + int nshift = MPN.count_leading_zeros(ywords[ylen - 1]); + if (nshift != 0) + { + // Shift up the denominator setting the most significant bit of + // the most significant word. + MPN.lshift(ywords, 0, ywords, ylen, nshift); + + // Shift up the numerator, possibly introducing a new most + // significant word. + int x_high = MPN.lshift(xwords, 0, xwords, xlen, nshift); + xwords[xlen++] = x_high; + } + + if (xlen == ylen) + xwords[xlen++] = 0; + MPN.divide(xwords, xlen, ywords, ylen); + rlen = ylen; + MPN.rshift0 (ywords, xwords, 0, rlen, nshift); + + qlen = xlen + 1 - ylen; + if (quotient != null) + { + for (int i = 0; i < qlen; i++) + xwords[i] = xwords[i+ylen]; + } + } + + if (ywords[rlen-1] < 0) + { + ywords[rlen] = 0; + rlen++; + } + + // Now the quotient is in xwords, and the remainder is in ywords. + + boolean add_one = false; + if (rlen > 1 || ywords[0] != 0) + { // Non-zero remainder i.e. in-exact quotient. + switch (rounding_mode) + { + case TRUNCATE: + break; + case CEILING: + case FLOOR: + if (qNegative == (rounding_mode == FLOOR)) + add_one = true; + break; + case ROUND: + // int cmp = compareTo(remainder<<1, abs(y)); + BigInteger tmp = remainder == null ? new BigInteger() : remainder; + tmp.set(ywords, rlen); + tmp = shift(tmp, 1); + if (yNegative) + tmp.setNegative(); + int cmp = compareTo(tmp, y); + // Now cmp == compareTo(sign(y)*(remainder<<1), y) + if (yNegative) + cmp = -cmp; + add_one = (cmp == 1) || (cmp == 0 && (xwords[0]&1) != 0); + } + } + if (quotient != null) + { + quotient.set(xwords, qlen); + if (qNegative) + { + if (add_one) // -(quotient + 1) == ~(quotient) + quotient.setInvert(); + else + quotient.setNegative(); + } + else if (add_one) + quotient.setAdd(1); + } + if (remainder != null) + { + // The remainder is by definition: X-Q*Y + remainder.set(ywords, rlen); + if (add_one) + { + // Subtract the remainder from Y: + // abs(R) = abs(Y) - abs(orig_rem) = -(abs(orig_rem) - abs(Y)). + BigInteger tmp; + if (y.words == null) + { + tmp = remainder; + tmp.set(yNegative ? ywords[0] + y.ival : ywords[0] - y.ival); + } + else + tmp = BigInteger.add(remainder, y, yNegative ? 1 : -1); + // Now tmp <= 0. + // In this case, abs(Q) = 1 + floor(abs(X)/abs(Y)). + // Hence, abs(Q*Y) > abs(X). + // So sign(remainder) = -sign(X). + if (xNegative) + remainder.setNegative(tmp); + else + remainder.set(tmp); + } + else + { + // If !add_one, then: abs(Q*Y) <= abs(X). + // So sign(remainder) = sign(X). + if (xNegative) + remainder.setNegative(); + } + } + } + + public BigInteger divide(BigInteger val) + { + if (val.isZero()) + throw new ArithmeticException("divisor is zero"); + + BigInteger quot = new BigInteger(); + divide(this, val, quot, null, TRUNCATE); + return quot.canonicalize(); + } + + public BigInteger remainder(BigInteger val) + { + if (val.isZero()) + throw new ArithmeticException("divisor is zero"); + + BigInteger rem = new BigInteger(); + divide(this, val, null, rem, TRUNCATE); + return rem.canonicalize(); + } + + public BigInteger[] divideAndRemainder(BigInteger val) + { + if (val.isZero()) + throw new ArithmeticException("divisor is zero"); + + BigInteger[] result = new BigInteger[2]; + result[0] = new BigInteger(); + result[1] = new BigInteger(); + divide(this, val, result[0], result[1], TRUNCATE); + result[0].canonicalize(); + result[1].canonicalize(); + return result; + } + + public BigInteger mod(BigInteger m) + { + if (m.isNegative() || m.isZero()) + throw new ArithmeticException("non-positive modulus"); + + BigInteger rem = new BigInteger(); + divide(this, m, null, rem, FLOOR); + return rem.canonicalize(); + } + + /** Calculate the integral power of a BigInteger. + * @param exponent the exponent (must be non-negative) + */ + public BigInteger pow(int exponent) + { + if (exponent <= 0) + { + if (exponent == 0) + return ONE; + throw new ArithmeticException("negative exponent"); + } + if (isZero()) + return this; + int plen = words == null ? 1 : ival; // Length of pow2. + int blen = ((bitLength() * exponent) >> 5) + 2 * plen; + boolean negative = isNegative() && (exponent & 1) != 0; + int[] pow2 = new int [blen]; + int[] rwords = new int [blen]; + int[] work = new int [blen]; + getAbsolute(pow2); // pow2 = abs(this); + int rlen = 1; + rwords[0] = 1; // rwords = 1; + for (;;) // for (i = 0; ; i++) + { + // pow2 == this**(2**i) + // prod = this**(sum(j=0..i-1, (exponent>>j)&1)) + if ((exponent & 1) != 0) + { // r *= pow2 + MPN.mul(work, pow2, plen, rwords, rlen); + int[] temp = work; work = rwords; rwords = temp; + rlen += plen; + while (rwords[rlen - 1] == 0) rlen--; + } + exponent >>= 1; + if (exponent == 0) + break; + // pow2 *= pow2; + MPN.mul(work, pow2, plen, pow2, plen); + int[] temp = work; work = pow2; pow2 = temp; // swap to avoid a copy + plen *= 2; + while (pow2[plen - 1] == 0) plen--; + } + if (rwords[rlen - 1] < 0) + rlen++; + if (negative) + negate(rwords, rwords, rlen); + return BigInteger.make(rwords, rlen); + } + + private static int[] euclidInv(int a, int b, int prevDiv) + { + if (b == 0) + throw new ArithmeticException("not invertible"); + + if (b == 1) + // Success: values are indeed invertible! + // Bottom of the recursion reached; start unwinding. + return new int[] { -prevDiv, 1 }; + + int[] xy = euclidInv(b, a % b, a / b); // Recursion happens here. + a = xy[0]; // use our local copy of 'a' as a work var + xy[0] = a * -prevDiv + xy[1]; + xy[1] = a; + return xy; + } + + private static void euclidInv(BigInteger a, BigInteger b, + BigInteger prevDiv, BigInteger[] xy) + { + if (b.isZero()) + throw new ArithmeticException("not invertible"); + + if (b.isOne()) + { + // Success: values are indeed invertible! + // Bottom of the recursion reached; start unwinding. + xy[0] = neg(prevDiv); + xy[1] = ONE; + return; + } + + // Recursion happens in the following conditional! + + // If a just contains an int, then use integer math for the rest. + if (a.words == null) + { + int[] xyInt = euclidInv(b.ival, a.ival % b.ival, a.ival / b.ival); + xy[0] = new BigInteger(xyInt[0]); + xy[1] = new BigInteger(xyInt[1]); + } + else + { + BigInteger rem = new BigInteger(); + BigInteger quot = new BigInteger(); + divide(a, b, quot, rem, FLOOR); + // quot and rem may not be in canonical form. ensure + rem.canonicalize(); + quot.canonicalize(); + euclidInv(b, rem, quot, xy); + } + + BigInteger t = xy[0]; + xy[0] = add(xy[1], times(t, prevDiv), -1); + xy[1] = t; + } + + public BigInteger modInverse(BigInteger y) + { + if (y.isNegative() || y.isZero()) + throw new ArithmeticException("non-positive modulo"); + + // Degenerate cases. + if (y.isOne()) + return ZERO; + if (isOne()) + return ONE; + + // Use Euclid's algorithm as in gcd() but do this recursively + // rather than in a loop so we can use the intermediate results as we + // unwind from the recursion. + // Used http://www.math.nmsu.edu/~crypto/EuclideanAlgo.html as reference. + BigInteger result = new BigInteger(); + boolean swapped = false; + + if (y.words == null) + { + // The result is guaranteed to be less than the modulus, y (which is + // an int), so simplify this by working with the int result of this + // modulo y. Also, if this is negative, make it positive via modulo + // math. Note that BigInteger.mod() must be used even if this is + // already an int as the % operator would provide a negative result if + // this is negative, BigInteger.mod() never returns negative values. + int xval = (words != null || isNegative()) ? mod(y).ival : ival; + int yval = y.ival; + + // Swap values so x > y. + if (yval > xval) + { + int tmp = xval; xval = yval; yval = tmp; + swapped = true; + } + // Normally, the result is in the 2nd element of the array, but + // if originally x < y, then x and y were swapped and the result + // is in the 1st element of the array. + result.ival = + euclidInv(yval, xval % yval, xval / yval)[swapped ? 0 : 1]; + + // Result can't be negative, so make it positive by adding the + // original modulus, y.ival (not the possibly "swapped" yval). + if (result.ival < 0) + result.ival += y.ival; + } + else + { + // As above, force this to be a positive value via modulo math. + BigInteger x = isNegative() ? this.mod(y) : this; + + // Swap values so x > y. + if (x.compareTo(y) < 0) + { + result = x; x = y; y = result; // use 'result' as a work var + swapped = true; + } + // As above (for ints), result will be in the 2nd element unless + // the original x and y were swapped. + BigInteger rem = new BigInteger(); + BigInteger quot = new BigInteger(); + divide(x, y, quot, rem, FLOOR); + // quot and rem may not be in canonical form. ensure + rem.canonicalize(); + quot.canonicalize(); + BigInteger[] xy = new BigInteger[2]; + euclidInv(y, rem, quot, xy); + result = swapped ? xy[0] : xy[1]; + + // Result can't be negative, so make it positive by adding the + // original modulus, y (which is now x if they were swapped). + if (result.isNegative()) + result = add(result, swapped ? x : y, 1); + } + + return result; + } + + public BigInteger modPow(BigInteger exponent, BigInteger m) + { + if (m.isNegative() || m.isZero()) + throw new ArithmeticException("non-positive modulo"); + + if (exponent.isNegative()) + return modInverse(m); + if (exponent.isOne()) + return mod(m); + + // To do this naively by first raising this to the power of exponent + // and then performing modulo m would be extremely expensive, especially + // for very large numbers. The solution is found in Number Theory + // where a combination of partial powers and moduli can be done easily. + // + // We'll use the algorithm for Additive Chaining which can be found on + // p. 244 of "Applied Cryptography, Second Edition" by Bruce Schneier. + BigInteger s = ONE; + BigInteger t = this; + BigInteger u = exponent; + + while (!u.isZero()) + { + if (u.and(ONE).isOne()) + s = times(s, t).mod(m); + u = u.shiftRight(1); + t = times(t, t).mod(m); + } + + return s; + } + + /** Calculate Greatest Common Divisor for non-negative ints. */ + private static int gcd(int a, int b) + { + // Euclid's algorithm, copied from libg++. + int tmp; + if (b > a) + { + tmp = a; a = b; b = tmp; + } + for(;;) + { + if (b == 0) + return a; + if (b == 1) + return b; + tmp = b; + b = a % b; + a = tmp; + } + } + + public BigInteger gcd(BigInteger y) + { + int xval = ival; + int yval = y.ival; + if (words == null) + { + if (xval == 0) + return abs(y); + if (y.words == null + && xval != Integer.MIN_VALUE && yval != Integer.MIN_VALUE) + { + if (xval < 0) + xval = -xval; + if (yval < 0) + yval = -yval; + return valueOf(gcd(xval, yval)); + } + xval = 1; + } + if (y.words == null) + { + if (yval == 0) + return abs(this); + yval = 1; + } + int len = (xval > yval ? xval : yval) + 1; + int[] xwords = new int[len]; + int[] ywords = new int[len]; + getAbsolute(xwords); + y.getAbsolute(ywords); + len = MPN.gcd(xwords, ywords, len); + BigInteger result = new BigInteger(0); + result.ival = len; + result.words = xwords; + return result.canonicalize(); + } + + /** + *

    Returns true if this BigInteger is probably prime, + * false if it's definitely composite. If certainty + * is <= 0, true is returned.

    + * + * @param certainty a measure of the uncertainty that the caller is willing + * to tolerate: if the call returns true the probability that + * this BigInteger is prime exceeds (1 - 1/2certainty). + * The execution time of this method is proportional to the value of this + * parameter. + * @return true if this BigInteger is probably prime, + * false if it's definitely composite. + */ + public boolean isProbablePrime(int certainty) + { + if (certainty < 1) + return true; + + /** We'll use the Rabin-Miller algorithm for doing a probabilistic + * primality test. It is fast, easy and has faster decreasing odds of a + * composite passing than with other tests. This means that this + * method will actually have a probability much greater than the + * 1 - .5^certainty specified in the JCL (p. 117), but I don't think + * anyone will complain about better performance with greater certainty. + * + * The Rabin-Miller algorithm can be found on pp. 259-261 of "Applied + * Cryptography, Second Edition" by Bruce Schneier. + */ + + // First rule out small prime factors + BigInteger rem = new BigInteger(); + int i; + for (i = 0; i < primes.length; i++) + { + if (words == null && ival == primes[i]) + return true; + + divide(this, smallFixNums[primes[i] - minFixNum], null, rem, TRUNCATE); + if (rem.canonicalize().isZero()) + return false; + } + + // Now perform the Rabin-Miller test. + + // Set b to the number of times 2 evenly divides (this - 1). + // I.e. 2^b is the largest power of 2 that divides (this - 1). + BigInteger pMinus1 = add(this, -1); + int b = pMinus1.getLowestSetBit(); + + // Set m such that this = 1 + 2^b * m. + BigInteger m = pMinus1.divide(valueOf(2L << b - 1)); + + // The HAC (Handbook of Applied Cryptography), Alfred Menezes & al. Note + // 4.49 (controlling the error probability) gives the number of trials + // for an error probability of 1/2**80, given the number of bits in the + // number to test. we shall use these numbers as is if/when 'certainty' + // is less or equal to 80, and twice as much if it's greater. + int bits = this.bitLength(); + for (i = 0; i < k.length; i++) + if (bits <= k[i]) + break; + int trials = t[i]; + if (certainty > 80) + trials *= 2; + BigInteger z; + for (int t = 0; t < trials; t++) + { + // The HAC (Handbook of Applied Cryptography), Alfred Menezes & al. + // Remark 4.28 states: "...A strategy that is sometimes employed + // is to fix the bases a to be the first few primes instead of + // choosing them at random. + z = smallFixNums[primes[t] - minFixNum].modPow(m, this); + if (z.isOne() || z.equals(pMinus1)) + continue; // Passes the test; may be prime. + + for (i = 0; i < b; ) + { + if (z.isOne()) + return false; + i++; + if (z.equals(pMinus1)) + break; // Passes the test; may be prime. + + z = z.modPow(valueOf(2), this); + } + + if (i == b && !z.equals(pMinus1)) + return false; + } + return true; + } + + private void setInvert() + { + if (words == null) + ival = ~ival; + else + { + for (int i = ival; --i >= 0; ) + words[i] = ~words[i]; + } + } + + private void setShiftLeft(BigInteger x, int count) + { + int[] xwords; + int xlen; + if (x.words == null) + { + if (count < 32) + { + set((long) x.ival << count); + return; + } + xwords = new int[1]; + xwords[0] = x.ival; + xlen = 1; + } + else + { + xwords = x.words; + xlen = x.ival; + } + int word_count = count >> 5; + count &= 31; + int new_len = xlen + word_count; + if (count == 0) + { + realloc(new_len); + for (int i = xlen; --i >= 0; ) + words[i+word_count] = xwords[i]; + } + else + { + new_len++; + realloc(new_len); + int shift_out = MPN.lshift(words, word_count, xwords, xlen, count); + count = 32 - count; + words[new_len-1] = (shift_out << count) >> count; // sign-extend. + } + ival = new_len; + for (int i = word_count; --i >= 0; ) + words[i] = 0; + } + + private void setShiftRight(BigInteger x, int count) + { + if (x.words == null) + set(count < 32 ? x.ival >> count : x.ival < 0 ? -1 : 0); + else if (count == 0) + set(x); + else + { + boolean neg = x.isNegative(); + int word_count = count >> 5; + count &= 31; + int d_len = x.ival - word_count; + if (d_len <= 0) + set(neg ? -1 : 0); + else + { + if (words == null || words.length < d_len) + realloc(d_len); + MPN.rshift0 (words, x.words, word_count, d_len, count); + ival = d_len; + if (neg) + words[d_len-1] |= -2 << (31 - count); + } + } + } + + private void setShift(BigInteger x, int count) + { + if (count > 0) + setShiftLeft(x, count); + else + setShiftRight(x, -count); + } + + private static BigInteger shift(BigInteger x, int count) + { + if (x.words == null) + { + if (count <= 0) + return valueOf(count > -32 ? x.ival >> (-count) : x.ival < 0 ? -1 : 0); + if (count < 32) + return valueOf((long) x.ival << count); + } + if (count == 0) + return x; + BigInteger result = new BigInteger(0); + result.setShift(x, count); + return result.canonicalize(); + } + + public BigInteger shiftLeft(int n) + { + return shift(this, n); + } + + public BigInteger shiftRight(int n) + { + return shift(this, -n); + } + + private void format(int radix, StringBuffer buffer) + { + if (words == null) + buffer.append(Integer.toString(ival, radix)); + else if (ival <= 2) + buffer.append(Long.toString(longValue(), radix)); + else + { + boolean neg = isNegative(); + int[] work; + if (neg || radix != 16) + { + work = new int[ival]; + getAbsolute(work); + } + else + work = words; + int len = ival; + + if (radix == 16) + { + if (neg) + buffer.append('-'); + int buf_start = buffer.length(); + for (int i = len; --i >= 0; ) + { + int word = work[i]; + for (int j = 8; --j >= 0; ) + { + int hex_digit = (word >> (4 * j)) & 0xF; + // Suppress leading zeros: + if (hex_digit > 0 || buffer.length() > buf_start) + buffer.append(Character.forDigit(hex_digit, 16)); + } + } + } + else + { + int i = buffer.length(); + for (;;) + { + int digit = MPN.divmod_1(work, work, len, radix); + buffer.append(Character.forDigit(digit, radix)); + while (len > 0 && work[len-1] == 0) len--; + if (len == 0) + break; + } + if (neg) + buffer.append('-'); + /* Reverse buffer. */ + int j = buffer.length() - 1; + while (i < j) + { + char tmp = buffer.charAt(i); + buffer.setCharAt(i, buffer.charAt(j)); + buffer.setCharAt(j, tmp); + i++; j--; + } + } + } + } + + public String toString() + { + return toString(10); + } + + public String toString(int radix) + { + if (words == null) + return Integer.toString(ival, radix); + if (ival <= 2) + return Long.toString(longValue(), radix); + int buf_size = ival * (MPN.chars_per_word(radix) + 1); + StringBuffer buffer = new StringBuffer(buf_size); + format(radix, buffer); + return buffer.toString(); + } + + public int intValue() + { + if (words == null) + return ival; + return words[0]; + } + + public long longValue() + { + if (words == null) + return ival; + if (ival == 1) + return words[0]; + return ((long)words[1] << 32) + ((long)words[0] & 0xffffffffL); + } + + public int hashCode() + { + // FIXME: May not match hashcode of JDK. + return words == null ? ival : (words[0] + words[ival - 1]); + } + + /* Assumes x and y are both canonicalized. */ + private static boolean equals(BigInteger x, BigInteger y) + { + if (x.words == null && y.words == null) + return x.ival == y.ival; + if (x.words == null || y.words == null || x.ival != y.ival) + return false; + for (int i = x.ival; --i >= 0; ) + { + if (x.words[i] != y.words[i]) + return false; + } + return true; + } + + /* Assumes this and obj are both canonicalized. */ + public boolean equals(Object obj) + { + if (! (obj instanceof BigInteger)) + return false; + return equals(this, (BigInteger) obj); + } + + private static BigInteger valueOf(String s, int radix) + throws NumberFormatException + { + int len = s.length(); + // Testing (len < MPN.chars_per_word(radix)) would be more accurate, + // but slightly more expensive, for little practical gain. + if (len <= 15 && radix <= 16) + return valueOf(Long.parseLong(s, radix)); + + int byte_len = 0; + byte[] bytes = new byte[len]; + boolean negative = false; + for (int i = 0; i < len; i++) + { + char ch = s.charAt(i); + if (ch == '-') + negative = true; + else if (ch == '_' || (byte_len == 0 && (ch == ' ' || ch == '\t'))) + continue; + else + { + int digit = Character.digit(ch, radix); + if (digit < 0) + break; + bytes[byte_len++] = (byte) digit; + } + } + return valueOf(bytes, byte_len, negative, radix); + } + + private static BigInteger valueOf(byte[] digits, int byte_len, + boolean negative, int radix) + { + int chars_per_word = MPN.chars_per_word(radix); + int[] words = new int[byte_len / chars_per_word + 1]; + int size = MPN.set_str(words, digits, byte_len, radix); + if (size == 0) + return ZERO; + if (words[size-1] < 0) + words[size++] = 0; + if (negative) + negate(words, words, size); + return make(words, size); + } + + public double doubleValue() + { + if (words == null) + return (double) ival; + if (ival <= 2) + return (double) longValue(); + if (isNegative()) + return neg(this).roundToDouble(0, true, false); + return roundToDouble(0, false, false); + } + + public float floatValue() + { + return (float) doubleValue(); + } + + /** Return true if any of the lowest n bits are one. + * (false if n is negative). */ + private boolean checkBits(int n) + { + if (n <= 0) + return false; + if (words == null) + return n > 31 || ((ival & ((1 << n) - 1)) != 0); + int i; + for (i = 0; i < (n >> 5) ; i++) + if (words[i] != 0) + return true; + return (n & 31) != 0 && (words[i] & ((1 << (n & 31)) - 1)) != 0; + } + + /** Convert a semi-processed BigInteger to double. + * Number must be non-negative. Multiplies by a power of two, applies sign, + * and converts to double, with the usual java rounding. + * @param exp power of two, positive or negative, by which to multiply + * @param neg true if negative + * @param remainder true if the BigInteger is the result of a truncating + * division that had non-zero remainder. To ensure proper rounding in + * this case, the BigInteger must have at least 54 bits. */ + private double roundToDouble(int exp, boolean neg, boolean remainder) + { + // Compute length. + int il = bitLength(); + + // Exponent when normalized to have decimal point directly after + // leading one. This is stored excess 1023 in the exponent bit field. + exp += il - 1; + + // Gross underflow. If exp == -1075, we let the rounding + // computation determine whether it is minval or 0 (which are just + // 0x0000 0000 0000 0001 and 0x0000 0000 0000 0000 as bit + // patterns). + if (exp < -1075) + return neg ? -0.0 : 0.0; + + // gross overflow + if (exp > 1023) + return neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; + + // number of bits in mantissa, including the leading one. + // 53 unless it's denormalized + int ml = (exp >= -1022 ? 53 : 53 + exp + 1022); + + // Get top ml + 1 bits. The extra one is for rounding. + long m; + int excess_bits = il - (ml + 1); + if (excess_bits > 0) + m = ((words == null) ? ival >> excess_bits + : MPN.rshift_long(words, ival, excess_bits)); + else + m = longValue() << (- excess_bits); + + // Special rounding for maxval. If the number exceeds maxval by + // any amount, even if it's less than half a step, it overflows. + if (exp == 1023 && ((m >> 1) == (1L << 53) - 1)) + { + if (remainder || checkBits(il - ml)) + return neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; + else + return neg ? - Double.MAX_VALUE : Double.MAX_VALUE; + } + + // Normal round-to-even rule: round up if the bit dropped is a one, and + // the bit above it or any of the bits below it is a one. + if ((m & 1) == 1 + && ((m & 2) == 2 || remainder || checkBits(excess_bits))) + { + m += 2; + // Check if we overflowed the mantissa + if ((m & (1L << 54)) != 0) + { + exp++; + // renormalize + m >>= 1; + } + // Check if a denormalized mantissa was just rounded up to a + // normalized one. + else if (ml == 52 && (m & (1L << 53)) != 0) + exp++; + } + + // Discard the rounding bit + m >>= 1; + + long bits_sign = neg ? (1L << 63) : 0; + exp += 1023; + long bits_exp = (exp <= 0) ? 0 : ((long)exp) << 52; + long bits_mant = m & ~(1L << 52); + return Double.longBitsToDouble(bits_sign | bits_exp | bits_mant); + } + + /** Copy the abolute value of this into an array of words. + * Assumes words.length >= (this.words == null ? 1 : this.ival). + * Result is zero-extended, but need not be a valid 2's complement number. + */ + private void getAbsolute(int[] words) + { + int len; + if (this.words == null) + { + len = 1; + words[0] = this.ival; + } + else + { + len = this.ival; + for (int i = len; --i >= 0; ) + words[i] = this.words[i]; + } + if (words[len - 1] < 0) + negate(words, words, len); + for (int i = words.length; --i > len; ) + words[i] = 0; + } + + /** Set dest[0:len-1] to the negation of src[0:len-1]. + * Return true if overflow (i.e. if src is -2**(32*len-1)). + * Ok for src==dest. */ + private static boolean negate(int[] dest, int[] src, int len) + { + long carry = 1; + boolean negative = src[len-1] < 0; + for (int i = 0; i < len; i++) + { + carry += ((long) (~src[i]) & 0xffffffffL); + dest[i] = (int) carry; + carry >>= 32; + } + return (negative && dest[len-1] < 0); + } + + /** Destructively set this to the negative of x. + * It is OK if x==this.*/ + private void setNegative(BigInteger x) + { + int len = x.ival; + if (x.words == null) + { + if (len == Integer.MIN_VALUE) + set(- (long) len); + else + set(-len); + return; + } + realloc(len + 1); + if (negate(words, x.words, len)) + words[len++] = 0; + ival = len; + } + + /** Destructively negate this. */ + private void setNegative() + { + setNegative(this); + } + + private static BigInteger abs(BigInteger x) + { + return x.isNegative() ? neg(x) : x; + } + + public BigInteger abs() + { + return abs(this); + } + + private static BigInteger neg(BigInteger x) + { + if (x.words == null && x.ival != Integer.MIN_VALUE) + return valueOf(- x.ival); + BigInteger result = new BigInteger(0); + result.setNegative(x); + return result.canonicalize(); + } + + public BigInteger negate() + { + return neg(this); + } + + /** Calculates ceiling(log2(this < 0 ? -this : this+1)) + * See Common Lisp: the Language, 2nd ed, p. 361. + */ + public int bitLength() + { + if (words == null) + return MPN.intLength(ival); + return MPN.intLength(words, ival); + } + + public byte[] toByteArray() + { + // Determine number of bytes needed. The method bitlength returns + // the size without the sign bit, so add one bit for that and then + // add 7 more to emulate the ceil function using integer math. + byte[] bytes = new byte[(bitLength() + 1 + 7) / 8]; + int nbytes = bytes.length; + + int wptr = 0; + int word; + + // Deal with words array until one word or less is left to process. + // If BigInteger is an int, then it is in ival and nbytes will be <= 4. + while (nbytes > 4) + { + word = words[wptr++]; + for (int i = 4; i > 0; --i, word >>= 8) + bytes[--nbytes] = (byte) word; + } + + // Deal with the last few bytes. If BigInteger is an int, use ival. + word = (words == null) ? ival : words[wptr]; + for ( ; nbytes > 0; word >>= 8) + bytes[--nbytes] = (byte) word; + + return bytes; + } + + /** Return the boolean opcode (for bitOp) for swapped operands. + * I.e. bitOp(swappedOp(op), x, y) == bitOp(op, y, x). + */ + private static int swappedOp(int op) + { + return + "\000\001\004\005\002\003\006\007\010\011\014\015\012\013\016\017" + .charAt(op); + } + + /** Do one the the 16 possible bit-wise operations of two BigIntegers. */ + private static BigInteger bitOp(int op, BigInteger x, BigInteger y) + { + switch (op) + { + case 0: return ZERO; + case 1: return x.and(y); + case 3: return x; + case 5: return y; + case 15: return valueOf(-1); + } + BigInteger result = new BigInteger(); + setBitOp(result, op, x, y); + return result.canonicalize(); + } + + /** Do one the the 16 possible bit-wise operations of two BigIntegers. */ + private static void setBitOp(BigInteger result, int op, + BigInteger x, BigInteger y) + { + if (y.words == null) ; + else if (x.words == null || x.ival < y.ival) + { + BigInteger temp = x; x = y; y = temp; + op = swappedOp(op); + } + int xi; + int yi; + int xlen, ylen; + if (y.words == null) + { + yi = y.ival; + ylen = 1; + } + else + { + yi = y.words[0]; + ylen = y.ival; + } + if (x.words == null) + { + xi = x.ival; + xlen = 1; + } + else + { + xi = x.words[0]; + xlen = x.ival; + } + if (xlen > 1) + result.realloc(xlen); + int[] w = result.words; + int i = 0; + // Code for how to handle the remainder of x. + // 0: Truncate to length of y. + // 1: Copy rest of x. + // 2: Invert rest of x. + int finish = 0; + int ni; + switch (op) + { + case 0: // clr + ni = 0; + break; + case 1: // and + for (;;) + { + ni = xi & yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 1; + break; + case 2: // andc2 + for (;;) + { + ni = xi & ~yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 1; + break; + case 3: // copy x + ni = xi; + finish = 1; // Copy rest + break; + case 4: // andc1 + for (;;) + { + ni = ~xi & yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 2; + break; + case 5: // copy y + for (;;) + { + ni = yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + break; + case 6: // xor + for (;;) + { + ni = xi ^ yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + finish = yi < 0 ? 2 : 1; + break; + case 7: // ior + for (;;) + { + ni = xi | yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 1; + break; + case 8: // nor + for (;;) + { + ni = ~(xi | yi); + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 2; + break; + case 9: // eqv [exclusive nor] + for (;;) + { + ni = ~(xi ^ yi); + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + finish = yi >= 0 ? 2 : 1; + break; + case 10: // c2 + for (;;) + { + ni = ~yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + break; + case 11: // orc2 + for (;;) + { + ni = xi | ~yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 1; + break; + case 12: // c1 + ni = ~xi; + finish = 2; + break; + case 13: // orc1 + for (;;) + { + ni = ~xi | yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 2; + break; + case 14: // nand + for (;;) + { + ni = ~(xi & yi); + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 2; + break; + default: + case 15: // set + ni = -1; + break; + } + // Here i==ylen-1; w[0]..w[i-1] have the correct result; + // and ni contains the correct result for w[i+1]. + if (i+1 == xlen) + finish = 0; + switch (finish) + { + case 0: + if (i == 0 && w == null) + { + result.ival = ni; + return; + } + w[i++] = ni; + break; + case 1: w[i] = ni; while (++i < xlen) w[i] = x.words[i]; break; + case 2: w[i] = ni; while (++i < xlen) w[i] = ~x.words[i]; break; + } + result.ival = i; + } + + /** Return the logical (bit-wise) "and" of a BigInteger and an int. */ + private static BigInteger and(BigInteger x, int y) + { + if (x.words == null) + return valueOf(x.ival & y); + if (y >= 0) + return valueOf(x.words[0] & y); + int len = x.ival; + int[] words = new int[len]; + words[0] = x.words[0] & y; + while (--len > 0) + words[len] = x.words[len]; + return make(words, x.ival); + } + + /** Return the logical (bit-wise) "and" of two BigIntegers. */ + public BigInteger and(BigInteger y) + { + if (y.words == null) + return and(this, y.ival); + else if (words == null) + return and(y, ival); + + BigInteger x = this; + if (ival < y.ival) + { + BigInteger temp = this; x = y; y = temp; + } + int i; + int len = y.isNegative() ? x.ival : y.ival; + int[] words = new int[len]; + for (i = 0; i < y.ival; i++) + words[i] = x.words[i] & y.words[i]; + for ( ; i < len; i++) + words[i] = x.words[i]; + return make(words, len); + } + + /** Return the logical (bit-wise) "(inclusive) or" of two BigIntegers. */ + public BigInteger or(BigInteger y) + { + return bitOp(7, this, y); + } + + /** Return the logical (bit-wise) "exclusive or" of two BigIntegers. */ + public BigInteger xor(BigInteger y) + { + return bitOp(6, this, y); + } + + /** Return the logical (bit-wise) negation of a BigInteger. */ + public BigInteger not() + { + return bitOp(12, this, ZERO); + } + + public BigInteger andNot(BigInteger val) + { + return and(val.not()); + } + + public BigInteger clearBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + return and(ONE.shiftLeft(n).not()); + } + + public BigInteger setBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + return or(ONE.shiftLeft(n)); + } + + public boolean testBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + return !and(ONE.shiftLeft(n)).isZero(); + } + + public BigInteger flipBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + return xor(ONE.shiftLeft(n)); + } + + public int getLowestSetBit() + { + if (isZero()) + return -1; + + if (words == null) + return MPN.findLowestBit(ival); + else + return MPN.findLowestBit(words); + } + + // bit4count[I] is number of '1' bits in I. + private static final byte[] bit4_count = { 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4}; + + private static int bitCount(int i) + { + int count = 0; + while (i != 0) + { + count += bit4_count[i & 15]; + i >>>= 4; + } + return count; + } + + private static int bitCount(int[] x, int len) + { + int count = 0; + while (--len >= 0) + count += bitCount(x[len]); + return count; + } + + /** Count one bits in a BigInteger. + * If argument is negative, count zero bits instead. */ + public int bitCount() + { + int i, x_len; + int[] x_words = words; + if (x_words == null) + { + x_len = 1; + i = bitCount(ival); + } + else + { + x_len = ival; + i = bitCount(x_words, x_len); + } + return isNegative() ? x_len * 32 - i : i; + } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + words = byteArrayToIntArray(magnitude, signum < 0 ? -1 : 0); + BigInteger result = make(words, words.length); + this.ival = result.ival; + this.words = result.words; + } + + private void writeObject(ObjectOutputStream s) + throws IOException, ClassNotFoundException + { + signum = signum(); + magnitude = toByteArray(); + s.defaultWriteObject(); + } +} diff --git a/libjava/classpath/java/math/class-dependencies.conf b/libjava/classpath/java/math/class-dependencies.conf new file mode 100644 index 0000000..4fbf75e --- /dev/null +++ b/libjava/classpath/java/math/class-dependencies.conf @@ -0,0 +1,58 @@ +# This property file contains dependencies of classes, methods, and +# field on other methods or classes. +# +# Syntax: +# +# : [... ] +# +# means that when is included, (... ) must +# be included as well. +# +# and are of the form +# +# +# +# or just +# +# +# +# Within dependencies, variables can be used. A variable is defined as +# follows: +# +# {variable}: value1 value2 ... value +# +# variables can be used on the right side of dependencies as follows: +# +# : com.bla.blu.{variable}.Class.m()V +# +# The use of the variable will expand to dependencies of the form +# +# : com.bla.blu.value1.Class.m()V +# : com.bla.blu.value2.Class.m()V +# ... +# : com.bla.blu.value.Class.m()V +# +# Variables can be redefined when building a system to select the +# required support for features like encodings, protocols, etc. +# +# Hints: +# +# - For methods and fields, the signature is mandatory. For +# specification, please see the Java Virtual Machine Specification by +# SUN. Unlike in the spec, field signatures (types) are in brackets. +# +# - Package names must be separated by '/' (and not '.'). E.g., +# java/lang/Class (this is necessary, because the '.' is used to +# separate method or field names from classes) +# +# - In case refers to a class, only the class itself will be +# included in the resulting binary, NOT necessarily all its methods +# and fields. If you want to refer to all methods and fields, you can +# write class.* as an abbreviation. +# +# - Abbreviations for packages are also possible: my/package/* means all +# methods and fields of all classes in my/package. +# +# - A line with a trailing '\' continues in the next line. + +# end of file diff --git a/libjava/classpath/java/math/package.html b/libjava/classpath/java/math/package.html new file mode 100644 index 0000000..62d12ea --- /dev/null +++ b/libjava/classpath/java/math/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.math + + +

    Arbitrary large decimals and integers.

    + + + diff --git a/libjava/classpath/java/net/Authenticator.java b/libjava/classpath/java/net/Authenticator.java new file mode 100644 index 0000000..229e140 --- /dev/null +++ b/libjava/classpath/java/net/Authenticator.java @@ -0,0 +1,313 @@ +/* Authenticator.java -- Abstract class for obtaining authentication info + Copyright (C) 1998, 2000, 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 java.net; + + +/** + * This abstract class provides a model for obtaining authentication + * information (in the form of a username and password) required by + * some network operations (such as hitting a password protected + * web site). + *

    + * To make use of this feature, a programmer must create a subclass + * that knows how to obtain the necessary info. An example + * would be a class that popped up a dialog box to prompt the user. + * After creating an instance of that subclass, the static + * setDefault method of this class is called to set up + * that instance as the object to use on subsequent calls to obtain + * authorization. + * + * @since 1.2 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status Believed to be JDK 1.4 complete + */ +public abstract class Authenticator +{ + /* + * Class Variables + */ + + /** + * This is the default Authenticator object to use for password requests + */ + private static Authenticator defaultAuthenticator; + + /* + * Instance Variables + */ + + /** + * The hostname of the site requesting authentication + */ + private String host; + + /** + * InternetAddress of the site requesting authentication + */ + private InetAddress addr; + + /** + * The port number of the site requesting authentication + */ + private int port; + + /** + * The protocol name of the site requesting authentication + */ + private String protocol; + + /** + * The prompt to display to the user when requesting authentication info + */ + private String prompt; + + /** + * The authentication scheme in use + */ + private String scheme; + + /* + * Class Methods + */ + + /** + * This method sets the default Authenticator object (an + * instance of a subclass of Authenticator) to use when + * prompting the user for + * information. Note that this method checks to see if the caller is + * allowed to set this value (the "setDefaultAuthenticator" permission) + * and throws a SecurityException if it is not. + * + * @param defAuth The new default Authenticator object to use + * + * @exception SecurityException If the caller does not have permission + * to perform this operation + */ + public static void setDefault(Authenticator defAuth) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new NetPermission("setDefaultAuthenticator")); + + defaultAuthenticator = defAuth; + } + + /** + * This method is called whenever a username and password for a given + * network operation is required. First, a security check is made to see + * if the caller has the "requestPasswordAuthentication" + * permission. If not, the method thows an exception. If there is no + * default Authenticator object, the method then returns + * null. Otherwise, the default authenticators's instance + * variables are initialized and it's getPasswordAuthentication + * method is called to get the actual authentication information to return. + * + * @param addr The address requesting authentication + * @param port The port requesting authentication + * @param protocol The protocol requesting authentication + * @param prompt The prompt to display to the user when requesting + * authentication info + * @param scheme The authentication scheme in use + * + * @return A PasswordAuthentication object with the user's + * authentication info. + * + * @exception SecurityException If the caller does not have permission to + * perform this operation + */ + public static PasswordAuthentication requestPasswordAuthentication(InetAddress addr, + int port, + String protocol, + String prompt, + String scheme) + throws SecurityException + { + return requestPasswordAuthentication(null, addr, port, protocol, prompt, + scheme); + } + + /** + * This method is called whenever a username and password for a given + * network operation is required. First, a security check is made to see + * if the caller has the "requestPasswordAuthentication" + * permission. If not, the method thows an exception. If there is no + * default Authenticator object, the method then returns + * null. Otherwise, the default authenticators's instance + * variables are initialized and it's getPasswordAuthentication + * method is called to get the actual authentication information to return. + * This method is the preferred one as it can be used with hostname + * when addr is unknown. + * + * @param host The hostname requesting authentication + * @param addr The address requesting authentication + * @param port The port requesting authentication + * @param protocol The protocol requesting authentication + * @param prompt The prompt to display to the user when requesting + * authentication info + * @param scheme The authentication scheme in use + * + * @return A PasswordAuthentication object with the user's + * authentication info. + * + * @exception SecurityException If the caller does not have permission to + * perform this operation + * + * @since 1.4 + */ + public static PasswordAuthentication requestPasswordAuthentication(String host, + InetAddress addr, + int port, + String protocol, + String prompt, + String scheme) + throws SecurityException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new NetPermission("requestPasswordAuthentication")); + + if (defaultAuthenticator == null) + return null; + + defaultAuthenticator.host = host; + defaultAuthenticator.addr = addr; + defaultAuthenticator.port = port; + defaultAuthenticator.protocol = protocol; + defaultAuthenticator.prompt = prompt; + defaultAuthenticator.scheme = scheme; + + return defaultAuthenticator.getPasswordAuthentication(); + } + + /* + * Constructors + */ + + /** + * Default, no-argument constructor for subclasses to call. + */ + public Authenticator() + { + } + + /* + * Instance Methods + */ + + /** + * This method returns the address of the site that is requesting + * authentication. + * + * @return The requesting site's address + */ + protected final InetAddress getRequestingSite() + { + return addr; + } + + /** + * Returns the hostname of the host or proxy requesting authorization, + * or null if not available. + * + * @return The name of the host requesting authentication, or + * null if it is not available. + * + * @since 1.4 + */ + protected final String getRequestingHost() + { + return host; + } + + /** + * This method returns the port of the site that is requesting + * authentication. + * + * @return The requesting port + */ + protected final int getRequestingPort() + { + return port; + } + + /** + * This method returns the requesting protocol of the operation that is + * requesting authentication + * + * @return The requesting protocol + */ + protected final String getRequestingProtocol() + { + return protocol; + } + + /** + * Returns the prompt that should be used when requesting authentication + * information from the user + * + * @return The user prompt + */ + protected final String getRequestingPrompt() + { + return prompt; + } + + /** + * This method returns the authentication scheme in use + * + * @return The authentication scheme + */ + protected final String getRequestingScheme() + { + return scheme; + } + + /** + * This method is called whenever a request for authentication is made. It + * can call the other getXXX methods to determine the information relevant + * to this request. Subclasses should override this method, which returns + * null by default. + * + * @return The PasswordAuthentication information + */ + protected PasswordAuthentication getPasswordAuthentication() + { + return null; + } +} // class Authenticator diff --git a/libjava/classpath/java/net/BindException.java b/libjava/classpath/java/net/BindException.java new file mode 100644 index 0000000..cfb509a --- /dev/null +++ b/libjava/classpath/java/net/BindException.java @@ -0,0 +1,74 @@ +/* BindException.java -- An exception occurred while binding to a socket + Copyright (C) 1998, 1999, 2000, 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 java.net; + + +/** + * This exception indicates that an error occurred while attempting to bind + * socket to a particular port. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class BindException extends SocketException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -5945005768251722951L; + + /** + * Create a new instance without a descriptive error message. + */ + public BindException() + { + } + + /** + * Create a new instance with a descriptive error message, such as the + * text from strerror(3). + * + * @param message a message describing the error that occurred + */ + public BindException(String message) + { + super(message); + } +} // class BindException diff --git a/libjava/classpath/java/net/ConnectException.java b/libjava/classpath/java/net/ConnectException.java new file mode 100644 index 0000000..c115d2f --- /dev/null +++ b/libjava/classpath/java/net/ConnectException.java @@ -0,0 +1,75 @@ +/* ConnectException.java -- An exception occurred while connecting to a host + Copyright (C) 1998, 1999, 2000, 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 java.net; + + +/** + * This exception indicates that an error occurred while attempting to + * connect to a remote host. Often this indicates that the remote host + * refused the connection (ie, is not listening on the target socket). + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class ConnectException extends SocketException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 3831404271622369215L; + + /** + * Create a new instance without a descriptive error message. + */ + public ConnectException() + { + } + + /** + * Create a new instance with a descriptive error message, such as the + * text from strerror(3). + * + * @param message a message describing the error that occurred + */ + public ConnectException(String message) + { + super(message); + } +} // class ConnectException diff --git a/libjava/classpath/java/net/ContentHandler.java b/libjava/classpath/java/net/ContentHandler.java new file mode 100644 index 0000000..7f63e74 --- /dev/null +++ b/libjava/classpath/java/net/ContentHandler.java @@ -0,0 +1,126 @@ +/* ContentHandler.java -- Abstract class for handling content from URL's + Copyright (C) 1998, 1999, 2000, 2001, 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 java.net; + +import java.io.IOException; + +/** + * 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 an abstract class that is the superclass for classes that read + * objects from URL's. Calling the getContent() method in the + * URL class or the URLConnection class will cause + * an instance of a subclass of ContentHandler to be created for + * the MIME type of the object being downloaded from the URL. Thus, this + * class is seldom needed by applications/applets directly, but only + * indirectly through methods in other classes. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public abstract class ContentHandler +{ + /* + * Constructors + */ + + /** + * Default, no-argument constructor. + */ + public ContentHandler() + { + } + + /* + * Instance Methods + */ + + /** + * This method reads from the InputStream of the passed in URL + * connection and uses the data downloaded to create an Object + * represening the content. For example, if the URL is pointing to a GIF + * file, this method might return an Image object. This method + * must be implemented by subclasses. + * + * @param urlc A URLConnection object to read data from. + * + * @return An object representing the data read + * + * @exception IOException If an error occurs + */ + public abstract Object getContent(URLConnection urlc) + throws IOException; + + /** + * This method reads from the InputStream of the passed in URL + * connection and uses the data downloaded to create an Object + * represening the content. For example, if the URL is pointing to a GIF + * file, this method might return an Image object. This method + * must be implemented by subclasses. This method uses the list of + * supplied classes as candidate types. If the data read doesn't match + * any of the supplied type, null is returned. + * + * @param urlc A URLConnection object to read data from. + * @param classes An array of types of objects that are candidate types + * for the data to be read. + * + * @return An object representing the data read, or null + * if the data does not match any of the candidate types. + * + * @exception IOException If an error occurs + * + * @since 1.3 + */ + public Object getContent(URLConnection urlc, Class[] classes) + throws IOException + { + Object obj = getContent(urlc); + + for (int i = 0; i < classes.length; i++) + { + if (classes[i].isInstance(obj)) + return obj; + } + + return null; + } +} // class ContentHandler diff --git a/libjava/classpath/java/net/ContentHandlerFactory.java b/libjava/classpath/java/net/ContentHandlerFactory.java new file mode 100644 index 0000000..51a92cf --- /dev/null +++ b/libjava/classpath/java/net/ContentHandlerFactory.java @@ -0,0 +1,65 @@ +/* ContentHandlerFactory.java -- Interface for creating content handlers + Copyright (C) 1998, 1999, 2000, 2001, 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 java.net; + + +/** + * 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 interface maps MIME types to ContentHandler objects. + * It consists of one method that, when passed a MIME type, returns a + * handler for that type. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public interface ContentHandlerFactory +{ + /** + * This method is passed a MIME type as a string and is responsible for + * returning the appropriate ContentHandler object. + * + * @param mimeType The MIME type to map to a ContentHandler + * + * @return The ContentHandler for the passed in MIME type + */ + ContentHandler createContentHandler(String mimeType); +} // interface ContentHandlerFactory diff --git a/libjava/classpath/java/net/DatagramPacket.java b/libjava/classpath/java/net/DatagramPacket.java new file mode 100644 index 0000000..e642f88 --- /dev/null +++ b/libjava/classpath/java/net/DatagramPacket.java @@ -0,0 +1,391 @@ +/* DatagramPacket.java -- Class to model a packet to be sent via UDP + Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.net; + + +/* + * 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 class models a packet of data that is to be sent across the network + * using a connectionless protocol such as UDP. It contains the data + * to be send, as well as the destination address and port. Note that + * datagram packets can arrive in any order and are not guaranteed to be + * delivered at all. + *

    + * This class can also be used for receiving data from the network. + *

    + * Note that for all method below where the buffer length passed by the + * caller cannot exceed the actually length of the byte array passed as + * the buffer, if this condition is not true, then the method silently + * reduces the length value to maximum allowable value. + * + * 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. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aarom M. Renn (arenn@urbanophile.com) (Documentation comments) + * @date April 28, 1999. + */ +public final class DatagramPacket +{ + /** + * The data buffer to send + */ + private byte[] buffer; + + /** + * This is the offset into the buffer to start sending from or receiving to. + */ + private int offset; + + /** + * The length of the data buffer to send. + */ + int length; + + /** + * The maximal length of the buffer. + */ + int maxlen; + + /** + * The address to which the packet should be sent or from which it + * was received. + */ + private InetAddress address; + + /** + * The port to which the packet should be sent or from which it was + * was received. + */ + private int port; + + /** + * This method initializes a new instance of DatagramPacket + * which has the specified buffer, offset, and length. + * + * @param buf The buffer for holding the incoming datagram. + * @param offset The offset into the buffer to start writing. + * @param length The maximum number of bytes to read. + * + * @since 1.2 + */ + public DatagramPacket(byte[] buf, int offset, int length) + { + setData(buf, offset, length); + address = null; + port = -1; + } + + /** + * Initializes a new instance of DatagramPacket for + * receiving packets from the network. + * + * @param buf A buffer for storing the returned packet data + * @param length The length of the buffer (must be <= buf.length) + */ + public DatagramPacket(byte[] buf, int length) + { + this(buf, 0, length); + } + + /** + * Initializes a new instance of DatagramPacket for + * transmitting packets across the network. + * + * @param buf A buffer containing the data to send + * @param offset The offset into the buffer to start writing from. + * @param length The length of the buffer (must be <= buf.length) + * @param address The address to send to + * @param port The port to send to + * + * @since 1.2 + */ + public DatagramPacket(byte[] buf, int offset, int length, + InetAddress address, int port) + { + setData(buf, offset, length); + setAddress(address); + setPort(port); + } + + /** + * Initializes a new instance of DatagramPacket for + * transmitting packets across the network. + * + * @param buf A buffer containing the data to send + * @param length The length of the buffer (must be <= buf.length) + * @param address The address to send to + * @param port The port to send to + */ + public DatagramPacket(byte[] buf, int length, InetAddress address, int port) + { + this(buf, 0, length, address, port); + } + + /** + * Initializes a new instance of DatagramPacket for + * transmitting packets across the network. + * + * @param buf A buffer containing the data to send + * @param offset The offset into the buffer to start writing from. + * @param length The length of the buffer (must be <= buf.length) + * @param address The socket address to send to + * + * @exception SocketException If an error occurs + * @exception IllegalArgumentException If address type is not supported + * + * @since 1.4 + */ + public DatagramPacket(byte[] buf, int offset, int length, + SocketAddress address) throws SocketException + { + if (! (address instanceof InetSocketAddress)) + throw new IllegalArgumentException("unsupported address type"); + + InetSocketAddress tmp = (InetSocketAddress) address; + setData(buf, offset, length); + setAddress(tmp.getAddress()); + setPort(tmp.getPort()); + } + + /** + * Initializes a new instance of DatagramPacket for + * transmitting packets across the network. + * + * @param buf A buffer containing the data to send + * @param length The length of the buffer (must be <= buf.length) + * @param address The socket address to send to + * + * @exception SocketException If an error occurs + * @exception IllegalArgumentException If address type is not supported + * + * @since 1.4 + */ + public DatagramPacket(byte[] buf, int length, SocketAddress address) + throws SocketException + { + this(buf, 0, length, address); + } + + /** + * Returns the address that this packet is being sent to or, if it was used + * to receive a packet, the address that is was received from. If the + * constructor that doesn not take an address was used to create this object + * and no packet was actually read into this object, then this method + * returns null. + * + * @return The address for this packet. + */ + public synchronized InetAddress getAddress() + { + return address; + } + + /** + * Returns the port number this packet is being sent to or, if it was used + * to receive a packet, the port that it was received from. If the + * constructor that doesn not take an address was used to create this object + * and no packet was actually read into this object, then this method + * will return 0. + * + * @return The port number for this packet + */ + public synchronized int getPort() + { + return port; + } + + /** + * Returns the data buffer for this packet + * + * @return This packet's data buffer + */ + public synchronized byte[] getData() + { + return buffer; + } + + /** + * This method returns the current offset value into the data buffer + * where data will be sent from. + * + * @return The buffer offset. + * + * @since 1.2 + */ + public synchronized int getOffset() + { + return offset; + } + + /** + * Returns the length of the data in the buffer + * + * @return The length of the data + */ + public synchronized int getLength() + { + return length; + } + + /** + * This sets the address to which the data packet will be transmitted. + * + * @param address The destination address + * + * @since 1.1 + */ + public synchronized void setAddress(InetAddress address) + { + this.address = address; + } + + /** + * This sets the port to which the data packet will be transmitted. + * + * @param port The destination port + * + * @since 1.1 + */ + public synchronized void setPort(int port) + { + if (port < 0 || port > 65535) + throw new IllegalArgumentException("Invalid port: " + port); + + this.port = port; + } + + /** + * Sets the address of the remote host this package will be sent + * + * @param address The socket address of the remove host + * + * @exception IllegalArgumentException If address type is not supported + * + * @since 1.4 + */ + public void setSocketAddress(SocketAddress address) + throws IllegalArgumentException + { + if (address == null) + throw new IllegalArgumentException("address may not be null"); + + InetSocketAddress tmp = (InetSocketAddress) address; + this.address = tmp.getAddress(); + this.port = tmp.getPort(); + } + + /** + * Gets the socket address of the host this packet + * will be sent to/is coming from + * + * @return The socket address of the remote host + * + * @since 1.4 + */ + public SocketAddress getSocketAddress() + { + return new InetSocketAddress(address, port); + } + + /** + * Sets the data buffer for this packet. + * + * @param buf The new buffer for this packet + * + * @exception NullPointerException If the argument is null + * + * @since 1.1 + */ + public void setData(byte[] buf) + { + setData(buf, 0, buf.length); + } + + /** + * This method sets the data buffer for the packet. + * + * @param buf The byte array containing the data for this packet. + * @param offset The offset into the buffer to start reading data from. + * @param length The number of bytes of data in the buffer. + * + * @exception NullPointerException If the argument is null + * + * @since 1.2 + */ + public synchronized void setData(byte[] buf, int offset, int length) + { + // This form of setData must be used if offset is to be changed. + if (buf == null) + throw new NullPointerException("Null buffer"); + if (offset < 0) + throw new IllegalArgumentException("Invalid offset: " + offset); + + buffer = buf; + this.offset = offset; + setLength(length); + } + + /** + * Sets the length of the data in the buffer. + * + * @param length The new length. (Where len <= buf.length) + * + * @exception IllegalArgumentException If the length is negative or + * if the length is greater than the packet's data buffer length + * + * @since 1.1 + */ + public synchronized void setLength(int length) + { + if (length < 0) + throw new IllegalArgumentException("Invalid length: " + length); + if (offset + length > buffer.length) + throw new IllegalArgumentException("Potential buffer overflow - offset: " + + offset + " length: " + length); + + this.length = length; + this.maxlen = length; + } +} diff --git a/libjava/classpath/java/net/DatagramSocket.java b/libjava/classpath/java/net/DatagramSocket.java new file mode 100644 index 0000000..8596b7f --- /dev/null +++ b/libjava/classpath/java/net/DatagramSocket.java @@ -0,0 +1,933 @@ +/* DatagramSocket.java -- A class to model UDP sockets + 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 java.net; + +import gnu.java.net.PlainDatagramSocketImpl; +import gnu.java.nio.DatagramChannelImpl; + +import java.io.IOException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.IllegalBlockingModeException; + + +/** + * 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 class models a connectionless datagram socket that sends + * individual packets of data across the network. In the TCP/IP world, + * this means UDP. Datagram packets do not have guaranteed delivery, + * or any guarantee about the order the data will be received on the + * remote host. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @date May 3, 1999. + */ +public class DatagramSocket +{ + /** + * This is the user DatagramSocketImplFactory for this class. If this + * variable is null, a default factory is used. + */ + private static DatagramSocketImplFactory factory; + + /** + * This is the implementation object used by this socket. + */ + private DatagramSocketImpl impl; + + /** + * True if socket implementation was created. + */ + private boolean implCreated; + + /** + * This is the address we are "connected" to + */ + private InetAddress remoteAddress; + + /** + * This is the port we are "connected" to + */ + private int remotePort = -1; + + /** + * True if socket is bound. + */ + private boolean bound; + + /** + * Creates a DatagramSocket from a specified + * DatagramSocketImpl instance + * + * @param impl The DatagramSocketImpl the socket will be + * created from + * + * @since 1.4 + */ + protected DatagramSocket(DatagramSocketImpl impl) + { + if (impl == null) + throw new NullPointerException("impl may not be null"); + + this.impl = impl; + this.remoteAddress = null; + this.remotePort = -1; + } + + /** + * Initializes a new instance of DatagramSocket that binds to + * a random port and every address on the local machine. + * + * @exception SocketException If an error occurs. + * @exception SecurityException If a security manager exists and + * its checkListen method doesn't allow the operation. + */ + public DatagramSocket() throws SocketException + { + this(new InetSocketAddress(0)); + } + + /** + * Initializes a new instance of DatagramSocket that binds to + * the specified port and every address on the local machine. + * + * @param port The local port number to bind to. + * + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation. + * @exception SocketException If an error occurs. + */ + public DatagramSocket(int port) throws SocketException + { + this(new InetSocketAddress(port)); + } + + /** + * Initializes a new instance of DatagramSocket that binds to + * the specified local port and address. + * + * @param port The local port number to bind to. + * @param addr The local address to bind to. + * + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation. + * @exception SocketException If an error occurs. + */ + public DatagramSocket(int port, InetAddress addr) throws SocketException + { + this(new InetSocketAddress(addr, port)); + } + + /** + * Initializes a new instance of DatagramSocket that binds to + * the specified local port and address. + * + * @param address The local address and port number to bind to. + * + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation. + * @exception SocketException If an error occurs. + * + * @since 1.4 + */ + public DatagramSocket(SocketAddress address) throws SocketException + { + String propVal = System.getProperty("impl.prefix"); + if (propVal == null || propVal.equals("")) + impl = new PlainDatagramSocketImpl(); + else + try + { + impl = + (DatagramSocketImpl) Class.forName("java.net." + propVal + + "DatagramSocketImpl") + .newInstance(); + } + catch (Exception e) + { + System.err.println("Could not instantiate class: java.net." + + propVal + "DatagramSocketImpl"); + impl = new PlainDatagramSocketImpl(); + } + + if (address != null) + bind(address); + } + + // This needs to be accessible from java.net.MulticastSocket + DatagramSocketImpl getImpl() throws SocketException + { + try + { + if (! implCreated) + { + impl.create(); + implCreated = true; + } + + return impl; + } + catch (IOException e) + { + SocketException se = new SocketException(); + se.initCause(e); + throw se; + } + } + + /** + * Closes this datagram socket. + */ + public void close() + { + if (isClosed()) + return; + + try + { + getImpl().close(); + } + catch (SocketException e) + { + // Ignore this case, just close the socket in finally clause. + } + finally + { + remoteAddress = null; + remotePort = -1; + impl = null; + } + + try + { + if (getChannel() != null) + getChannel().close(); + } + catch (IOException e) + { + // Do nothing. + } + } + + /** + * This method returns the remote address to which this socket is + * connected. If this socket is not connected, then this method will + * return null. + * + * @return The remote address. + * + * @since 1.2 + */ + public InetAddress getInetAddress() + { + return remoteAddress; + } + + /** + * This method returns the remote port to which this socket is + * connected. If this socket is not connected, then this method will + * return -1. + * + * @return The remote port. + * + * @since 1.2 + */ + public int getPort() + { + return remotePort; + } + + /** + * Returns the local address this datagram socket is bound to. + * + * @return The local address is the socket is bound or null + * + * @since 1.1 + */ + public InetAddress getLocalAddress() + { + if (! isBound()) + return null; + + InetAddress localAddr; + + try + { + localAddr = + (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR); + + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkConnect(localAddr.getHostName(), -1); + } + catch (SecurityException e) + { + localAddr = InetAddress.ANY_IF; + } + catch (SocketException e) + { + // This cannot happen as we are bound. + return null; + } + + return localAddr; + } + + /** + * Returns the local port this socket is bound to. + * + * @return The local port number. + */ + public int getLocalPort() + { + if (isClosed()) + return -1; + + try + { + return getImpl().getLocalPort(); + } + catch (SocketException e) + { + // This cannot happen as we are bound. + return 0; + } + } + + /** + * Returns the value of the socket's SO_TIMEOUT setting. If this method + * returns 0 then SO_TIMEOUT is disabled. + * + * @return The current timeout in milliseconds. + * + * @exception SocketException If an error occurs. + * + * @since 1.1 + */ + public synchronized int getSoTimeout() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.SO_TIMEOUT); + + if (buf instanceof Integer) + return ((Integer) buf).intValue(); + + throw new SocketException("unexpected type"); + } + + /** + * Sets the value of the socket's SO_TIMEOUT value. A value of 0 will + * disable SO_TIMEOUT. Any other value is the number of milliseconds + * a socket read/write will block before timing out. + * + * @param timeout The new SO_TIMEOUT value in milliseconds. + * + * @exception SocketException If an error occurs. + * + * @since 1.1 + */ + public synchronized void setSoTimeout(int timeout) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (timeout < 0) + throw new IllegalArgumentException("Invalid timeout: " + timeout); + + getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); + } + + /** + * This method returns the value of the system level socket option + * SO_SNDBUF, which is used by the operating system to tune buffer + * sizes for data transfers. + * + * @return The send buffer size. + * + * @exception SocketException If an error occurs. + * + * @since 1.2 + */ + public int getSendBufferSize() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.SO_SNDBUF); + + if (buf instanceof Integer) + return ((Integer) buf).intValue(); + + throw new SocketException("unexpected type"); + } + + /** + * This method sets the value for the system level socket option + * SO_SNDBUF to the specified value. Note that valid values for this + * option are specific to a given operating system. + * + * @param size The new send buffer size. + * + * @exception SocketException If an error occurs. + * @exception IllegalArgumentException If size is 0 or negative. + * + * @since 1.2 + */ + public void setSendBufferSize(int size) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (size < 0) + throw new IllegalArgumentException("Buffer size is less than 0"); + + getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size)); + } + + /** + * This method returns the value of the system level socket option + * SO_RCVBUF, which is used by the operating system to tune buffer + * sizes for data transfers. + * + * @return The receive buffer size. + * + * @exception SocketException If an error occurs. + * + * @since 1.2 + */ + public int getReceiveBufferSize() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.SO_RCVBUF); + + if (buf instanceof Integer) + return ((Integer) buf).intValue(); + + throw new SocketException("unexpected type"); + } + + /** + * This method sets the value for the system level socket option + * SO_RCVBUF to the specified value. Note that valid values for this + * option are specific to a given operating system. + * + * @param size The new receive buffer size. + * + * @exception SocketException If an error occurs. + * @exception IllegalArgumentException If size is 0 or negative. + * + * @since 1.2 + */ + public void setReceiveBufferSize(int size) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (size < 0) + throw new IllegalArgumentException("Buffer size is less than 0"); + + getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size)); + } + + /** + * This method connects this socket to the specified address and port. + * When a datagram socket is connected, it will only send or receive + * packets to and from the host to which it is connected. A multicast + * socket that is connected may only send and not receive packets. + * + * @param address The address to connect this socket to. + * @param port The port to connect this socket to. + * + * @exception SocketException If an error occurs. + * @exception IllegalArgumentException If address or port are invalid. + * @exception SecurityException If the caller is not allowed to send + * datagrams to or receive from this address and port. + * + * @since 1.2 + */ + public void connect(InetAddress address, int port) + { + if (address == null) + throw new IllegalArgumentException("Connect address may not be null"); + + if ((port < 1) || (port > 65535)) + throw new IllegalArgumentException("Port number is illegal: " + port); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkConnect(address.getHostName(), port); + + try + { + getImpl().connect(address, port); + remoteAddress = address; + remotePort = port; + } + catch (SocketException e) + { + // This means simply not connected or connect not implemented. + } + } + + /** + * This method disconnects this socket from the address/port it was + * connected to. If the socket was not connected in the first place, + * this method does nothing. + * + * @since 1.2 + */ + public void disconnect() + { + if (! isConnected()) + return; + + try + { + getImpl().disconnect(); + } + catch (SocketException e) + { + // This cannot happen as we are connected. + } + finally + { + remoteAddress = null; + remotePort = -1; + } + } + + /** + * Reads a datagram packet from the socket. Note that this method + * will block until a packet is received from the network. On return, + * the passed in DatagramPacket is populated with the data + * received and all the other information about the packet. + * + * @param p A DatagramPacket for storing the data + * + * @exception IOException If an error occurs. + * @exception SocketTimeoutException If setSoTimeout was previously called + * and the timeout has expired. + * @exception PortUnreachableException If the socket is connected to a + * currently unreachable destination. Note, there is no guarantee that the + * exception will be thrown. + * @exception IllegalBlockingModeException If this socket has an associated + * channel, and the channel is in non-blocking mode. + * @exception SecurityException If a security manager exists and its + * checkAccept method doesn't allow the receive. + */ + public synchronized void receive(DatagramPacket p) throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (remoteAddress != null && remoteAddress.isMulticastAddress()) + throw new IOException + ("Socket connected to a multicast address my not receive"); + + if (getChannel() != null && ! getChannel().isBlocking() + && ! ((DatagramChannelImpl) getChannel()).isInChannelOperation()) + throw new IllegalBlockingModeException(); + + getImpl().receive(p); + + SecurityManager s = System.getSecurityManager(); + if (s != null && isConnected()) + s.checkAccept(p.getAddress().getHostName(), p.getPort()); + } + + /** + * Sends the specified packet. The host and port to which the packet + * are to be sent should be set inside the packet. + * + * @param p The datagram packet to send. + * + * @exception IOException If an error occurs. + * @exception SecurityException If a security manager exists and its + * checkMulticast or checkConnect method doesn't allow the send. + * @exception PortUnreachableException If the socket is connected to a + * currently unreachable destination. Note, there is no guarantee that the + * exception will be thrown. + * @exception IllegalBlockingModeException If this socket has an associated + * channel, and the channel is in non-blocking mode. + */ + public void send(DatagramPacket p) throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + // JDK1.2: Don't do security checks if socket is connected; see jdk1.2 api. + SecurityManager s = System.getSecurityManager(); + if (s != null && ! isConnected()) + { + InetAddress addr = p.getAddress(); + if (addr.isMulticastAddress()) + s.checkMulticast(addr); + else + s.checkConnect(addr.getHostAddress(), p.getPort()); + } + + if (isConnected()) + { + if (p.getAddress() != null + && (remoteAddress != p.getAddress() || remotePort != p.getPort())) + throw new IllegalArgumentException + ("DatagramPacket address does not match remote address"); + } + + // FIXME: if this is a subclass of MulticastSocket, + // use getTimeToLive for TTL val. + if (getChannel() != null && ! getChannel().isBlocking() + && ! ((DatagramChannelImpl) getChannel()).isInChannelOperation()) + throw new IllegalBlockingModeException(); + + getImpl().send(p); + } + + /** + * Binds the socket to the given socket address. + * + * @param address The socket address to bind to. + * + * @exception SocketException If an error occurs. + * @exception SecurityException If a security manager exists and + * its checkListen method doesn't allow the operation. + * @exception IllegalArgumentException If address type is not supported. + * + * @since 1.4 + */ + public void bind(SocketAddress address) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (! (address instanceof InetSocketAddress)) + throw new IllegalArgumentException("unsupported address type"); + + InetAddress addr = ((InetSocketAddress) address).getAddress(); + int port = ((InetSocketAddress) address).getPort(); + + if (port < 0 || port > 65535) + throw new IllegalArgumentException("Invalid port: " + port); + + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkListen(port); + + if (addr == null) + addr = InetAddress.ANY_IF; + + try + { + getImpl().bind(port, addr); + bound = true; + } + catch (SocketException exception) + { + getImpl().close(); + throw exception; + } + catch (RuntimeException exception) + { + getImpl().close(); + throw exception; + } + catch (Error error) + { + getImpl().close(); + throw error; + } + } + + /** + * Checks if the datagram socket is closed. + * + * @return True if socket is closed, false otherwise. + * + * @since 1.4 + */ + public boolean isClosed() + { + return impl == null; + } + + /** + * Returns the datagram channel assoziated with this datagram socket. + * + * @return The associated DatagramChannel object or null + * + * @since 1.4 + */ + public DatagramChannel getChannel() + { + return null; + } + + /** + * Connects the datagram socket to a specified socket address. + * + * @param address The socket address to connect to. + * + * @exception SocketException If an error occurs. + * @exception IllegalArgumentException If address type is not supported. + * + * @since 1.4 + */ + public void connect(SocketAddress address) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (! (address instanceof InetSocketAddress)) + throw new IllegalArgumentException("unsupported address type"); + + InetSocketAddress tmp = (InetSocketAddress) address; + connect(tmp.getAddress(), tmp.getPort()); + } + + /** + * Returns the binding state of the socket. + * + * @return True if socket bound, false otherwise. + * + * @since 1.4 + */ + public boolean isBound() + { + return bound; + } + + /** + * Returns the connection state of the socket. + * + * @return True if socket is connected, false otherwise. + * + * @since 1.4 + */ + public boolean isConnected() + { + return remoteAddress != null; + } + + /** + * Returns the SocketAddress of the host this socket is conneted to + * or null if this socket is not connected. + * + * @return The socket address of the remote host if connected or null + * + * @since 1.4 + */ + public SocketAddress getRemoteSocketAddress() + { + if (! isConnected()) + return null; + + return new InetSocketAddress(remoteAddress, remotePort); + } + + /** + * Returns the local SocketAddress this socket is bound to. + * + * @return The local SocketAddress or null if the socket is not bound. + * + * @since 1.4 + */ + public SocketAddress getLocalSocketAddress() + { + if (! isBound()) + return null; + + return new InetSocketAddress(getLocalAddress(), getLocalPort()); + } + + /** + * Enables/Disables SO_REUSEADDR. + * + * @param on Whether or not to have SO_REUSEADDR turned on. + * + * @exception SocketException If an error occurs. + * + * @since 1.4 + */ + public void setReuseAddress(boolean on) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); + } + + /** + * Checks if SO_REUSEADDR is enabled. + * + * @return True if SO_REUSEADDR is set on the socket, false otherwise. + * + * @exception SocketException If an error occurs. + * + * @since 1.4 + */ + public boolean getReuseAddress() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.SO_REUSEADDR); + + if (buf instanceof Boolean) + return ((Boolean) buf).booleanValue(); + + throw new SocketException("unexpected type"); + } + + /** + * Enables/Disables SO_BROADCAST + * + * @param enable True if SO_BROADCAST should be enabled, false otherwise. + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public void setBroadcast(boolean enable) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(enable)); + } + + /** + * Checks if SO_BROADCAST is enabled + * + * @return Whether SO_BROADCAST is set + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public boolean getBroadcast() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.SO_BROADCAST); + + if (buf instanceof Boolean) + return ((Boolean) buf).booleanValue(); + + throw new SocketException("unexpected type"); + } + + /** + * Sets the traffic class value + * + * @param tc The traffic class + * + * @exception SocketException If an error occurs + * @exception IllegalArgumentException If tc value is illegal + * + * @see DatagramSocket#getTrafficClass() + * + * @since 1.4 + */ + public void setTrafficClass(int tc) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (tc < 0 || tc > 255) + throw new IllegalArgumentException(); + + getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc)); + } + + /** + * Returns the current traffic class + * + * @return The current traffic class. + * + * @see DatagramSocket#setTrafficClass(int tc) + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public int getTrafficClass() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.IP_TOS); + + if (buf instanceof Integer) + return ((Integer) buf).intValue(); + + throw new SocketException("unexpected type"); + } + + /** + * Sets the datagram socket implementation factory for the application + * + * @param fac The factory to set + * + * @exception IOException If an error occurs + * @exception SocketException If the factory is already defined + * @exception SecurityException If a security manager exists and its + * checkSetFactory method doesn't allow the operation + */ + public static void setDatagramSocketImplFactory(DatagramSocketImplFactory fac) + throws IOException + { + if (factory != null) + throw new SocketException("DatagramSocketImplFactory already defined"); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSetFactory(); + + factory = fac; + } +} diff --git a/libjava/classpath/java/net/DatagramSocketImpl.java b/libjava/classpath/java/net/DatagramSocketImpl.java new file mode 100644 index 0000000..cfcde92 --- /dev/null +++ b/libjava/classpath/java/net/DatagramSocketImpl.java @@ -0,0 +1,296 @@ +/* DatagramSocketImpl.java -- Abstract class for UDP socket implementations + Copyright (C) 1998, 1999 2000, 2001, + 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 java.net; + +import java.io.FileDescriptor; +import java.io.IOException; + + +/** + * This abstract class models a datagram socket implementation. An + * actual implementation class would implement these methods, probably + * via redirecting them to native code. + *

    + * 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. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + */ +public abstract class DatagramSocketImpl implements SocketOptions +{ + /** + * The local port to which this socket is bound + */ + protected int localPort; + + /** + * The FileDescriptor object for this object. + */ + protected FileDescriptor fd; + + /** + * Default, no-argument constructor for subclasses to call. + */ + public DatagramSocketImpl() + { + } + + /** + * This method binds the socket to the specified local port and address. + * + * @param lport The port number to bind to + * @param laddr The address to bind to + * + * @exception SocketException If an error occurs + */ + protected abstract void bind(int lport, InetAddress laddr) + throws SocketException; + + /** + * This methods closes the socket + */ + protected abstract void close(); + + /** + * Creates a new datagram socket. + * + * @exception SocketException If an error occurs + */ + protected abstract void create() throws SocketException; + + /** + * Takes a peek at the next packet received in order to retrieve the + * address of the sender + * + * @param i The InetAddress to fill in with the information + * about the sender if the next packet + * + * @return The port number of the sender of the packet + * + * @exception IOException If an error occurs + * @exception PortUnreachableException May be thrown if the socket is + * connected to a currently unreachable destination. Note, there is no + * guarantee that the exception will be thrown. + */ + protected abstract int peek(InetAddress i) throws IOException; + + /** + * Takes a peek at the next packet received. This packet is not consumed. + * With the next peekData/receive operation this packet will be read again. + * + * @param p The DatagramPacket to fill in with the data sent. + * + * @return The port number of the sender of the packet. + * + * @exception IOException If an error occurs + * @exception PortUnreachableException May be thrown if the socket is + * connected to a currently unreachable destination. Note, there is no + * guarantee that the exception will be thrown. + * + * @since 1.4 + */ + protected abstract int peekData(DatagramPacket p) throws IOException; + + /** + * Transmits the specified packet of data to the network. The destination + * host and port should be encoded in the packet. + * + * @param p The packet to send + * + * @exception IOException If an error occurs + * @exception PortUnreachableException May be thrown if the socket is + * connected to a currently unreachable destination. Note, there is no + * guarantee that the exception will be thrown. + */ + protected abstract void send(DatagramPacket p) throws IOException; + + /** + * Receives a packet of data from the network Will block until a packet + * arrives. The packet info in populated into the passed in + * DatagramPacket object. + * + * @param p A place to store the incoming packet. + * + * @exception IOException If an error occurs + * @exception PortUnreachableException May be thrown if the socket is + * connected to a currently unreachable destination. Note, there is no + * guarantee that the exception will be thrown. + */ + protected abstract void receive(DatagramPacket p) throws IOException; + + /** + * Connects the socket to a host specified by address and port. + * + * @param address The InetAddress of the host to connect to + * @param port The port number of the host to connect to + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + protected void connect(InetAddress address, int port) + throws SocketException + { + // This method has to be overwritten by real implementations + } + + /** + * Disconnects the socket. + * + * @since 1.4 + */ + protected void disconnect() + { + // This method has to be overwritten by real implementations + } + + /** + * Sets the Time to Live (TTL) setting on this socket to the specified + * value. Use setTimeToLive(int) instead. + * + * @param ttl The new Time to Live value + * + * @exception IOException If an error occurs + * @deprecated + */ + protected abstract void setTTL(byte ttl) throws IOException; + + /** + * This method returns the current Time to Live (TTL) setting on this + * socket. Use getTimeToLive() instead. + * + * @return the current time-to-live + * + * @exception IOException If an error occurs + * + * @deprecated // FIXME: when ? + */ + protected abstract byte getTTL() throws IOException; + + /** + * Sets the Time to Live (TTL) setting on this socket to the specified + * value. + * + * @param ttl The new Time to Live value + * + * @exception IOException If an error occurs + */ + protected abstract void setTimeToLive(int ttl) throws IOException; + + /** + * This method returns the current Time to Live (TTL) setting on this + * socket. + * + * @return the current time-to-live + * + * @exception IOException If an error occurs + */ + protected abstract int getTimeToLive() throws IOException; + + /** + * Causes this socket to join the specified multicast group + * + * @param inetaddr The multicast address to join with + * + * @exception IOException If an error occurs + */ + protected abstract void join(InetAddress inetaddr) throws IOException; + + /** + * Causes the socket to leave the specified multicast group. + * + * @param inetaddr The multicast address to leave + * + * @exception IOException If an error occurs + */ + protected abstract void leave(InetAddress inetaddr) throws IOException; + + /** + * Causes this socket to join the specified multicast group on a specified + * device + * + * @param mcastaddr The address to leave + * @param netIf The specified network interface to join the group at + * + * @exception IOException If an error occurs + * + * @since 1.4 + */ + protected abstract void joinGroup(SocketAddress mcastaddr, + NetworkInterface netIf) + throws IOException; + + /** + * Leaves a multicast group + * + * @param mcastaddr The address to join + * @param netIf The specified network interface to leave the group at + * + * @exception IOException If an error occurs + * + * @since 1.4 + */ + protected abstract void leaveGroup(SocketAddress mcastaddr, + NetworkInterface netIf) + throws IOException; + + /** + * Returns the FileDescriptor for this socket + * + * @return the file descriptor associated with this socket + */ + protected FileDescriptor getFileDescriptor() + { + return fd; + } + + /** + * Returns the local port this socket is bound to + * + * @return the local port + */ + protected int getLocalPort() + { + return localPort; + } +} diff --git a/libjava/classpath/java/net/DatagramSocketImplFactory.java b/libjava/classpath/java/net/DatagramSocketImplFactory.java new file mode 100644 index 0000000..014651a --- /dev/null +++ b/libjava/classpath/java/net/DatagramSocketImplFactory.java @@ -0,0 +1,60 @@ +/* DatagramSocketImplFactory.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 java.net; + + +/** Written using on-line Java Platform 1.4 API Specification. + * Status: Believed complete and correct. + */ +/** + * This interface defines one method which returns a + * DatagramSocketImpl object. + * This should not be needed by ordinary applications. + * + * @author Michael Koch (konqueror@gmx.de) + * @since 1.3 + */ +public interface DatagramSocketImplFactory +{ + /** + * This method returns an instance of the DatagramSocketImpl object + * + * @return A DatagramSocketImpl object + */ + DatagramSocketImpl createDatagramSocketImpl(); +} // interface DatagramSocketImplFactory diff --git a/libjava/classpath/java/net/FileNameMap.java b/libjava/classpath/java/net/FileNameMap.java new file mode 100644 index 0000000..6f1d25a --- /dev/null +++ b/libjava/classpath/java/net/FileNameMap.java @@ -0,0 +1,65 @@ +/* FileNameMap.java -- Maps filenames to MIME types + Copyright (C) 1998, 1999, 2000, 2001, 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 java.net; + + +/** + * 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 interface has one method which, when passed a filename, returns + * the MIME type associated with that filename. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + */ +public interface FileNameMap +{ + /** + * This method is passed a filename and is responsible for determining + * the appropriate MIME type for that file. + * + * @param filename The name of the file to generate a MIME type for. + * + * @return The MIME type for the filename passed in. + */ + String getContentTypeFor(String filename); +} // interface FileNameMap diff --git a/libjava/classpath/java/net/HttpURLConnection.java b/libjava/classpath/java/net/HttpURLConnection.java new file mode 100644 index 0000000..07eae48 --- /dev/null +++ b/libjava/classpath/java/net/HttpURLConnection.java @@ -0,0 +1,589 @@ +/* HttpURLConnection.java -- Subclass of communications links using + Hypertext Transfer Protocol. + Copyright (C) 1998, 1999, 2000, 2002, 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.net; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; +import java.security.Permission; + + +/* + * 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 class provides a common abstract implementation for those + * URL connection classes that will connect using the HTTP protocol. + * In addition to the functionality provided by the URLConnection + * class, it defines constants for HTTP return code values and + * methods for setting the HTTP request method and determining whether + * or not to follow redirects. + * + * @since 1.1 + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class HttpURLConnection extends URLConnection +{ + /* HTTP Success Response Codes */ + + /** + * Indicates that the client may continue with its request. This value + * is specified as part of RFC 2068 but was not included in Sun's JDK, so + * beware of using this value + */ + static final int HTTP_CONTINUE = 100; + + /** + * Indicates the request succeeded. + */ + public static final int HTTP_OK = 200; + + /** + * The requested resource has been created. + */ + public static final int HTTP_CREATED = 201; + + /** + * The request has been accepted for processing but has not completed. + * There is no guarantee that the requested action will actually ever + * be completed succesfully, but everything is ok so far. + */ + public static final int HTTP_ACCEPTED = 202; + + /** + * The meta-information returned in the header is not the actual data + * from the original server, but may be from a local or other copy. + * Normally this still indicates a successful completion. + */ + public static final int HTTP_NOT_AUTHORITATIVE = 203; + + /** + * The server performed the request, but there is no data to send + * back. This indicates that the user's display should not be changed. + */ + public static final int HTTP_NO_CONTENT = 204; + + /** + * The server performed the request, but there is no data to sent back, + * however, the user's display should be "reset" to clear out any form + * fields entered. + */ + public static final int HTTP_RESET = 205; + + /** + * The server completed the partial GET request for the resource. + */ + public static final int HTTP_PARTIAL = 206; + + /* HTTP Redirection Response Codes */ + + /** + * There is a list of choices available for the requested resource. + */ + public static final int HTTP_MULT_CHOICE = 300; + + /** + * The resource has been permanently moved to a new location. + */ + public static final int HTTP_MOVED_PERM = 301; + + /** + * The resource requested has been temporarily moved to a new location. + */ + public static final int HTTP_MOVED_TEMP = 302; + + /** + * The response to the request issued is available at another location. + */ + public static final int HTTP_SEE_OTHER = 303; + + /** + * The document has not been modified since the criteria specified in + * a conditional GET. + */ + public static final int HTTP_NOT_MODIFIED = 304; + + /** + * The requested resource needs to be accessed through a proxy. + */ + public static final int HTTP_USE_PROXY = 305; + + /* HTTP Client Error Response Codes */ + + /** + * The request was misformed or could not be understood. + */ + public static final int HTTP_BAD_REQUEST = 400; + + /** + * The request made requires user authorization. Try again with + * a correct authentication header. + */ + public static final int HTTP_UNAUTHORIZED = 401; + + /** + * Code reserved for future use - I hope way in the future. + */ + public static final int HTTP_PAYMENT_REQUIRED = 402; + + /** + * There is no permission to access the requested resource. + */ + public static final int HTTP_FORBIDDEN = 403; + + /** + * The requested resource was not found. + */ + public static final int HTTP_NOT_FOUND = 404; + + /** + * The specified request method is not allowed for this resource. + */ + public static final int HTTP_BAD_METHOD = 405; + + /** + * Based on the input headers sent, the resource returned in response + * to the request would not be acceptable to the client. + */ + public static final int HTTP_NOT_ACCEPTABLE = 406; + + /** + * The client must authenticate with a proxy prior to attempting this + * request. + */ + public static final int HTTP_PROXY_AUTH = 407; + + /** + * The request timed out. + */ + public static final int HTTP_CLIENT_TIMEOUT = 408; + + /** + * There is a conflict between the current state of the resource and the + * requested action. + */ + public static final int HTTP_CONFLICT = 409; + + /** + * The requested resource is no longer available. This ususally indicates + * a permanent condition. + */ + public static final int HTTP_GONE = 410; + + /** + * A Content-Length header is required for this request, but was not + * supplied. + */ + public static final int HTTP_LENGTH_REQUIRED = 411; + + /** + * A client specified pre-condition was not met on the server. + */ + public static final int HTTP_PRECON_FAILED = 412; + + /** + * The request sent was too large for the server to handle. + */ + public static final int HTTP_ENTITY_TOO_LARGE = 413; + + /** + * The name of the resource specified was too long. + */ + public static final int HTTP_REQ_TOO_LONG = 414; + + /** + * The request is in a format not supported by the requested resource. + */ + public static final int HTTP_UNSUPPORTED_TYPE = 415; + + /* HTTP Server Error Response Codes */ + + /** + * This error code indicates that some sort of server error occurred. + * + * @deprecated + */ + public static final int HTTP_SERVER_ERROR = 500; + + /** + * The server encountered an unexpected error (such as a CGI script crash) + * that prevents the request from being fulfilled. + */ + public static final int HTTP_INTERNAL_ERROR = 500; + + /** + * The server does not support the requested functionality. + * @since 1.3 + */ + public static final int HTTP_NOT_IMPLEMENTED = 501; + + /** + * The proxy encountered a bad response from the server it was proxy-ing for + */ + public static final int HTTP_BAD_GATEWAY = 502; + + /** + * The HTTP service is not availalble, such as because it is overloaded + * and does not want additional requests. + */ + public static final int HTTP_UNAVAILABLE = 503; + + /** + * The proxy timed out getting a reply from the remote server it was + * proxy-ing for. + */ + public static final int HTTP_GATEWAY_TIMEOUT = 504; + + /** + * This server does not support the protocol version requested. + */ + public static final int HTTP_VERSION = 505; + + // Non-HTTP response static variables + + /** + * Flag to indicate whether or not redirects should be automatically + * followed by default. + */ + private static boolean followRedirects = true; + + /** + * This is a list of valid request methods, separated by "|" characters. + */ + private static final String valid_methods = + "|GET|POST|HEAD|OPTIONS|PUT|DELETE|TRACE|"; + + // Instance Variables + + /** + * The requested method in use for this connection. Default is GET. + */ + protected String method = "GET"; + + /** + * The response code received from the server + */ + protected int responseCode = -1; + + /** + * The response message string received from the server. + */ + protected String responseMessage; + + /** + * If this instance should follow redirect requests. + */ + protected boolean instanceFollowRedirects = followRedirects; + + /** + * Whether we already got a valid response code for this connection. + * Used by getResponseCode() and + * getResponseMessage(). + */ + private boolean gotResponseVals; + + /** + * Create an HttpURLConnection for the specified URL + * + * @param url The URL to create this connection for. + */ + protected HttpURLConnection(URL url) + { + super(url); + } + + /** + * Closes the connection to the server. + */ + public abstract void disconnect(); + + /** + * Returns a boolean indicating whether or not this connection is going + * through a proxy + * + * @return true if through a proxy, false otherwise + */ + public abstract boolean usingProxy(); + + /** + * Sets whether HTTP redirects (requests with response code 3xx) should be + * automatically followed by this class. True by default + * + * @param set true if redirects should be followed, false otherwis. + * + * @exception SecurityException If a security manager exists and its + * checkSetFactory method doesn't allow the operation + */ + public static void setFollowRedirects(boolean set) + { + // Throw an exception if an extant security mgr precludes + // setting the factory. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkSetFactory(); + + followRedirects = set; + } + + /** + * Returns a boolean indicating whether or not HTTP redirects will + * automatically be followed or not. + * + * @return true if redirects will be followed, false otherwise + */ + public static boolean getFollowRedirects() + { + return followRedirects; + } + + /** + * Returns the value of this HttpURLConnection's instanceFollowRedirects + * field + * + * @return true if following redirects is enabled, false otherwise + */ + public boolean getInstanceFollowRedirects() + { + return instanceFollowRedirects; + } + + /** + * Sets the value of this HttpURLConnection's instanceFollowRedirects field + * + * @param follow true to enable following redirects, false otherwise + */ + public void setInstanceFollowRedirects(boolean follow) + { + instanceFollowRedirects = follow; + } + + /** + * Set the method for the URL request, one of: + * GET POST HEAD OPTIONS PUT DELETE TRACE are legal + * + * @param method the method to use + * + * @exception ProtocolException If the method cannot be reset or if the + * requested method isn't valid for HTTP + */ + public void setRequestMethod(String method) throws ProtocolException + { + if (connected) + throw new ProtocolException("Already connected"); + + method = method.toUpperCase(); + if (valid_methods.indexOf("|" + method + "|") != -1) + this.method = method; + else + throw new ProtocolException("Invalid HTTP request method: " + method); + } + + /** + * The request method currently in use for this connection. + * + * @return The request method + */ + public String getRequestMethod() + { + return method; + } + + /** + * Gets the status code from an HTTP response message, or -1 if + * the response code could not be determined. + * Note that all valid response codes have class variables + * defined for them in this class. + * + * @return The response code + * + * @exception IOException If an error occurs + */ + public int getResponseCode() throws IOException + { + if (! gotResponseVals) + getResponseVals(); + return responseCode; + } + + /** + * Gets the HTTP response message, if any, returned along with the + * response code from a server. Null if no response message was set + * or an error occured while connecting. + * + * @return The response message + * + * @exception IOException If an error occurs + */ + public String getResponseMessage() throws IOException + { + if (! gotResponseVals) + getResponseVals(); + return responseMessage; + } + + private void getResponseVals() throws IOException + { + // getHeaderField() will connect for us, but do it here first in + // order to pick up IOExceptions. + if (! connected) + connect(); + + gotResponseVals = true; + + // If responseCode not yet explicitly set by subclass + if (responseCode == -1) + { + // Response is the first header received from the connection. + String respField = getHeaderField(0); + + if (respField == null || ! respField.startsWith("HTTP/")) + { + // Set to default values on failure. + responseCode = -1; + responseMessage = null; + return; + } + + int firstSpc; + int nextSpc; + firstSpc = respField.indexOf(' '); + nextSpc = respField.indexOf(' ', firstSpc + 1); + responseMessage = respField.substring(nextSpc + 1); + String codeStr = respField.substring(firstSpc + 1, nextSpc); + try + { + responseCode = Integer.parseInt(codeStr); + } + catch (NumberFormatException e) + { + // Set to default values on failure. + responseCode = -1; + responseMessage = null; + } + } + } + + /** + * Returns a permission object representing the permission necessary to make + * the connection represented by this object + * + * @return the permission necessary for this connection + * + * @exception IOException If an error occurs + */ + public Permission getPermission() throws IOException + { + URL url = getURL(); + String host = url.getHost(); + int port = url.getPort(); + if (port == -1) + port = 80; + + host = host + ":" + port; + + return new SocketPermission(host, "connect"); + } + + /** + * This method allows the caller to retrieve any data that might have + * been sent despite the fact that an error occurred. For example, the + * HTML page sent along with a 404 File Not Found error. If the socket + * is not connected, or if no error occurred or no data was returned, + * this method returns null. + * + * @return An InputStream for reading error data. + */ + public InputStream getErrorStream() + { + if (! connected) + return null; + + int code; + try + { + code = getResponseCode(); + } + catch (IOException e) + { + code = -1; + } + + if (code == -1) + return null; + + if (((code / 100) != 4) || ((code / 100) != 5)) + return null; + + try + { + PushbackInputStream pbis = new PushbackInputStream(getInputStream()); + + int i = pbis.read(); + if (i == -1) + return null; + + pbis.unread(i); + return pbis; + } + catch (IOException e) + { + return null; + } + } + + /** + * Returns the value of the named field parsed as date + * + * @param key the key of the header field + * @param value the default value if the header field is not present + * + * @return the value of the header field + */ + public long getHeaderFieldDate(String key, long value) + { + // FIXME: implement this correctly + // http://www.w3.org/Protocols/HTTP-NG/ng-notes.txt + return super.getHeaderFieldDate(key, value); + } +} diff --git a/libjava/classpath/java/net/Inet4Address.java b/libjava/classpath/java/net/Inet4Address.java new file mode 100644 index 0000000..00c6501 --- /dev/null +++ b/libjava/classpath/java/net/Inet4Address.java @@ -0,0 +1,233 @@ +/* Inet4Address.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 java.net; + +import java.io.ObjectStreamException; + +/* + * Written using on-line Java Platform 1.4 API Specification and + * RFC 1884 (http://www.ietf.org/rfc/rfc1884.txt), + * RFC 1918 (http://www.ietf.org/rfc/rfc1918.txt), + * RFC 2365 (http://www.ietf.org/rfc/rfc2365.txt) + * + * @author Michael Koch + * @status Believed complete and correct. + */ +public final class Inet4Address extends InetAddress +{ + /** + * For compatability with Sun's JDK 1.4.2 rev. 5 + */ + static final long serialVersionUID = 3286316764910316507L; + + /** + * needed for serialization + */ + private Object writeReplace() throws ObjectStreamException + { + return new InetAddress(addr, hostName); + } + + /** + * Initializes this object's addr instance variable from the passed in + * byte array. Note that this constructor is protected and is called + * only by static methods in this class. + * + * @param addr The IP number of this address as an array of bytes + * @param hostname The hostname of this IP address. + */ + Inet4Address(byte[] addr, String host) + { + super(addr, host); + } + + /** + * Checks if the address is a multicast address + * + * @since 1.1 + */ + public boolean isMulticastAddress() + { + return super.isMulticastAddress(); + } + + /** + * Checks if this address is a loopback address + */ + public boolean isLoopbackAddress() + { + return super.isLoopbackAddress(); + } + + /** + * Checks if this address is a wildcard address + * + * @since 1.4 + */ + public boolean isAnyLocalAddress() + { + return super.isAnyLocalAddress(); + } + + /** + * Checks if this address is a link local address + * + * @since 1.4 + */ + public boolean isLinkLocalAddress() + { + return super.isLinkLocalAddress(); + } + + /** + * Checks if this address is a site local address + * + * @since 1.4 + */ + public boolean isSiteLocalAddress() + { + return super.isSiteLocalAddress(); + } + + /** + * Checks if this multicast address has global scope + * + * @since 1.4 + */ + public boolean isMCGlobal() + { + return super.isMCGlobal(); + } + + /** + * Checks if this multicast address has node scope + * + * @since 1.4 + */ + public boolean isMCNodeLocal() + { + return isMCNodeLocal(); + } + + /** + * Checks if this multicast address has link scope + * + * @since 1.4 + */ + public boolean isMCLinkLocal() + { + return super.isMCLinkLocal(); + } + + /** + * Checks if this multicast address has site scope + * + * @since 1.4 + */ + public boolean isMCSiteLocal() + { + return super.isMCSiteLocal(); + } + + /** + * Checks if this multicast address has organization scope + * + * @since 1.4 + */ + public boolean isMCOrgLocal() + { + return isMCOrgLocal(); + } + + /** + * Returns the address of the current instance + */ + public byte[] getAddress() + { + return (byte[]) addr.clone(); + } + + /** + * Returns the address as string + * + * @since 1.0.2 + */ + public String getHostAddress() + { + return super.getHostAddress(); + } + + /** + * Computes the hashcode of the instance + */ + public int hashCode() + { + int hash = 0; + int len = addr.length; + int i = len > 4 ? len - 4 : 0; + + for (; i < len; i++) + hash = (hash << 8) | (addr[i] & 0xFF); + + return hash; + } + + /** + * Compare the current Inet4Address instance with obj + * + * @param obj Object to compare with + */ + public boolean equals(Object obj) + { + if (! (obj instanceof InetAddress)) + return false; + + byte[] addr1 = addr; + byte[] addr2 = ((InetAddress) obj).addr; + + if (addr1.length != addr2.length) + return false; + + for (int i = addr1.length; --i >= 0;) + if (addr1[i] != addr2[i]) + return false; + + return true; + } +} diff --git a/libjava/classpath/java/net/Inet6Address.java b/libjava/classpath/java/net/Inet6Address.java new file mode 100644 index 0000000..0d62fe9 --- /dev/null +++ b/libjava/classpath/java/net/Inet6Address.java @@ -0,0 +1,261 @@ +/* Inet6Address.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 java.net; + +import java.util.Arrays; + +/* + * Written using on-line Java Platform 1.4 API Specification and + * RFC 1884 (http://www.ietf.org/rfc/rfc1884.txt) + * + * @author Michael Koch + * @status Believed complete and correct. + */ +public final class Inet6Address extends InetAddress +{ + static final long serialVersionUID = 6880410070516793377L; + + /** + * Needed for serialization + */ + byte[] ipaddress; + + /** + * Create an Inet6Address object + * + * @param addr The IP address + * @param host The hostname + */ + Inet6Address(byte[] addr, String host) + { + super(addr, host); + // Super constructor clones the addr. Get a reference to the clone. + this.ipaddress = this.addr; + } + + /** + * Utility routine to check if the InetAddress is an IP multicast address + * + * @since 1.1 + */ + public boolean isMulticastAddress() + { + return ipaddress[0] == 0xFF; + } + + /** + * Utility routine to check if the InetAddress in a wildcard address + * + * @since 1.4 + */ + public boolean isAnyLocalAddress() + { + byte[] anylocal = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + return Arrays.equals(ipaddress, anylocal); + } + + /** + * Utility routine to check if the InetAddress is a loopback address + * + * @since 1.4 + */ + public boolean isLoopbackAddress() + { + byte[] loopback = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + + return Arrays.equals(ipaddress, loopback); + } + + /** + * Utility routine to check if the InetAddress is an link local address + * + * @since 1.4 + */ + public boolean isLinkLocalAddress() + { + return ipaddress[0] == 0xFA; + } + + /** + * Utility routine to check if the InetAddress is a site local address + * + * @since 1.4 + */ + public boolean isSiteLocalAddress() + { + return ipaddress[0] == 0xFB; + } + + /** + * Utility routine to check if the multicast address has global scope + * + * @since 1.4 + */ + public boolean isMCGlobal() + { + if (! isMulticastAddress()) + return false; + + return (ipaddress[1] & 0x0F) == 0xE; + } + + /** + * Utility routine to check if the multicast address has node scope + * + * @since 1.4 + */ + public boolean isMCNodeLocal() + { + if (! isMulticastAddress()) + return false; + + return (ipaddress[1] & 0x0F) == 0x1; + } + + /** + * Utility routine to check if the multicast address has link scope + * + * @since 1.4 + */ + public boolean isMCLinkLocal() + { + if (! isMulticastAddress()) + return false; + + return (ipaddress[1] & 0x0F) == 0x2; + } + + /** + * Utility routine to check if the multicast address has site scope + * + * @since 1.4 + */ + public boolean isMCSiteLocal() + { + if (! isMulticastAddress()) + return false; + + return (ipaddress[1] & 0x0F) == 0x5; + } + + /** + * Utility routine to check if the multicast address has organization scope + * + * @since 1.4 + */ + public boolean isMCOrgLocal() + { + if (! isMulticastAddress()) + return false; + + return (ipaddress[1] & 0x0F) == 0x8; + } + + /** + * Returns the raw IP address of this InetAddress object. The result is in + * network byte order: the highest order byte of the address is i + * n getAddress()[0] + */ + public byte[] getAddress() + { + return (byte[]) ipaddress.clone(); + } + + /** + * Returns the IP address string in textual presentation + */ + public String getHostAddress() + { + StringBuffer sbuf = new StringBuffer(40); + + for (int i = 0; i < 16; i += 2) + { + int x = ((ipaddress[i] & 0xFF) << 8) | (ipaddress[i + 1] & 0xFF); + + if (i > 0) + sbuf.append(':'); + + sbuf.append(Integer.toHexString(x)); + } + + return sbuf.toString(); + } + + /** + * Returns a hashcode for this IP address + */ + public int hashCode() + { + return super.hashCode(); + } + + /** + * Compares this object against the specified object + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Inet6Address)) + return false; + + // this.ipaddress is never set in this class except to + // the value of the super class' addr. The super classes + // equals(Object) will do the compare. + return super.equals(obj); + } + + /** + * Utility routine to check if the InetAddress is an + * IPv4 compatible IPv6 address + * + * @since 1.4 + */ + public boolean isIPv4CompatibleAddress() + { + if (ipaddress[0] != 0x00 || ipaddress[1] != 0x00 || ipaddress[2] != 0x00 + || ipaddress[3] != 0x00 || ipaddress[4] != 0x00 + || ipaddress[5] != 0x00 || ipaddress[6] != 0x00 + || ipaddress[7] != 0x00 || ipaddress[8] != 0x00 + || ipaddress[9] != 0x00 || ipaddress[10] != 0x00 + || ipaddress[11] != 0x00) + return false; + + return true; + } +} diff --git a/libjava/classpath/java/net/InetAddress.java b/libjava/classpath/java/net/InetAddress.java new file mode 100644 index 0000000..94dc6cb --- /dev/null +++ b/libjava/classpath/java/net/InetAddress.java @@ -0,0 +1,813 @@ +/* InetAddress.java -- Class to model an Internet address + 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 java.net; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.util.HashMap; +import java.util.StringTokenizer; + +/** + * This class models an Internet address. It does not have a public + * constructor. Instead, new instances of this objects are created + * using the static methods getLocalHost(), getByName(), and + * getAllByName(). + * + *

    This class fulfills the function of the C style functions gethostname(), + * gethostbyname(), and gethostbyaddr(). It resolves Internet DNS names + * into their corresponding numeric addresses and vice versa.

    + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner + * + * @specnote This class is not final since JK 1.4 + */ +public class InetAddress implements Serializable +{ + private static final long serialVersionUID = 3286316764910316507L; + + /** + * The default DNS hash table size, + * Use a prime number happy with hash table. + */ + private static final int DEFAULT_CACHE_SIZE = 89; + + /** + * The default caching period in minutes. + */ + private static final int DEFAULT_CACHE_PERIOD = 4 * 60; + + /** + * Percentage of cache entries to purge when the table gets full. + */ + private static final int DEFAULT_CACHE_PURGE_PCT = 30; + + /** + * The special IP address INADDR_ANY. + */ + private static InetAddress inaddr_any; + + /** + * Dummy InetAddress, used to bind socket to any (all) network interfaces. + */ + static InetAddress ANY_IF; + + /** + * Stores static localhost address object. + */ + static InetAddress LOCALHOST; + + /** + * The size of the cache. + */ + private static int cache_size = 0; + + /** + * The length of time we will continue to read the address from cache + * before forcing another lookup. + */ + private static int cache_period = 0; + + /** + * What percentage of the cache we will purge if it gets full. + */ + private static int cache_purge_pct = 0; + + /** + * HashMap to use as DNS lookup cache. + * Use HashMap because all accesses to cache are already synchronized. + */ + private static HashMap cache; + + static + { + // Look for properties that override default caching behavior + cache_size = + Integer.getInteger("gnu.java.net.dns_cache_size", DEFAULT_CACHE_SIZE) + .intValue(); + cache_period = + Integer.getInteger("gnu.java.net.dns_cache_period", + DEFAULT_CACHE_PERIOD * 60 * 1000).intValue(); + + cache_purge_pct = + Integer.getInteger("gnu.java.net.dns_cache_purge_pct", + DEFAULT_CACHE_PURGE_PCT).intValue(); + + // Fallback to defaults if necessary + if ((cache_purge_pct < 1) || (cache_purge_pct > 100)) + cache_purge_pct = DEFAULT_CACHE_PURGE_PCT; + + // Create the cache + if (cache_size != 0) + cache = new HashMap(cache_size); + + // precompute the ANY_IF address + try + { + ANY_IF = getInaddrAny(); + + byte[] ip_localhost = { 127, 0, 0, 1 }; + LOCALHOST = new Inet4Address(ip_localhost, "localhost"); + } + catch (UnknownHostException uhe) + { + // Hmmm, make one up and hope that it works. + byte[] zeros = { 0, 0, 0, 0 }; + ANY_IF = new Inet4Address(zeros, "0.0.0.0"); + } + } + + /** + * The Serialized Form specifies that an int 'address' is saved/restored. + * This class uses a byte array internally so we'll just do the conversion + * at serialization time and leave the rest of the algorithm as is. + */ + private int address; + + /** + * An array of octets representing an IP address. + */ + transient byte[] addr; + + /** + * The name of the host for this address. + */ + String hostName; + + /** + * The time this address was looked up. + */ + transient long lookup_time; + + /** + * The field 'family' seems to be the AF_ value. + * FIXME: Much of the code in the other java.net classes does not make + * use of this family field. A better implementation would be to make + * use of getaddrinfo() and have other methods just check the family + * field rather than examining the length of the address each time. + */ + int family; + + /** + * Initializes this object's addr instance variable from the passed in + * byte array. Note that this constructor is protected and is called + * only by static methods in this class. + * + * @param ipaddr The IP number of this address as an array of bytes + * @param hostname The hostname of this IP address. + */ + InetAddress(byte[] ipaddr, String hostname) + { + addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone(); + hostName = hostname; + + lookup_time = System.currentTimeMillis(); + + family = 2; /* AF_INET */ + } + + /** + * Returns true if this address is a multicast address, false otherwise. + * An address is multicast if the high four bits are "1110". These are + * also known as "Class D" addresses. + * + * @return true if mulitcast, false if not + * + * @since 1.1 + */ + public boolean isMulticastAddress() + { + // Mask against high order bits of 1110 + if (addr.length == 4) + return (addr[0] & 0xf0) == 0xe0; + + return false; + } + + /** + * Utility routine to check if the InetAddress in a wildcard address + * + * @since 1.4 + */ + public boolean isAnyLocalAddress() + { + // This is the IPv4 implementation. + // Any class derived from InetAddress should override this. + return equals(ANY_IF); + } + + /** + * Utility routine to check if the InetAddress is a loopback address + * + * @since 1.4 + */ + public boolean isLoopbackAddress() + { + // This is the IPv4 implementation. + // Any class derived from InetAddress should override this. + return (addr[0] & 0xff) == 0x7f; + } + + /** + * Utility routine to check if InetAddress is a link local address + * + * @since 1.4 + */ + public boolean isLinkLocalAddress() + { + // This is the IPv4 implementation. + // Any class derived from InetAddress should override this. + // XXX: This seems to not exist with IPv4 addresses + return false; + } + + /** + * Utility routine to check if InetAddress is a site local address + * + * @since 1.4 + */ + public boolean isSiteLocalAddress() + { + // This is the IPv4 implementation. + // Any class derived from InetAddress should override this. + + // 10.0.0.0/8 + if ((addr[0] & 0xff) == 0x0a) + return true; + + // 172.16.0.0/12 + if ((addr[0] & 0xff) == 0xac && (addr[1] & 0xf0) == 0x10) + return true; + + // 192.168.0.0/16 + if ((addr[0] & 0xff) == 0xc0 && (addr[1] & 0xff) == 0xa8) + return true; + + // XXX: Do we need to check more addresses here ? + return false; + } + + /** + * Utility routine to check if InetAddress is a global multicast address + * + * @since 1.4 + */ + public boolean isMCGlobal() + { + // This is the IPv4 implementation. + // Any class derived from InetAddress should override this. + // XXX: This seems to not exist with IPv4 addresses + return false; + } + + /** + * Utility routine to check if InetAddress is a node local multicast address. + * + * @since 1.4 + */ + public boolean isMCNodeLocal() + { + // This is the IPv4 implementation. + // Any class derived from InetAddress should override this. + // XXX: This seems to not exist with IPv4 addresses + return false; + } + + /** + * Utility routine to check if InetAddress is a link local multicast address. + * + * @since 1.4 + */ + public boolean isMCLinkLocal() + { + // This is the IPv4 implementation. + // Any class derived from InetAddress should override this. + if (! isMulticastAddress()) + return false; + + return ((addr[0] & 0xff) == 0xe0 + && (addr[1] & 0xff) == 0x00 + && (addr[2] & 0xff) == 0x00); + } + + /** + * Utility routine to check if InetAddress is a site local multicast address. + * + * @since 1.4 + */ + public boolean isMCSiteLocal() + { + // This is the IPv4 implementation. + // Any class derived from InetAddress should override this. + // XXX: This seems to not exist with IPv4 addresses + return false; + } + + /** + * Utility routine to check if InetAddress is a organization local + * multicast address. + * + * @since 1.4 + */ + public boolean isMCOrgLocal() + { + // This is the IPv4 implementation. + // Any class derived from InetAddress should override this. + // XXX: This seems to not exist with IPv4 addresses + return false; + } + + /** + * Returns the hostname for this address. This will return the IP address + * as a String if there is no hostname available for this address + * + * @return The hostname for this address + */ + public String getHostName() + { + if (hostName != null) + return hostName; + + try + { + hostName = VMInetAddress.getHostByAddr(addr); + return hostName; + } + catch (UnknownHostException e) + { + return getHostAddress(); + } + } + + /** + * Returns the canonical hostname represented by this InetAddress + * + * @since 1.4 + */ + public String getCanonicalHostName() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + try + { + sm.checkConnect(hostName, -1); + } + catch (SecurityException e) + { + return getHostAddress(); + } + } + + // Try to find the FDQN now + InetAddress address; + byte[] ipaddr = getAddress(); + + if (ipaddr.length == 16) + address = new Inet6Address(getAddress(), null); + else + address = new Inet4Address(getAddress(), null); + + return address.getHostName(); + } + + /** + * Returns the IP address of this object as a byte array. + * + * @return IP address + */ + public byte[] getAddress() + { + // An experiment shows that JDK1.2 returns a different byte array each + // time. This makes sense, in terms of security. + return (byte[]) addr.clone(); + } + + /** + * Returns the IP address of this object as a String. The address is in + * the dotted octet notation, for example, "127.0.0.1". + * + * @return The IP address of this object in String form + * + * @since 1.0.2 + */ + public String getHostAddress() + { + StringBuffer sb = new StringBuffer(40); + + int len = addr.length; + int i = 0; + + for ( ; ; ) + { + sb.append(addr[i] & 0xff); + i++; + + if (i == len) + break; + + sb.append('.'); + } + + return sb.toString(); + } + + /** + * Returns a hash value for this address. Useful for creating hash + * tables. Overrides Object.hashCode() + * + * @return A hash value for this address. + */ + public int hashCode() + { + // There hashing algorithm is not specified, but a simple experiment + // shows that it is equal to the address, as a 32-bit big-endian integer. + int hash = 0; + int len = addr.length; + int i = len > 4 ? len - 4 : 0; + + for (; i < len; i++) + hash = (hash << 8) | (addr[i] & 0xff); + + return hash; + } + + /** + * Tests this address for equality against another InetAddress. The two + * addresses are considered equal if they contain the exact same octets. + * This implementation overrides Object.equals() + * + * @param obj The address to test for equality + * + * @return true if the passed in object's address is equal to this one's, + * false otherwise + */ + public boolean equals(Object obj) + { + if (! (obj instanceof InetAddress)) + return false; + + // "The Java Class Libraries" 2nd edition says "If a machine has + // multiple names instances of InetAddress for different name of + // that same machine are not equal. This is because they have + // different host names." This violates the description in the + // JDK 1.2 API documentation. A little experimentation + // shows that the latter is correct. + byte[] addr2 = ((InetAddress) obj).addr; + + if (addr.length != addr2.length) + return false; + + for (int i = 0; i < addr.length; i++) + if (addr[i] != addr2[i]) + return false; + + return true; + } + + /** + * Converts this address to a String. This string contains the IP in + * dotted decimal form. For example: "127.0.0.1" This method is equivalent + * to getHostAddress() and overrides Object.toString() + * + * @return This address in String form + */ + public String toString() + { + String addr = getHostAddress(); + String host = (hostName != null) ? hostName : ""; + return host + "/" + addr; + } + + /** + * Returns an InetAddress object given the raw IP address. + * + * The argument is in network byte order: the highest order byte of the + * address is in getAddress()[0]. + * + * @param addr The IP address to create the InetAddress object from + * + * @exception UnknownHostException If IP address has illegal length + * + * @since 1.4 + */ + public static InetAddress getByAddress(byte[] addr) + throws UnknownHostException + { + return getByAddress(null, addr); + } + + /** + * Creates an InetAddress based on the provided host name and IP address. + * No name service is checked for the validity of the address. + * + * @param host The hostname of the InetAddress object to create + * @param addr The IP address to create the InetAddress object from + * + * @exception UnknownHostException If IP address is of illegal length + * + * @since 1.4 + */ + public static InetAddress getByAddress(String host, byte[] addr) + throws UnknownHostException + { + if (addr.length == 4) + return new Inet4Address(addr, host); + + if (addr.length == 16) + return new Inet6Address(addr, host); + + throw new UnknownHostException("IP address has illegal length"); + } + + /** + * If hostname is a valid numeric IP address, return the numeric address. + * Otherwise, return null. + * + * @param hostname the name of the host + */ + private static byte[] aton(String hostname) + { + StringTokenizer st = new StringTokenizer(hostname, "."); + + if (st.countTokens() == 4) + { + int index; + byte[] address = new byte[4]; + + for (index = 0; index < 4; index++) + { + try + { + short n = Short.parseShort(st.nextToken()); + + if ((n < 0) || (n > 255)) + break; + + address[index] = (byte) n; + } + catch (NumberFormatException e) + { + break; + } + } + + if (index == 4) + return address; + } + + return null; + } + + /** + * Returns an InetAddress object representing the IP address of the given + * hostname. This name can be either a hostname such as "www.urbanophile.com" + * or an IP address in dotted decimal format such as "127.0.0.1". If the + * hostname is null or "", the hostname of the local machine is supplied by + * default. This method is equivalent to returning the first element in + * the InetAddress array returned from GetAllByName. + * + * @param hostname The name of the desired host, or null for the local + * loopback address. + * + * @return The address of the host as an InetAddress object. + * + * @exception UnknownHostException If no IP address for the host could + * be found + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + */ + public static InetAddress getByName(String hostname) + throws UnknownHostException + { + InetAddress[] addresses = getAllByName(hostname); + return addresses[0]; + } + + /** + * Returns an array of InetAddress objects representing all the host/ip + * addresses of a given host, given the host's name. This name can be + * either a hostname such as "www.urbanophile.com" or an IP address in + * dotted decimal format such as "127.0.0.1". If the value is null, the + * hostname of the local machine is supplied by default. + * + * @param hostname The name of the desired host, or null for the + * local loopback address. + * + * @return All addresses of the host as an array of InetAddress objects. + * + * @exception UnknownHostException If no IP address for the host could + * be found + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + */ + public static InetAddress[] getAllByName(String hostname) + throws UnknownHostException + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkConnect(hostname, -1); + + InetAddress[] addresses; + + // Default to current host if necessary + if (hostname == null) + { + addresses = new InetAddress[1]; + addresses[0] = LOCALHOST; + return addresses; + } + + // Check the cache for this host before doing a lookup + addresses = checkCacheFor(hostname); + + if (addresses != null) + return addresses; + + // Not in cache, try the lookup + byte[][] iplist = VMInetAddress.getHostByName(hostname); + + if (iplist.length == 0) + throw new UnknownHostException(hostname); + + addresses = new InetAddress[iplist.length]; + + for (int i = 0; i < iplist.length; i++) + { + if (iplist[i].length != 4) + throw new UnknownHostException(hostname); + + addresses[i] = new Inet4Address(iplist[i], hostname); + } + + addToCache(hostname, addresses); + return addresses; + } + + /** + * This method checks the DNS cache to see if we have looked this hostname + * up before. If so, we return the cached addresses unless it has been in the + * cache too long. + * + * @param hostname The hostname to check for + * + * @return The InetAddress for this hostname or null if not available + */ + private static synchronized InetAddress[] checkCacheFor(String hostname) + { + InetAddress[] addresses = null; + + if (cache_size == 0) + return null; + + Object obj = cache.get(hostname); + if (obj == null) + return null; + + if (obj instanceof InetAddress[]) + addresses = (InetAddress[]) obj; + + if (addresses == null) + return null; + + if (cache_period != -1) + if ((System.currentTimeMillis() - addresses[0].lookup_time) > cache_period) + { + cache.remove(hostname); + return null; + } + + return addresses; + } + + /** + * This method adds an InetAddress object to our DNS cache. Note that + * if the cache is full, then we run a purge to get rid of old entries. + * This will cause a performance hit, thus applications using lots of + * lookups should set the cache size to be very large. + * + * @param hostname The hostname to cache this address under + * @param obj The InetAddress or InetAddress array to store + */ + private static synchronized void addToCache(String hostname, Object obj) + { + if (cache_size == 0) + return; + + // Check to see if hash table is full + if (cache_size != -1) + if (cache.size() == cache_size) + { + // FIXME Add code to purge later. + } + + cache.put(hostname, obj); + } + + /** + * Returns the special address INADDR_ANY used for binding to a local + * port on all IP addresses hosted by a the local host. + * + * @return An InetAddress object representing INDADDR_ANY + * + * @exception UnknownHostException If an error occurs + */ + static InetAddress getInaddrAny() throws UnknownHostException + { + if (inaddr_any == null) + { + byte[] tmp = VMInetAddress.lookupInaddrAny(); + inaddr_any = new Inet4Address(tmp, null); + } + + return inaddr_any; + } + + /** + * Returns an InetAddress object representing the address of the current + * host. + * + * @return The local host's address + * + * @exception UnknownHostException If no IP address for the host could + * be found + */ + public static InetAddress getLocalHost() throws UnknownHostException + { + String hostname = VMInetAddress.getLocalHostname(); + return getByName(hostname); + } + + /* + * Needed for serialization + */ + private void readResolve() throws ObjectStreamException + { + // FIXME: implement this + } + + private void readObject(ObjectInputStream ois) + throws IOException, ClassNotFoundException + { + ois.defaultReadObject(); + addr = new byte[4]; + addr[3] = (byte) address; + + for (int i = 2; i >= 0; --i) + addr[i] = (byte) (address >>= 8); + + family = 2; /* AF_INET */ + } + + private void writeObject(ObjectOutputStream oos) throws IOException + { + // Build a 32 bit address from the last 4 bytes of a 4 byte IPv4 address + // or a 16 byte IPv6 address. + int len = addr.length; + int i = len - 4; + + for (; i < len; i++) + address = address << 8 | (addr[i] & 0xff); + + oos.defaultWriteObject(); + } +} diff --git a/libjava/classpath/java/net/InetSocketAddress.java b/libjava/classpath/java/net/InetSocketAddress.java new file mode 100644 index 0000000..30d34e7 --- /dev/null +++ b/libjava/classpath/java/net/InetSocketAddress.java @@ -0,0 +1,221 @@ +/* InetSocketAddress.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 java.net; + + +/** + * InetSocketAddress instances represent socket addresses + * in the java.nio package. They encapsulate a InetAddress and + * a port number. + * + * @since 1.4 + */ +public class InetSocketAddress extends SocketAddress +{ + /** + * Compatible with JDK 1.4+ + */ + private static final long serialVersionUID = 5076001401234631237L; + + /** + * Name of host. + */ + private String hostname; + + /** + * Address of host. + */ + private InetAddress addr; + + /** + * Port of host. + */ + private int port; + + /** + * Constructs an InetSocketAddress instance. + * + * @param addr Address of the socket + * @param port Port if the socket + * + * @exception IllegalArgumentException If the port number is illegel + */ + public InetSocketAddress(InetAddress addr, int port) + throws IllegalArgumentException + { + if (port < 0 || port > 65535) + throw new IllegalArgumentException("Bad port number: " + port); + + if (addr == null) + addr = InetAddress.ANY_IF; + + this.addr = addr; + this.port = port; + this.hostname = addr.getHostName(); + } + + /** + * Constructs an InetSocketAddress instance. + * + * @param port Port if the socket + * + * @exception IllegalArgumentException If the port number is illegal + */ + public InetSocketAddress(int port) throws IllegalArgumentException + { + this((InetAddress) null, port); + } + + /** + * Constructs an InetSocketAddress instance. + * + * @param hostname The hostname for the socket address + * @param port The port for the socket address + * + * @exception IllegalArgumentException If the port number is illegal + */ + public InetSocketAddress(String hostname, int port) + throws IllegalArgumentException + { + if (hostname == null) + throw new IllegalArgumentException("Null host name value"); + + if (port < 0 || port > 65535) + throw new IllegalArgumentException("Bad port number: " + port); + + this.port = port; + this.hostname = hostname; + + try + { + this.addr = InetAddress.getByName(hostname); + } + catch (Exception e) // UnknownHostException, SecurityException + { + this.addr = null; + } + } + + /** + * Test if obj is a InetSocketAddress and + * has the same address and port + * + * @param obj The obj to compare this address with. + * + * @return True if obj is equal. + */ + public final boolean equals(Object obj) + { + // InetSocketAddress objects are equal when addr and port are equal. + // The hostname may differ. + if (obj instanceof InetSocketAddress) + { + InetSocketAddress sa = (InetSocketAddress) obj; + + if (addr == null && sa.addr != null) + return false; + else if (addr == null && sa.addr == null) + return hostname.equals(sa.hostname) && sa.port == port; + else + return addr.equals(sa.addr) && sa.port == port; + } + + return false; + } + + /** + * Returns the InetAddress or + * null if its unresolved + * + * @return The IP address of this address. + */ + public final InetAddress getAddress() + { + return addr; + } + + /** + * Returns hostname + * + * @return The hostname of this address. + */ + public final String getHostName() + { + return hostname; + } + + /** + * Returns the port + * + * @return The port of this address. + */ + public final int getPort() + { + return port; + } + + /** + * Returns the hashcode of the InetSocketAddress + * + * @return The hashcode for this address. + */ + public final int hashCode() + { + return port + addr.hashCode(); + } + + /** + * Checks wether the address has been resolved or not + * + * @return True if address is unresolved. + */ + public final boolean isUnresolved() + { + return addr == null; + } + + /** + * Returns the InetSocketAddress as string + * + * @return A string represenation of this address. + */ + public String toString() + { + return (addr == null ? hostname : addr.getHostName()) + ":" + port; + } +} diff --git a/libjava/classpath/java/net/JarURLConnection.java b/libjava/classpath/java/net/JarURLConnection.java new file mode 100644 index 0000000..3067ecb --- /dev/null +++ b/libjava/classpath/java/net/JarURLConnection.java @@ -0,0 +1,228 @@ +/* JarURLConnection.java -- Class for manipulating remote jar files + Copyright (C) 1998, 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 java.net; + +import java.io.IOException; +import java.security.cert.Certificate; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + + +/** + * This abstract class represents a common superclass for implementations + * of jar URL's. A jar URL is a special type of URL that allows JAR + * files on remote systems to be accessed. It has the form: + *

    + * jar:<standard URL pointing to jar filei>!/file/within/jarfile + *

    for example: + *

    + * jar:http://www.urbanophile.com/java/foo.jar!/com/urbanophile/bar.class + *

    + * That example URL points to the file /com/urbanophile/bar.class in the + * remote JAR file http://www.urbanophile.com/java/foo.jar. The HTTP + * protocol is used only as an example. Any supported remote protocol + * can be used. + *

    + * This class currently works by retrieving the entire jar file into a + * local cache file, then performing standard jar operations on it. + * (At least this is true for the default protocol implementation). + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Kresten Krab Thorup (krab@gnu.org) + * @date Aug 10, 1999. + * + * @since 1.2 + */ +public abstract class JarURLConnection extends URLConnection +{ + /** + * This is the actual URL that points the remote jar file. This is parsed + * out of the jar URL by the constructor. + */ + private final URL jarFileURL; + + /** + * The connection to the jar file itself. A JarURLConnection + * can represent an entry in a jar file or an entire jar file. In + * either case this describes just the jar file itself. + */ + protected URLConnection jarFileURLConnection; + + /** + * This is the jar file "entry name" or portion after the "!/" in the + * URL which represents the pathname inside the actual jar file. + */ + private final String entryName; + + /** + * Creates a JarURLConnection from an URL object + * + * @param url The URL object for this connection. + * + * @exception MalformedURLException If url is invalid + * + * @specnote This constructor is protected since JDK 1.4 + */ + protected JarURLConnection(URL url) throws MalformedURLException + { + super(url); + + if (! url.getProtocol().equals("jar")) + throw new MalformedURLException(url + ": Not jar protocol."); + + String spec = url.getFile(); + int bang = spec.indexOf("!/"); + if (bang == -1) + throw new MalformedURLException(url + ": No `!/' in spec."); + + // Extract the url for the jar itself. + jarFileURL = new URL(spec.substring(0, bang)); + + // Get the name of the entry, if any. + entryName = spec.length() == (bang + 2) ? null : spec.substring(bang + 2); + } + + /** + * This method returns the "real" URL where the JarFile is located. + * //****Is this right?***** + * + * @return The remote URL + */ + public URL getJarFileURL() + { + return jarFileURL; + } + + /** + * Returns the "entry name" portion of the jar URL. This is the portion + * after the "!/" in the jar URL that represents the pathname inside the + * actual jar file. + * + * @return The entry name. + */ + public String getEntryName() + { + return entryName; + } + + /** + * Returns the entry in this jar file specified by the URL. + * + * @return The jar entry + * + * @exception IOException If an error occurs + */ + public JarEntry getJarEntry() throws IOException + { + JarFile jarFile = getJarFile(); + + return jarFile != null ? jarFile.getJarEntry(entryName) : null; + } + + /** + * Returns a read-only JarFile object for the remote jar file + * + * @return The JarFile object + * + * @exception IOException If an error occurs + */ + public abstract JarFile getJarFile() throws IOException; + + /** + * Returns an array of Certificate objects for the jar file entry specified + * by this URL or null if there are none + * + * @return A Certificate array + * + * @exception IOException If an error occurs + */ + public Certificate[] getCertificates() throws IOException + { + JarEntry entry = getJarEntry(); + + return entry != null ? entry.getCertificates() : null; + } + + /** + * Returns the main Attributes for the jar file specified in the URL or + * null if there are none + * + * @return The main Attributes for the JAR file for this connection + * + * @exception IOException If an error occurs + */ + public Attributes getMainAttributes() throws IOException + { + Manifest manifest = getManifest(); + + return manifest != null ? manifest.getMainAttributes() : null; + } + + /** + * Returns the Attributes for the Jar entry specified by the URL or null + * if none + * + * @return The Attributes object for this connection if the URL for it points + * to a JAR file entry, null otherwise + * + * @exception IOException If an error occurs + */ + public Attributes getAttributes() throws IOException + { + JarEntry entry = getJarEntry(); + + return entry != null ? entry.getAttributes() : null; + } + + /** + * Returns a Manifest object for this jar file, or null if there is no + * manifest. + * + * @return The Manifest for this connection, or null if none + * + * @exception IOException If an error occurs + */ + public Manifest getManifest() throws IOException + { + JarFile file = getJarFile(); + + return file != null ? file.getManifest() : null; + } +} diff --git a/libjava/classpath/java/net/MalformedURLException.java b/libjava/classpath/java/net/MalformedURLException.java new file mode 100644 index 0000000..27e2018 --- /dev/null +++ b/libjava/classpath/java/net/MalformedURLException.java @@ -0,0 +1,74 @@ +/* MalformedURLException.java -- A URL was not in a valid format + Copyright (C) 1998, 1999, 2000, 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 java.net; + +import java.io.IOException; + + +/** + * This exception indicates that a URL passed to an object was not in a + * valid format. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class MalformedURLException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -182787522200415866L; + + /** + * Create a new instance without a descriptive error message. + */ + public MalformedURLException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message a message describing the error that occurred + */ + public MalformedURLException(String message) + { + super(message); + } +} // class MalformedURLException diff --git a/libjava/classpath/java/net/MimeTypeMapper.java b/libjava/classpath/java/net/MimeTypeMapper.java new file mode 100644 index 0000000..1747f4d --- /dev/null +++ b/libjava/classpath/java/net/MimeTypeMapper.java @@ -0,0 +1,213 @@ +/* MimeTypeMapper.java -- A class for mapping file names to MIME types + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.net; + +import java.util.Hashtable; + + +/** + * This non-public class is used to implement the FileNameMap interface + * which defines a mechanism for mapping filenames to MIME types. + * + * @version 0.5 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +class MimeTypeMapper implements FileNameMap +{ + /** + * This array of strings is used to identify a MIME type based on a file + * extension. This is list is based on the Apache mime.types file. + */ + protected static final String[][] mime_strings = + { + { "application/mac-binhex40", "hqx" }, + { "application/mac-compactpro", "cpt" }, + { "application/msword", "doc" }, + { "application/octet-stream", "bin" }, + { "application/octet-stream", "dms" }, + { "application/octet-stream", "lha" }, + { "application/octet-stream", "lzh" }, + { "application/octet-stream", "exe" }, + { "application/octet-stream", "class" }, + { "application/oda", "oda" }, + { "application/pdf", "pdf" }, + { "application/postscript", "ai" }, + { "application/postscript", "eps" }, + { "application/postscript", "ps" }, + { "application/powerpoint", "ppt" }, + { "application/rtf", "rtf" }, + { "application/x-bcpio", "bcpio" }, + { "application/x-cdlink", "vcd" }, + { "application/x-compress", "Z" }, + { "application/x-cpio", "cpio" }, + { "application/x-csh", "csh" }, + { "application/x-director", "dcr" }, + { "application/x-director", "dir" }, + { "application/x-director", "dxr" }, + { "application/x-dvi", "dvi" }, + { "application/x-gtar", "gtar" }, + { "application/x-gzip", "gz" }, + { "application/x-hdf", "hdf" }, + { "application/x-httpd-cgi", "cgi" }, + { "application/x-koan", "skp" }, + { "application/x-koan", "skd" }, + { "application/x-koan", "skt" }, + { "application/x-koan", "skm" }, + { "application/x-latex", "latex" }, + { "application/x-mif", "mif" }, + { "application/x-netcdf", "nc" }, + { "application/x-netcdf", "cdf" }, + { "application/x-sh", "sh" }, + { "application/x-shar", "shar" }, + { "application/x-stuffit", "sit" }, + { "application/x-sv4cpio", "sv4cpio" }, + { "application/x-sv4crc", "sv4crc" }, + { "application/x-tar", "tar" }, + { "application/x-tcl", "tcl" }, + { "application/x-tex", "tex" }, + { "application/x-texinfo", "texinfo" }, + { "application/x-texinfo", "texi" }, + { "application/x-troff", "t" }, + { "application/x-troff", "tr" }, + { "application/x-troff", "roff" }, + { "application/x-troff-man", "man" }, + { "application/x-troff-me", "me" }, + { "application/x-troff-ms", "ms" }, + { "application/x-ustar", "ustar" }, + { "application/x-wais-source", "src" }, + { "application/zip", "zip" }, + { "audio/basic", "au" }, + { "audio/basic", "snd" }, + { "audio/mpeg", "mpga" }, + { "audio/mpeg", "mp2" }, + { "audio/mpeg", "mp3" }, + { "audio/x-aiff", "aif" }, + { "audio/x-aiff", "aiff" }, + { "audio/x-aiff", "aifc" }, + { "audio/x-pn-realaudio", "ram" }, + { "audio/x-pn-realaudio-plugin", "rpm" }, + { "audio/x-realaudio", "ra" }, + { "audio/x-wav", "wav" }, + { "chemical/x-pdb", "pdb" }, + { "chemical/x-pdb", "xyz" }, + { "image/gif", "gif" }, + { "image/ief", "ief" }, + { "image/jpeg", "jpeg" }, + { "image/jpeg", "jpg" }, + { "image/jpeg", "jpe" }, + { "image/png", "png" }, + { "image/tiff", "tiff" }, + { "image/tiff", "tif" }, + { "image/x-cmu-raster", "ras" }, + { "image/x-portable-anymap", "pnm" }, + { "image/x-portable-bitmap", "pbm" }, + { "image/x-portable-graymap", "pgm" }, + { "image/x-portable-pixmap", "ppm" }, + { "image/x-rgb", "rgb" }, + { "image/x-xbitmap", "xbm" }, + { "image/x-xpixmap", "xpm" }, + { "image/x-xwindowdump", "xwd" }, + { "text/html", "html" }, + { "text/html", "htm" }, + { "text/plain", "txt" }, + { "text/richtext", "rtx" }, + { "text/tab-separated-values", "tsv" }, + { "text/x-setext", "etx" }, + { "text/x-sgml", "sgml" }, + { "text/x-sgml", "sgm" }, + { "video/mpeg", "mpeg" }, + { "video/mpeg", "mpg" }, + { "video/mpeg", "mpe" }, + { "video/quicktime", "qt" }, + { "video/quicktime", "mov" }, + { "video/x-msvideo", "avi" }, + { "video/x-sgi-movie", "movie" }, + { "x-conference/x-cooltalk", "ice" }, + { "x-world/x-vrml", "wrl" }, + { "x-world/x-vrml", "vrml" } + }; + + /** + * The MIME types above are put into this Hashtable for faster lookup. + */ + private static Hashtable mime_types = new Hashtable(150); + + // Static initializer to load MIME types into Hashtable + static + { + for (int i = 0; i < mime_strings.length; i++) + mime_types.put(mime_strings[i][1], mime_strings[i][0]); + } + + /** + * Create a new MimeTypeMapper object. + */ + public MimeTypeMapper() + { + // Do nothing here. + } + + /** + * The method returns the MIME type of the filename passed as an argument. + * The value returned is based on the extension of the filename. The + * default content type returned if this method cannot determine the + * actual content type is "application/octet-stream" + * + * @param filename The name of the file to return the MIME type for + * + * @return The MIME type + */ + public String getContentTypeFor(String filename) + { + int index = filename.lastIndexOf("."); + if (index != -1) + { + if (index == filename.length()) + return "application/octet-stream"; + else + filename = filename.substring(index + 1); + } + + String type = (String) mime_types.get(filename); + if (type == null) + return "application/octet-stream"; + else + return type; + } +} diff --git a/libjava/classpath/java/net/MulticastSocket.java b/libjava/classpath/java/net/MulticastSocket.java new file mode 100644 index 0000000..03bdf1e --- /dev/null +++ b/libjava/classpath/java/net/MulticastSocket.java @@ -0,0 +1,486 @@ +/* MulticastSocket.java -- Class for using multicast sockets + Copyright (C) 1998, 1999, 2000, 2001, 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 java.net; + +import java.io.IOException; +import java.util.Enumeration; + + +/** + * 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 class models a multicast UDP socket. A multicast address is a + * class D internet address (one whose most significant bits are 1110). + * A multicast group consists of a multicast address and a well known + * port number. All members of the group listening on that address and + * port will receive all the broadcasts to the group. + *

    + * Please note that applets are not allowed to use multicast sockets + * + * 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. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) (Documentation comments) + * @since 1.1 + * @date May 18, 1999. + */ +public class MulticastSocket extends DatagramSocket +{ + /** + * Create a MulticastSocket that this not bound to any address + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation + */ + public MulticastSocket() throws IOException + { + this(new InetSocketAddress(0)); + } + + /** + * Create a multicast socket bound to the specified port + * + * @param port The port to bind to + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation + */ + public MulticastSocket(int port) throws IOException + { + this(new InetSocketAddress(port)); + } + + /** + * Create a multicast socket bound to the specified SocketAddress. + * + * @param address The SocketAddress the multicast socket will be bound to + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation + * + * @since 1.4 + */ + public MulticastSocket(SocketAddress address) throws IOException + { + super((SocketAddress) null); + setReuseAddress(true); + if (address != null) + bind(address); + } + + /** + * Returns the interface being used for multicast packets + * + * @return The multicast interface + * + * @exception SocketException If an error occurs + */ + public InetAddress getInterface() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + return (InetAddress) getImpl().getOption(SocketOptions.IP_MULTICAST_IF); + } + + /** + * Returns the current value of the "Time to Live" option. This is the + * number of hops a packet can make before it "expires". This method id + * deprecated. Use getTimeToLive instead. + * + * @return The TTL value + * + * @exception IOException If an error occurs + * + * @deprecated 1.2 Replaced by getTimeToLive() + * + * @see MulticastSocket#getTimeToLive() + */ + public byte getTTL() throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + // Use getTTL here rather than getTimeToLive in case we're using an impl + // other than the default PlainDatagramSocketImpl and it doesn't have + // getTimeToLive yet. + return getImpl().getTTL(); + } + + /** + * Returns the current value of the "Time to Live" option. This is the + * number of hops a packet can make before it "expires". + * + * @return The TTL value + * + * @exception IOException If an error occurs + * + * @since 1.2 + */ + public int getTimeToLive() throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + return getImpl().getTimeToLive(); + } + + /** + * Sets the interface to use for sending multicast packets. + * + * @param addr The new interface to use. + * + * @exception SocketException If an error occurs. + * + * @since 1.4 + */ + public void setInterface(InetAddress addr) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().setOption(SocketOptions.IP_MULTICAST_IF, addr); + } + + /** + * Sets the local network interface used to send multicast messages + * + * @param netIf The local network interface used to send multicast messages + * + * @exception SocketException If an error occurs + * + * @see MulticastSocket#getNetworkInterface() + * + * @since 1.4 + */ + public void setNetworkInterface(NetworkInterface netIf) + throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Enumeration e = netIf.getInetAddresses(); + + if (! e.hasMoreElements()) + throw new SocketException("no network devices found"); + + InetAddress address = (InetAddress) e.nextElement(); + getImpl().setOption(SocketOptions.IP_MULTICAST_IF, address); + } + + /** + * Gets the local network interface which is used to send multicast messages + * + * @return The local network interface to send multicast messages + * + * @exception SocketException If an error occurs + * + * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) + * + * @since 1.4 + */ + public NetworkInterface getNetworkInterface() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + InetAddress address = + (InetAddress) getImpl().getOption(SocketOptions.IP_MULTICAST_IF); + NetworkInterface netIf = NetworkInterface.getByInetAddress(address); + + return netIf; + } + + /** + * Disable/Enable local loopback of multicast packets. The option is used by + * the platform's networking code as a hint for setting whether multicast + * data will be looped back to the local socket. + * + * Because this option is a hint, applications that want to verify what + * loopback mode is set to should call #getLoopbackMode + * + * @param disable True to disable loopback mode + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public void setLoopbackMode(boolean disable) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, + Boolean.valueOf(disable)); + } + + /** + * Checks if local loopback mode is enabled + * + * @return true if loopback mode is enabled, false otherwise + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public boolean getLoopbackMode() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP); + + if (buf instanceof Boolean) + return ((Boolean) buf).booleanValue(); + + throw new SocketException("unexpected type"); + } + + /** + * Sets the "Time to Live" value for a socket. The value must be between + * 1 and 255. + * + * @param ttl The new TTL value + * + * @exception IOException If an error occurs + * + * @deprecated 1.2 Replaced by setTimeToLive + * + * @see MulticastSocket#setTimeToLive(int ttl) + */ + public void setTTL(byte ttl) throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + // Use setTTL here rather than setTimeToLive in case we're using an impl + // other than the default PlainDatagramSocketImpl and it doesn't have + // setTimeToLive yet. + getImpl().setTTL(ttl); + } + + /** + * Sets the "Time to Live" value for a socket. The value must be between + * 1 and 255. + * + * @param ttl The new TTL value + * + * @exception IOException If an error occurs + * + * @since 1.2 + */ + public void setTimeToLive(int ttl) throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (ttl <= 0 || ttl > 255) + throw new IllegalArgumentException("Invalid ttl: " + ttl); + + getImpl().setTimeToLive(ttl); + } + + /** + * Joins the specified multicast group. + * + * @param mcastaddr The address of the group to join + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkMulticast method doesn't allow the operation + */ + public void joinGroup(InetAddress mcastaddr) throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (! mcastaddr.isMulticastAddress()) + throw new IOException("Not a Multicast address"); + + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkMulticast(mcastaddr); + + getImpl().join(mcastaddr); + } + + /** + * Leaves the specified multicast group + * + * @param mcastaddr The address of the group to leave + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkMulticast method doesn't allow the operation + */ + public void leaveGroup(InetAddress mcastaddr) throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (! mcastaddr.isMulticastAddress()) + throw new IOException("Not a Multicast address"); + + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkMulticast(mcastaddr); + + getImpl().leave(mcastaddr); + } + + /** + * Joins the specified mulitcast group on a specified interface. + * + * @param mcastaddr The multicast address to join + * @param netIf The local network interface to receive the multicast + * messages on or null to defer the interface set by #setInterface or + * #setNetworkInterface + * + * @exception IOException If an error occurs + * @exception IllegalArgumentException If address type is not supported + * @exception SecurityException If a security manager exists and its + * checkMulticast method doesn't allow the operation + * + * @see MulticastSocket#setInterface(InetAddress addr) + * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) + * + * @since 1.4 + */ + public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) + throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (! (mcastaddr instanceof InetSocketAddress)) + throw new IllegalArgumentException("SocketAddress type not supported"); + + InetSocketAddress tmp = (InetSocketAddress) mcastaddr; + + if (! tmp.getAddress().isMulticastAddress()) + throw new IOException("Not a Multicast address"); + + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkMulticast(tmp.getAddress()); + + getImpl().joinGroup(mcastaddr, netIf); + } + + /** + * Leaves the specified mulitcast group on a specified interface. + * + * @param mcastaddr The multicast address to leave + * @param netIf The local networki interface or null to defer to the + * interface set by setInterface or setNetworkInterface + * + * @exception IOException If an error occurs + * @exception IllegalArgumentException If address type is not supported + * @exception SecurityException If a security manager exists and its + * checkMulticast method doesn't allow the operation + * + * @see MulticastSocket#setInterface(InetAddress addr) + * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) + * + * @since 1.4 + */ + public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) + throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + InetSocketAddress tmp = (InetSocketAddress) mcastaddr; + + if (! tmp.getAddress().isMulticastAddress()) + throw new IOException("Not a Multicast address"); + + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkMulticast(tmp.getAddress()); + + getImpl().leaveGroup(mcastaddr, netIf); + } + + /** + * Sends a packet of data to a multicast address with a TTL that is + * different from the default TTL on this socket. The default TTL for + * the socket is not changed. + * + * @param packet The packet of data to send + * @param ttl The TTL for this packet + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkConnect or checkMulticast method doesn't allow the operation + * + * @deprecated + */ + public synchronized void send(DatagramPacket packet, byte ttl) + throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + SecurityManager s = System.getSecurityManager(); + if (s != null) + { + InetAddress addr = packet.getAddress(); + if (addr.isMulticastAddress()) + s.checkPermission(new SocketPermission(addr.getHostName() + + packet.getPort(), + "accept,connect")); + else + s.checkConnect(addr.getHostAddress(), packet.getPort()); + } + + int oldttl = getImpl().getTimeToLive(); + getImpl().setTimeToLive(((int) ttl) & 0xFF); + getImpl().send(packet); + getImpl().setTimeToLive(oldttl); + } +} diff --git a/libjava/classpath/java/net/NetPermission.java b/libjava/classpath/java/net/NetPermission.java new file mode 100644 index 0000000..cabe54e --- /dev/null +++ b/libjava/classpath/java/net/NetPermission.java @@ -0,0 +1,90 @@ +/* NetPermission.java -- A class for basic miscellaneous network permission + Copyright (C) 1998, 2000, 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 java.net; + +import java.security.BasicPermission; + + +/** + * This class is used to model miscellaneous network permissions. It is + * a subclass of BasicPermission. This means that it models a + * "boolean" permission. One that you either have or do not have. Thus + * there is no permitted action list associated with this object. + * + * The following permission names are defined for this class: + * + *

      + *
    • setDefaultAuthenticator - Grants the ability to install a facility + * to collect username and password information when requested by a + * web site or proxy server.
    • + *
    • requestPasswordAuthentication - Grants the ability to ask the + * authentication facility for the user's password.
    • + *
    • specifyStreamHandler - Grants the permission to specify the + * stream handler class used when loading from a URL.
    • + *
    + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public final class NetPermission extends BasicPermission +{ + static final long serialVersionUID = -8343910153355041693L; + + /** + * Initializes a new instance of NetPermission with the + * specified name. + * + * @param name The name of this permission. + */ + public NetPermission(String name) + { + super(name); + } + + /** + * Initializes a new instance of NetPermission with the + * specified name and perms. Note that the perms field is irrelevant and is + * ignored. This constructor should never need to be used. + * + * @param name The name of this permission + * @param perms The permitted actions of this permission (ignored) + */ + public NetPermission(String name, String perms) + { + super(name); + } +} diff --git a/libjava/classpath/java/net/NetworkInterface.java b/libjava/classpath/java/net/NetworkInterface.java new file mode 100644 index 0000000..eccd2da --- /dev/null +++ b/libjava/classpath/java/net/NetworkInterface.java @@ -0,0 +1,259 @@ +/* NetworkInterface.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 java.net; + +import java.util.Enumeration; +import java.util.Vector; + +/** + * This class models a network interface on the host computer. A network + * interface contains a name (typically associated with a specific + * hardware adapter) and a list of addresses that are bound to it. + * For example, an ethernet interface may be named "eth0" and have the + * address 192.168.1.101 assigned to it. + * + * @author Michael Koch (konqueror@gmx.de) + * @since 1.4 + */ +public final class NetworkInterface +{ + private String name; + private Vector inetAddresses; + + NetworkInterface(String name, InetAddress address) + { + this.name = name; + this.inetAddresses = new Vector(1, 1); + this.inetAddresses.add(address); + } + + NetworkInterface(String name, InetAddress[] addresses) + { + this.name = name; + this.inetAddresses = new Vector(addresses.length, 1); + + for (int i = 0; i < addresses.length; i++) + this.inetAddresses.add(addresses[i]); + } + + /** + * Returns the name of the network interface + * + * @return The name of the interface. + */ + public String getName() + { + return name; + } + + /** + * Returns all available addresses of the network interface + * + * If a @see SecurityManager is available all addresses are checked + * with @see SecurityManager::checkConnect() if they are available. + * Only InetAddresses are returned where the security manager + * doesn't throw an exception. + * + * @return An enumeration of all addresses. + */ + public Enumeration getInetAddresses() + { + SecurityManager s = System.getSecurityManager(); + + if (s == null) + return inetAddresses.elements(); + + Vector tmpInetAddresses = new Vector(1, 1); + + for (Enumeration addresses = inetAddresses.elements(); + addresses.hasMoreElements();) + { + InetAddress addr = (InetAddress) addresses.nextElement(); + try + { + s.checkConnect(addr.getHostAddress(), 58000); + tmpInetAddresses.add(addr); + } + catch (SecurityException e) + { + // Ignore. + } + } + + return tmpInetAddresses.elements(); + } + + /** + * Returns the display name of the interface + * + * @return The display name of the interface + */ + public String getDisplayName() + { + return name; + } + + /** + * Returns an network interface by name + * + * @param name The name of the interface to return + * + * @return a NetworkInterface object representing the interface, + * or null if there is no interface with that name. + * + * @exception SocketException If an error occurs + * @exception NullPointerException If the specified name is null + */ + public static NetworkInterface getByName(String name) + throws SocketException + { + Vector networkInterfaces = VMNetworkInterface.getInterfaces(); + + for (Enumeration e = networkInterfaces.elements(); e.hasMoreElements();) + { + NetworkInterface tmp = (NetworkInterface) e.nextElement(); + + if (name.equals(tmp.getName())) + return tmp; + } + + // No interface with the given name found. + return null; + } + + /** + * Return a network interface by its address + * + * @param addr The address of the interface to return + * + * @return the interface, or null if none found + * + * @exception SocketException If an error occurs + * @exception NullPointerException If the specified addess is null + */ + public static NetworkInterface getByInetAddress(InetAddress addr) + throws SocketException + { + Vector networkInterfaces = VMNetworkInterface.getInterfaces(); + + for (Enumeration interfaces = networkInterfaces.elements(); + interfaces.hasMoreElements();) + { + NetworkInterface tmp = (NetworkInterface) interfaces.nextElement(); + + for (Enumeration addresses = tmp.inetAddresses.elements(); + addresses.hasMoreElements();) + { + if (addr.equals((InetAddress) addresses.nextElement())) + return tmp; + } + } + + throw new SocketException("no network interface is bound to such an IP address"); + } + + /** + * Return an Enumeration of all available network interfaces + * + * @return all interfaces + * + * @exception SocketException If an error occurs + */ + public static Enumeration getNetworkInterfaces() throws SocketException + { + Vector networkInterfaces = VMNetworkInterface.getInterfaces(); + + if (networkInterfaces.isEmpty()) + return null; + + return networkInterfaces.elements(); + } + + /** + * Checks if the current instance is equal to obj + * + * @param obj The object to compare with + * + * @return true if equal, false otherwise + */ + public boolean equals(Object obj) + { + if (! (obj instanceof NetworkInterface)) + return false; + + NetworkInterface tmp = (NetworkInterface) obj; + + return (name.equals(tmp.name) && inetAddresses.equals(tmp.inetAddresses)); + } + + /** + * Returns the hashcode of the current instance + * + * @return the hashcode + */ + public int hashCode() + { + // FIXME: hash correctly + return name.hashCode() + inetAddresses.hashCode(); + } + + /** + * Returns a string representation of the interface + * + * @return the string + */ + public String toString() + { + // FIXME: check if this is correct + String result; + String separator = System.getProperty("line.separator"); + + result = + "name: " + getDisplayName() + " (" + getName() + ") addresses:" + + separator; + + for (Enumeration e = inetAddresses.elements(); e.hasMoreElements();) + { + InetAddress address = (InetAddress) e.nextElement(); + result += address.toString() + ";" + separator; + } + + return result; + } +} diff --git a/libjava/classpath/java/net/NoRouteToHostException.java b/libjava/classpath/java/net/NoRouteToHostException.java new file mode 100644 index 0000000..48c3a8e --- /dev/null +++ b/libjava/classpath/java/net/NoRouteToHostException.java @@ -0,0 +1,74 @@ +/* NoRouteToHostException.java -- Cannot connect to a host + Copyright (C) 1998, 1999, 2000, 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 java.net; + + +/** + * This exception indicates that there is no TCP/IP route to the requested + * host. This is often due to a misconfigured routing table. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class NoRouteToHostException extends SocketException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -1897550894873493790L; + + /** + * Create an instance without a descriptive error message. + */ + public NoRouteToHostException() + { + } + + /** + * Create an instance with a descriptive error message, such as the text + * from strerror(3). + * + * @param message a message describing the error that occurred + */ + public NoRouteToHostException(String message) + { + super(message); + } +} // class NoRouteToHostException diff --git a/libjava/classpath/java/net/PasswordAuthentication.java b/libjava/classpath/java/net/PasswordAuthentication.java new file mode 100644 index 0000000..1d4ec89 --- /dev/null +++ b/libjava/classpath/java/net/PasswordAuthentication.java @@ -0,0 +1,92 @@ +/* PasswordAuthentication.java -- Container class for username/password pairs + Copyright (C) 1998, 2000, 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 java.net; + + +/** + * This class serves a container for username/password pairs. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * + * @since 1.2 + */ +public final class PasswordAuthentication +{ + /** + * The username + */ + private String username; + + /** + * The password + */ + private char[] password; + + /** + * Creates a new PasswordAuthentication object from the + * specified username and password. + * + * @param username The username for this object + * @param password The password for this object + */ + public PasswordAuthentication(String username, char[] password) + { + this.username = username; + this.password = password; + } + + /** + * Returns the username associated with this object + * + * @return The username + */ + public String getUserName() + { + return username; + } + + /** + * Returns the password associated with this object + * + * @return The password + */ + public char[] getPassword() + { + return password; + } +} diff --git a/libjava/classpath/java/net/PortUnreachableException.java b/libjava/classpath/java/net/PortUnreachableException.java new file mode 100644 index 0000000..49a8c9e --- /dev/null +++ b/libjava/classpath/java/net/PortUnreachableException.java @@ -0,0 +1,72 @@ +/* PortUnreachableException.java -- received an ICMP port unreachable datagram + 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 java.net; + + +/** + * This exception signals that an ICMP port unreachable datagram has been + * received. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public class PortUnreachableException extends SocketException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 8462541992376507323L; + + /** + * Create a new instance without a descriptive error message. + */ + public PortUnreachableException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message a message describing the error that occurred + */ + public PortUnreachableException(String message) + { + super(message); + } +} // class PortUnreachableException diff --git a/libjava/classpath/java/net/ProtocolException.java b/libjava/classpath/java/net/ProtocolException.java new file mode 100644 index 0000000..27718a9 --- /dev/null +++ b/libjava/classpath/java/net/ProtocolException.java @@ -0,0 +1,75 @@ +/* ProtocolException.java -- a low level protocol error occurred + Copyright (C) 1998, 1999, 2000, 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 java.net; + +import java.io.IOException; + + +/** + * This exception indicates that some sort of low level protocol + * exception occurred. Look in the descriptive message (if any) for + * details on what went wrong. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class ProtocolException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -6098449442062388080L; + + /** + * Create a new instance without a descriptive error message. + */ + public ProtocolException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message a message describing the error that occurred + */ + public ProtocolException(String message) + { + super(message); + } +} // class ProtocolException diff --git a/libjava/classpath/java/net/STATUS b/libjava/classpath/java/net/STATUS new file mode 100644 index 0000000..25dff96 --- /dev/null +++ b/libjava/classpath/java/net/STATUS @@ -0,0 +1,48 @@ +X ContentHandlerFactory +X FileNameMap +X SocketImplFactory +X URLStreamHandlerFactory +* Authenticator +* ContentHandler ++ DatagramPacket ++ DatagramSocket ++ DatagramSocketImpl ++ HttpURLConnection ++ InetAddress +* JarURLConnection ++ MulticastSocket +* NetPermission +* PasswordAuthentication ++ PlainDatagramSocketImpl ++ PlainSocketImpl (internal) ++ ServerSocket ++ Socket ++ SocketImpl ++ SocketInputStream (internal) ++ SocketOptions (internal) ++ SocketOutputStream (internal) +* SocketPermission ++ URL + URLClassLoader ++ URLConnection +* URLEncoder ++ URLStreamHandler +X BindException +X ConnectException +X MalformedURLException +X NoRouteToHostException +X ProtocolException +X SocketException +X UnknownHostException +X UnknownServiceException + +--------------- ++ Native InetAddress ++ Native SocketImpl ++ Native DatagramSocketImpl ++ Protocol Handler for HTTP + Protocol Handler for FTP ++ ContentHandler for text + ContentHandler for gif + ContentHandler for jpeg + diff --git a/libjava/classpath/java/net/ServerSocket.java b/libjava/classpath/java/net/ServerSocket.java new file mode 100644 index 0000000..f73c748 --- /dev/null +++ b/libjava/classpath/java/net/ServerSocket.java @@ -0,0 +1,599 @@ +/* ServerSocket.java -- Class for implementing server side sockets + 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 java.net; + +import gnu.java.net.PlainSocketImpl; + +import java.io.IOException; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.ServerSocketChannel; + + +/* Written using on-line Java Platform 1.2 API Specification. + * Status: I believe all methods are implemented. + */ + +/** + * This class models server side sockets. The basic model is that the + * server socket is created and bound to some well known port. It then + * listens for and accepts connections. At that point the client and + * server sockets are ready to communicate with one another utilizing + * whatever application layer protocol they desire. + * + * As with the Socket class, most instance methods of this class + * simply redirect their calls to an implementation class. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + */ +public class ServerSocket +{ + /** + * This is the user defined SocketImplFactory, if one is supplied + */ + private static SocketImplFactory factory; + + /** + * This is the SocketImp object to which most instance methods in this + * class are redirected + */ + private SocketImpl impl; + + /** + * We need to retain the local address even after the socket is closed. + */ + private InetSocketAddress local; + + /* + * This constructor is only used by java.nio. + */ + + // FIXME: Workaround a bug in gcj. + //ServerSocket (PlainSocketImpl impl) throws IOException + ServerSocket(SocketImpl impl) throws IOException + { + if (impl == null) + throw new NullPointerException("impl may not be null"); + + this.impl = impl; + this.impl.create(true); + } + + /* + * This method is only used by java.nio. + */ + + // FIXME: Workaround a bug in gcj. + //PlainSocketImpl getImpl() + SocketImpl getImpl() + { + return impl; + } + + /** + * Constructor that simply sets the implementation. + * + * @exception IOException If an error occurs + * + * @specnote This constructor is public since JDK 1.4 + */ + public ServerSocket() throws IOException + { + if (factory != null) + impl = factory.createSocketImpl(); + else + impl = new PlainSocketImpl(); + + impl.create(true); + } + + /** + * Creates a server socket and binds it to the specified port. If the + * port number is 0, a random free port will be chosen. The pending + * connection queue on this socket will be set to 50. + * + * @param port The port number to bind to + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation + */ + public ServerSocket(int port) throws IOException + { + this(port, 50); + } + + /** + * Creates a server socket and binds it to the specified port. If the + * port number is 0, a random free port will be chosen. The pending + * connection queue on this socket will be set to the value passed as + * arg2. + * + * @param port The port number to bind to + * @param backlog The length of the pending connection queue + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation + */ + public ServerSocket(int port, int backlog) throws IOException + { + this(port, backlog, null); + } + + /** + * Creates a server socket and binds it to the specified port. If the + * port number is 0, a random free port will be chosen. The pending + * connection queue on this socket will be set to the value passed as + * backlog. The third argument specifies a particular local address to + * bind t or null to bind to all local address. + * + * @param port The port number to bind to + * @param backlog The length of the pending connection queue + * @param bindAddr The address to bind to, or null to bind to all addresses + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation + * + * @since 1.1 + */ + public ServerSocket(int port, int backlog, InetAddress bindAddr) + throws IOException + { + this(); + + // bind/listen socket + bind(new InetSocketAddress(bindAddr, port), backlog); + } + + /** + * Binds the server socket to a specified socket address + * + * @param endpoint The socket address to bind to + * + * @exception IOException If an error occurs + * @exception IllegalArgumentException If address type is not supported + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation + * + * @since 1.4 + */ + public void bind(SocketAddress endpoint) throws IOException + { + bind(endpoint, 50); + } + + /** + * Binds the server socket to a specified socket address + * + * @param endpoint The socket address to bind to + * @param backlog The length of the pending connection queue + * + * @exception IOException If an error occurs + * @exception IllegalArgumentException If address type is not supported + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation + * + * @since 1.4 + */ + public void bind(SocketAddress endpoint, int backlog) + throws IOException + { + if (isClosed()) + throw new SocketException("ServerSocket is closed"); + + if (! (endpoint instanceof InetSocketAddress)) + throw new IllegalArgumentException("Address type not supported"); + + InetSocketAddress tmp = (InetSocketAddress) endpoint; + + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkListen(tmp.getPort()); + + InetAddress addr = tmp.getAddress(); + + // Initialize addr with 0.0.0.0. + if (addr == null) + addr = InetAddress.ANY_IF; + + try + { + impl.bind(addr, tmp.getPort()); + impl.listen(backlog); + local = new InetSocketAddress( + (InetAddress) impl.getOption(SocketOptions.SO_BINDADDR), + impl.getLocalPort()); + } + catch (IOException exception) + { + close(); + throw exception; + } + catch (RuntimeException exception) + { + close(); + throw exception; + } + catch (Error error) + { + close(); + throw error; + } + } + + /** + * This method returns the local address to which this socket is bound + * + * @return The socket's local address + */ + public InetAddress getInetAddress() + { + if (local == null) + return null; + + return local.getAddress(); + } + + /** + * This method returns the local port number to which this socket is bound + * + * @return The socket's port number + */ + public int getLocalPort() + { + if (local == null) + return -1; + + return local.getPort(); + } + + /** + * Returns the local socket address + * + * @return the local socket address, null if not bound + * + * @since 1.4 + */ + public SocketAddress getLocalSocketAddress() + { + return local; + } + + /** + * Accepts a new connection and returns a connected Socket + * instance representing that connection. This method will block until a + * connection is available. + * + * @return socket object for the just accepted connection + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkListen method doesn't allow the operation + * @exception IllegalBlockingModeException If this socket has an associated + * channel, and the channel is in non-blocking mode + * @exception SocketTimeoutException If a timeout was previously set with + * setSoTimeout and the timeout has been reached + */ + public Socket accept() throws IOException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkListen(impl.getLocalPort()); + + Socket socket = new Socket(); + + try + { + implAccept(socket); + } + catch (IOException e) + { + try + { + socket.close(); + } + catch (IOException e2) + { + // Ignore. + } + + throw e; + } + + return socket; + } + + /** + * This protected method is used to help subclasses override + * ServerSocket.accept(). The passed in socket will be + * connected when this method returns. + * + * @param socket The socket that is used for the accepted connection + * + * @exception IOException If an error occurs + * @exception IllegalBlockingModeException If this socket has an associated + * channel, and the channel is in non-blocking mode + * + * @since 1.1 + */ + protected final void implAccept(Socket socket) throws IOException + { + if (isClosed()) + throw new SocketException("ServerSocket is closed"); + + // The Sun spec says that if we have an associated channel and + // it is in non-blocking mode, we throw an IllegalBlockingModeException. + // However, in our implementation if the channel itself initiated this + // operation, then we must honor it regardless of its blocking mode. + if (getChannel() != null && ! getChannel().isBlocking() + && ! ((PlainSocketImpl) getImpl()).isInChannelOperation()) + throw new IllegalBlockingModeException(); + + impl.accept(socket.impl); + socket.implCreated = true; + } + + /** + * Closes this socket and stops listening for connections + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + if (isClosed()) + return; + + impl.close(); + impl = null; + + if (getChannel() != null) + getChannel().close(); + } + + /** + * Returns the unique ServerSocketChannel object + * associated with this socket, if any. + * + *

    The socket only has a ServerSocketChannel if its created + * by ServerSocketChannel.open().

    + * + * @return the associated socket channel, null if none exists + * + * @since 1.4 + */ + public ServerSocketChannel getChannel() + { + return null; + } + + /** + * Returns true when the socket is bound, otherwise false + * + * @return true if socket is bound, false otherwise + * + * @since 1.4 + */ + public boolean isBound() + { + return local != null; + } + + /** + * Returns true if the socket is closed, otherwise false + * + * @return true if socket is closed, false otherwise + * + * @since 1.4 + */ + public boolean isClosed() + { + return impl == null; + } + + /** + * Sets the value of SO_TIMEOUT. A value of 0 implies that SO_TIMEOUT is + * disabled (ie, operations never time out). This is the number of + * milliseconds a socket operation can block before an + * InterruptedIOException is thrown. + * + * @param timeout The new SO_TIMEOUT value + * + * @exception SocketException If an error occurs + * + * @since 1.1 + */ + public void setSoTimeout(int timeout) throws SocketException + { + if (isClosed()) + throw new SocketException("ServerSocket is closed"); + + if (timeout < 0) + throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0"); + + impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); + } + + /** + * Retrieves the current value of the SO_TIMEOUT setting. A value of 0 + * implies that SO_TIMEOUT is disabled (ie, operations never time out). + * This is the number of milliseconds a socket operation can block before + * an InterruptedIOException is thrown. + * + * @return The value of SO_TIMEOUT + * + * @exception IOException If an error occurs + * + * @since 1.1 + */ + public int getSoTimeout() throws IOException + { + if (isClosed()) + throw new SocketException("ServerSocket is closed"); + + Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT); + + if (! (timeout instanceof Integer)) + throw new IOException("Internal Error"); + + return ((Integer) timeout).intValue(); + } + + /** + * Enables/Disables the SO_REUSEADDR option + * + * @param on true if SO_REUSEADDR should be enabled, false otherwise + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public void setReuseAddress(boolean on) throws SocketException + { + if (isClosed()) + throw new SocketException("ServerSocket is closed"); + + impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); + } + + /** + * Checks if the SO_REUSEADDR option is enabled + * + * @return true if SO_REUSEADDR is set, false otherwise + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public boolean getReuseAddress() throws SocketException + { + if (isClosed()) + throw new SocketException("ServerSocket is closed"); + + Object reuseaddr = impl.getOption(SocketOptions.SO_REUSEADDR); + + if (! (reuseaddr instanceof Boolean)) + throw new SocketException("Internal Error"); + + return ((Boolean) reuseaddr).booleanValue(); + } + + /** + * This method sets the value for the system level socket option + * SO_RCVBUF to the specified value. Note that valid values for this + * option are specific to a given operating system. + * + * @param size The new receive buffer size. + * + * @exception SocketException If an error occurs or Socket is not connected + * @exception IllegalArgumentException If size is 0 or negative + * + * @since 1.4 + */ + public void setReceiveBufferSize(int size) throws SocketException + { + if (isClosed()) + throw new SocketException("ServerSocket is closed"); + + if (size <= 0) + throw new IllegalArgumentException("SO_RCVBUF value must be > 0"); + + impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size)); + } + + /** + * This method returns the value of the system level socket option + * SO_RCVBUF, which is used by the operating system to tune buffer + * sizes for data transfers. + * + * @return The receive buffer size. + * + * @exception SocketException If an error occurs or Socket is not connected + * + * @since 1.4 + */ + public int getReceiveBufferSize() throws SocketException + { + if (isClosed()) + throw new SocketException("ServerSocket is closed"); + + Object buf = impl.getOption(SocketOptions.SO_RCVBUF); + + if (! (buf instanceof Integer)) + throw new SocketException("Internal Error: Unexpected type"); + + return ((Integer) buf).intValue(); + } + + /** + * Returns the value of this socket as a String. + * + * @return This socket represented as a String. + */ + public String toString() + { + if (! isBound()) + return "ServerSocket[unbound]"; + + return ("ServerSocket[addr=" + getInetAddress() + ",port=" + + impl.getPort() + ",localport=" + impl.getLocalPort() + "]"); + } + + /** + * Sets the SocketImplFactory for all + * ServerSocket's. This may only be done + * once per virtual machine. Subsequent attempts will generate an + * exception. Note that a SecurityManager check is made prior + * to setting the factory. If insufficient privileges exist to set the + * factory, an exception will be thrown + * + * @param fac the factory to set + * + * @exception SecurityException If this operation is not allowed by the + * SecurityManager. + * @exception SocketException If the factory object is already defined + * @exception IOException If any other error occurs + */ + public static synchronized void setSocketFactory(SocketImplFactory fac) + throws IOException + { + factory = fac; + } +} diff --git a/libjava/classpath/java/net/Socket.java b/libjava/classpath/java/net/Socket.java new file mode 100644 index 0000000..9432a6b --- /dev/null +++ b/libjava/classpath/java/net/Socket.java @@ -0,0 +1,1284 @@ +/* Socket.java -- Client socket implementation + 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 java.net; + +import gnu.java.net.PlainSocketImpl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.SocketChannel; + + +/* Written using on-line Java Platform 1.2 API Specification. + * Status: I believe all methods are implemented. + */ + +/** + * This class models a client site socket. A socket is a TCP/IP endpoint + * for network communications conceptually similar to a file handle. + *

    + * This class does not actually do any work. Instead, it redirects all of + * its calls to a socket implementation object which implements the + * SocketImpl interface. The implementation class is + * instantiated by factory class that implements the + * SocketImplFactory interface. A default + * factory is provided, however the factory may be set by a call to + * the setSocketImplFactory method. Note that this may only be + * done once per virtual machine. If a subsequent attempt is made to set the + * factory, a SocketException will be thrown. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + */ +public class Socket +{ + /** + * This is the user SocketImplFactory for this class. If this variable is + * null, a default factory is used. + */ + static SocketImplFactory factory; + + /** + * The implementation object to which calls are redirected + */ + // package-private because ServerSocket.implAccept() needs to access it. + SocketImpl impl; + + /** + * True if socket implementation was created by calling their + * create() method. + */ + // package-private because ServerSocket.implAccept() needs to access it. + boolean implCreated; + + /** + * True if the socket is bound. + */ + private boolean bound; + + /** + * True if input is shutdown. + */ + private boolean inputShutdown; + + /** + * True if output is shutdown. + */ + private boolean outputShutdown; + + /** + * Initializes a new instance of Socket object without + * connecting to a remote host. This useful for subclasses of socket that + * might want this behavior. + * + * @specnote This constructor is public since JDK 1.4 + * @since 1.1 + */ + public Socket() + { + if (factory != null) + impl = factory.createSocketImpl(); + else + impl = new PlainSocketImpl(); + } + + /** + * Initializes a new instance of Socket object without + * connecting to a remote host. This is useful for subclasses of socket + * that might want this behavior. + *

    + * Additionally, this socket will be created using the supplied + * implementation class instead the default class or one returned by a + * factory. If this value is null, the default Socket + * implementation is used. + * + * @param impl The SocketImpl to use for this + * Socket + * + * @exception SocketException If an error occurs + * + * @since 1.1 + */ + protected Socket(SocketImpl impl) throws SocketException + { + if (impl == null) + this.impl = new PlainSocketImpl(); + else + this.impl = impl; + } + + /** + * Initializes a new instance of Socket and connects to the + * hostname and port specified as arguments. + * + * @param host The name of the host to connect to + * @param port The port number to connect to + * + * @exception UnknownHostException If the hostname cannot be resolved to a + * network address. + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + */ + public Socket(String host, int port) + throws UnknownHostException, IOException + { + this(InetAddress.getByName(host), port, null, 0, true); + } + + /** + * Initializes a new instance of Socket and connects to the + * address and port number specified as arguments. + * + * @param address The address to connect to + * @param port The port number to connect to + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + */ + public Socket(InetAddress address, int port) throws IOException + { + this(address, port, null, 0, true); + } + + /** + * Initializes a new instance of Socket that connects to the + * named host on the specified port and binds to the specified local address + * and port. + * + * @param host The name of the remote host to connect to. + * @param port The remote port to connect to. + * @param localAddr The local address to bind to. + * @param localPort The local port to bind to. + * + * @exception SecurityException If the SecurityManager + * exists and does not allow a connection to the specified host/port or + * binding to the specified local host/port. + * @exception IOException If a connection error occurs. + * + * @since 1.1 + */ + public Socket(String host, int port, InetAddress localAddr, int localPort) + throws IOException + { + this(InetAddress.getByName(host), port, localAddr, localPort, true); + } + + /** + * Initializes a new instance of Socket and connects to the + * address and port number specified as arguments, plus binds to the + * specified local address and port. + * + * @param address The remote address to connect to + * @param port The remote port to connect to + * @param localAddr The local address to connect to + * @param localPort The local port to connect to + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + * + * @since 1.1 + */ + public Socket(InetAddress address, int port, InetAddress localAddr, + int localPort) throws IOException + { + this(address, port, localAddr, localPort, true); + } + + /** + * Initializes a new instance of Socket and connects to the + * hostname and port specified as arguments. If the stream argument is set + * to true, then a stream socket is created. If it is + * false, a datagram socket is created. + * + * @param host The name of the host to connect to + * @param port The port to connect to + * @param stream true for a stream socket, false + * for a datagram socket + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + * + * @deprecated Use the DatagramSocket class to create + * datagram oriented sockets. + */ + public Socket(String host, int port, boolean stream) + throws IOException + { + this(InetAddress.getByName(host), port, null, 0, stream); + } + + /** + * Initializes a new instance of Socket and connects to the + * address and port number specified as arguments. If the stream param is + * true, a stream socket will be created, otherwise a datagram + * socket is created. + * + * @param host The address to connect to + * @param port The port number to connect to + * @param stream true to create a stream socket, + * false to create a datagram socket. + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + * + * @deprecated Use the DatagramSocket class to create + * datagram oriented sockets. + */ + public Socket(InetAddress host, int port, boolean stream) + throws IOException + { + this(host, port, null, 0, stream); + } + + /** + * This constructor is where the real work takes place. Connect to the + * specified address and port. Use default local values if not specified, + * otherwise use the local host and port passed in. Create as stream or + * datagram based on "stream" argument. + *

    + * + * @param raddr The remote address to connect to + * @param rport The remote port to connect to + * @param laddr The local address to connect to + * @param lport The local port to connect to + * @param stream true for a stream socket, false for a datagram socket + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + */ + private Socket(InetAddress raddr, int rport, InetAddress laddr, int lport, + boolean stream) throws IOException + { + this(); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkConnect(raddr.getHostName(), rport); + + // bind socket + SocketAddress bindaddr = + laddr == null ? null : new InetSocketAddress(laddr, lport); + bind(bindaddr); + + // connect socket + connect(new InetSocketAddress(raddr, rport)); + + // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port, + // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as + // that default. JDK 1.2 doc infers not to do a bind. + } + + private SocketImpl getImpl() throws SocketException + { + try + { + if (! implCreated) + { + impl.create(true); + implCreated = true; + } + } + catch (IOException e) + { + throw new SocketException(e.getMessage()); + } + + return impl; + } + + /** + * Binds the socket to the givent local address/port + * + * @param bindpoint The address/port to bind to + * + * @exception IOException If an error occurs + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + * @exception IllegalArgumentException If the address type is not supported + * + * @since 1.4 + */ + public void bind(SocketAddress bindpoint) throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + // XXX: JDK 1.4.1 API documentation says that if bindpoint is null the + // socket will be bound to an ephemeral port and a valid local address. + if (bindpoint == null) + bindpoint = new InetSocketAddress(InetAddress.ANY_IF, 0); + + if (! (bindpoint instanceof InetSocketAddress)) + throw new IllegalArgumentException(); + + InetSocketAddress tmp = (InetSocketAddress) bindpoint; + + // bind to address/port + try + { + getImpl().bind(tmp.getAddress(), tmp.getPort()); + bound = true; + } + catch (IOException exception) + { + close(); + throw exception; + } + catch (RuntimeException exception) + { + close(); + throw exception; + } + catch (Error error) + { + close(); + throw error; + } + } + + /** + * Connects the socket with a remote address. + * + * @param endpoint The address to connect to + * + * @exception IOException If an error occurs + * @exception IllegalArgumentException If the addess type is not supported + * @exception IllegalBlockingModeException If this socket has an associated + * channel, and the channel is in non-blocking mode + * + * @since 1.4 + */ + public void connect(SocketAddress endpoint) throws IOException + { + connect(endpoint, 0); + } + + /** + * Connects the socket with a remote address. A timeout of zero is + * interpreted as an infinite timeout. The connection will then block + * until established or an error occurs. + * + * @param endpoint The address to connect to + * @param timeout The length of the timeout in milliseconds, or + * 0 to indicate no timeout. + * + * @exception IOException If an error occurs + * @exception IllegalArgumentException If the address type is not supported + * @exception IllegalBlockingModeException If this socket has an associated + * channel, and the channel is in non-blocking mode + * @exception SocketTimeoutException If the timeout is reached + * + * @since 1.4 + */ + public void connect(SocketAddress endpoint, int timeout) + throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (! (endpoint instanceof InetSocketAddress)) + throw new IllegalArgumentException("unsupported address type"); + + // The Sun spec says that if we have an associated channel and + // it is in non-blocking mode, we throw an IllegalBlockingModeException. + // However, in our implementation if the channel itself initiated this + // operation, then we must honor it regardless of its blocking mode. + if (getChannel() != null && ! getChannel().isBlocking() + && ! ((PlainSocketImpl) getImpl()).isInChannelOperation()) + throw new IllegalBlockingModeException(); + + if (! isBound()) + bind(null); + + try + { + getImpl().connect(endpoint, timeout); + } + catch (IOException exception) + { + close(); + throw exception; + } + catch (RuntimeException exception) + { + close(); + throw exception; + } + catch (Error error) + { + close(); + throw error; + } + } + + /** + * Returns the address of the remote end of the socket. If this socket + * is not connected, then null is returned. + * + * @return The remote address this socket is connected to + */ + public InetAddress getInetAddress() + { + if (! isConnected()) + return null; + + try + { + return getImpl().getInetAddress(); + } + catch (SocketException e) + { + // This cannot happen as we are connected. + } + + return null; + } + + /** + * Returns the local address to which this socket is bound. If this socket + * is not connected, then a wildcard address, for which + * @see isAnyLocalAddress() is true, is returned. + * + * @return The local address + * + * @since 1.1 + */ + public InetAddress getLocalAddress() + { + if (! isBound()) + return InetAddress.ANY_IF; + + InetAddress addr = null; + + try + { + addr = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR); + } + catch (SocketException e) + { + // (hopefully) shouldn't happen + // throw new java.lang.InternalError + // ("Error in PlainSocketImpl.getOption"); + return null; + } + + // FIXME: According to libgcj, checkConnect() is supposed to be called + // before performing this operation. Problems: 1) We don't have the + // addr until after we do it, so we do a post check. 2). The docs I + // see don't require this in the Socket case, only DatagramSocket, but + // we'll assume they mean both. + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkConnect(addr.getHostName(), getLocalPort()); + + return addr; + } + + /** + * Returns the port number of the remote end of the socket connection. If + * this socket is not connected, then 0 is returned. + * + * @return The remote port this socket is connected to + */ + public int getPort() + { + if (! isConnected()) + return 0; + + try + { + return getImpl().getPort(); + } + catch (SocketException e) + { + // This cannot happen as we are connected. + } + + return 0; + } + + /** + * Returns the local port number to which this socket is bound. If this + * socket is not connected, then -1 is returned. + * + * @return The local port + */ + public int getLocalPort() + { + if (! isBound()) + return -1; + + try + { + if (getImpl() != null) + return getImpl().getLocalPort(); + } + catch (SocketException e) + { + // This cannot happen as we are bound. + } + + return -1; + } + + /** + * Returns local socket address. + * + * @return the local socket address, null if not bound + * + * @since 1.4 + */ + public SocketAddress getLocalSocketAddress() + { + if (! isBound()) + return null; + + InetAddress addr = getLocalAddress(); + + try + { + return new InetSocketAddress(addr, getImpl().getLocalPort()); + } + catch (SocketException e) + { + // This cannot happen as we are bound. + return null; + } + } + + /** + * Returns the remote socket address. + * + * @return the remote socket address, null of not connected + * + * @since 1.4 + */ + public SocketAddress getRemoteSocketAddress() + { + if (! isConnected()) + return null; + + try + { + return new InetSocketAddress(getImpl().getInetAddress(), + getImpl().getPort()); + } + catch (SocketException e) + { + // This cannot happen as we are connected. + return null; + } + } + + /** + * Returns an InputStream for reading from this socket. + * + * @return The InputStream object + * + * @exception IOException If an error occurs or Socket is not connected + */ + public InputStream getInputStream() throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (! isConnected()) + throw new IOException("not connected"); + + return getImpl().getInputStream(); + } + + /** + * Returns an OutputStream for writing to this socket. + * + * @return The OutputStream object + * + * @exception IOException If an error occurs or Socket is not connected + */ + public OutputStream getOutputStream() throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (! isConnected()) + throw new IOException("not connected"); + + return getImpl().getOutputStream(); + } + + /** + * Sets the TCP_NODELAY option on the socket. + * + * @param on true to enable, false to disable + * + * @exception SocketException If an error occurs or Socket is not connected + * + * @since 1.1 + */ + public void setTcpNoDelay(boolean on) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on)); + } + + /** + * Tests whether or not the TCP_NODELAY option is set on the socket. + * Returns true if enabled, false if disabled. When on it disables the + * Nagle algorithm which means that packets are always send immediatly and + * never merged together to reduce network trafic. + * + * @return Whether or not TCP_NODELAY is set + * + * @exception SocketException If an error occurs or Socket not connected + * + * @since 1.1 + */ + public boolean getTcpNoDelay() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object on = getImpl().getOption(SocketOptions.TCP_NODELAY); + + if (on instanceof Boolean) + return (((Boolean) on).booleanValue()); + else + throw new SocketException("Internal Error"); + } + + /** + * Sets the value of the SO_LINGER option on the socket. If the + * SO_LINGER option is set on a socket and there is still data waiting to + * be sent when the socket is closed, then the close operation will block + * until either that data is delivered or until the timeout period + * expires. The linger interval is specified in hundreths of a second + * (platform specific?) + * + * @param on true to enable SO_LINGER, false to disable + * @param linger The SO_LINGER timeout in hundreths of a second or -1 if + * SO_LINGER not set. + * + * @exception SocketException If an error occurs or Socket not connected + * @exception IllegalArgumentException If linger is negative + * + * @since 1.1 + */ + public void setSoLinger(boolean on, int linger) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (on) + { + if (linger < 0) + throw new IllegalArgumentException("SO_LINGER must be >= 0"); + + if (linger > 65535) + linger = 65535; + + getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger)); + } + else + getImpl().setOption(SocketOptions.SO_LINGER, Boolean.valueOf(false)); + } + + /** + * Returns the value of the SO_LINGER option on the socket. If the + * SO_LINGER option is set on a socket and there is still data waiting to + * be sent when the socket is closed, then the close operation will block + * until either that data is delivered or until the timeout period + * expires. This method either returns the timeouts (in hundredths of + * of a second (platform specific?)) if SO_LINGER is set, or -1 if + * SO_LINGER is not set. + * + * @return The SO_LINGER timeout in hundreths of a second or -1 + * if SO_LINGER not set + * + * @exception SocketException If an error occurs or Socket is not connected + * + * @since 1.1 + */ + public int getSoLinger() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object linger = getImpl().getOption(SocketOptions.SO_LINGER); + + if (linger instanceof Integer) + return (((Integer) linger).intValue()); + else + return -1; + } + + /** + * Sends urgent data through the socket + * + * @param data The data to send. + * Only the lowest eight bits of data are sent + * + * @exception IOException If an error occurs + * + * @since 1.4 + */ + public void sendUrgentData(int data) throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().sendUrgentData(data); + } + + /** + * Enables/disables the SO_OOBINLINE option + * + * @param on True if SO_OOBLINE should be enabled + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public void setOOBInline(boolean on) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on)); + } + + /** + * Returns the current setting of the SO_OOBINLINE option for this socket + * + * @return True if SO_OOBINLINE is set, false otherwise. + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public boolean getOOBInline() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.SO_OOBINLINE); + + if (buf instanceof Boolean) + return (((Boolean) buf).booleanValue()); + else + throw new SocketException("Internal Error: Unexpected type"); + } + + /** + * Sets the value of the SO_TIMEOUT option on the socket. If this value + * is set, and an read/write is performed that does not complete within + * the timeout period, a short count is returned (or an EWOULDBLOCK signal + * would be sent in Unix if no data had been read). A value of 0 for + * this option implies that there is no timeout (ie, operations will + * block forever). On systems that have separate read and write timeout + * values, this method returns the read timeout. This + * value is in milliseconds. + * + * @param timeout The length of the timeout in milliseconds, or + * 0 to indicate no timeout. + * + * @exception SocketException If an error occurs or Socket not connected + * + * @since 1.1 + */ + public synchronized void setSoTimeout(int timeout) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (timeout < 0) + throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0"); + + getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); + } + + /** + * Returns the value of the SO_TIMEOUT option on the socket. If this value + * is set, and an read/write is performed that does not complete within + * the timeout period, a short count is returned (or an EWOULDBLOCK signal + * would be sent in Unix if no data had been read). A value of 0 for + * this option implies that there is no timeout (ie, operations will + * block forever). On systems that have separate read and write timeout + * values, this method returns the read timeout. This + * value is in thousandths of a second (implementation specific?). + * + * @return The length of the timeout in thousandth's of a second or 0 + * if not set + * + * @exception SocketException If an error occurs or Socket not connected + * + * @since 1.1 + */ + public synchronized int getSoTimeout() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object timeout = getImpl().getOption(SocketOptions.SO_TIMEOUT); + if (timeout instanceof Integer) + return (((Integer) timeout).intValue()); + else + return 0; + } + + /** + * This method sets the value for the system level socket option + * SO_SNDBUF to the specified value. Note that valid values for this + * option are specific to a given operating system. + * + * @param size The new send buffer size. + * + * @exception SocketException If an error occurs or Socket not connected + * @exception IllegalArgumentException If size is 0 or negative + * + * @since 1.2 + */ + public void setSendBufferSize(int size) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (size <= 0) + throw new IllegalArgumentException("SO_SNDBUF value must be > 0"); + + getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size)); + } + + /** + * This method returns the value of the system level socket option + * SO_SNDBUF, which is used by the operating system to tune buffer + * sizes for data transfers. + * + * @return The send buffer size. + * + * @exception SocketException If an error occurs or socket not connected + * + * @since 1.2 + */ + public int getSendBufferSize() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.SO_SNDBUF); + + if (buf instanceof Integer) + return (((Integer) buf).intValue()); + else + throw new SocketException("Internal Error: Unexpected type"); + } + + /** + * This method sets the value for the system level socket option + * SO_RCVBUF to the specified value. Note that valid values for this + * option are specific to a given operating system. + * + * @param size The new receive buffer size. + * + * @exception SocketException If an error occurs or Socket is not connected + * @exception IllegalArgumentException If size is 0 or negative + * + * @since 1.2 + */ + public void setReceiveBufferSize(int size) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (size <= 0) + throw new IllegalArgumentException("SO_RCVBUF value must be > 0"); + + getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size)); + } + + /** + * This method returns the value of the system level socket option + * SO_RCVBUF, which is used by the operating system to tune buffer + * sizes for data transfers. + * + * @return The receive buffer size. + * + * @exception SocketException If an error occurs or Socket is not connected + * + * @since 1.2 + */ + public int getReceiveBufferSize() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.SO_RCVBUF); + + if (buf instanceof Integer) + return (((Integer) buf).intValue()); + else + throw new SocketException("Internal Error: Unexpected type"); + } + + /** + * This method sets the value for the socket level socket option + * SO_KEEPALIVE. + * + * @param on True if SO_KEEPALIVE should be enabled + * + * @exception SocketException If an error occurs or Socket is not connected + * + * @since 1.3 + */ + public void setKeepAlive(boolean on) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on)); + } + + /** + * This method returns the value of the socket level socket option + * SO_KEEPALIVE. + * + * @return The setting + * + * @exception SocketException If an error occurs or Socket is not connected + * + * @since 1.3 + */ + public boolean getKeepAlive() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object buf = getImpl().getOption(SocketOptions.SO_KEEPALIVE); + + if (buf instanceof Boolean) + return (((Boolean) buf).booleanValue()); + else + throw new SocketException("Internal Error: Unexpected type"); + } + + /** + * Closes the socket. + * + * @exception IOException If an error occurs + */ + public synchronized void close() throws IOException + { + if (isClosed()) + return; + + getImpl().close(); + impl = null; + bound = false; + + if (getChannel() != null) + getChannel().close(); + } + + /** + * Converts this Socket to a String. + * + * @return The String representation of this Socket + */ + public String toString() + { + try + { + if (isConnected()) + return ("Socket[addr=" + getImpl().getInetAddress() + ",port=" + + getImpl().getPort() + ",localport=" + + getImpl().getLocalPort() + "]"); + } + catch (SocketException e) + { + // This cannot happen as we are connected. + } + + return "Socket[unconnected]"; + } + + /** + * Sets the SocketImplFactory. This may be done only once per + * virtual machine. Subsequent attempts will generate a + * SocketException. Note that a SecurityManager + * check is made prior to setting the factory. If + * insufficient privileges exist to set the factory, then an + * IOException will be thrown. + * + * @param fac the factory to set + * + * @exception SecurityException If the SecurityManager does + * not allow this operation. + * @exception SocketException If the SocketImplFactory is already defined + * @exception IOException If any other error occurs + */ + public static synchronized void setSocketImplFactory(SocketImplFactory fac) + throws IOException + { + // See if already set + if (factory != null) + throw new SocketException("SocketImplFactory already defined"); + + // Check permissions + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSetFactory(); + + if (fac == null) + throw new SocketException("SocketImplFactory cannot be null"); + + factory = fac; + } + + /** + * Closes the input side of the socket stream. + * + * @exception IOException If an error occurs. + * + * @since 1.3 + */ + public void shutdownInput() throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().shutdownInput(); + inputShutdown = true; + } + + /** + * Closes the output side of the socket stream. + * + * @exception IOException If an error occurs. + * + * @since 1.3 + */ + public void shutdownOutput() throws IOException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().shutdownOutput(); + outputShutdown = true; + } + + /** + * Returns the socket channel associated with this socket. + * + * @return the associated socket channel, + * null if no associated channel exists + * + * @since 1.4 + */ + public SocketChannel getChannel() + { + return null; + } + + /** + * Checks if the SO_REUSEADDR option is enabled + * + * @return True if SO_REUSEADDR is set, false otherwise. + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public boolean getReuseAddress() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object reuseaddr = getImpl().getOption(SocketOptions.SO_REUSEADDR); + + if (! (reuseaddr instanceof Boolean)) + throw new SocketException("Internal Error"); + + return ((Boolean) reuseaddr).booleanValue(); + } + + /** + * Enables/Disables the SO_REUSEADDR option + * + * @param reuseAddress true if SO_REUSEADDR should be enabled, + * false otherwise + * + * @exception SocketException If an error occurs + * + * @since 1.4 + */ + public void setReuseAddress(boolean reuseAddress) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + getImpl().setOption(SocketOptions.SO_REUSEADDR, + Boolean.valueOf(reuseAddress)); + } + + /** + * Returns the current traffic class + * + * @return The current traffic class. + * + * @exception SocketException If an error occurs + * + * @see Socket#setTrafficClass(int tc) + * + * @since 1.4 + */ + public int getTrafficClass() throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + Object obj = getImpl().getOption(SocketOptions.IP_TOS); + + if (obj instanceof Integer) + return ((Integer) obj).intValue(); + else + throw new SocketException("Unexpected type"); + } + + /** + * Sets the traffic class value + * + * @param tc The traffic class + * + * @exception SocketException If an error occurs + * @exception IllegalArgumentException If tc value is illegal + * + * @see Socket#getTrafficClass() + * + * @since 1.4 + */ + public void setTrafficClass(int tc) throws SocketException + { + if (isClosed()) + throw new SocketException("socket is closed"); + + if (tc < 0 || tc > 255) + throw new IllegalArgumentException(); + + getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc)); + } + + /** + * Checks if the socket is connected + * + * @return True if socket is connected, false otherwise. + * + * @since 1.4 + */ + public boolean isConnected() + { + try + { + if (getImpl() == null) + return false; + + return getImpl().getInetAddress() != null; + } + catch (SocketException e) + { + return false; + } + } + + /** + * Checks if the socket is already bound. + * + * @return True if socket is bound, false otherwise. + * + * @since 1.4 + */ + public boolean isBound() + { + return bound; + } + + /** + * Checks if the socket is closed. + * + * @return True if socket is closed, false otherwise. + * + * @since 1.4 + */ + public boolean isClosed() + { + return impl == null; + } + + /** + * Checks if the socket's input stream is shutdown + * + * @return True if input is shut down. + * + * @since 1.4 + */ + public boolean isInputShutdown() + { + return inputShutdown; + } + + /** + * Checks if the socket's output stream is shutdown + * + * @return True if output is shut down. + * + * @since 1.4 + */ + public boolean isOutputShutdown() + { + return outputShutdown; + } +} diff --git a/libjava/classpath/java/net/SocketAddress.java b/libjava/classpath/java/net/SocketAddress.java new file mode 100644 index 0000000..48ab010 --- /dev/null +++ b/libjava/classpath/java/net/SocketAddress.java @@ -0,0 +1,63 @@ +/* SocketAddress.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 java.net; + +import java.io.Serializable; + + +/** + * Abstract base class for InetSocketAddress. + * InetSocketAddress is to my knowledge the only derived + * class. [Ronald] + * + * @since 1.4 + */ +public abstract class SocketAddress implements Serializable +{ + /** + * Compatible with JDK 1.4+ + */ + static final long serialVersionUID = 5215720748342549866L; + + /** + * Initializes the socket address. + */ + public SocketAddress() + { + } +} diff --git a/libjava/classpath/java/net/SocketException.java b/libjava/classpath/java/net/SocketException.java new file mode 100644 index 0000000..37b2f6f --- /dev/null +++ b/libjava/classpath/java/net/SocketException.java @@ -0,0 +1,75 @@ +/* SocketException.java -- An exception occurred while performing a socket op + Copyright (C) 1998, 1999, 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 java.net; + +import java.io.IOException; + + +/** + * This exception indicates that a generic error occurred related to an + * operation on a socket. Check the descriptive message (if any) for + * details on the nature of this error + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner + * @status updated to 1.4 + */ +public class SocketException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -5935874303556886934L; + + /** + * Create a new instance without a descriptive error message. + */ + public SocketException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message a message describing the error that occurred + */ + public SocketException(String message) + { + super(message); + } +} // class SocketException diff --git a/libjava/classpath/java/net/SocketImpl.java b/libjava/classpath/java/net/SocketImpl.java new file mode 100644 index 0000000..77f470b --- /dev/null +++ b/libjava/classpath/java/net/SocketImpl.java @@ -0,0 +1,321 @@ +/* SocketImpl.java -- Abstract socket implementation class + Copyright (C) 1998, 1999, 2000, 2001, 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 java.net; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + + +/* Written using on-line Java Platform 1.2 API Specification. + * Believed complete and correct. + */ + +/** + * This abstract class serves as the parent class for socket implementations. + * The implementation class serves an intermediary to native routines that + * perform system specific socket operations. + *

    + * A default implementation is provided by the system, but this can be + * changed via installing a SocketImplFactory (through a call + * to the static method Socket.setSocketImplFactory). A + * subclass of Socket can also pass in a SocketImpl + * to the Socket(SocketImpl) constructor to use an + * implementation different from the system default without installing + * a factory. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + */ +public abstract class SocketImpl implements SocketOptions +{ + /** + * The address of the remote end of the socket connection + */ + protected InetAddress address; + + /** + * A FileDescriptor object representing this socket connection. + */ + protected FileDescriptor fd; + + /** + * The port number the socket is bound to locally + */ + protected int localport = -1; + + /** + * The port number of the remote end of the socket connection + */ + protected int port; + + /** + * Default, no-argument constructor for use by subclasses. + */ + public SocketImpl() + { + } + + /** + * Creates a new socket that is not bound to any local address/port and + * is not connected to any remote address/port. This will be created as + * a stream socket if the stream parameter is true, or a datagram socket + * if the stream parameter is false. + * + * @param stream true for a stream socket, false for a datagram socket + * + * @exception IOException If an error occurs + */ + protected abstract void create(boolean stream) throws IOException; + + /** + * Connects to the remote hostname and port specified as arguments. + * + * @param host The remote hostname to connect to + * @param port The remote port to connect to + * + * @exception IOException If an error occurs + */ + protected abstract void connect(String host, int port) + throws IOException; + + /** + * Connects to the remote address and port specified as arguments. + * + * @param host The remote address to connect to + * @param port The remote port to connect to + * + * @exception IOException If an error occurs + */ + protected abstract void connect(InetAddress host, int port) + throws IOException; + + /** + * Connects to the socket to the host specified in address. This + * method blocks until successful connected or the timeout occurs. + * A timeout of zero means no timout. + * + * @param address Data of remote host + * @param timeout time to wait to stop connecting + * + * @exception IOException If an error occurs + * + * @since 1.4 + */ + protected abstract void connect(SocketAddress address, int timeout) + throws IOException; + + /** + * Binds to the specified port on the specified addr. Note that this addr + * must represent a local IP address. + *

    + * Note that it is unspecified how to bind to all interfaces on the localhost + * (INADDR_ANY). + * + * @param host The address to bind to + * @param port The port number to bind to + * + * @exception IOException If an error occurs + */ + protected abstract void bind(InetAddress host, int port) + throws IOException; + + /** + * Starts listening for connections on a socket. The backlog 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 backlog The length of the pending connection queue + * + * @exception IOException If an error occurs + */ + protected abstract void listen(int backlog) throws IOException; + + /** + * Accepts a connection on this socket. + * + * @param s The implementation object for the accepted connection. + * + * @exception IOException If an error occurs + */ + protected abstract void accept(SocketImpl s) throws IOException; + + /** + * Returns an InputStream object for reading from this socket. + * + * @return An InputStream for reading from this socket. + * + * @exception IOException If an error occurs + */ + protected abstract InputStream getInputStream() throws IOException; + + /** + * Returns an OutputStream object for writing to this socket + * + * @return An OutputStream for writing to this socket. + * + * @exception IOException If an error occurs. + */ + protected abstract OutputStream getOutputStream() throws IOException; + + /** + * Returns the number of bytes that the caller can read from this socket + * without blocking. + * + * @return The number of readable bytes before blocking + * + * @exception IOException If an error occurs + */ + protected abstract int available() throws IOException; + + /** + * Closes the socket. This will normally cause any resources, such as the + * InputStream, OutputStream and associated file descriptors to be freed. + *

    + * Note that if the SO_LINGER option is set on this socket, then the + * operation could block. + * + * @exception IOException If an error occurs + */ + protected abstract void close() throws IOException; + + /** + * Returns the FileDescriptor objects for this socket. + * + * @return A FileDescriptor for this socket. + */ + protected FileDescriptor getFileDescriptor() + { + return fd; + } + + /** + * Returns the remote address this socket is connected to + * + * @return The remote address + */ + protected InetAddress getInetAddress() + { + return address; + } + + /** + * Returns the remote port this socket is connected to + * + * @return The remote port + */ + protected int getPort() + { + return port; + } + + /** + * Returns true or false when this socket supports sending urgent data + * or not. + * + * @return true if the socket implementation supports sending urgent data, + * false otherwise + * + * @since 1.4 + */ + protected boolean supportsUrgentData() + { + // This method has to be overwritten by socket classes that support + // sending urgend data. + return false; + } + + /** + * Sends one byte of urgent data to the socket. + * + * @param data The byte to send, the low eight bits of it + * + * @exception IOException If an error occurs + * + * @since 1.4 + */ + protected abstract void sendUrgentData(int data) throws IOException; + + /** + * Returns the local port this socket is bound to + * + * @return The local port + */ + protected int getLocalPort() + { + return localport; + } + + /** + * Returns a String representing the remote host and port of + * this socket. + * + * @return A String for this socket. + */ + public String toString() + { + return "[addr=" + + ((address == null) ? "0.0.0.0/0.0.0.0" : address.toString()) + + ",port=" + port + ",localport=" + localport + "]"; + } + + /** + * Shut down the input side of this socket. Subsequent reads will + * return end-of-file. + * + * @exception IOException if an error occurs + */ + protected void shutdownInput() throws IOException + { + throw new IOException("Not implemented in this socket class"); + } + + /** + * Shut down the output side of this socket. Subsequent writes will + * fail with an IOException. + * + * @exception IOException if an error occurs + */ + protected void shutdownOutput() throws IOException + { + throw new IOException("Not implemented in this socket class"); + } +} diff --git a/libjava/classpath/java/net/SocketImplFactory.java b/libjava/classpath/java/net/SocketImplFactory.java new file mode 100644 index 0000000..b7cb10c --- /dev/null +++ b/libjava/classpath/java/net/SocketImplFactory.java @@ -0,0 +1,59 @@ +/* SocketImplFactory.java -- Interface to create a SocketImpl object + Copyright (C) 1998, 1999, 2000, 2001, 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 java.net; + + +/** Written using on-line Java Platform 1.2 API Specification. + * Status: Believed complete and correct. + */ +/** + * This interface defines one method which returns a SocketImpl + * object. This should not be needed by ordinary applications. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + */ +public interface SocketImplFactory +{ + /** + * This method returns an instance of the SocketImpl object + * + * @return A SocketImpl object + */ + SocketImpl createSocketImpl(); +} // interface SocketImplFactory diff --git a/libjava/classpath/java/net/SocketOptions.java b/libjava/classpath/java/net/SocketOptions.java new file mode 100644 index 0000000..659bf75 --- /dev/null +++ b/libjava/classpath/java/net/SocketOptions.java @@ -0,0 +1,166 @@ +/* SocketOptions.java -- Implements options for sockets (duh!) + Copyright (C) 1998, 1999, 2000, 2001, + 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 java.net; + + +/** + * Written using on-line Java Platform 1.2 API Specification. + * Status: Believed complete and correct. + */ +/** + * This interface is used by SocketImpl and + * DatagramSocketImpl to implement options + * on sockets. + * + * @since 1.2 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @status should be completely JDK 1.4 compatible + */ +public interface SocketOptions +{ + /** + * Option id for the SO_KEEPALIVE value + * @since 1.3 + */ + int SO_KEEPALIVE = 0x8; + + /** + * Option id for the SO_LINGER value + */ + int SO_LINGER = 0x80; // 128 + + /** + * Option id for the SO_TIMEOUT value + */ + int SO_TIMEOUT = 0x1006; // 4102 + + /** + * Retrieve the local address to which the socket is bound. + */ + int SO_BINDADDR = 0x0F; // 15 + + /** + * Option id for the send buffer size + * @since 1.2 + */ + int SO_SNDBUF = 0x1001; // 4097 + + /** + * Option id for the receive buffer size + * @since 1.2 + */ + int SO_RCVBUF = 0x1002; // 4098 + + /** + * Sets the SO_REUSEADDR parameter on a socket + */ + int SO_REUSEADDR = 0x04; // 4 + + /** + * Sets SO_BROADCAST for a socket + * @since 1.4 + */ + int SO_BROADCAST = 0x20; // 32 + + /** + * Sets SO_OOBINLINE for a socket + * @since 1.4 + */ + int SO_OOBINLINE = 0x1003; // 4099 + + /** + * Option id for the TCP_NODELAY value + */ + int TCP_NODELAY = 0x01; // 1 + + /** + * Options id for the IP_MULTICAST_IF value + */ + int IP_MULTICAST_IF = 0x10; // 16 + + /** + * same as above + * @since 1.4 + */ + int IP_MULTICAST_IF2 = 0x1F; // 31 + + /** + * This option enables or disables local loopback of multicast datagrams. + * @since 1.4 + */ + int IP_MULTICAST_LOOP = 0x12; // 18 + + /** + * This option sets the type-of-service or traffic class field in the + * IP header for a TCP or UDP socket. + * @since 1.4 + */ + int IP_TOS = 0x03; // 3 + + /** + * 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. For options that are set to on or off, the + * value passed will be a Boolean. The optionId + * parameter is one of the defined constants in this interface. + * + * @param optionId The identifier of the option + * @param val The value to set the option to + * + * @exception SocketException If an error occurs + */ + void setOption(int optionId, Object val) throws SocketException; + + /** + * Returns the current setting of the specified option. The + * Object returned will be an Integer for options + * that have integer values. For options that are set to on or off, a + * Boolean will be returned. The optionId + * parameter is one of the defined constants in this interface. + * + * @param optionId The option identifier + * + * @return The current value of the option + * + * @exception SocketException If an error occurs + */ + Object getOption(int optionId) throws SocketException; +} // interface SocketOptions diff --git a/libjava/classpath/java/net/SocketPermission.java b/libjava/classpath/java/net/SocketPermission.java new file mode 100644 index 0000000..8ccd01b --- /dev/null +++ b/libjava/classpath/java/net/SocketPermission.java @@ -0,0 +1,408 @@ +/* SocketPermission.java -- Class modeling permissions for socket operations + Copyright (C) 1998, 2000, 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 java.net; + +import java.io.Serializable; +import java.security.Permission; +import java.security.PermissionCollection; + + +/** + * This class models a specific set of permssions for connecting to a + * host. There are two elements to this, the host/port combination and + * the permission list. + *

    + * The host/port combination is specified as followed + *

    + *

    + * hostname[:[-]port[-[port]]]
    + * 
    + *

    + * The hostname portion can be either a hostname or IP address. If it is + * a hostname, a wildcard is allowed in hostnames. This wildcard is a "*" + * and matches one or more characters. Only one "*" may appear in the + * host and it must be the leftmost character. For example, + * "*.urbanophile.com" matches all hosts in the "urbanophile.com" domain. + *

    + * The port portion can be either a single value, or a range of values + * treated as inclusive. The first or the last port value in the range + * can be omitted in which case either the minimum or maximum legal + * value for a port (respectively) is used by default. Here are some + * examples: + *

      + *
    • 8080 - Represents port 8080 only
    • + *
    • 2000-3000 - Represents ports 2000 through 3000 inclusive
    • + *
    • -4000 - Represents ports 0 through 4000 inclusive
    • + *
    • 1024- - Represents ports 1024 through 65535 inclusive
    • + *

    + * The permission list is a comma separated list of individual permissions. + * These individual permissions are: + *

    + *

    + * accept
    + * connect
    + * listen
    + * resolve
    + * 
    + *

    + * The "listen" permission is only relevant if the host is localhost. If + * any permission at all is specified, then resolve permission is implied to + * exist. + *

    + * Here are a variety of examples of how to create SocketPermission's + *

    + * SocketPermission("www.urbanophile.com", "connect");
    + *   Can connect to any port on www.urbanophile.com
    + * SocketPermission("www.urbanophile.com:80", "connect,accept");
    + *   Can connect to or accept connections from www.urbanophile.com on port 80
    + * SocketPermission("localhost:1024-", "listen,accept,connect");
    + *   Can connect to, accept from, an listen on any local port number 1024
    + *   and up.
    + * SocketPermission("*.edu", "connect");
    + *   Can connect to any host in the edu domain
    + * SocketPermission("197.197.20.1", "accept");
    + *   Can accept connections from 197.197.20.1
    + * 

    + * + * This class also supports IPv6 addresses. These should be specified + * in either RFC 2732 format or in full uncompressed form. + * + * @since 1.2 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public final class SocketPermission extends Permission implements Serializable +{ + static final long serialVersionUID = -7204263841984476862L; + +// FIXME: Needs serialization work, including readObject/writeObject methods. + + /** + * A hostname/port combination as described above + */ + private transient String hostport; + + /** + * A comma separated list of actions for which we have permission + */ + private String actions; + + /** + * Initializes a new instance of SocketPermission with the + * specified host/port combination and actions string. + * + * @param hostport The hostname/port number combination + * @param actions The actions string + */ + public SocketPermission(String hostport, String actions) + { + super(hostport); + + this.hostport = hostport; + this.actions = actions; + } + + /** + * Tests this object for equality against another. This will be true if + * and only if the passed object is an instance of + * SocketPermission and both its hostname/port combination + * and permissions string are identical. + * + * @param obj The object to test against for equality + * + * @return true if object is equal to this object, + * false otherwise. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof SocketPermission)) + return false; + + if (((SocketPermission) obj).hostport.equals(hostport)) + if (((SocketPermission) obj).actions.equals(actions)) + return true; + + return false; + } + + /** + * Returns a hash code value for this object. Overrides the + * Permission.hashCode(). + * + * @return A hash code + */ + public int hashCode() + { + int hash = 100; + if (hostport != null) + hash += hostport.hashCode(); + if (actions != null) + hash += actions.hashCode(); + return hash; + } + + /** + * Returns the list of permission actions in this object in canonical + * order. The canonical order is "connect,listen,accept,resolve" + * + * @return The permitted action string. + */ + public String getActions() + { + boolean found = false; + StringBuffer sb = new StringBuffer(""); + + if (actions.indexOf("connect") != -1) + { + sb.append("connect"); + found = true; + } + + if (actions.indexOf("listen") != -1) + if (found) + sb.append(",listen"); + else + { + sb.append("listen"); + found = true; + } + + if (actions.indexOf("accept") != -1) + if (found) + sb.append(",accept"); + else + { + sb.append("accept"); + found = true; + } + + if (found) + sb.append(",resolve"); + else if (actions.indexOf("resolve") != -1) + sb.append("resolve"); + + return sb.toString(); + } + + /** + * Returns a new PermissionCollection object that can hold + * SocketPermission's. + * + * @return A new PermissionCollection. + */ + public PermissionCollection newPermissionCollection() + { + // FIXME: Implement + + return null; + } + + /** + * Returns true if the permission object passed it is implied by the + * this permission. This will be true if: + * + *

      + *
    • The argument is of type SocketPermission
    • + *
    • The actions list of the argument are in this object's actions
    • + *
    • The port range of the argument is within this objects port range
    • + *
    • The hostname is equal to or a subset of this objects hostname
    • + *
    + * + *

    The argument's hostname will be a subset of this object's hostname if:

    + * + *
      + *
    • The argument's hostname or IP address is equal to this object's.
    • + *
    • The argument's canonical hostname is equal to this object's.
    • + *
    • The argument's canonical name matches this domains hostname with + * wildcards
    • + *
    + * + * @param perm The Permission to check against + * + * @return true if the Permission is implied by + * this object, false otherwise. + */ + public boolean implies(Permission perm) + { + SocketPermission p; + + // First make sure we are the right object type + if (perm instanceof SocketPermission) + p = (SocketPermission) perm; + else + return false; + + // Next check the actions + String ourlist = getActions(); + String theirlist = p.getActions(); + + if (! ourlist.startsWith(theirlist)) + return false; + + // Now check ports + int ourfirstport = 0; + + // Now check ports + int ourlastport = 0; + + // Now check ports + int theirfirstport = 0; + + // Now check ports + int theirlastport = 0; + + // Get ours + if (hostport.indexOf(":") == -1) + { + ourfirstport = 0; + ourlastport = 65535; + } + else + { + // FIXME: Needs bulletproofing. + // This will dump if hostport if all sorts of bad data was passed to + // the constructor + String range = hostport.substring(hostport.indexOf(":") + 1); + if (range.startsWith("-")) + ourfirstport = 0; + else if (range.indexOf("-") == -1) + ourfirstport = Integer.parseInt(range); + else + ourfirstport = + Integer.parseInt(range.substring(0, range.indexOf("-"))); + + if (range.endsWith("-")) + ourlastport = 65535; + else if (range.indexOf("-") == -1) + ourlastport = Integer.parseInt(range); + else + ourlastport = + Integer.parseInt(range.substring(range.indexOf("-") + 1, + range.length())); + } + + // Get theirs + if (p.hostport.indexOf(":") == -1) + { + theirfirstport = 0; + ourlastport = 65535; + } + else + { + // This will dump if hostport if all sorts of bad data was passed to + // the constructor + String range = p.hostport.substring(hostport.indexOf(":") + 1); + if (range.startsWith("-")) + theirfirstport = 0; + else if (range.indexOf("-") == -1) + theirfirstport = Integer.parseInt(range); + else + theirfirstport = + Integer.parseInt(range.substring(0, range.indexOf("-"))); + + if (range.endsWith("-")) + theirlastport = 65535; + else if (range.indexOf("-") == -1) + theirlastport = Integer.parseInt(range); + else + theirlastport = + Integer.parseInt(range.substring(range.indexOf("-") + 1, + range.length())); + } + + // Now check them + if ((theirfirstport < ourfirstport) || (theirlastport > ourlastport)) + return false; + + // Finally we can check the hosts + String ourhost; + + // Finally we can check the hosts + String theirhost; + + // Get ours + if (hostport.indexOf(":") == -1) + ourhost = hostport; + else + ourhost = hostport.substring(0, hostport.indexOf(":")); + + // Get theirs + if (p.hostport.indexOf(":") == -1) + theirhost = p.hostport; + else + theirhost = p.hostport.substring(0, p.hostport.indexOf(":")); + + // Are they equal? + if (ourhost.equals(theirhost)) + return true; + + // Try the canonical names + String ourcanonical = null; + + // Try the canonical names + String theircanonical = null; + try + { + ourcanonical = InetAddress.getByName(ourhost).getHostName(); + theircanonical = InetAddress.getByName(theirhost).getHostName(); + } + catch (UnknownHostException e) + { + // Who didn't resolve? Just assume current address is canonical enough + // Is this ok to do? + if (ourcanonical == null) + ourcanonical = ourhost; + if (theircanonical == null) + theircanonical = theirhost; + } + + if (ourcanonical.equals(theircanonical)) + return true; + + // Well, last chance. Try for a wildcard + if (ourhost.indexOf("*.") != -1) + { + String wild_domain = ourhost.substring(ourhost.indexOf("*" + 1)); + if (theircanonical.endsWith(wild_domain)) + return true; + } + + // Didn't make it + return false; + } +} diff --git a/libjava/classpath/java/net/SocketTimeoutException.java b/libjava/classpath/java/net/SocketTimeoutException.java new file mode 100644 index 0000000..21b0dcd --- /dev/null +++ b/libjava/classpath/java/net/SocketTimeoutException.java @@ -0,0 +1,73 @@ +/* SocketTimeoutException.java -- the socket timed out + 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 java.net; + +import java.io.InterruptedIOException; + + +/** + * This exception signals that a socket read or accept timed out. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public class SocketTimeoutException extends InterruptedIOException +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = -8846654841826352300L; + + /** + * Create a new instance without a descriptive error message. + */ + public SocketTimeoutException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message a message describing the error that occurred + */ + public SocketTimeoutException(String message) + { + super(message); + } +} // class SocketTimeoutException diff --git a/libjava/classpath/java/net/TODO b/libjava/classpath/java/net/TODO new file mode 100644 index 0000000..e48969d --- /dev/null +++ b/libjava/classpath/java/net/TODO @@ -0,0 +1,24 @@ +-- DNS cache purging. + +-- Implement ContentHandler chaining (non-JDK feature) + +-- Implement MIME type by file determination chaining using external + disk files. (non-JDK feature) + +-- Implement determining MIME type from an InputStream + +-- Datagram peek()'s + +-- Finalize methods for sockets + +-- HTTP - caching (supported by JDK?) + +-- HTTP - all protocol support beyond basic GET functionality + +-- Fix call to Date(String) in URLConnection.getHeaderFieldDate() when + I figure out why DateFormat isn't working. + +-- Finish off all JDK 1.2 permissions stuff + +-- Write URLClassLoader + diff --git a/libjava/classpath/java/net/URI.java b/libjava/classpath/java/net/URI.java new file mode 100644 index 0000000..aeceeee --- /dev/null +++ b/libjava/classpath/java/net/URI.java @@ -0,0 +1,1438 @@ +/* URI.java -- An URI class + 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 java.net; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *

    + * A URI instance represents that defined by + * RFC3986, + * with some deviations. + *

    + *

    + * At its highest level, a URI consists of: + *

    + * [scheme:]scheme-specific-part + * [#fragment] + *

    + *

    + * where # and : are literal characters, + * and those parts enclosed in square brackets are optional. + *

    + *

    + * There are two main types of URI. An opaque URI is one + * which just consists of the above three parts, and is not further + * defined. An example of such a URI would be mailto: URI. + * In contrast, hierarchical URIs give further definition + * to the scheme-specific part, so as represent some part of a hierarchical + * structure. + *

    + *

    + * [//authority][path] + * [?query] + *

    + *

    + * with / and ? being literal characters. + * When server-based, the authority section is further subdivided into: + *

    + *

    + * [user-info@]host + * [:port] + *

    + *

    + * with @ and : as literal characters. + * Authority sections that are not server-based are said to be registry-based. + *

    + *

    + * Hierarchical URIs can be either relative or absolute. Absolute URIs + * always start with a `/', while relative URIs don't + * specify a scheme. Opaque URIs are always absolute. + *

    + *

    + * Each part of the URI may have one of three states: undefined, empty + * or containing some content. The former two of these are represented + * by null and the empty string in Java, respectively. + * The scheme-specific part may never be undefined. It also follows from + * this that the path sub-part may also not be undefined, so as to ensure + * the former. + *

    + *

    Character Escaping and Quoting

    + *

    + * The characters that can be used within a valid URI are restricted. + * There are two main classes of characters which can't be used as is + * within the URI: + *

    + *
      + *
    1. Characters outside the US-ASCII character set. + * These have to be escaped in order to create + * an RFC-compliant URI; this means replacing the character with the + * appropriate hexadecimal value, preceded by a `%'.
    2. + *
    3. Illegal characters (e.g. space characters, + * control characters) are quoted, which results in them being encoded + * in the same way as non-US-ASCII characters.
    4. + *
    + *

    + * The set of valid characters differs depending on the section of the URI: + *

    + *
      + *
    • Scheme: Must be an alphanumeric, `-', `.' or '+'.
    • + *
    • Authority:Composed of the username, host, port, `@' + * and `:'.
    • + *
    • Username: Allows unreserved or percent-encoded + * characters, sub-delimiters and `:'.
    • + *
    • Host: Allows unreserved or percent-encoded + * characters, sub-delimiters and square brackets (`[' and `]') for IPv6 + * addresses.
    • + *
    • Port: Digits only.
    • + *
    • Path: Allows the path characters and `/'. + *
    • Query: Allows the path characters, `?' and '/'. + *
    • Fragment: Allows the path characters, `?' and '/'. + *
    + *

    + * These definitions reference the following sets of characters: + *

    + *
      + *
    • Unreserved characters: The alphanumerics plus + * `-', `.', `_', and `~'.
    • + *
    • Sub-delimiters: `!', `$', `&', `(', `)', `*', + * `+', `,', `;', `=' and the single-quote itself.
    • + *
    • Path characters: Unreserved and percent-encoded + * characters and the sub-delimiters along with `@' and `:'.
    • + *
    + *

    + * The constructors and accessor methods allow the use and retrieval of + * URI components which contain non-US-ASCII characters directly. + * They are only escaped when the toASCIIString() method + * is used. In contrast, illegal characters are always quoted, with the + * exception of the return values of the non-raw accessors. + *

    + * + * @author Ito Kazumitsu (ito.kazumitsu@hitachi-cable.co.jp) + * @author Dalibor Topic (robilad@kaffe.org) + * @author Michael Koch (konqueror@gmx.de) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.4 + */ +public final class URI + implements Comparable, Serializable +{ + /** + * For serialization compatability. + */ + static final long serialVersionUID = -6052424284110960213L; + + /** + * Regular expression for parsing URIs. + * + * Taken from RFC 2396, Appendix B. + * This expression doesn't parse IPv6 addresses. + */ + private static final String URI_REGEXP = + "^(([^:/?#]+):)?((//([^/?#]*))?([^?#]*)(\\?([^#]*))?)?(#(.*))?"; + + /** + * Regular expression for parsing the authority segment. + */ + private static final String AUTHORITY_REGEXP = + "(([^?#]*)@)?([^?#:]*)(:([0-9]*))?"; + + /** + * Valid characters (taken from rfc2396/3986) + */ + private static final String RFC2396_DIGIT = "0123456789"; + private static final String RFC2396_LOWALPHA = "abcdefghijklmnopqrstuvwxyz"; + private static final String RFC2396_UPALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private static final String RFC2396_ALPHA = + RFC2396_LOWALPHA + RFC2396_UPALPHA; + private static final String RFC2396_ALPHANUM = RFC2396_DIGIT + RFC2396_ALPHA; + private static final String RFC3986_UNRESERVED = RFC2396_ALPHANUM + "-._~"; + private static final String RFC3986_SUBDELIMS = "!$&'()*+,;="; + private static final String RFC3986_REG_NAME = + RFC3986_UNRESERVED + RFC3986_SUBDELIMS + "%"; + private static final String RFC3986_PCHAR = RFC3986_UNRESERVED + + RFC3986_SUBDELIMS + ":@%"; + private static final String RFC3986_SEGMENT = RFC3986_PCHAR; + private static final String RFC3986_PATH_SEGMENTS = RFC3986_SEGMENT + "/"; + private static final String RFC3986_SSP = RFC3986_PCHAR + "?/"; + private static final String RFC3986_HOST = RFC3986_REG_NAME + "[]"; + private static final String RFC3986_USERINFO = RFC3986_REG_NAME + ":"; + + /** + * Index of scheme component in parsed URI. + */ + private static final int SCHEME_GROUP = 2; + + /** + * Index of scheme-specific-part in parsed URI. + */ + private static final int SCHEME_SPEC_PART_GROUP = 3; + + /** + * Index of authority component in parsed URI. + */ + private static final int AUTHORITY_GROUP = 5; + + /** + * Index of path component in parsed URI. + */ + private static final int PATH_GROUP = 6; + + /** + * Index of query component in parsed URI. + */ + private static final int QUERY_GROUP = 8; + + /** + * Index of fragment component in parsed URI. + */ + private static final int FRAGMENT_GROUP = 10; + + /** + * Index of userinfo component in parsed authority section. + */ + private static final int AUTHORITY_USERINFO_GROUP = 2; + + /** + * Index of host component in parsed authority section. + */ + private static final int AUTHORITY_HOST_GROUP = 3; + + /** + * Index of port component in parsed authority section. + */ + private static final int AUTHORITY_PORT_GROUP = 5; + + /** + * The compiled version of the URI regular expression. + */ + private static final Pattern URI_PATTERN; + + /** + * The compiled version of the authority regular expression. + */ + private static final Pattern AUTHORITY_PATTERN; + + /** + * The set of valid hexadecimal characters. + */ + private static final String HEX = "0123456789ABCDEF"; + + private transient String scheme; + private transient String rawSchemeSpecificPart; + private transient String schemeSpecificPart; + private transient String rawAuthority; + private transient String authority; + private transient String rawUserInfo; + private transient String userInfo; + private transient String rawHost; + private transient String host; + private transient int port = -1; + private transient String rawPath; + private transient String path; + private transient String rawQuery; + private transient String query; + private transient String rawFragment; + private transient String fragment; + private String string; + + /** + * Static initializer to pre-compile the regular expressions. + */ + static + { + URI_PATTERN = Pattern.compile(URI_REGEXP); + AUTHORITY_PATTERN = Pattern.compile(AUTHORITY_REGEXP); + } + + private void readObject(ObjectInputStream is) + throws ClassNotFoundException, IOException + { + this.string = (String) is.readObject(); + try + { + parseURI(this.string); + } + catch (URISyntaxException x) + { + // Should not happen. + throw new RuntimeException(x); + } + } + + private void writeObject(ObjectOutputStream os) throws IOException + { + if (string == null) + string = toString(); + os.writeObject(string); + } + + /** + *

    + * Returns the string content of the specified group of the supplied + * matcher. The returned value is modified according to the following: + *

    + *
      + *
    • If the resulting string has a length greater than 0, then + * that string is returned.
    • + *
    • If a string of zero length, is matched, then the content + * of the preceding group is considered. If this is also an empty + * string, then null is returned to indicate an undefined + * value. Otherwise, the value is truly the empty string and this is + * the returned value.
    • + *
    + *

    + * This method is used for matching against all parts of the URI + * that may be either undefined or empty (i.e. all those but the + * scheme-specific part and the path). In each case, the preceding + * group is the content of the original group, along with some + * additional distinguishing feature. For example, the preceding + * group for the query includes the preceding question mark, + * while that of the fragment includes the hash symbol. The presence + * of these features enables disambiguation between the two cases + * of a completely unspecified value and a simple non-existant value. + * The scheme differs in that it will never return an empty string; + * the delimiter follows the scheme rather than preceding it, so + * it becomes part of the following section. The same is true + * of the user information. + *

    + * + * @param match the matcher, which contains the results of the URI + * matched against the URI regular expression. + * @return either the matched content, null for undefined + * values, or an empty string for a URI part with empty content. + */ + private static String getURIGroup(Matcher match, int group) + { + String matched = match.group(group); + return matched.length() == 0 + ? ((match.group(group - 1).length() == 0) ? null : "") : matched; + } + + /** + * Sets fields of this URI by parsing the given string. + * + * @param str The string to parse + * + * @exception URISyntaxException If the given string violates RFC 2396 + */ + private void parseURI(String str) throws URISyntaxException + { + Matcher matcher = URI_PATTERN.matcher(str); + + if (matcher.matches()) + { + scheme = getURIGroup(matcher, SCHEME_GROUP); + rawSchemeSpecificPart = matcher.group(SCHEME_SPEC_PART_GROUP); + schemeSpecificPart = unquote(rawSchemeSpecificPart); + if (!isOpaque()) + { + rawAuthority = getURIGroup(matcher, AUTHORITY_GROUP); + rawPath = matcher.group(PATH_GROUP); + rawQuery = getURIGroup(matcher, QUERY_GROUP); + } + rawFragment = getURIGroup(matcher, FRAGMENT_GROUP); + } + else + throw new URISyntaxException(str, + "doesn't match URI regular expression"); + parseServerAuthority(); + + // We must eagerly unquote the parts, because this is the only time + // we may throw an exception. + authority = unquote(rawAuthority); + userInfo = unquote(rawUserInfo); + host = unquote(rawHost); + path = unquote(rawPath); + query = unquote(rawQuery); + fragment = unquote(rawFragment); + } + + /** + * Unquote "%" + hex quotes characters + * + * @param str The string to unquote or null. + * + * @return The unquoted string or null if str was null. + * + * @exception URISyntaxException If the given string contains invalid + * escape sequences. + */ + private static String unquote(String str) throws URISyntaxException + { + if (str == null) + return null; + byte[] buf = new byte[str.length()]; + 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 URISyntaxException(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 URISyntaxException(str, "Invalid quoted character"); + buf[pos++] = (byte) (hi * 16 + lo); + } + 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); + } + } + + /** + * Quote characters illegal in URIs in given string. + * + * Replace illegal characters by encoding their UTF-8 + * representation as "%" + hex code for each resulting + * UTF-8 character. + * + * @param str The string to quote + * + * @return The quoted string. + */ + private static String quote(String str) + { + return quote(str, RFC3986_SSP); + } + + /** + * Quote characters illegal in URI authorities in given string. + * + * Replace illegal characters by encoding their UTF-8 + * representation as "%" + hex code for each resulting + * UTF-8 character. + * + * @param str The string to quote + * + * @return The quoted string. + */ + private static String quoteAuthority(String str) + { + // Technically, we should be using RFC2396_AUTHORITY, but + // it contains no additional characters. + return quote(str, RFC3986_REG_NAME); + } + + /** + * Quotes the characters in the supplied string that are not part of + * the specified set of legal characters. + * + * @param str the string to quote + * @param legalCharacters the set of legal characters + * + * @return the quoted string. + */ + private static String quote(String str, String legalCharacters) + { + StringBuffer sb = new StringBuffer(str.length()); + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (legalCharacters.indexOf(c) == -1) + { + if (c <= 127) + { + sb.append('%'); + sb.append(HEX.charAt(c / 16)); + sb.append(HEX.charAt(c % 16)); + } + } + else + sb.append(c); + } + return sb.toString(); + } + + /** + * Quote characters illegal in URI hosts in given string. + * + * Replace illegal characters by encoding their UTF-8 + * representation as "%" + hex code for each resulting + * UTF-8 character. + * + * @param str The string to quote + * + * @return The quoted string. + */ + private static String quoteHost(String str) + { + return quote(str, RFC3986_HOST); + } + + /** + * Quote characters illegal in URI paths in given string. + * + * Replace illegal characters by encoding their UTF-8 + * representation as "%" + hex code for each resulting + * UTF-8 character. + * + * @param str The string to quote + * + * @return The quoted string. + */ + private static String quotePath(String str) + { + // Technically, we should be using RFC2396_PATH, but + // it contains no additional characters. + return quote(str, RFC3986_PATH_SEGMENTS); + } + + /** + * Quote characters illegal in URI user infos in given string. + * + * Replace illegal characters by encoding their UTF-8 + * representation as "%" + hex code for each resulting + * UTF-8 character. + * + * @param str The string to quote + * + * @return The quoted string. + */ + private static String quoteUserInfo(String str) + { + return quote(str, RFC3986_USERINFO); + } + + /** + * Creates an URI from the given string + * + * @param str The string to create the URI from + * + * @exception URISyntaxException If the given string violates RFC 2396 + * @exception NullPointerException If str is null + */ + public URI(String str) throws URISyntaxException + { + this.string = str; + parseURI(str); + } + + /** + * Create an URI from the given components + * + * @param scheme The scheme name + * @param userInfo The username and authorization info + * @param host The hostname + * @param port The port number + * @param path The path + * @param query The query + * @param fragment The fragment + * + * @exception URISyntaxException If the given string violates RFC 2396 + */ + public URI(String scheme, String userInfo, String host, int port, + String path, String query, String fragment) + throws URISyntaxException + { + this((scheme == null ? "" : scheme + ":") + + (userInfo == null && host == null && port == -1 ? "" : "//") + + (userInfo == null ? "" : quoteUserInfo(userInfo) + "@") + + (host == null ? "" : quoteHost(host)) + + (port == -1 ? "" : ":" + String.valueOf(port)) + + (path == null ? "" : quotePath(path)) + + (query == null ? "" : "?" + quote(query)) + + (fragment == null ? "" : "#" + quote(fragment))); + } + + /** + * Create an URI from the given components + * + * @param scheme The scheme name + * @param authority The authority + * @param path The apth + * @param query The query + * @param fragment The fragment + * + * @exception URISyntaxException If the given string violates RFC 2396 + */ + public URI(String scheme, String authority, String path, String query, + String fragment) throws URISyntaxException + { + this((scheme == null ? "" : scheme + ":") + + (authority == null ? "" : "//" + quoteAuthority(authority)) + + (path == null ? "" : quotePath(path)) + + (query == null ? "" : "?" + quote(query)) + + (fragment == null ? "" : "#" + quote(fragment))); + } + + /** + * Create an URI from the given components + * + * @param scheme The scheme name + * @param host The hostname + * @param path The path + * @param fragment The fragment + * + * @exception URISyntaxException If the given string violates RFC 2396 + */ + public URI(String scheme, String host, String path, String fragment) + throws URISyntaxException + { + this(scheme, null, host, -1, path, null, fragment); + } + + /** + * Create an URI from the given components + * + * @param scheme The scheme name + * @param ssp The scheme specific part + * @param fragment The fragment + * + * @exception URISyntaxException If the given string violates RFC 2396 + */ + public URI(String scheme, String ssp, String fragment) + throws URISyntaxException + { + this((scheme == null ? "" : scheme + ":") + + (ssp == null ? "" : quote(ssp)) + + (fragment == null ? "" : "#" + quote(fragment))); + } + + /** + * Create an URI from the given string + * + * @param str The string to create the URI from + * + * @exception IllegalArgumentException If the given string violates RFC 2396 + * @exception NullPointerException If str is null + */ + public static URI create(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException e) + { + throw (IllegalArgumentException) new IllegalArgumentException() + .initCause(e); + } + } + + /** + * Attempts to parse this URI's authority component, if defined, + * into user-information, host, and port components. The purpose + * of this method was to disambiguate between some authority sections, + * which form invalid server-based authories, but valid registry + * based authorities. In the updated RFC 3986, the authority section + * is defined differently, with registry-based authorities part of + * the host section. Thus, this method is now simply an explicit + * way of parsing any authority section. + * + * @return the URI, with the authority section parsed into user + * information, host and port components. + * @throws URISyntaxException if the given string violates RFC 2396 + */ + public URI parseServerAuthority() throws URISyntaxException + { + if (rawAuthority != null) + { + Matcher matcher = AUTHORITY_PATTERN.matcher(rawAuthority); + + if (matcher.matches()) + { + rawUserInfo = getURIGroup(matcher, AUTHORITY_USERINFO_GROUP); + rawHost = getURIGroup(matcher, AUTHORITY_HOST_GROUP); + + String portStr = getURIGroup(matcher, AUTHORITY_PORT_GROUP); + + if (portStr != null) + try + { + port = Integer.parseInt(portStr); + } + catch (NumberFormatException e) + { + URISyntaxException use = + new URISyntaxException + (string, "doesn't match URI regular expression"); + use.initCause(e); + throw use; + } + } + else + throw new URISyntaxException(string, + "doesn't match URI regular expression"); + } + return this; + } + + /** + *

    + * Returns a normalized version of the URI. If the URI is opaque, + * or its path is already in normal form, then this URI is simply + * returned. Otherwise, the following transformation of the path + * element takes place: + *

    + *
      + *
    1. All `.' segments are removed.
    2. + *
    3. Each `..' segment which can be paired with a prior non-`..' segment + * is removed along with the preceding segment.
    4. + *
    5. A `.' segment is added to the front if the first segment contains + * a colon (`:'). This is a deviation from the RFC, which prevents + * confusion between the path and the scheme.
    6. + *
    + *

    + * The resulting URI will be free of `.' and `..' segments, barring those + * that were prepended or which couldn't be paired, respectively. + *

    + * + * @return the normalized URI. + */ + public URI normalize() + { + if (isOpaque() || path.indexOf("/./") == -1 && path.indexOf("/../") == -1) + return this; + try + { + return new URI(scheme, authority, normalizePath(path), query, + fragment); + } + catch (URISyntaxException e) + { + throw (Error) new InternalError("Normalized URI variant could not "+ + "be constructed").initCause(e); + } + } + + /** + *

    + * Normalize the given path. The following transformation takes place: + *

    + *
      + *
    1. All `.' segments are removed.
    2. + *
    3. Each `..' segment which can be paired with a prior non-`..' segment + * is removed along with the preceding segment.
    4. + *
    5. A `.' segment is added to the front if the first segment contains + * a colon (`:'). This is a deviation from the RFC, which prevents + * confusion between the path and the scheme.
    6. + *
    + *

    + * The resulting URI will be free of `.' and `..' segments, barring those + * that were prepended or which couldn't be paired, respectively. + *

    + * + * @param relativePath the relative path to be normalized. + * @return the normalized path. + */ + private String normalizePath(String relativePath) + { + /* + This follows the algorithm in section 5.2.4. of RFC3986, + but doesn't modify the input buffer. + */ + StringBuffer input = new StringBuffer(relativePath); + StringBuffer output = new StringBuffer(); + int start = 0; + while (start < input.length()) + { + /* A */ + if (input.indexOf("../",start) == start) + { + start += 3; + continue; + } + if (input.indexOf("./",start) == start) + { + start += 2; + continue; + } + /* B */ + if (input.indexOf("/./",start) == start) + { + start += 2; + continue; + } + if (input.indexOf("/.",start) == start + && input.charAt(start + 2) != '.') + { + start += 1; + input.setCharAt(start,'/'); + continue; + } + /* C */ + if (input.indexOf("/../",start) == start) + { + start += 3; + removeLastSegment(output); + continue; + } + if (input.indexOf("/..",start) == start) + { + start += 2; + input.setCharAt(start,'/'); + removeLastSegment(output); + continue; + } + /* D */ + if (start == input.length() - 1 && input.indexOf(".",start) == start) + { + input.delete(0,1); + continue; + } + if (start == input.length() - 2 && input.indexOf("..",start) == start) + { + input.delete(0,2); + continue; + } + /* E */ + int indexOfSlash = input.indexOf("/",start); + while (indexOfSlash == start) + { + output.append("/"); + ++start; + indexOfSlash = input.indexOf("/",start); + } + if (indexOfSlash == -1) + indexOfSlash = input.length(); + output.append(input.substring(start, indexOfSlash)); + start = indexOfSlash; + } + return output.toString(); + } + + /** + * Removes the last segment of the path from the specified buffer. + * + * @param buffer the buffer containing the path. + */ + private void removeLastSegment(StringBuffer buffer) + { + int lastSlash = buffer.lastIndexOf("/"); + if (lastSlash == -1) + buffer.setLength(0); + else + buffer.setLength(lastSlash); + } + + /** + * Resolves the given URI against this URI + * + * @param uri The URI to resolve against this URI + * + * @return The resulting URI, or null when it couldn't be resolved + * for some reason. + * + * @throws NullPointerException if uri is null + */ + public URI resolve(URI uri) + { + if (uri.isAbsolute()) + return uri; + if (uri.isOpaque()) + return uri; + + String scheme = uri.getScheme(); + String schemeSpecificPart = uri.getSchemeSpecificPart(); + String authority = uri.getAuthority(); + String path = uri.getPath(); + String query = uri.getQuery(); + String fragment = uri.getFragment(); + + try + { + if (fragment != null && path != null && path.equals("") + && scheme == null && authority == null && query == null) + return new URI(this.scheme, this.schemeSpecificPart, fragment); + + if (authority == null) + { + authority = this.authority; + if (path == null) + path = ""; + if (! (path.startsWith("/"))) + { + StringBuffer basepath = new StringBuffer(this.path); + int i = this.path.lastIndexOf('/'); + + if (i >= 0) + basepath.delete(i + 1, basepath.length()); + + basepath.append(path); + path = normalizePath(basepath.toString()); + } + } + return new URI(this.scheme, authority, path, query, fragment); + } + catch (URISyntaxException e) + { + throw (Error) new InternalError("Resolved URI variant could not "+ + "be constructed").initCause(e); + } + } + + /** + * Resolves the given URI string against this URI + * + * @param str The URI as string to resolve against this URI + * + * @return The resulting URI + * + * @throws IllegalArgumentException If the given URI string + * violates RFC 2396 + * @throws NullPointerException If uri is null + */ + public URI resolve(String str) throws IllegalArgumentException + { + return resolve(create(str)); + } + + /** + *

    + * Relativizes the given URI against this URI. The following + * algorithm is used: + *

    + *
      + *
    • If either URI is opaque, the given URI is returned.
    • + *
    • If the schemes of the URIs differ, the given URI is returned.
    • + *
    • If the authority components of the URIs differ, then the given + * URI is returned.
    • + *
    • If the path of this URI is not a prefix of the supplied URI, + * then the given URI is returned.
    • + *
    • If all the above conditions hold, a new URI is created using the + * query and fragment components of the given URI, along with a path + * computed by removing the path of this URI from the start of the path + * of the supplied URI.
    • + *
    + * + * @param uri the URI to relativize agsint this URI + * @return the resulting URI + * @throws NullPointerException if the uri is null + */ + public URI relativize(URI uri) + { + if (isOpaque() || uri.isOpaque()) + return uri; + if (scheme == null && uri.getScheme() != null) + return uri; + if (scheme != null && !(scheme.equals(uri.getScheme()))) + return uri; + if (rawAuthority == null && uri.getRawAuthority() != null) + return uri; + if (rawAuthority != null && !(rawAuthority.equals(uri.getRawAuthority()))) + return uri; + if (!(uri.getRawPath().startsWith(rawPath))) + return uri; + try + { + return new URI(null, null, + uri.getRawPath().substring(rawPath.length()), + uri.getRawQuery(), uri.getRawFragment()); + } + catch (URISyntaxException e) + { + throw (Error) new InternalError("Relativized URI variant could not "+ + "be constructed").initCause(e); + } + } + + /** + * Creates an URL from an URI + * + * @throws MalformedURLException If a protocol handler for the URL could + * not be found, or if some other error occurred while constructing the URL + * @throws IllegalArgumentException If the URI is not absolute + */ + public URL toURL() throws IllegalArgumentException, MalformedURLException + { + if (isAbsolute()) + return new URL(this.toString()); + + throw new IllegalArgumentException("not absolute"); + } + + /** + * Returns the scheme of the URI + */ + public String getScheme() + { + return scheme; + } + + /** + * Tells whether this URI is absolute or not + */ + public boolean isAbsolute() + { + return scheme != null; + } + + /** + * Tell whether this URI is opaque or not + */ + public boolean isOpaque() + { + return ((scheme != null) && ! (schemeSpecificPart.startsWith("/"))); + } + + /** + * Returns the raw scheme specific part of this URI. + * The scheme-specific part is never undefined, though it may be empty + */ + public String getRawSchemeSpecificPart() + { + return rawSchemeSpecificPart; + } + + /** + * Returns the decoded scheme specific part of this URI. + */ + public String getSchemeSpecificPart() + { + return schemeSpecificPart; + } + + /** + * Returns the raw authority part of this URI + */ + public String getRawAuthority() + { + return rawAuthority; + } + + /** + * Returns the decoded authority part of this URI + */ + public String getAuthority() + { + return authority; + } + + /** + * Returns the raw user info part of this URI + */ + public String getRawUserInfo() + { + return rawUserInfo; + } + + /** + * Returns the decoded user info part of this URI + */ + public String getUserInfo() + { + return userInfo; + } + + /** + * Returns the hostname of the URI + */ + public String getHost() + { + return host; + } + + /** + * Returns the port number of the URI + */ + public int getPort() + { + return port; + } + + /** + * Returns the raw path part of this URI + */ + public String getRawPath() + { + return rawPath; + } + + /** + * Returns the path of the URI + */ + public String getPath() + { + return path; + } + + /** + * Returns the raw query part of this URI + */ + public String getRawQuery() + { + return rawQuery; + } + + /** + * Returns the query of the URI + */ + public String getQuery() + { + return query; + } + + /** + * Return the raw fragment part of this URI + */ + public String getRawFragment() + { + return rawFragment; + } + + /** + * Returns the fragment of the URI + */ + public String getFragment() + { + return fragment; + } + + /** + *

    + * Compares the URI with the given object for equality. If the + * object is not a URI, then the method returns false. + * Otherwise, the following criteria are observed: + *

    + *
      + *
    • The scheme of the URIs must either be null (undefined) in both cases, + * or equal, ignorant of case.
    • + *
    • The raw fragment of the URIs must either be null (undefined) in both + * cases, or equal, ignorant of case.
    • + *
    • Both URIs must be of the same type (opaque or hierarchial)
    • + *
    • For opaque URIs:
    • + *
        + *
      • The raw scheme-specific parts must be equal.
      • + *
      + *
    • For hierarchical URIs:
    • + *
        + *
      • The raw paths must be equal, ignorant of case.
      • + *
      • The raw queries are either both undefined or both equal, ignorant + * of case.
      • + *
      • The raw authority sections are either both undefined or:
      • + *
      • For registry-based authorities:
      • + *
        • they are equal.
        + *
      • For server-based authorities:
      • + *
          + *
        • the hosts are equal, ignoring case
        • + *
        • the ports are equal
        • + *
        • the user information components are equal
        • + *
        + *
      + *
    + * + * @param obj the obj to compare the URI with. + * @return true if the objects are equal, according to + * the specification above. + */ + public boolean equals(Object obj) + { + if (!(obj instanceof URI)) + return false; + URI uriObj = (URI) obj; + if (scheme == null) + { + if (uriObj.getScheme() != null) + return false; + } + else + if (!(scheme.equalsIgnoreCase(uriObj.getScheme()))) + return false; + if (rawFragment == null) + { + if (uriObj.getRawFragment() != null) + return false; + } + else + if (!(rawFragment.equalsIgnoreCase(uriObj.getRawFragment()))) + return false; + boolean opaqueThis = isOpaque(); + boolean opaqueObj = uriObj.isOpaque(); + if (opaqueThis && opaqueObj) + return rawSchemeSpecificPart.equals(uriObj.getRawSchemeSpecificPart()); + else if (!opaqueThis && !opaqueObj) + { + boolean common = rawPath.equalsIgnoreCase(uriObj.getRawPath()) + && ((rawQuery == null && uriObj.getRawQuery() == null) + || rawQuery.equalsIgnoreCase(uriObj.getRawQuery())); + if (rawAuthority == null && uriObj.getRawAuthority() == null) + return common; + if (host == null) + return common + && rawAuthority.equalsIgnoreCase(uriObj.getRawAuthority()); + return common + && host.equalsIgnoreCase(uriObj.getHost()) + && port == uriObj.getPort() + && (rawUserInfo == null ? + uriObj.getRawUserInfo() == null : + rawUserInfo.equalsIgnoreCase(uriObj.getRawUserInfo())); + } + else + return false; + } + + /** + * Computes the hashcode of the URI + */ + public int hashCode() + { + return (getScheme() == null ? 0 : 13 * getScheme().hashCode()) + + 17 * getRawSchemeSpecificPart().hashCode() + + (getRawFragment() == null ? 0 : 21 + getRawFragment().hashCode()); + } + + /** + * Compare the URI with another object that must also be a URI. + * Undefined components are taken to be less than any other component. + * The following criteria are observed: + *

    + *
      + *
    • Two URIs with different schemes are compared according to their + * scheme, regardless of case.
    • + *
    • A hierarchical URI is less than an opaque URI with the same + * scheme.
    • + *
    • For opaque URIs:
    • + *
        + *
      • URIs with differing scheme-specific parts are ordered according + * to the ordering of the scheme-specific part.
      • + *
      • URIs with the same scheme-specific part are ordered by the + * raw fragment.
      • + *
      + *
    • For hierarchical URIs:
    • + *
        + *
      • URIs are ordered according to their raw authority sections, + * if they are unequal.
      • + *
      • For registry-based authorities:
      • + *
        • they are ordered according to the ordering of the authority + * component.
        + *
      • For server-based authorities:
      • + *
          + *
        • URIs are ordered according to the raw user information.
        • + *
        • URIs with the same user information are ordered by the host, + * ignoring case.
        • + *
        • URIs with the same host are ordered by the port.
        • + *
        + *
      • URIs with the same authority section are ordered by the raw path.
      • + *
      • URIs with the same path are ordered by their raw query.
      • + *
      • URIs with the same query are ordered by their raw fragments.
      • + *
      + *
    + * + * @param obj This object to compare this URI with + * @return a negative integer, zero or a positive integer depending + * on whether this URI is less than, equal to or greater + * than that supplied, respectively. + * @throws ClassCastException if the given object is not a URI + */ + public int compareTo(Object obj) + throws ClassCastException + { + URI uri = (URI) obj; + if (scheme == null && uri.getScheme() != null) + return -1; + if (scheme != null) + { + int sCompare = scheme.compareToIgnoreCase(uri.getScheme()); + if (sCompare != 0) + return sCompare; + } + boolean opaqueThis = isOpaque(); + boolean opaqueObj = uri.isOpaque(); + if (opaqueThis && !opaqueObj) + return 1; + if (!opaqueThis && opaqueObj) + return -1; + if (opaqueThis) + { + int ssCompare = + rawSchemeSpecificPart.compareTo(uri.getRawSchemeSpecificPart()); + if (ssCompare == 0) + return compareFragments(uri); + else + return ssCompare; + } + if (rawAuthority == null && uri.getRawAuthority() != null) + return -1; + if (rawAuthority != null) + { + int aCompare = rawAuthority.compareTo(uri.getRawAuthority()); + if (aCompare != 0) + { + if (host == null) + return aCompare; + if (rawUserInfo == null && uri.getRawUserInfo() != null) + return -1; + int uCompare = rawUserInfo.compareTo(uri.getRawUserInfo()); + if (uCompare != 0) + return uCompare; + if (host == null && uri.getHost() != null) + return -1; + int hCompare = host.compareTo(uri.getHost()); + if (hCompare != 0) + return hCompare; + return new Integer(port).compareTo(new Integer(uri.getPort())); + } + } + if (rawPath == null && uri.getRawPath() != null) + return -1; + if (rawPath != null) + { + int pCompare = rawPath.compareTo(uri.getRawPath()); + if (pCompare != 0) + return pCompare; + } + if (rawQuery == null && uri.getRawQuery() != null) + return -1; + if (rawQuery != null) + { + int qCompare = rawQuery.compareTo(uri.getRawQuery()); + if (qCompare != 0) + return qCompare; + } + return compareFragments(uri); + } + + /** + * Compares the fragment of this URI with that of the supplied URI. + * + * @param uri the URI to compare with this one. + * @return a negative integer, zero or a positive integer depending + * on whether this uri's fragment is less than, equal to + * or greater than the fragment of the uri supplied, respectively. + */ + private int compareFragments(URI uri) + { + if (rawFragment == null && uri.getRawFragment() != null) + return -1; + else if (rawFragment == null) + return 0; + else + return rawFragment.compareTo(uri.getRawFragment()); + } + + /** + * Returns the URI as a String. If the URI was created using a constructor, + * then this will be the same as the original input string. + * + * @return a string representation of the URI. + */ + public String toString() + { + return (scheme == null ? "" : scheme + ":") + + rawSchemeSpecificPart + + (rawFragment == null ? "" : "#" + rawFragment); + } + + /** + * Returns the URI as US-ASCII string. This is the same as the result + * from toString() for URIs that don't contain any non-US-ASCII + * characters. Otherwise, the non-US-ASCII characters are replaced + * by their percent-encoded representations. + * + * @return a string representation of the URI, containing only US-ASCII + * characters. + */ + public String toASCIIString() + { + String strRep = toString(); + boolean inNonAsciiBlock = false; + StringBuffer buffer = new StringBuffer(); + StringBuffer encBuffer = null; + for (int i = 0; i < strRep.length(); i++) + { + char c = strRep.charAt(i); + if (c <= 127) + { + if (inNonAsciiBlock) + { + buffer.append(escapeCharacters(encBuffer.toString())); + inNonAsciiBlock = false; + } + buffer.append(c); + } + else + { + if (!inNonAsciiBlock) + { + encBuffer = new StringBuffer(); + inNonAsciiBlock = true; + } + encBuffer.append(c); + } + } + return buffer.toString(); + } + + /** + * Converts the non-ASCII characters in the supplied string + * to their equivalent percent-encoded representations. + * That is, they are replaced by "%" followed by their hexadecimal value. + * + * @param str a string including non-ASCII characters. + * @return the string with the non-ASCII characters converted to their + * percent-encoded representations. + */ + private static String escapeCharacters(String str) + { + try + { + StringBuffer sb = new StringBuffer(); + // this is far from optimal, but it works + byte[] utf8 = str.getBytes("utf-8"); + for (int j = 0; j < utf8.length; j++) + { + sb.append('%'); + sb.append(HEX.charAt((utf8[j] & 0xff) / 16)); + sb.append(HEX.charAt((utf8[j] & 0xff) % 16)); + } + return sb.toString(); + } + catch (java.io.UnsupportedEncodingException x) + { + throw (Error) new InternalError("Escaping error").initCause(x); + } + } + +} diff --git a/libjava/classpath/java/net/URISyntaxException.java b/libjava/classpath/java/net/URISyntaxException.java new file mode 100644 index 0000000..27a70bd --- /dev/null +++ b/libjava/classpath/java/net/URISyntaxException.java @@ -0,0 +1,144 @@ +/* URISyntaxException.java -- a string could not be parsed as a URI + 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 java.net; + + +/** + * This exception is thrown when a String cannot be parsed as a URI. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see URI + * @since 1.4 + * @status updated to 1.4 + */ +public class URISyntaxException extends Exception +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 2137979680897488891L; + + /** + * The failed input. + * + * @serial the bad URI + */ + private final String input; + + /** + * The index of failure. + * + * @serial the location of the problem + */ + private final int index; + + /** + * Create an exception from the invalid string, with the index set to -1. + * + * @param input the bad URI + * @param msg the descriptive error message + * @throws NullPointerException if input or msg are null + */ + public URISyntaxException(String input, String msg) + { + this(input, msg, -1); + } + + /** + * Create an exception from the invalid string, with the index of the + * point of failure. + * + * @param input the bad URI + * @param msg the descriptive error message + * @param index the index of the parse error, or -1 + * @throws NullPointerException if input or msg are null + * @throws IllegalArgumentException if index < -1 + */ + public URISyntaxException(String input, String msg, int index) + { + // The toString() hack checks for null. + super(msg.toString()); + this.input = input.toString(); + this.index = index; + if (index < -1) + throw new IllegalArgumentException(); + } + + /** + * Returns the bad input string. + * + * @return the bad URI, guaranteed non-null + */ + public String getInput() + { + return input; + } + + /** + * Returns the reason for the failure. + * + * @return the message, guaranteed non-null + */ + public String getReason() + { + return super.getMessage(); + } + + /** + * Returns the index of the failure, or -1. + * + * @return the index of failure + */ + public int getIndex() + { + return index; + } + + /** + * Returns a message describing the parse error, as if by + * getReason() + (getIndex() >= 0 ? " at index " + getIndex() : "") + * + ": " + getInput(). + * + * @return the message string + */ + public String getMessage() + { + return (super.getMessage() + (index >= 0 ? " at index " + index : "") + + ": " + input); + } +} diff --git a/libjava/classpath/java/net/URL.java b/libjava/classpath/java/net/URL.java new file mode 100644 index 0000000..627dbc3 --- /dev/null +++ b/libjava/classpath/java/net/URL.java @@ -0,0 +1,956 @@ +/* URL.java -- Uniform Resource Locator Class + Copyright (C) 1998, 1999, 2000, 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 java.net; + +import gnu.java.net.URLParseError; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.StringTokenizer; + + +/* + * 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 final class represents an Internet Uniform Resource Locator (URL). + * For details on the syntax of URL's and what they can be used for, + * refer to RFC 1738, available from + * http://ds.internic.net/rfcs/rfc1738.txt + *

    + * There are a great many protocols supported by URL's such as "http", + * "ftp", and "file". This object can handle any arbitrary URL for which + * a URLStreamHandler object can be written. Default protocol handlers + * are provided for the "http" and "ftp" protocols. Additional protocols + * handler implementations may be provided in the future. In any case, + * an application or applet can install its own protocol handlers that + * can be "chained" with other protocol hanlders in the system to extend + * the base functionality provided with this class. (Note, however, that + * unsigned applets cannot access properties by default or install their + * own protocol handlers). + *

    + * This chaining is done via the system property java.protocol.handler.pkgs + * If this property is set, it is assumed to be a "|" separated list of + * package names in which to attempt locating protocol handlers. The + * protocol handler is searched for by appending the string + * ".<protocol>.Handler" to each packed in the list until a hander is + * found. If a protocol handler is not found in this list of packages, or if + * the property does not exist, then the default protocol handler of + * "gnu.java.net.<protocol>.Handler" is tried. If this is + * unsuccessful, a MalformedURLException is thrown. + *

    + * All of the constructor methods of URL attempt to load a protocol + * handler and so any needed protocol handlers must be installed when + * the URL is constructed. + *

    + * Here is an example of how URL searches for protocol handlers. Assume + * the value of java.protocol.handler.pkgs is "com.foo|com.bar" and the + * URL is "news://comp.lang.java.programmer". URL would looking the + * following places for protocol handlers: + *

    +  * com.foo.news.Handler
    +  * com.bar.news.Handler
    +  * gnu.java.net.news.Handler
    +  * 

    + * If the protocol handler is not found in any of those locations, a + * MalformedURLException would be thrown. + *

    + * Please note that a protocol handler must be a subclass of + * URLStreamHandler. + *

    + * Normally, this class caches protocol handlers. Once it finds a handler + * for a particular protocol, it never tries to look up a new handler + * again. However, if the system property + * gnu.java.net.nocache_protocol_handlers is set, then this + * caching behavior is disabled. This property is specific to this + * implementation. Sun's JDK may or may not do protocol caching, but it + * almost certainly does not examine this property. + *

    + * Please also note that an application can install its own factory for + * loading protocol handlers (see setURLStreamHandlerFactory). If this is + * done, then the above information is superseded and the behavior of this + * class in loading protocol handlers is dependent on that factory. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * + * @see URLStreamHandler + */ +public final class URL implements Serializable +{ + private static final String DEFAULT_SEARCH_PATH = + "gnu.java.net.protocol|gnu.inet"; + + // Cached System ClassLoader + private static ClassLoader systemClassLoader; + + /** + * The name of the protocol for this URL. + * The protocol is always stored in lower case. + */ + private String protocol; + + /** + * The "authority" portion of the URL. + */ + private String authority; + + /** + * The hostname or IP address of this protocol. + * This includes a possible user. For example joe@some.host.net. + */ + private String host; + + /** + * The user information necessary to establish the connection. + */ + private String userInfo; + + /** + * The port number of this protocol or -1 if the port number used is + * the default for this protocol. + */ + private int port = -1; // Initialize for constructor using context. + + /** + * The "file" portion of the URL. It is defined as path[?query]. + */ + private String file; + + /** + * The anchor portion of the URL. + */ + private String ref; + + /** + * This is the hashCode for this URL + */ + private int hashCode; + + /** + * The protocol handler in use for this URL + */ + transient URLStreamHandler ph; + + /** + * If an application installs its own protocol handler factory, this is + * where we keep track of it. + */ + private static URLStreamHandlerFactory factory; + private static final long serialVersionUID = -7627629688361524110L; + + /** + * This a table where we cache protocol handlers to avoid the overhead + * of looking them up each time. + */ + private static HashMap ph_cache = new HashMap(); + + /** + * Whether or not to cache protocol handlers. + */ + private static boolean cache_handlers; + + static + { + String s = System.getProperty("gnu.java.net.nocache_protocol_handlers"); + + if (s == null) + cache_handlers = true; + else + cache_handlers = false; + } + + /** + * Constructs a URL and loads a protocol handler for the values passed as + * arguments. + * + * @param protocol The protocol for this URL ("http", "ftp", etc) + * @param host The hostname or IP address to connect to + * @param port The port number to use, or -1 to use the protocol's + * default port + * @param file The "file" portion of the URL. + * + * @exception MalformedURLException If a protocol handler cannot be loaded or + * a parse error occurs. + */ + public URL(String protocol, String host, int port, String file) + throws MalformedURLException + { + this(protocol, host, port, file, null); + } + + /** + * Constructs a URL and loads a protocol handler for the values passed in + * as arugments. Uses the default port for the protocol. + * + * @param protocol The protocol for this URL ("http", "ftp", etc) + * @param host The hostname or IP address for this URL + * @param file The "file" portion of this URL. + * + * @exception MalformedURLException If a protocol handler cannot be loaded or + * a parse error occurs. + */ + public URL(String protocol, String host, String file) + throws MalformedURLException + { + this(protocol, host, -1, file, null); + } + + /** + * This method initializes a new instance of URL with the + * specified protocol, host, port, and file. Additionally, this method + * allows the caller to specify a protocol handler to use instead of + * the default. If this handler is specified, the caller must have + * the "specifyStreamHandler" permission (see NetPermission) + * or a SecurityException will be thrown. + * + * @param protocol The protocol for this URL ("http", "ftp", etc) + * @param host The hostname or IP address to connect to + * @param port The port number to use, or -1 to use the protocol's default + * port + * @param file The "file" portion of the URL. + * @param ph The protocol handler to use with this URL. + * + * @exception MalformedURLException If no protocol handler can be loaded + * for the specified protocol. + * @exception SecurityException If the SecurityManager exists + * and does not allow the caller to specify its own protocol handler. + * + * @since 1.2 + */ + public URL(String protocol, String host, int port, String file, + URLStreamHandler ph) throws MalformedURLException + { + if (protocol == null) + throw new MalformedURLException("null protocol"); + protocol = protocol.toLowerCase(); + this.protocol = protocol; + + if (ph != null) + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new NetPermission("specifyStreamHandler")); + + this.ph = ph; + } + else + this.ph = getURLStreamHandler(protocol); + + if (this.ph == null) + throw new MalformedURLException("Protocol handler not found: " + + protocol); + + this.host = host; + this.port = port; + this.authority = (host != null) ? host : ""; + if (port >= 0 && host != null) + this.authority += ":" + port; + + int hashAt = file.indexOf('#'); + if (hashAt < 0) + { + this.file = file; + this.ref = null; + } + else + { + this.file = file.substring(0, hashAt); + this.ref = file.substring(hashAt + 1); + } + hashCode = hashCode(); // Used for serialization. + } + + /** + * Initializes a URL from a complete string specification such as + * "http://www.urbanophile.com/arenn/". First the protocol name is parsed + * out of the string. Then a handler is located for that protocol and + * the parseURL() method of that protocol handler is used to parse the + * remaining fields. + * + * @param spec The complete String representation of a URL + * + * @exception MalformedURLException If a protocol handler cannot be found + * or the URL cannot be parsed + */ + public URL(String spec) throws MalformedURLException + { + this((URL) null, spec != null ? spec : "", (URLStreamHandler) null); + } + + /** + * This method parses a String representation of a URL within the + * context of an existing URL. Principally this means that any + * fields not present the URL are inheritied from the context URL. + * This allows relative URL's to be easily constructed. If the + * context argument is null, then a complete URL must be specified + * in the URL string. If the protocol parsed out of the URL is + * different from the context URL's protocol, then then URL String + * is also expected to be a complete URL. + * + * @param context The context on which to parse the specification + * @param spec The string to parse an URL + * + * @exception MalformedURLException If a protocol handler cannot be found + * for the URL cannot be parsed + */ + public URL(URL context, String spec) throws MalformedURLException + { + this(context, spec, (URLStreamHandler) null); + } + + /** + * Creates an URL from given arguments + * This method parses a String representation of a URL within the + * context of an existing URL. Principally this means that any fields + * not present the URL are inheritied from the context URL. This allows + * relative URL's to be easily constructed. If the context argument is + * null, then a complete URL must be specified in the URL string. + * If the protocol parsed out of the URL is different + * from the context URL's protocol, then then URL String is also + * expected to be a complete URL. + *

    + * Additionally, this method allows the caller to specify a protocol handler + * to use instead of the default. If this handler is specified, the caller + * must have the "specifyStreamHandler" permission + * (see NetPermission) or a SecurityException + * will be thrown. + * + * @param context The context in which to parse the specification + * @param spec The string to parse as an URL + * @param ph The stream handler for the URL + * + * @exception MalformedURLException If a protocol handler cannot be found + * or the URL cannot be parsed + * @exception SecurityException If the SecurityManager exists + * and does not allow the caller to specify its own protocol handler. + * + * @since 1.2 + */ + public URL(URL context, String spec, URLStreamHandler ph) + throws MalformedURLException + { + /* A protocol is defined by the doc as the substring before a ':' + * as long as the ':' occurs before any '/'. + * + * If context is null, then spec must be an absolute URL. + * + * The relative URL need not specify all the components of a URL. + * If the protocol, host name, or port number is missing, the value + * is inherited from the context. A bare file component is appended + * to the context's file. The optional anchor is not inherited. + */ + + // If this is an absolute URL, then ignore context completely. + // An absolute URL must have chars prior to "://" but cannot have a colon + // right after the "://". The second colon is for an optional port value + // and implies that the host from the context is used if available. + int colon; + int slash = spec.indexOf('/'); + if ((colon = spec.indexOf("://", 1)) > 0 + && ((colon < slash || slash < 0)) + && ! spec.regionMatches(colon, "://:", 0, 4)) + context = null; + + if ((colon = spec.indexOf(':')) > 0 + && (colon < slash || slash < 0)) + { + // Protocol specified in spec string. + protocol = spec.substring(0, colon).toLowerCase(); + if (context != null && context.protocol.equals(protocol)) + { + // The 1.2 doc specifically says these are copied to the new URL. + host = context.host; + port = context.port; + file = context.file; + userInfo = context.userInfo; + if (file == null || file.length() == 0) + file = "/"; + authority = context.authority; + } + } + else if (context != null) + { + // Protocol NOT specified in spec string. + // Use context fields (except ref) as a foundation for relative URLs. + colon = -1; + protocol = context.protocol; + host = context.host; + port = context.port; + file = context.file; + userInfo = context.userInfo; + if (file == null || file.length() == 0) + file = "/"; + authority = context.authority; + } + else // Protocol NOT specified in spec. and no context available. + throw new MalformedURLException("Absolute URL required with null" + + " context: " + spec); + + protocol = protocol.trim(); + + if (ph != null) + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new NetPermission("specifyStreamHandler")); + + this.ph = ph; + } + else + this.ph = getURLStreamHandler(protocol); + + if (this.ph == null) + throw new MalformedURLException("Protocol handler not found: " + + protocol); + + // JDK 1.2 doc for parseURL specifically states that any '#' ref + // is to be excluded by passing the 'limit' as the indexOf the '#' + // if one exists, otherwise pass the end of the string. + int hashAt = spec.indexOf('#', colon + 1); + + try + { + this.ph.parseURL(this, spec, colon + 1, + hashAt < 0 ? spec.length() : hashAt); + } + catch (URLParseError e) + { + throw new MalformedURLException(e.getMessage()); + } + + if (hashAt >= 0) + ref = spec.substring(hashAt + 1); + + hashCode = hashCode(); // Used for serialization. + } + + /** + * Test another URL for equality with this one. This will be true only if + * the argument is non-null and all of the fields in the URL's match + * exactly (ie, protocol, host, port, file, and ref). Overrides + * Object.equals(), implemented by calling the equals method of the handler. + * + * @param obj The URL to compare with + * + * @return true if the URL is equal, false otherwise + */ + public boolean equals(Object obj) + { + if (! (obj instanceof URL)) + return false; + + return ph.equals(this, (URL) obj); + } + + /** + * Returns the contents of this URL as an object by first opening a + * connection, then calling the getContent() method against the connection + * + * @return A content object for this URL + * @exception IOException If opening the connection or getting the + * content fails. + * + * @since 1.3 + */ + public Object getContent() throws IOException + { + return openConnection().getContent(); + } + + /** + * Gets the contents of this URL + * + * @param classes The allow classes for the content object. + * + * @return a context object for this URL. + * + * @exception IOException If an error occurs + */ + public Object getContent(Class[] classes) throws IOException + { + // FIXME: implement this + return getContent(); + } + + /** + * Returns the file portion of the URL. + * Defined as path[?query]. + * Returns the empty string if there is no file portion. + * + * @return The filename specified in this URL, or an empty string if empty. + */ + public String getFile() + { + return file == null ? "" : file; + } + + /** + * Returns the path of the URL. This is the part of the file before any '?' + * character. + * + * @return The path specified in this URL, or null if empty. + * + * @since 1.3 + */ + public String getPath() + { + // The spec says we need to return an empty string, but some + // applications depends on receiving null when the path is empty. + if (file == null) + return null; + int quest = file.indexOf('?'); + return quest < 0 ? getFile() : file.substring(0, quest); + } + + /** + * Returns the authority of the URL + * + * @return The authority specified in this URL. + * + * @since 1.3 + */ + public String getAuthority() + { + return authority; + } + + /** + * Returns the host of the URL + * + * @return The host specified in this URL. + */ + public String getHost() + { + int at = (host == null) ? -1 : host.indexOf('@'); + return at < 0 ? host : host.substring(at + 1, host.length()); + } + + /** + * Returns the port number of this URL or -1 if the default port number is + * being used. + * + * @return The port number + * + * @see #getDefaultPort() + */ + public int getPort() + { + return port; + } + + /** + * Returns the default port of the URL. If the StreamHandler for the URL + * protocol does not define a default port it returns -1. + * + * @return The default port of the current protocol. + */ + public int getDefaultPort() + { + return ph.getDefaultPort(); + } + + /** + * Returns the protocol of the URL + * + * @return The specified protocol. + */ + public String getProtocol() + { + return protocol; + } + + /** + * Returns the ref (sometimes called the "# reference" or "anchor") portion + * of the URL. + * + * @return The ref + */ + public String getRef() + { + return ref; + } + + /** + * Returns the user information of the URL. This is the part of the host + * name before the '@'. + * + * @return the user at a particular host or null when no user defined. + */ + public String getUserInfo() + { + if (userInfo != null) + return userInfo; + int at = (host == null) ? -1 : host.indexOf('@'); + return at < 0 ? null : host.substring(0, at); + } + + /** + * Returns the query of the URL. This is the part of the file before the + * '?'. + * + * @return the query part of the file, or null when there is no query part. + */ + public String getQuery() + { + int quest = (file == null) ? -1 : file.indexOf('?'); + return quest < 0 ? null : file.substring(quest + 1, file.length()); + } + + /** + * Returns a hashcode computed by the URLStreamHandler of this URL + * + * @return The hashcode for this URL. + */ + public int hashCode() + { + if (hashCode != 0) + return hashCode; // Use cached value if available. + else + return ph.hashCode(this); + } + + /** + * Returns a URLConnection object that represents a connection to the remote + * object referred to by the URL. The URLConnection is created by calling the + * openConnection() method of the protocol handler + * + * @return A URLConnection for this URL + * + * @exception IOException If an error occurs + */ + public URLConnection openConnection() throws IOException + { + return ph.openConnection(this); + } + + /** + * Opens a connection to this URL and returns an InputStream for reading + * from that connection + * + * @return An InputStream for this URL. + * + * @exception IOException If an error occurs + */ + public InputStream openStream() throws IOException + { + return openConnection().getInputStream(); + } + + /** + * Tests whether or not another URL refers to the same "file" as this one. + * This will be true if and only if the passed object is not null, is a + * URL, and matches all fields but the ref (ie, protocol, host, port, + * and file); + * + * @param url The URL object to test with + * + * @return true if URL matches this URL's file, false otherwise + */ + public boolean sameFile(URL url) + { + return ph.sameFile(this, url); + } + + /** + * Sets the specified fields of the URL. This is not a public method so + * that only URLStreamHandlers can modify URL fields. This might be called + * by the parseURL() method in that class. URLs are otherwise + * constant. If the given protocol does not exist, it will keep the previously + * set protocol. + * + * @param protocol The protocol name for this URL + * @param host The hostname or IP address for this URL + * @param port The port number of this URL + * @param file The "file" portion of this URL. + * @param ref The anchor portion of this URL. + */ + protected void set(String protocol, String host, int port, String file, + String ref) + { + URLStreamHandler protocolHandler = null; + protocol = protocol.toLowerCase(); + if (! this.protocol.equals(protocol)) + protocolHandler = getURLStreamHandler(protocol); + + // It is an hidden feature of the JDK. If the protocol does not exist, + // we keep the previously initialized protocol. + if (protocolHandler != null) + { + this.ph = protocolHandler; + this.protocol = protocol; + } + this.authority = ""; + this.port = port; + this.host = host; + this.file = file; + this.ref = ref; + + if (host != null) + this.authority += host; + if (port >= 0) + this.authority += ":" + port; + + hashCode = hashCode(); // Used for serialization. + } + + /** + * Sets the specified fields of the URL. This is not a public method so + * that only URLStreamHandlers can modify URL fields. URLs are otherwise + * constant. If the given protocol does not exist, it will keep the previously + * set protocol. + * + * @param protocol The protocol name for this URL. + * @param host The hostname or IP address for this URL. + * @param port The port number of this URL. + * @param authority The authority of this URL. + * @param userInfo The user and password (if needed) of this URL. + * @param path The "path" portion of this URL. + * @param query The query of this URL. + * @param ref The anchor portion of this URL. + * + * @since 1.3 + */ + protected void set(String protocol, String host, int port, String authority, + String userInfo, String path, String query, String ref) + { + URLStreamHandler protocolHandler = null; + protocol = protocol.toLowerCase(); + if (! this.protocol.equals(protocol)) + protocolHandler = getURLStreamHandler(protocol); + + // It is an hidden feature of the JDK. If the protocol does not exist, + // we keep the previously initialized protocol. + if (protocolHandler != null) + { + this.ph = protocolHandler; + this.protocol = protocol; + } + this.host = host; + this.userInfo = userInfo; + this.port = port; + this.authority = authority; + if (query == null) + this.file = path; + else + this.file = path + "?" + query; + this.ref = ref; + hashCode = hashCode(); // Used for serialization. + } + + /** + * Sets the URLStreamHandlerFactory for this class. This factory is + * responsible for returning the appropriate protocol handler for + * a given URL. + * + * @param fac The URLStreamHandlerFactory class to use + * + * @exception Error If the factory is alread set. + * @exception SecurityException If a security manager exists and its + * checkSetFactory method doesn't allow the operation + */ + public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) + { + if (factory != null) + throw new Error("URLStreamHandlerFactory already set"); + + // Throw an exception if an extant security mgr precludes + // setting the factory. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkSetFactory(); + factory = fac; + } + + /** + * Returns a String representing this URL. The String returned is + * created by calling the protocol handler's toExternalForm() method. + * + * @return A string for this URL + */ + public String toExternalForm() + { + // Identical to toString(). + return ph.toExternalForm(this); + } + + /** + * Returns a String representing this URL. Identical to toExternalForm(). + * The value returned is created by the protocol handler's + * toExternalForm method. Overrides Object.toString() + * + * @return A string for this URL + */ + public String toString() + { + // Identical to toExternalForm(). + return ph.toExternalForm(this); + } + + /** + * This internal method is used in two different constructors to load + * a protocol handler for this URL. + * + * @param protocol The protocol to load a handler for + * + * @return A URLStreamHandler for this protocol, or null when not found. + */ + private static synchronized URLStreamHandler getURLStreamHandler(String protocol) + { + URLStreamHandler ph = null; + + // First, see if a protocol handler is in our cache. + if (cache_handlers) + { + if ((ph = (URLStreamHandler) ph_cache.get(protocol)) != null) + return ph; + } + + // If a non-default factory has been set, use it to find the protocol. + if (factory != null) + { + ph = factory.createURLStreamHandler(protocol); + } + + // Non-default factory may have returned null or a factory wasn't set. + // Use the default search algorithm to find a handler for this protocol. + if (ph == null) + { + // Get the list of packages to check and append our default handler + // to it, along with the JDK specified default as a last resort. + // Except in very unusual environments the JDK specified one shouldn't + // ever be needed (or available). + String ph_search_path = + System.getProperty("java.protocol.handler.pkgs"); + + // Tack our default package on at the ends. + if (ph_search_path != null) + ph_search_path += "|" + DEFAULT_SEARCH_PATH; + else + ph_search_path = DEFAULT_SEARCH_PATH; + + // Finally loop through our search path looking for a match. + StringTokenizer pkgPrefix = new StringTokenizer(ph_search_path, "|"); + + // Cache the systemClassLoader + if (systemClassLoader == null) + { + systemClassLoader = (ClassLoader) AccessController.doPrivileged + (new PrivilegedAction() { + public Object run() + { + return ClassLoader.getSystemClassLoader(); + } + }); + } + + do + { + try + { + // Try to get a class from the system/application + // classloader, initialize it, make an instance + // and try to cast it to a URLStreamHandler. + String clsName = + (pkgPrefix.nextToken() + "." + protocol + ".Handler"); + Class c = Class.forName(clsName, true, systemClassLoader); + ph = (URLStreamHandler) c.newInstance(); + } + catch (ThreadDeath death) + { + throw death; + } + catch (Throwable t) + { + // Ignored. + } + } + while (ph == null && pkgPrefix.hasMoreTokens()); + } + + // Update the hashtable with the new protocol handler. + if (ph != null && cache_handlers) + ph_cache.put(protocol, ph); + else + ph = null; + + return ph; + } + + private void readObject(ObjectInputStream ois) + throws IOException, ClassNotFoundException + { + ois.defaultReadObject(); + this.ph = getURLStreamHandler(protocol); + if (this.ph == null) + throw new IOException("Handler for protocol " + protocol + " not found"); + } + + private void writeObject(ObjectOutputStream oos) throws IOException + { + oos.defaultWriteObject(); + } + + /** + * Returns the equivalent URI object for this URL. + * This is the same as calling new URI(this.toString()). + * RFC2396-compliant URLs are guaranteed a successful conversion to + * a URI instance. However, there are some values which + * form valid URLs, but which do not also form RFC2396-compliant URIs. + * + * @throws URISyntaxException if this URL is not RFC2396-compliant, + * and thus can not be successfully converted to a URI. + */ + public URI toURI() + throws URISyntaxException + { + return new URI(toString()); + } + +} diff --git a/libjava/classpath/java/net/URLClassLoader.java b/libjava/classpath/java/net/URLClassLoader.java new file mode 100644 index 0000000..8ebc3e0 --- /dev/null +++ b/libjava/classpath/java/net/URLClassLoader.java @@ -0,0 +1,1171 @@ +/* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs + Copyright (C) 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 java.net; + +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FilePermission; +import java.io.IOException; +import java.io.InputStream; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.security.PrivilegedAction; +import java.security.SecureClassLoader; +import java.security.cert.Certificate; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + + +/** + * A secure class loader that can load classes and resources from + * multiple locations. Given an array of URLs this class + * loader will retrieve classes and resources by fetching them from + * possible remote locations. Each URL is searched in + * order in which it was added. If the file portion of the + * URL ends with a '/' character then it is interpreted + * as a base directory, otherwise it is interpreted as a jar file from + * which the classes/resources are resolved. + * + *

    New instances can be created by two static + * newInstance() methods or by three public + * contructors. Both ways give the option to supply an initial array + * of URLs and (optionally) a parent classloader (that is + * different from the standard system class loader).

    + * + *

    Normally creating a URLClassLoader throws a + * SecurityException if a SecurityManager is + * installed and the checkCreateClassLoader() method does + * not return true. But the newInstance() methods may be + * used by any code as long as it has permission to acces the given + * URLs. URLClassLoaders created by the + * newInstance() methods also explicitly call the + * checkPackageAccess() method of + * SecurityManager if one is installed before trying to + * load a class. Note that only subclasses of + * URLClassLoader can add new URLs after the + * URLClassLoader had been created. But it is always possible to get + * an array of all URLs that the class loader uses to resolve classes + * and resources by way of the getURLs() method.

    + * + *

    Open issues: + *

      + * + *
    • Should the URLClassLoader actually add the locations found in + * the manifest or is this the responsibility of some other + * loader/(sub)class? (see + * Extension Mechanism Architecture - Bundles Extensions)
    • + * + *
    • How does definePackage() and sealing work + * precisely?
    • + * + *
    • We save and use the security context (when a created by + * newInstance() but do we have to use it in more + * places?
    • + * + *
    • The use of URLStreamHandlers has not been tested.
    • + * + *
    + *

    + * + * @since 1.2 + * + * @author Mark Wielaard (mark@klomp.org) + * @author Wu Gansha (gansha.wu@intel.com) + */ +public class URLClassLoader extends SecureClassLoader +{ + // Class Variables + + /** + * A global cache to store mappings between URLLoader and URL, + * so we can avoid do all the homework each time the same URL + * comes. + * XXX - Keeps these loaders forever which prevents garbage collection. + */ + private static HashMap urlloaders = new HashMap(); + + /** + * A cache to store mappings between handler factory and its + * private protocol handler cache (also a HashMap), so we can avoid + * create handlers each time the same protocol comes. + */ + private static HashMap factoryCache = new HashMap(5); + + // Instance variables + + /** Locations to load classes from */ + private final Vector urls = new Vector(); + + /** + * Store pre-parsed information for each url into this vector: each + * element is a URL loader. A jar file has its own class-path + * attribute which adds to the URLs that will be searched, but this + * does not add to the list of urls. + */ + private final Vector urlinfos = new Vector(); + + /** Factory used to get the protocol handlers of the URLs */ + private final URLStreamHandlerFactory factory; + + /** + * The security context when created from newInstance() + * or null when created through a normal constructor or when no + * SecurityManager was installed. + */ + private final AccessControlContext securityContext; + + // Helper classes + + /** + * A URLLoader contains all logic to load resources from a + * given base URL. + */ + abstract static 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; + + /** + * 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; + + URLLoader(URLClassLoader classloader, URL baseURL) + { + this(classloader, baseURL, baseURL); + } + + URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL) + { + this.classloader = classloader; + this.baseURL = baseURL; + this.noCertCodeSource = new CodeSource(overrideURL, null); + } + + /** + * Returns a Resource loaded by this + * URLLoader, or null when no + * Resource with the given name exists. + */ + abstract Resource getResource(String s); + + /** + * Returns the Manifest associated with the + * Resources loaded by this URLLoader or + * null there is no such Manifest. + */ + Manifest getManifest() + { + return null; + } + + Vector getClassPath() + { + return null; + } + } + + /** + * 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. + */ + abstract static class Resource + { + final URLLoader loader; + final String name; + + Resource(URLLoader loader, String name) + { + this.loader = loader; + this.name = name; + } + + /** + * Returns the non-null CodeSource associated with + * this resource. + */ + 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. + */ + Certificate[] getCertificates() + { + return null; + } + + /** + * Return a URL that can be used to access this resource. + */ + abstract URL getURL(); + + /** + * Returns the size of this Resource in bytes or + * -1 when unknown. + */ + abstract int getLength(); + + /** + * Returns the non-null InputStream through which + * this resource can be loaded. + */ + abstract InputStream getInputStream() throws IOException; + } + + /** + * A JarURLLoader is a type of URLLoader + * only loading from jar url. + */ + static final class JarURLLoader extends URLLoader + { + final JarFile jarfile; // The jar file for this url + final URL baseJarURL; // Base jar: url for all resources loaded from jar + + Vector classPath; // The "Class-Path" attribute of this Jar's manifest + + public JarURLLoader(URLClassLoader classloader, URL baseURL) + { + super(classloader, baseURL); + + // Cache url prefix for all resources in this jar url. + String external = baseURL.toExternalForm(); + StringBuffer sb = new StringBuffer(external.length() + 6); + sb.append("jar:"); + sb.append(external); + sb.append("!/"); + String jarURL = sb.toString(); + + this.classPath = null; + URL baseJarURL = null; + JarFile jarfile = null; + try + { + baseJarURL = + new URL(null, jarURL, classloader.getURLStreamHandler("jar")); + + jarfile = + ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); + + Manifest manifest; + Attributes attributes; + String classPathString; + + if ((manifest = jarfile.getManifest()) != null + && (attributes = manifest.getMainAttributes()) != null + && ((classPathString + = attributes.getValue(Attributes.Name.CLASS_PATH)) + != null)) + { + this.classPath = new Vector(); + + StringTokenizer st = new StringTokenizer(classPathString, " "); + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + URL url = new URL(baseURL, e); + this.classPath.add(url); + } + catch (java.net.MalformedURLException xx) + { + // Give up + } + } + } + } + catch (IOException ioe) + { + /* ignored */ + } + + this.baseJarURL = baseJarURL; + this.jarfile = jarfile; + } + + /** get resource with the name "name" in the jar url */ + Resource getResource(String name) + { + if (jarfile == null) + return null; + + if (name.startsWith("/")) + name = name.substring(1); + + JarEntry je = jarfile.getJarEntry(name); + if (je != null) + return new JarURLResource(this, name, je); + else + return null; + } + + Manifest getManifest() + { + try + { + return (jarfile == null) ? null : jarfile.getManifest(); + } + catch (IOException ioe) + { + return null; + } + } + + Vector getClassPath() + { + return classPath; + } + } + + static final class JarURLResource extends Resource + { + private final JarEntry entry; + + JarURLResource(JarURLLoader loader, String name, JarEntry entry) + { + super(loader, name); + this.entry = entry; + } + + InputStream getInputStream() throws IOException + { + return ((JarURLLoader) loader).jarfile.getInputStream(entry); + } + + int getLength() + { + return (int) entry.getSize(); + } + + 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(); + } + + URL getURL() + { + try + { + return new URL(((JarURLLoader) loader).baseJarURL, name, + loader.classloader.getURLStreamHandler("jar")); + } + catch (MalformedURLException e) + { + InternalError ie = new InternalError(); + ie.initCause(e); + throw ie; + } + } + } + + /** + * Loader for remote directories. + */ + static final class RemoteURLLoader extends URLLoader + { + private final String protocol; + + RemoteURLLoader(URLClassLoader classloader, URL url) + { + super(classloader, url); + protocol = url.getProtocol(); + } + + /** + * Get a remote resource. + * Returns null if no such resource exists. + */ + Resource getResource(String name) + { + try + { + URL url = + new URL(baseURL, name, classloader.getURLStreamHandler(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; + } + } + } + + /** + * A resource from some remote location. + */ + static final class RemoteResource extends Resource + { + private final URL url; + private final InputStream stream; + private final int length; + + RemoteResource(RemoteURLLoader loader, String name, URL url, + InputStream stream, int length) + { + super(loader, name); + this.url = url; + this.stream = stream; + this.length = length; + } + + InputStream getInputStream() throws IOException + { + return stream; + } + + public int getLength() + { + return length; + } + + public URL getURL() + { + return url; + } + } + + /** + * A FileURLLoader is a type of URLLoader + * only loading from file url. + */ + static final class FileURLLoader extends URLLoader + { + File dir; //the file for this file url + + FileURLLoader(URLClassLoader classloader, URL url) + { + super(classloader, url); + dir = new File(baseURL.getFile()); + } + + /** get resource with the name "name" in the file url */ + Resource getResource(String name) + { + File file = new File(dir, name); + if (file.exists() && !file.isDirectory()) + return new FileResource(this, name, file); + return null; + } + } + + static final class FileResource extends Resource + { + final File file; + + FileResource(FileURLLoader loader, String name, File file) + { + super(loader, name); + this.file = file; + } + + InputStream getInputStream() throws IOException + { + return new FileInputStream(file); + } + + public int getLength() + { + return (int) file.length(); + } + + public URL getURL() + { + try + { + return new URL(loader.baseURL, name, + loader.classloader.getURLStreamHandler("file")); + } + catch (MalformedURLException e) + { + InternalError ie = new InternalError(); + ie.initCause(e); + throw ie; + } + } + } + + // Constructors + + /** + * Creates a URLClassLoader that gets classes from the supplied URLs. + * To determine if this classloader may be created the constructor of + * the super class (SecureClassLoader) is called first, which + * can throw a SecurityException. Then the supplied URLs are added + * in the order given to the URLClassLoader which uses these URLs to + * load classes and resources (after using the default parent ClassLoader). + * + * @exception SecurityException if the SecurityManager disallows the + * creation of a ClassLoader. + * @param urls Locations that should be searched by this ClassLoader when + * resolving Classes or Resources. + * @see SecureClassLoader + */ + public URLClassLoader(URL[] urls) throws SecurityException + { + super(); + this.factory = null; + this.securityContext = null; + addURLs(urls); + } + + /** + * Creates a URLClassLoader that gets classes from the supplied + * URLs. + * To determine if this classloader may be created the constructor of + * the super class (SecureClassLoader) is called first, which + * can throw a SecurityException. Then the supplied URLs are added + * in the order given to the URLClassLoader which uses these URLs to + * load classes and resources (after using the supplied parent ClassLoader). + * @exception SecurityException if the SecurityManager disallows the + * creation of a ClassLoader. + * @exception SecurityException + * @param urls Locations that should be searched by this ClassLoader when + * resolving Classes or Resources. + * @param parent The parent class loader used before trying this class + * loader. + * @see SecureClassLoader + */ + public URLClassLoader(URL[] urls, ClassLoader parent) + throws SecurityException + { + super(parent); + this.factory = null; + this.securityContext = null; + addURLs(urls); + } + + // Package-private to avoid a trampoline constructor. + /** + * Package-private constructor used by the static + * newInstance(URL[]) method. Creates an + * URLClassLoader with the given parent but without any + * URLs yet. This is used to bypass the normal security + * check for creating classloaders, but remembers the security + * context which will be used when defining classes. The + * URLs to load from must be added by the + * newInstance() method in the security context of the + * caller. + * + * @param securityContext the security context of the unprivileged code. + */ + URLClassLoader(ClassLoader parent, AccessControlContext securityContext) + { + super(parent); + this.factory = null; + this.securityContext = securityContext; + } + + /** + * Creates a URLClassLoader that gets classes from the supplied URLs. + * To determine if this classloader may be created the constructor of + * the super class (SecureClassLoader) is called first, which + * can throw a SecurityException. Then the supplied URLs are added + * in the order given to the URLClassLoader which uses these URLs to + * load classes and resources (after using the supplied parent ClassLoader). + * It will use the supplied URLStreamHandlerFactory to get the + * protocol handlers of the supplied URLs. + * @exception SecurityException if the SecurityManager disallows the + * creation of a ClassLoader. + * @exception SecurityException + * @param urls Locations that should be searched by this ClassLoader when + * resolving Classes or Resources. + * @param parent The parent class loader used before trying this class + * loader. + * @param factory Used to get the protocol handler for the URLs. + * @see SecureClassLoader + */ + public URLClassLoader(URL[] urls, ClassLoader parent, + URLStreamHandlerFactory factory) + throws SecurityException + { + super(parent); + this.securityContext = null; + this.factory = factory; + addURLs(urls); + + // If this factory is still not in factoryCache, add it, + // since we only support three protocols so far, 5 is enough + // for cache initial size + synchronized (factoryCache) + { + if (factory != null && factoryCache.get(factory) == null) + factoryCache.put(factory, new HashMap(5)); + } + } + + // Methods + + /** + * Adds a new location to the end of the internal URL store. + * @param newUrl the location to add + */ + protected void addURL(URL newUrl) + { + urls.add(newUrl); + addURLImpl(newUrl); + } + + private void addURLImpl(URL newUrl) + { + synchronized (urlloaders) + { + if (newUrl == null) + return; // Silently ignore... + + // Reset the toString() value. + thisString = null; + + // Check global cache to see if there're already url loader + // for this url. + URLLoader loader = (URLLoader) urlloaders.get(newUrl); + if (loader == null) + { + String file = newUrl.getFile(); + String protocol = newUrl.getProtocol(); + + // Check that it is not a directory + if (! (file.endsWith("/") || file.endsWith(File.separator))) + loader = new JarURLLoader(this, newUrl); + else if ("file".equals(protocol)) + loader = new FileURLLoader(this, newUrl); + else + loader = new RemoteURLLoader(this, newUrl); + + // Cache it. + urlloaders.put(newUrl, loader); + } + + urlinfos.add(loader); + + Vector extraUrls = loader.getClassPath(); + if (extraUrls != null) + { + Iterator it = extraUrls.iterator(); + while (it.hasNext()) + { + URL url = (URL)it.next(); + URLLoader extraLoader = (URLLoader) urlloaders.get(url); + if (! urlinfos.contains (extraLoader)) + addURLImpl(url); + } + } + + } + } + + /** + * Adds an array of new locations to the end of the internal URL store. + * @param newUrls the locations to add + */ + private void addURLs(URL[] newUrls) + { + for (int i = 0; i < newUrls.length; i++) + addURL(newUrls[i]); + } + + /** + * Defines a Package based on the given name and the supplied manifest + * information. The manifest indicates the tile, version and + * vendor information of the specification and implementation and wheter the + * package is sealed. If the Manifest indicates that the package is sealed + * then the Package will be sealed with respect to the supplied URL. + * + * @exception IllegalArgumentException If this package name already exists + * in this class loader + * @param name The name of the package + * @param manifest The manifest describing the specification, + * implementation and sealing details of the package + * @param url the code source url to seal the package + * @return the defined Package + */ + protected Package definePackage(String name, Manifest manifest, URL url) + throws IllegalArgumentException + { + Attributes attr = manifest.getMainAttributes(); + String specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); + String specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); + String specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); + String implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); + String implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); + String implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); + + // Look if the Manifest indicates that this package is sealed + // XXX - most likely not completely correct! + // Shouldn't we also check the sealed attribute of the complete jar? + // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled + // But how do we get that jar manifest here? + String sealed = attr.getValue(Attributes.Name.SEALED); + if ("false".equals(sealed)) + // make sure that the URL is null so the package is not sealed + url = null; + + return definePackage(name, specTitle, specVersion, specVendor, implTitle, + implVersion, implVendor, url); + } + + /** + * Finds (the first) class by name from one of the locations. The locations + * are searched in the order they were added to the URLClassLoader. + * + * @param className the classname to find + * @exception ClassNotFoundException when the class could not be found or + * loaded + * @return a Class object representing the found class + */ + protected Class findClass(final String className) + throws ClassNotFoundException + { + // Just try to find the resource by the (almost) same name + String resourceName = className.replace('.', '/') + ".class"; + Resource resource = findURLResource(resourceName); + if (resource == null) + throw new ClassNotFoundException(className + " not found in " + this); + + // Try to read the class data, create the CodeSource, Package and + // construct the class (and watch out for those nasty IOExceptions) + try + { + byte[] data; + InputStream in = resource.getInputStream(); + try + { + int length = resource.getLength(); + if (length != -1) + { + // We know the length of the data. + // Just try to read it in all at once + data = new byte[length]; + int pos = 0; + while (length - pos > 0) + { + int len = in.read(data, pos, length - pos); + if (len == -1) + throw new EOFException("Not enough data reading from: " + + in); + pos += len; + } + } + else + { + // We don't know the data length. + // Have to read it in chunks. + ByteArrayOutputStream out = new ByteArrayOutputStream(4096); + byte[] b = new byte[4096]; + int l = 0; + while (l != -1) + { + l = in.read(b); + if (l != -1) + out.write(b, 0, l); + } + data = out.toByteArray(); + } + } + finally + { + in.close(); + } + final byte[] classData = data; + + // Now get the CodeSource + final CodeSource source = resource.getCodeSource(); + + // Find out package name + String packageName = null; + int lastDot = className.lastIndexOf('.'); + if (lastDot != -1) + packageName = className.substring(0, lastDot); + + if (packageName != null && getPackage(packageName) == null) + { + // define the package + Manifest manifest = resource.loader.getManifest(); + if (manifest == null) + definePackage(packageName, null, null, null, null, null, null, + null); + else + definePackage(packageName, manifest, resource.loader.baseURL); + } + + // And finally construct the class! + SecurityManager sm = System.getSecurityManager(); + Class result = null; + if (sm != null && securityContext != null) + { + result = (Class)AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + return defineClass(className, classData, + 0, classData.length, + source); + } + }, securityContext); + } + else + result = defineClass(className, classData, 0, classData.length, source); + + super.setSigners(result, resource.getCertificates()); + return result; + } + catch (IOException ioe) + { + ClassNotFoundException cnfe; + cnfe = new ClassNotFoundException(className + " not found in " + this); + cnfe.initCause(ioe); + throw cnfe; + } + } + + // Cached String representation of this URLClassLoader + private String thisString; + + /** + * Returns a String representation of this URLClassLoader giving the + * actual Class name, the URLs that are searched and the parent + * ClassLoader. + */ + public String toString() + { + synchronized (urlloaders) + { + if (thisString == null) + { + StringBuffer sb = new StringBuffer(); + sb.append(this.getClass().getName()); + sb.append("{urls=[" ); + URL[] thisURLs = getURLs(); + for (int i = 0; i < thisURLs.length; i++) + { + sb.append(thisURLs[i]); + if (i < thisURLs.length - 1) + sb.append(','); + } + sb.append(']'); + sb.append(", parent="); + sb.append(getParent()); + sb.append('}'); + thisString = sb.toString(); + } + return thisString; + } + } + + /** + * Finds the first occurrence of a resource that can be found. The locations + * are searched in the order they were added to the URLClassLoader. + * + * @param resourceName the resource name to look for + * @return the URLResource for the resource if found, null otherwise + */ + private Resource findURLResource(String resourceName) + { + int max = urlinfos.size(); + for (int i = 0; i < max; i++) + { + URLLoader loader = (URLLoader) urlinfos.elementAt(i); + if (loader == null) + continue; + + Resource resource = loader.getResource(resourceName); + if (resource != null) + return resource; + } + return null; + } + + /** + * Finds the first occurrence of a resource that can be found. + * + * @param resourceName the resource name to look for + * @return the URL if found, null otherwise + */ + public URL findResource(String resourceName) + { + Resource resource = findURLResource(resourceName); + if (resource != null) + return resource.getURL(); + + // Resource not found + return null; + } + + /** + * If the URLStreamHandlerFactory has been set this return the appropriate + * URLStreamHandler for the given protocol, if not set returns null. + * + * @param protocol the protocol for which we need a URLStreamHandler + * @return the appropriate URLStreamHandler or null + */ + URLStreamHandler getURLStreamHandler(String protocol) + { + if (factory == null) + return null; + + URLStreamHandler handler; + synchronized (factoryCache) + { + // Check if there're handler for the same protocol in cache. + HashMap cache = (HashMap) factoryCache.get(factory); + handler = (URLStreamHandler) cache.get(protocol); + if (handler == null) + { + // Add it to cache. + handler = factory.createURLStreamHandler(protocol); + cache.put(protocol, handler); + } + } + return handler; + } + + /** + * Finds all the resources with a particular name from all the locations. + * + * @exception IOException when an error occurs accessing one of the + * locations + * @param resourceName the name of the resource to lookup + * @return a (possible empty) enumeration of URLs where the resource can be + * found + */ + public Enumeration findResources(String resourceName) + throws IOException + { + Vector resources = new Vector(); + int max = urlinfos.size(); + for (int i = 0; i < max; i++) + { + URLLoader loader = (URLLoader) urlinfos.elementAt(i); + Resource resource = loader.getResource(resourceName); + if (resource != null) + resources.add(resource.getURL()); + } + return resources.elements(); + } + + /** + * Returns the permissions needed to access a particular code + * source. These permissions includes those returned by + * SecureClassLoader.getPermissions() and the actual + * permissions to access the objects referenced by the URL of the + * code source. The extra permissions added depend on the protocol + * and file portion of the URL in the code source. If the URL has + * the "file" protocol ends with a '/' character then it must be a + * directory and a file Permission to read everything in that + * directory and all subdirectories is added. If the URL had the + * "file" protocol and doesn't end with a '/' character then it must + * be a normal file and a file permission to read that file is + * added. If the URL has any other protocol then a + * socket permission to connect and accept connections from the host + * portion of the URL is added. + * + * @param source The codesource that needs the permissions to be accessed + * @return the collection of permissions needed to access the code resource + * @see java.security.SecureClassLoader#getPermissions() + */ + protected PermissionCollection getPermissions(CodeSource source) + { + // XXX - This implementation does exactly as the Javadoc describes. + // But maybe we should/could use URLConnection.getPermissions()? + // First get the permissions that would normally be granted + PermissionCollection permissions = super.getPermissions(source); + + // Now add any extra permissions depending on the URL location. + URL url = source.getLocation(); + String protocol = url.getProtocol(); + if (protocol.equals("file")) + { + String file = url.getFile(); + + // If the file end in / it must be an directory. + if (file.endsWith("/") || file.endsWith(File.separator)) + { + // Grant permission to read everything in that directory and + // all subdirectories. + permissions.add(new FilePermission(file + "-", "read")); + } + else + { + // It is a 'normal' file. + // Grant permission to access that file. + permissions.add(new FilePermission(file, "read")); + } + } + else + { + // Grant permission to connect to and accept connections from host + String host = url.getHost(); + if (host != null) + permissions.add(new SocketPermission(host, "connect,accept")); + } + + return permissions; + } + + /** + * Returns all the locations that this class loader currently uses the + * resolve classes and resource. This includes both the initially supplied + * URLs as any URLs added later by the loader. + * @return All the currently used URLs + */ + public URL[] getURLs() + { + return (URL[]) urls.toArray(new URL[urls.size()]); + } + + /** + * Creates a new instance of a URLClassLoader that gets + * classes from the supplied URLs. This class loader + * will have as parent the standard system class loader. + * + * @param urls the initial URLs used to resolve classes and + * resources + * + * @return the class loader + * + * @exception SecurityException when the calling code does not have + * permission to access the given URLs + */ + public static URLClassLoader newInstance(URL[] urls) + throws SecurityException + { + return newInstance(urls, null); + } + + /** + * Creates a new instance of a URLClassLoader that gets + * classes from the supplied URLs and with the supplied + * loader as parent class loader. + * + * @param urls the initial URLs used to resolve classes and + * resources + * @param parent the parent class loader + * + * @return the class loader + * + * @exception SecurityException when the calling code does not have + * permission to access the given URLs + */ + public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent) + throws SecurityException + { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) + return new URLClassLoader(urls, parent); + else + { + final Object securityContext = sm.getSecurityContext(); + + // XXX - What to do with anything else then an AccessControlContext? + if (! (securityContext instanceof AccessControlContext)) + throw new SecurityException("securityContext must be AccessControlContext: " + + securityContext); + + URLClassLoader loader = + (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return new URLClassLoader(parent, + (AccessControlContext) securityContext); + } + }); + loader.addURLs(urls); + return loader; + } + } +} diff --git a/libjava/classpath/java/net/URLConnection.java b/libjava/classpath/java/net/URLConnection.java new file mode 100644 index 0000000..0a12d58 --- /dev/null +++ b/libjava/classpath/java/net/URLConnection.java @@ -0,0 +1,1021 @@ +/* URLConnection.java -- Abstract superclass for reading from URL's + Copyright (C) 1998, 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 java.net; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.AllPermission; +import java.security.Permission; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.Locale; +import java.util.Map; + +/** + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * Status: One guessContentTypeFrom... methods not implemented. + * getContent method assumes content type from response; see comment there. + */ +/** + * This class models a connection that retrieves the information pointed + * to by a URL object. This is typically a connection to a remote node + * on the network, but could be a simple disk read. + *

    + * A URLConnection object is normally created by calling the openConnection() + * method of a URL object. This method is somewhat misnamed because it does + * not actually open the connection. Instead, it return an unconnected + * instance of this object. The caller then has the opportunity to set + * various connection options prior to calling the actual connect() method. + *

    + * After the connection has been opened, there are a number of methods in + * this class that access various attributes of the data, typically + * represented by headers sent in advance of the actual data itself. + *

    + * Also of note are the getInputStream and getContent() methods which allow + * the caller to retrieve the actual data from the connection. Note that + * for some types of connections, writing is also allowed. The setDoOutput() + * method must be called prior to connecing in order to enable this, then + * the getOutputStream method called after the connection in order to + * obtain a stream to write the output to. + *

    + * The getContent() method is of particular note. This method returns an + * Object that encapsulates the data returned. There is no way do determine + * the type of object that will be returned in advance. This is determined + * by the actual content handlers as described in the description of that + * method. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public abstract class URLConnection +{ + /** + * This is an object that maps filenames to MIME types. The interface + * to do this is implemented by this class, so just create an empty + * instance and store it here. + */ + private static FileNameMap fileNameMap; + + /** + * This is the ContentHandlerFactory set by the caller, if any + */ + private static ContentHandlerFactory factory; + + /** + * This is the default value that will be used to determine whether or + * not user interaction should be allowed. + */ + private static boolean defaultAllowUserInteraction; + + /** + * This is the default flag indicating whether or not to use caches to + * store the data returned from a server + */ + private static boolean defaultUseCaches = true; + + /** + * This variable determines whether or not interaction is allowed with + * the user. For example, to prompt for a username and password. + */ + protected boolean allowUserInteraction; + + /** + * Indicates whether or not a connection has been established to the + * destination specified in the URL + */ + protected boolean connected; + + /** + * Indicates whether or not input can be read from this URL + */ + protected boolean doInput = true; + + /** + * Indicates whether or not output can be sent to this URL + */ + protected boolean doOutput; + + /** + * If this flag is set, the protocol is allowed to cache data whenever + * it can (caching is not guaranteed). If it is not set, the protocol + * must a get a fresh copy of the data. + *

    + * This field is set by the setUseCaches method and returned by the + * getUseCaches method. + * + * Its default value is that determined by the last invocation of + * setDefaultUseCaches + */ + protected boolean useCaches; + + /** + * If this value is non-zero, then the connection will only attempt to + * fetch the document pointed to by the URL if the document has been + * modified more recently than the date set in this variable. That date + * should be specified as the number of seconds since 1/1/1970 GMT. + */ + protected long ifModifiedSince; + + /** + * This is the URL associated with this connection + */ + protected URL url; + private static SimpleDateFormat[] dateFormats; + private static boolean dateformats_initialized; + + /* Cached ParsePosition, used when parsing dates. */ + private ParsePosition position; + + /** + * Creates a URL connection to a given URL. A real connection is not made. + * Use #connect to do this. + * + * @param url The Object to create the URL connection to + * + * @see URLConnection#connect() + */ + protected URLConnection(URL url) + { + // Set up all our instance variables + this.url = url; + allowUserInteraction = defaultAllowUserInteraction; + useCaches = defaultUseCaches; + } + + /** + * Establishes the actual connection to the URL associated with this + * connection object + * + * @exception IOException if an error occurs + */ + public abstract void connect() throws IOException; + + /** + * Returns the URL object associated with this connection + * + * @return The URL for this connection. + */ + public URL getURL() + { + return url; + } + + /** + * Returns the value of the content-length header field or -1 if the value + * is not known or not present. + * + * @return The content-length field + */ + public int getContentLength() + { + return getHeaderFieldInt("content-length", -1); + } + + /** + * Returns the the content-type of the data pointed to by the URL. This + * method first tries looking for a content-type header. If that is not + * present, it attempts to use the file name to determine the content's + * MIME type. If that is unsuccessful, the method returns null. The caller + * may then still attempt to determine the MIME type by a call to + * guessContentTypeFromStream() + * + * @return The content MIME type + */ + public String getContentType() + { + return getHeaderField("content-type"); + } + + /** + * Returns the value of the content-encoding field or null if it is not + * known or not present. + * + * @return The content-encoding field + */ + public String getContentEncoding() + { + return getHeaderField("content-encoding"); + } + + /** + * Returns the value of the expires header or 0 if not known or present. + * If populated, the return value is number of seconds since midnight + * on 1/1/1970 GMT. + * + * @return The expiration time. + */ + public long getExpiration() + { + return getHeaderFieldDate("expires", 0L); + } + + /** + * Returns the date of the document pointed to by the URL as reported in + * the date field of the header or 0 if the value is not present or not + * known. If populated, the return value is number of seconds since + * midnight on 1/1/1970 GMT. + * + * @return The document date + */ + public long getDate() + { + return getHeaderFieldDate("date", 0L); + } + + /** + * Returns the value of the last-modified header field or 0 if not known known + * or not present. If populated, the return value is the number of seconds + * since midnight on 1/1/1970. + * + * @return The last modified time + */ + public long getLastModified() + { + return getHeaderFieldDate("last-modified", 0L); + } + + /** + * Return a String representing the header value at the specified index. + * This allows the caller to walk the list of header fields. The analogous + * getHeaderFieldKey(int) method allows access to the corresponding key + * for this header field + * + * @param index The index into the header field list to retrieve the value for + * + * @return The header value or null if index is past the end of the headers + */ + public String getHeaderField(int index) + { + // Subclasses for specific protocols override this. + return null; + } + + /** + * Returns a String representing the value of the header field having + * the named key. Returns null if the header field does not exist. + * + * @param name The key of the header field + * + * @return The value of the header field as a String + */ + public String getHeaderField(String name) + { + // Subclasses for specific protocols override this. + return null; + } + + /** + * Returns a map of all sent header fields + * + * @return all header fields + * + * @since 1.4 + */ + public Map getHeaderFields() + { + // Subclasses for specific protocols override this. + return Collections.EMPTY_MAP; + } + + /** + * Returns the value of the named header field as an int. If the field + * is not present or cannot be parsed as an integer, the default value + * will be returned. + * + * @param name The header field key to lookup + * @param defaultValue The defaule value if the header field is not found + * or can't be parsed. + * + * @return The value of the header field or the default value if the field + * is missing or malformed + */ + public int getHeaderFieldInt(String name, int defaultValue) + { + String value = getHeaderField(name); + + if (value == null) + return defaultValue; + + try + { + return Integer.parseInt(value); + } + catch (NumberFormatException e) + { + return defaultValue; + } + } + + /** + * Returns the value of the named header field as a date. This date will + * be the number of seconds since midnight 1/1/1970 GMT or the default + * value if the field is not present or cannot be converted to a date. + * + * @param name The name of the header field + * @param defaultValue The default date if the header field is not found + * or can't be converted. + * + * @return Returns the date value of the header filed or the default value + * if the field is missing or malformed + */ + public long getHeaderFieldDate(String name, long defaultValue) + { + if (! dateformats_initialized) + initializeDateFormats(); + + if (position == null) + position = new ParsePosition(0); + + long result = defaultValue; + String str = getHeaderField(name); + + if (str != null) + { + for (int i = 0; i < dateFormats.length; i++) + { + SimpleDateFormat df = dateFormats[i]; + position.setIndex(0); + position.setErrorIndex(0); + Date date = df.parse(str, position); + if (date != null) + return date.getTime(); + } + } + + return result; + } + + /** + * Returns a String representing the header key at the specified index. + * This allows the caller to walk the list of header fields. The analogous + * getHeaderField(int) method allows access to the corresponding value for + * this tag. + * + * @param index The index into the header field list to retrieve the key for. + * + * @return The header field key or null if index is past the end + * of the headers. + */ + public String getHeaderFieldKey(int index) + { + // Subclasses for specific protocols override this. + return null; + } + + /** + * This method returns the content of the document pointed to by the + * URL as an Object. The type of object depends on the MIME type of + * the object and particular content hander loaded. Most text type + * content handlers will return a subclass of + * InputStream. Images usually return a class that + * implements ImageProducer. There is not guarantee + * what type of object will be returned, however. + * + *

    This class first determines the MIME type of the content, then + * creates a ContentHandler object to process the input. If the + * ContentHandlerFactory is set, then that object is + * called to load a content handler, otherwise a class called + * gnu.java.net.content.<content_type> is tried. If this + * handler does not exist, the method will simple return the + * InputStream returned by + * getInputStream(). Note that the default + * implementation of getInputStream() throws a + * UnknownServiceException so subclasses are encouraged + * to override this method.

    + * + * @return the content + * + * @exception IOException If an error with the connection occurs. + * @exception UnknownServiceException If the protocol does not support the + * content type at all. + */ + public Object getContent() throws IOException + { + if (!connected) + connect(); + + // FIXME: Doc indicates that other criteria should be applied as + // heuristics to determine the true content type, e.g. see + // guessContentTypeFromName() and guessContentTypeFromStream methods + // as well as FileNameMap class & fileNameMap field & get/set methods. + String type = getContentType(); + ContentHandler ch = getContentHandler(type); + + if (ch != null) + return ch.getContent(this); + + return getInputStream(); + } + + /** + * Retrieves the content of this URLConnection + * + * @param classes The allowed classes for the content + * + * @return the content + * + * @exception IOException If an error occurs + * @exception UnknownServiceException If the protocol does not support the + * content type + */ + public Object getContent(Class[] classes) throws IOException + { + // FIXME: implement this + return getContent(); + } + + /** + * This method returns a Permission object representing the + * permissions required to access this URL. This method returns + * java.security.AllPermission by default. Subclasses should + * override it to return a more specific permission. For example, an + * HTTP URL should return an instance of SocketPermission + * for the appropriate host and port. + *

    + * Note that because of items such as HTTP redirects, the permission + * object returned might be different before and after connecting. + * + * @return A Permission object + * + * @exception IOException If the computation of the permission requires + * network or file I/O and an exception occurs while computing it + */ + public Permission getPermission() throws IOException + { + // Subclasses may override this. + return new AllPermission(); + } + + /** + * Returns an InputStream for this connection. As this default + * implementation returns null, subclasses should override this method + * + * @return An InputStream for this connection + * + * @exception IOException If an error occurs + * @exception UnknownServiceException If the protocol does not support input + */ + public InputStream getInputStream() throws IOException + { + // Subclasses for specific protocols override this. + throw new UnknownServiceException("Protocol " + url.getProtocol() + + " does not support input."); + } + + /** + * Returns an OutputStream for this connection. As this default + * implementation returns null, subclasses should override this method + * + * @return An OutputStream for this connection + * + * @exception IOException If an error occurs + * @exception UnknownServiceException If the protocol does not support output + */ + public OutputStream getOutputStream() throws IOException + { + // Subclasses for specific protocols override this. + throw new UnknownServiceException("Protocol " + url.getProtocol() + + " does not support output."); + } + + /** + * The methods prints the value of this object as a String by calling the + * toString() method of its associated URL. Overrides Object.toString() + * + * @return A String representation of this object + */ + public String toString() + { + return this.getClass().getName() + ":" + url.toString(); + } + + /** + * Returns the value of a flag indicating whether or not input is going + * to be done for this connection. This default to true unless the + * doOutput flag is set to false, in which case this defaults to false. + * + * @param input true if input is to be done, + * false otherwise + * + * @exception IllegalStateException If already connected + */ + public void setDoInput(boolean input) + { + if (connected) + throw new IllegalStateException("Already connected"); + + doInput = input; + } + + /** + * Returns the value of a flag indicating whether or not input is going + * to be done for this connection. This default to true unless the + * doOutput flag is set to false, in which case this defaults to false. + * + * @return true if input is to be done, false otherwise + */ + public boolean getDoInput() + { + return doInput; + } + + /** + * Returns a boolean flag indicating whether or not output will be done + * on this connection. The default value is false, so this method can + * be used to override the default + * + * @param output ture if output is to be done, false otherwise + * + * @exception IllegalStateException If already connected + */ + public void setDoOutput(boolean output) + { + if (connected) + throw new IllegalStateException("Already connected"); + + doOutput = output; + } + + /** + * Returns a boolean flag indicating whether or not output will be done + * on this connection. This defaults to false. + * + * @return true if output is to be done, false otherwise + */ + public boolean getDoOutput() + { + return doOutput; + } + + /** + * Sets a boolean flag indicating whether or not user interaction is + * allowed for this connection. (For example, in order to prompt for + * username and password info. + * + * @param allow true if user interaction should be allowed, false otherwise. + * + * @exception IllegalStateException If already connected + */ + public void setAllowUserInteraction(boolean allow) + { + allowUserInteraction = allow; + } + + /** + * Returns a boolean flag indicating whether or not user interaction is + * allowed for this connection. (For example, in order to prompt for + * username and password info. + * + * @return true if user interaction is allowed, false otherwise + */ + public boolean getAllowUserInteraction() + { + return allowUserInteraction; + } + + /** + * Sets the default flag for whether or not interaction with a user + * is allowed. This will be used for all connections unless overridden + * + * @param allow true to allow user interaction, false otherwise + */ + public static void setDefaultAllowUserInteraction(boolean allow) + { + defaultAllowUserInteraction = allow; + } + + /** + * Returns the default flag for whether or not interaction with a user + * is allowed. This will be used for all connections unless overridden + * + * @return true if user interaction is allowed, false otherwise + */ + public static boolean getDefaultAllowUserInteraction() + { + return defaultAllowUserInteraction; + } + + /** + * Sets a boolean flag indicating whether or not caching will be used + * (if possible) to store data downloaded via the connection. + * + * @param usecaches The new value + * + * @exception IllegalStateException If already connected + */ + public void setUseCaches(boolean usecaches) + { + if (connected) + throw new IllegalStateException("Already connected"); + + useCaches = usecaches; + } + + /** + * Returns a boolean flag indicating whether or not caching will be used + * (if possible) to store data downloaded via the connection. + * + * @return true if caching should be used if possible, false otherwise + */ + public boolean getUseCaches() + { + return useCaches; + } + + /** + * Sets the ifModified since instance variable. If this value is non + * zero and the underlying protocol supports it, the actual document will + * not be fetched unless it has been modified since this time. The value + * passed should be 0 if this feature is to be disabled or the time expressed + * as the number of seconds since midnight 1/1/1970 GMT otherwise. + * + * @param ifmodifiedsince The new value in milliseconds + * since January 1, 1970 GMT + * + * @exception IllegalStateException If already connected + */ + public void setIfModifiedSince(long ifmodifiedsince) + { + if (connected) + throw new IllegalStateException("Already connected"); + + ifModifiedSince = ifmodifiedsince; + } + + /** + * Returns the ifModified since instance variable. If this value is non + * zero and the underlying protocol supports it, the actual document will + * not be fetched unless it has been modified since this time. The value + * returned will be 0 if this feature is disabled or the time expressed + * as the number of seconds since midnight 1/1/1970 GMT otherwise + * + * @return The ifModifiedSince value + */ + public long getIfModifiedSince() + { + return ifModifiedSince; + } + + /** + * Returns the default value used to determine whether or not caching + * of documents will be done when possible. + * + * @return true if caches will be used, false otherwise + */ + public boolean getDefaultUseCaches() + { + return defaultUseCaches; + } + + /** + * Sets the default value used to determine whether or not caching + * of documents will be done when possible. + * + * @param use true to use caches if possible by default, false otherwise + */ + public void setDefaultUseCaches(boolean use) + { + defaultUseCaches = use; + } + + /** + * Sets the value of the named request property + * + * @param key The name of the property + * @param value The value of the property + * + * @exception IllegalStateException If already connected + * @exception NullPointerException If key is null + * + * @see URLConnection#getRequestProperty(String key) + * @see URLConnection#addRequestProperty(String key, String value) + * + * @since 1.4 + */ + public void setRequestProperty(String key, String value) + { + if (connected) + throw new IllegalStateException("Already connected"); + + if (key == null) + throw new NullPointerException("key is null"); + + // Do nothing unless overridden by subclasses that support setting + // header fields in the request. + } + + /** + * Adds a new request property by a key/value pair. + * This method does not overwrite existing properties with the same key. + * + * @param key Key of the property to add + * @param value Value of the Property to add + * + * @exception IllegalStateException If already connected + * @exception NullPointerException If key is null + * + * @see URLConnection#getRequestProperty(String key) + * @see URLConnection#setRequestProperty(String key, String value) + * + * @since 1.4 + */ + public void addRequestProperty(String key, String value) + { + if (connected) + throw new IllegalStateException("Already connected"); + + if (key == null) + throw new NullPointerException("key is null"); + + // Do nothing unless overridden by subclasses that support adding + // header fields in the request. + } + + /** + * Returns the value of the named request property. + * + * @param key The name of the property + * + * @return Value of the property + * + * @exception IllegalStateException If already connected + * + * @see URLConnection#setRequestProperty(String key, String value) + * @see URLConnection#addRequestProperty(String key, String value) + */ + public String getRequestProperty(String key) + { + if (connected) + throw new IllegalStateException("Already connected"); + + // Overridden by subclasses that support reading header fields from the + // request. + return null; + } + + /** + * Returns an unmodifiable Map containing the request properties. + * + * @return The map of properties + * + * @exception IllegalStateException If already connected + * + * @since 1.4 + */ + public Map getRequestProperties() + { + if (connected) + throw new IllegalStateException("Already connected"); + + // Overridden by subclasses that support reading header fields from the + // request. + return Collections.EMPTY_MAP; + } + + /** + * Sets the default value of a request property. This will be used + * for all connections unless the value of the property is manually + * overridden. + * + * @param key The request property name the default is being set for + * @param value The value to set the default to + * + * @deprecated 1.3 The method setRequestProperty should be used instead. + * This method does nothing now. + * + * @see URLConnection#setRequestProperty(String key, String value) + */ + public static void setDefaultRequestProperty(String key, String value) + { + // This method does nothing since JDK 1.3. + } + + /** + * Returns the default value of a request property. This will be used + * for all connections unless the value of the property is manually + * overridden. + * + * @param key The request property to return the default value of + * + * @return The value of the default property or null if not available + * + * @deprecated 1.3 The method getRequestProperty should be used instead. + * This method does nothing now. + * + * @see URLConnection#getRequestProperty(String key) + */ + public static String getDefaultRequestProperty(String key) + { + // This method does nothing since JDK 1.3. + return null; + } + + /** + * Set's the ContentHandlerFactory for an application. This can be called + * once and only once. If it is called again, then an Error is thrown. + * Unlike for other set factory methods, this one does not do a security + * check prior to setting the factory. + * + * @param factory The ContentHandlerFactory for this application + * + * @exception Error If the factory has already been defined + * @exception SecurityException If a security manager exists and its + * checkSetFactory method doesn't allow the operation + */ + public static synchronized void setContentHandlerFactory(ContentHandlerFactory factory) + { + if (URLConnection.factory != null) + throw new Error("ContentHandlerFactory already set"); + + // Throw an exception if an extant security mgr precludes + // setting the factory. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkSetFactory(); + + URLConnection.factory = factory; + } + + /** + * Returns the MIME type of a file based on the name of the file. This + * works by searching for the file's extension in a list of file extensions + * and returning the MIME type associated with it. If no type is found, + * then a MIME type of "application/octet-stream" will be returned. + * + * @param filename The filename to determine the MIME type for + * + * @return The MIME type String + * + * @specnote public since JDK 1.4 + */ + public static String guessContentTypeFromName(String filename) + { + return getFileNameMap().getContentTypeFor(filename.toLowerCase()); + } + + /** + * Returns the MIME type of a stream based on the first few characters + * at the beginning of the stream. This routine can be used to determine + * the MIME type if a server is believed to be returning an incorrect + * MIME type. This method returns "application/octet-stream" if it + * cannot determine the MIME type. + *

    + * NOTE: Overriding MIME types sent from the server can be obnoxious + * to user's. See Internet Exploder 4 if you don't believe me. + * + * @param is The InputStream to determine the MIME type from + * + * @return The MIME type + * + * @exception IOException If an error occurs + */ + public static String guessContentTypeFromStream(InputStream is) + throws IOException + { + return "application/octet-stream"; + } + + /** + * This method returns the FileNameMap object being used + * to decode MIME types by file extension. + * + * @return The FileNameMap. + * + * @since 1.2 + */ + public static synchronized FileNameMap getFileNameMap() + { + // Delayed initialization. + if (fileNameMap == null) + fileNameMap = new MimeTypeMapper(); + + return fileNameMap; + } + + /** + * This method set the FileNameMap object being used + * to decode MIME types by file extension. + * + * @param map The FileNameMap. + * + * @exception SecurityException If a security manager exists and its + * checkSetFactory method doesn't allow the operation + * + * @since 1.2 + */ + public static synchronized void setFileNameMap(FileNameMap map) + { + // Throw an exception if an extant security manager precludes + // setting the factory. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkSetFactory(); + + fileNameMap = map; + } + + private ContentHandler getContentHandler(String contentType) + { + // No content type so just handle it as the default. + if (contentType == null || contentType.equals("")) + return null; + + ContentHandler handler = null; + + // If a non-default factory has been set, use it. + if (factory != null) + handler = factory.createContentHandler(contentType); + + // Then try our default class. + try + { + String typeClass = contentType.replace('/', '.'); + + // Deal with "Content-Type: text/html; charset=ISO-8859-1". + int parameterBegin = typeClass.indexOf(';'); + if (parameterBegin >= 1) + typeClass = typeClass.substring(0, parameterBegin); + + Class cls = Class.forName("gnu.java.net.content." + typeClass); + Object obj = cls.newInstance(); + + if (obj instanceof ContentHandler) + { + handler = (ContentHandler) obj; + return handler; + } + } + catch (ClassNotFoundException e) + { + // Ignore. + } + catch (InstantiationException e) + { + // Ignore. + } + catch (IllegalAccessException e) + { + // Ignore. + } + + return handler; + } + + // We don't put these in a static initializer, because it creates problems + // with initializer co-dependency: SimpleDateFormat's constructors eventually + // depend on URLConnection (via the java.text.*Symbols classes). + private static synchronized void initializeDateFormats() + { + if (dateformats_initialized) + return; + + Locale locale = new Locale("En", "Us", "Unix"); + dateFormats = new SimpleDateFormat[3]; + dateFormats[0] = + new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'", locale); + dateFormats[1] = + new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'", locale); + dateFormats[2] = new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale); + dateformats_initialized = true; + } +} diff --git a/libjava/classpath/java/net/URLDecoder.java b/libjava/classpath/java/net/URLDecoder.java new file mode 100644 index 0000000..ca40c38 --- /dev/null +++ b/libjava/classpath/java/net/URLDecoder.java @@ -0,0 +1,180 @@ +/* URLDecoder.java -- Class to decode URL's from encoded form. + Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.net; + +import java.io.UnsupportedEncodingException; + + +/** + * This utility class contains static methods that converts a + * string encoded in the x-www-form-urlencoded format to the original + * text. The x-www-form-urlencoded format replaces certain disallowed + * characters with encoded equivalents. All upper case and lower case + * letters in the US alphabet remain as is, the space character (' ') + * is replaced with '+' sign, and all other characters are converted to a + * "%XX" format where XX is the hexadecimal representation of that character + * in a given character encoding (default is "UTF-8"). + *

    + * This method is very useful for decoding strings sent to CGI scripts + * + * Written using on-line Java Platform 1.2/1.4 API Specification. + * Status: Believed complete and correct. + * + * @since 1.2 + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) (documentation comments) + * @author Mark Wielaard (mark@klomp.org) + */ +public class URLDecoder +{ + /** + * Public contructor. Note that this class has only static methods. + */ + public URLDecoder() + { + } + + /** + * This method translates the passed in string from x-www-form-urlencoded + * format using the default encoding "UTF-8" to decode the hex encoded + * unsafe characters. + * + * @param s the String to convert + * + * @return the converted String + * + * @deprecated + */ + public static String decode(String s) + { + try + { + return decode(s, "UTF-8"); + } + catch (UnsupportedEncodingException uee) + { + // Should never happen since UTF-8 encoding should always be supported + return s; + } + } + + /** + * This method translates the passed in string from x-www-form-urlencoded + * format using the given character encoding to decode the hex encoded + * unsafe characters. + * + * This implementation will decode the string even if it contains + * unsafe characters (characters that should have been encoded) or if the + * two characters following a % do not represent a hex encoded byte. + * In those cases the unsafe character or the % character will be added + * verbatim to the decoded result. + * + * @param s the String to convert + * @param encoding the character encoding to use the decode the hex encoded + * unsafe characters + * + * @return the converted String + * + * @exception UnsupportedEncodingException If the named encoding is not + * supported + * + * @since 1.4 + */ + public static String decode(String s, String encoding) + throws UnsupportedEncodingException + { + // First convert all '+' characters to spaces. + String str = s.replace('+', ' '); + + // Then go through the whole string looking for byte encoded characters + int i; + int start = 0; + byte[] bytes = null; + int length = str.length(); + StringBuffer result = new StringBuffer(length); + while ((i = str.indexOf('%', start)) >= 0) + { + // Add all non-encoded characters to the result buffer + result.append(str.substring(start, i)); + start = i; + + // Get all consecutive encoded bytes + while ((i + 2 < length) && (str.charAt(i) == '%')) + i += 3; + + // Decode all these bytes + if ((bytes == null) || (bytes.length < ((i - start) / 3))) + bytes = new byte[((i - start) / 3)]; + + int index = 0; + try + { + while (start < i) + { + String sub = str.substring(start + 1, start + 3); + bytes[index] = (byte) Integer.parseInt(sub, 16); + index++; + start += 3; + } + } + catch (NumberFormatException nfe) + { + // One of the hex encoded strings was bad + } + + // Add the bytes as characters according to the given encoding + result.append(new String(bytes, 0, index, encoding)); + + // Make sure we skip to just after a % sign + // There might not have been enough encoded characters after the % + // or the hex chars were not actually hex chars (NumberFormatException) + if (start < length && s.charAt(start) == '%') + { + result.append('%'); + start++; + } + } + + // Add any characters left + if (start < str.length()) + result.append(str.substring(start)); + + return result.toString(); + } +} // class URLDecoder diff --git a/libjava/classpath/java/net/URLEncoder.java b/libjava/classpath/java/net/URLEncoder.java new file mode 100644 index 0000000..dacc384 --- /dev/null +++ b/libjava/classpath/java/net/URLEncoder.java @@ -0,0 +1,184 @@ +/* URLEncoder.java -- Class to convert strings to a properly encoded URL + Copyright (C) 1998, 1999, 2001, 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 java.net; + +import java.io.UnsupportedEncodingException; + + +/* + * Written using on-line Java Platform 1.2/1.4 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * Status: Believed complete and correct. + */ + +/** + * This utility class contains static methods that converts a + * string into a fully encoded URL string in x-www-form-urlencoded + * format. This format replaces certain disallowed characters with + * encoded equivalents. All upper case and lower case letters in the + * US alphabet remain as is, the space character (' ') is replaced with + * '+' sign, and all other characters are converted to a "%XX" format + * where XX is the hexadecimal representation of that character in a + * certain encoding (by default, the platform encoding, though the + * standard is "UTF-8"). + *

    + * This method is very useful for encoding strings to be sent to CGI scripts + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @author Mark Wielaard (mark@klomp.org) + */ +public class URLEncoder +{ + /** + * This method translates the passed in string into x-www-form-urlencoded + * format using the default encoding. The standard encoding is + * "UTF-8", and the two-argument form of this method should be used + * instead. + * + * @param s The String to convert + * + * @return The converted String + * + * @deprecated + */ + public static String encode(String s) + { + try + { + // We default to 8859_1 for compatibility with the same + // default elsewhere in the library. + return encode(s, System.getProperty("file.encoding", "8859_1")); + } + catch (UnsupportedEncodingException uee) + { + // Should never happen since default should always be supported + return s; + } + } + + /** + * This method translates the passed in string into x-www-form-urlencoded + * format using the character encoding to hex-encode the unsafe characters. + * + * @param s The String to convert + * @param encoding The encoding to use for unsafe characters + * + * @return The converted String + * + * @exception UnsupportedEncodingException If the named encoding is not + * supported + * + * @since 1.4 + */ + public static String encode(String s, String encoding) + throws UnsupportedEncodingException + { + int length = s.length(); + int start = 0; + int i = 0; + + StringBuffer result = new StringBuffer(length); + while (true) + { + while (i < length && isSafe(s.charAt(i))) + i++; + + // Safe character can just be added + result.append(s.substring(start, i)); + + // Are we done? + if (i >= length) + return result.toString(); + else if (s.charAt(i) == ' ') + { + result.append('+'); // Replace space char with plus symbol. + i++; + } + else + { + // Get all unsafe characters + start = i; + char c; + while (i < length && (c = s.charAt(i)) != ' ' && ! isSafe(c)) + i++; + + // Convert them to %XY encoded strings + String unsafe = s.substring(start, i); + byte[] bytes = unsafe.getBytes(encoding); + for (int j = 0; j < bytes.length; j++) + { + result.append('%'); + int val = bytes[j]; + result.append(hex.charAt((val & 0xf0) >> 4)); + result.append(hex.charAt(val & 0x0f)); + } + } + start = i; + } + } + + /** + * Private static method that returns true if the given char is either + * a uppercase or lowercase letter from 'a' till 'z', or a digit froim + * '0' till '9', or one of the characters '-', '_', '.' or '*'. Such + * 'safe' character don't have to be url encoded. + */ + private static boolean isSafe(char c) + { + return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' + || c == '*'); + } + + /** + * Private constructor that does nothing. Included to avoid a default + * public constructor being created by the compiler. + */ + private URLEncoder() + { + } + + /** + * Used to convert to hex. We don't use Integer.toHexString, since + * it converts to lower case (and the Sun docs pretty clearly + * specify upper case here), and because it doesn't provide a + * leading 0. + */ + private static final String hex = "0123456789ABCDEF"; +} diff --git a/libjava/classpath/java/net/URLStreamHandler.java b/libjava/classpath/java/net/URLStreamHandler.java new file mode 100644 index 0000000..57ce2df --- /dev/null +++ b/libjava/classpath/java/net/URLStreamHandler.java @@ -0,0 +1,532 @@ +/* URLStreamHandler.java -- Abstract superclass for all protocol handlers + Copyright (C) 1998, 1999, 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 java.net; + +import java.io.File; +import java.io.IOException; + + +/* + * 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 class is the superclass of all URL protocol handlers. The URL + * class loads the appropriate protocol handler to establish a connection + * to a (possibly) remote service (eg, "http", "ftp") and to do protocol + * specific parsing of URL's. Refer to the URL class documentation for + * details on how that class locates and loads protocol handlers. + *

    + * A protocol handler implementation should override the openConnection() + * method, and optionally override the parseURL() and toExternalForm() + * methods if necessary. (The default implementations will parse/write all + * URL's in the same form as http URL's). A protocol specific subclass + * of URLConnection will most likely need to be created as well. + *

    + * Note that the instance methods in this class are called as if they + * were static methods. That is, a URL object to act on is passed with + * every call rather than the caller assuming the URL is stored in an + * instance variable of the "this" object. + *

    + * The methods in this class are protected and accessible only to subclasses. + * URLStreamConnection objects are intended for use by the URL class only, + * not by other classes (unless those classes are implementing protocols). + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * + * @see URL + */ +public abstract class URLStreamHandler +{ + /** + * Creates a URLStreamHander + */ + public URLStreamHandler() + { + } + + /** + * Returns a URLConnection for the passed in URL. Note that this should + * not actually create the connection to the (possibly) remote host, but + * rather simply return a URLConnection object. The connect() method of + * URL connection is used to establish the actual connection, possibly + * after the caller sets up various connection options. + * + * @param url The URL to get a connection object for + * + * @return A URLConnection object for the given URL + * + * @exception IOException If an error occurs + */ + protected abstract URLConnection openConnection(URL url) + throws IOException; + + /** + * This method parses the string passed in as a URL and set's the + * instance data fields in the URL object passed in to the various values + * parsed out of the string. The start parameter is the position to start + * scanning the string. This is usually the position after the ":" which + * terminates the protocol name. The end parameter is the position to + * stop scanning. This will be either the end of the String, or the + * position of the "#" character, which separates the "file" portion of + * the URL from the "anchor" portion. + *

    + * This method assumes URL's are formatted like http protocol URL's, so + * subclasses that implement protocols with URL's the follow a different + * syntax should override this method. The lone exception is that if + * the protocol name set in the URL is "file", this method will accept + * an empty hostname (i.e., "file:///"), which is legal for that protocol + * + * @param url The URL object in which to store the results + * @param spec 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 spec, int start, int end) + { + String host = url.getHost(); + int port = url.getPort(); + String file = url.getFile(); + String ref = url.getRef(); + String userInfo = url.getUserInfo(); + String authority = url.getAuthority(); + String query = null; + + // On Windows we need to change \ to / for file URLs + char separator = File.separatorChar; + if (url.getProtocol().equals("file") && separator != '/') + { + file = file.replace(separator, '/'); + spec = spec.replace(separator, '/'); + } + + if (spec.regionMatches(start, "//", 0, 2)) + { + String genuineHost; + int hostEnd; + int colon; + int at_host; + + start += 2; + int slash = spec.indexOf('/', start); + if (slash >= 0) + hostEnd = slash; + else + hostEnd = end; + + authority = host = spec.substring(start, hostEnd); + + // We first need a genuine host name (with userinfo). + // So we check for '@': if it's present check the port in the + // section after '@' in the other case check it in the full string. + // P.S.: We don't care having '@' at the beginning of the string. + if ((at_host = host.indexOf('@')) >= 0) + { + genuineHost = host.substring(at_host); + userInfo = host.substring(0, at_host); + } + else + genuineHost = host; + + // Look for optional port number. It is valid for the non-port + // part of the host name to be null (e.g. a URL "http://:80"). + // TBD: JDK 1.2 in this case sets host to null rather than ""; + // this is undocumented and likely an unintended side effect in 1.2 + // so we'll be simple here and stick with "". Note that + // "http://" or "http:///" produce a "" host in JDK 1.2. + if ((colon = genuineHost.indexOf(':')) >= 0) + { + try + { + port = Integer.parseInt(genuineHost.substring(colon + 1)); + } + catch (NumberFormatException e) + { + // Ignore invalid port values; port is already set to u's + // port. + } + + // Now we must cut the port number in the original string. + if (at_host >= 0) + host = host.substring(0, at_host + colon); + else + host = host.substring(0, colon); + } + file = null; + start = hostEnd; + } + else if (host == null) + host = ""; + + if (file == null || file.length() == 0 + || (start < end && spec.charAt(start) == '/')) + { + // No file context available; just spec for file. + // Or this is an absolute path name; ignore any file context. + file = spec.substring(start, end); + ref = null; + } + else if (start < end) + { + // Context is available, but only override it if there is a new file. + int lastSlash = file.lastIndexOf('/'); + if (lastSlash < 0) + file = spec.substring(start, end); + else + file = (file.substring(0, lastSlash) + + '/' + spec.substring(start, end)); + + // For URLs constructed relative to a context, we + // need to canonicalise the file path. + file = canonicalizeFilename(file); + + ref = null; + } + + if (ref == null) + { + // Normally there should be no '#' in the file part, + // but we are nice. + int hash = file.indexOf('#'); + if (hash != -1) + { + ref = file.substring(hash + 1, file.length()); + file = file.substring(0, hash); + } + } + + // We care about the query tag only if there is no reference at all. + if (ref == null) + { + int queryTag = file.indexOf('?'); + if (queryTag != -1) + { + query = file.substring(queryTag + 1); + file = file.substring(0, queryTag); + } + } + + // XXX - Classpath used to call PlatformHelper.toCanonicalForm() on + // the file part. It seems like overhead, but supposedly there is some + // benefit in windows based systems (it also lowercased the string). + setURL(url, url.getProtocol(), host, port, authority, userInfo, file, query, ref); + } + + /* + * Canonicalize a filename. + */ + private static String canonicalizeFilename(String file) + { + // XXX - GNU Classpath has an implementation that might be more appropriate + // for Windows based systems (gnu.java.io.PlatformHelper.toCanonicalForm) + int index; + + // Replace "/./" with "/". This probably isn't very efficient in + // the general case, but it's probably not bad most of the time. + while ((index = file.indexOf("/./")) >= 0) + file = file.substring(0, index) + file.substring(index + 2); + + // Process "/../" correctly. This probably isn't very efficient in + // the general case, but it's probably not bad most of the time. + while ((index = file.indexOf("/../")) >= 0) + { + // Strip of the previous directory - if it exists. + int previous = file.lastIndexOf('/', index - 1); + if (previous >= 0) + file = file.substring(0, previous) + file.substring(index + 3); + else + break; + } + return file; + } + + /** + * Compares two URLs, excluding the fragment component + * + * @param url1 The first url + * @param url2 The second url to compare with the first + * + * @return True if both URLs point to the same file, false otherwise. + * + * @specnote Now protected + */ + protected boolean sameFile(URL url1, URL url2) + { + if (url1 == url2) + return true; + + // This comparison is very conservative. It assumes that any + // field can be null. + if (url1 == null || url2 == null) + return false; + int p1 = url1.getPort(); + if (p1 == -1) + p1 = url1.ph.getDefaultPort(); + int p2 = url2.getPort(); + if (p2 == -1) + p2 = url2.ph.getDefaultPort(); + if (p1 != p2) + return false; + String s1; + String s2; + s1 = url1.getProtocol(); + s2 = url2.getProtocol(); + if (s1 != s2 && (s1 == null || ! s1.equals(s2))) + return false; + s1 = url1.getHost(); + s2 = url2.getHost(); + if (s1 != s2 && (s1 == null || ! s1.equals(s2))) + return false; + s1 = canonicalizeFilename(url1.getFile()); + s2 = canonicalizeFilename(url2.getFile()); + if (s1 != s2 && (s1 == null || ! s1.equals(s2))) + return false; + return true; + } + + /** + * This methods sets the instance variables representing the various fields + * of the URL to the values passed in. + * + * @param u The URL to modify + * @param protocol The protocol to set + * @param host The host name to et + * @param port The port number to set + * @param file The filename to set + * @param ref The reference + * + * @exception SecurityException If the protocol handler of the URL is + * different from this one + * + * @deprecated 1.2 Please use + * #setURL(URL,String,String,int,String,String,String,String); + */ + protected void setURL(URL u, String protocol, String host, int port, + String file, String ref) + { + u.set(protocol, host, port, file, ref); + } + + /** + * Sets the fields of the URL argument to the indicated values + * + * @param u The URL to modify + * @param protocol The protocol to set + * @param host The host name to set + * @param port The port number to set + * @param authority The authority to set + * @param userInfo The user information to set + * @param path The path/filename to set + * @param query The query part to set + * @param ref The reference + * + * @exception SecurityException If the protocol handler of the URL is + * different from this one + */ + protected void setURL(URL u, String protocol, String host, int port, + String authority, String userInfo, String path, + String query, String ref) + { + u.set(protocol, host, port, authority, userInfo, path, query, ref); + } + + /** + * Provides the default equals calculation. May be overidden by handlers for + * other protocols that have different requirements for equals(). This method + * requires that none of its arguments is null. This is guaranteed by the + * fact that it is only called by java.net.URL class. + * + * @param url1 An URL object + * @param url2 An URL object + * + * @return True if both given URLs are equal, false otherwise. + */ + protected boolean equals(URL url1, URL url2) + { + // This comparison is very conservative. It assumes that any + // field can be null. + return (url1.getPort() == url2.getPort() + && ((url1.getProtocol() == null && url2.getProtocol() == null) + || (url1.getProtocol() != null + && url1.getProtocol().equals(url2.getProtocol()))) + && ((url1.getUserInfo() == null && url2.getUserInfo() == null) + || (url1.getUserInfo() != null + && url1.getUserInfo().equals(url2.getUserInfo()))) + && ((url1.getAuthority() == null && url2.getAuthority() == null) + || (url1.getAuthority() != null + && url1.getAuthority().equals(url2.getAuthority()))) + && ((url1.getHost() == null && url2.getHost() == null) + || (url1.getHost() != null && url1.getHost().equals(url2.getHost()))) + && ((url1.getPath() == null && url2.getPath() == null) + || (url1.getPath() != null && url1.getPath().equals(url2.getPath()))) + && ((url1.getQuery() == null && url2.getQuery() == null) + || (url1.getQuery() != null + && url1.getQuery().equals(url2.getQuery()))) + && ((url1.getRef() == null && url2.getRef() == null) + || (url1.getRef() != null && url1.getRef().equals(url2.getRef())))); + } + + /** + * Compares the host components of two URLs. + * + * @param url1 The first URL. + * @param url2 The second URL. + * + * @return True if both URLs contain the same host. + * + * @exception UnknownHostException If an unknown host is found + */ + protected boolean hostsEqual(URL url1, URL url2) + { + InetAddress addr1 = getHostAddress(url1); + InetAddress addr2 = getHostAddress(url2); + + if (addr1 != null && addr2 != null) + return addr1.equals(addr2); + + String host1 = url1.getHost(); + String host2 = url2.getHost(); + + if (host1 != null && host2 != null) + return host1.equalsIgnoreCase(host2); + + return host1 == null && host2 == null; + } + + /** + * Get the IP address of our host. An empty host field or a DNS failure will + * result in a null return. + * + * @param url The URL to return the host address for. + * + * @return The address of the hostname in url. + */ + protected InetAddress getHostAddress(URL url) + { + String hostname = url.getHost(); + + if (hostname.equals("")) + return null; + + try + { + return InetAddress.getByName(hostname); + } + catch (UnknownHostException e) + { + return null; + } + } + + /** + * Returns the default port for a URL parsed by this handler. This method is + * meant to be overidden by handlers with default port numbers. + * + * @return The default port number. + */ + protected int getDefaultPort() + { + return -1; + } + + /** + * Provides the default hash calculation. May be overidden by handlers for + * other protocols that have different requirements for hashCode calculation. + * + * @param url The URL to calc the hashcode for. + * + * @return The hashcode for the given URL. + */ + protected int hashCode(URL url) + { + return url.getProtocol().hashCode() + + ((url.getHost() == null) ? 0 : url.getHost().hashCode()) + + url.getFile().hashCode() + url.getPort(); + } + + /** + * This method converts a URL object into a String. This method creates + * Strings in the mold of http URL's, so protocol handlers which use URL's + * that have a different syntax should override this method + * + * @param url The URL object to convert + * + * @return A string representation of the url + */ + protected String toExternalForm(URL url) + { + String protocol; + String file; + String ref; + String authority; + + protocol = url.getProtocol(); + authority = url.getAuthority(); + if (authority == null) + authority = ""; + + file = url.getFile(); + ref = url.getRef(); + + // Guess a reasonable size for the string buffer so we have to resize + // at most once. + int size = protocol.length() + authority.length() + file.length() + 24; + StringBuffer sb = new StringBuffer(size); + + if (protocol != null && protocol.length() > 0) + { + sb.append(protocol); + sb.append(":"); + } + + if (authority.length() != 0) + { + sb.append("//").append(authority); + } + + sb.append(file); + + if (ref != null) + sb.append('#').append(ref); + + return sb.toString(); + } +} diff --git a/libjava/classpath/java/net/URLStreamHandlerFactory.java b/libjava/classpath/java/net/URLStreamHandlerFactory.java new file mode 100644 index 0000000..c92c71f --- /dev/null +++ b/libjava/classpath/java/net/URLStreamHandlerFactory.java @@ -0,0 +1,65 @@ +/* URLStreamHandlerFactory.java -- Maps protocols to URLStreamHandlers + Copyright (C) 1998, 1999, 2000, 2001, 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 java.net; + + +/** + * 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 interface contains one method which maps the protocol portion of + * a URL (eg, "http" in "http://www.urbanophile.com/arenn/") to a + * URLStreamHandler object. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public interface URLStreamHandlerFactory +{ + /** + * This method maps the protocol portion of a URL to a + * URLStreamHandler object. + * + * @param protocol The protocol name to map ("http", "ftp", etc). + * + * @return The URLStreamHandler for the specified protocol + */ + URLStreamHandler createURLStreamHandler(String protocol); +} // interface URLStreamHandlerFactory diff --git a/libjava/classpath/java/net/UnknownHostException.java b/libjava/classpath/java/net/UnknownHostException.java new file mode 100644 index 0000000..c5ba183 --- /dev/null +++ b/libjava/classpath/java/net/UnknownHostException.java @@ -0,0 +1,77 @@ +/* UnknownHostException.java -- The hostname is unknown + Copyright (C) 1998, 1999, 2000, 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 java.net; + +import java.io.IOException; + + +/** + * This exception indicates that an attempt was made to reference a hostname + * or IP address that is not valid. This could possibly indicate that a + * DNS problem has occurred, but most often means that the host was not + * correctly specified. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner + * @status updated to 1.4 + */ +public class UnknownHostException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4639126076052875403L; + + /** + * Create a new instance without a descriptive error message. + */ + public UnknownHostException() + { + } + + /** + * Create a new instance with a descriptive error message, such as the + * name of the host that could not be resolved. + * + * @param message a message describing the error that occurred + */ + public UnknownHostException(String message) + { + super(message); + } +} // class UnknownHostException diff --git a/libjava/classpath/java/net/UnknownServiceException.java b/libjava/classpath/java/net/UnknownServiceException.java new file mode 100644 index 0000000..65cc8f5 --- /dev/null +++ b/libjava/classpath/java/net/UnknownServiceException.java @@ -0,0 +1,76 @@ +/* UnknownServiceException.java -- A service error occurred + Copyright (C) 1998, 1999, 2000, 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 java.net; + +import java.io.IOException; + + +/** + * Contrary to what you might think, this does not indicate that the + * TCP/IP service name specified was invalid. Instead it indicates that + * the MIME type returned from a URL could not be determined or that an + * attempt was made to write to a read-only URL. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class UnknownServiceException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4169033248853639508L; + + /** + * Create a new instance without a descriptive error message. + */ + public UnknownServiceException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message a message describing the error that occurred + */ + public UnknownServiceException(String message) + { + super(message); + } +} // class UnknownServiceException diff --git a/libjava/classpath/java/net/class-dependencies.conf b/libjava/classpath/java/net/class-dependencies.conf new file mode 100644 index 0000000..8b130f5 --- /dev/null +++ b/libjava/classpath/java/net/class-dependencies.conf @@ -0,0 +1,122 @@ +# This property file contains dependencies of classes, methods, and +# field on other methods or classes. +# +# Syntax: +# +# : [... ] +# +# means that when is included, (... ) must +# be included as well. +# +# and are of the form +# +# +# +# or just +# +# +# +# Within dependencies, variables can be used. A variable is defined as +# follows: +# +# {variable}: value1 value2 ... value +# +# variables can be used on the right side of dependencies as follows: +# +# : com.bla.blu.{variable}.Class.m()V +# +# The use of the variable will expand to dependencies of the form +# +# : com.bla.blu.value1.Class.m()V +# : com.bla.blu.value2.Class.m()V +# ... +# : com.bla.blu.value.Class.m()V +# +# Variables can be redefined when building a system to select the +# required support for features like encodings, protocols, etc. +# +# Hints: +# +# - For methods and fields, the signature is mandatory. For +# specification, please see the Java Virtual Machine Specification by +# SUN. Unlike in the spec, field signatures (types) are in brackets. +# +# - Package names must be separated by '/' (and not '.'). E.g., +# java/lang/Class (this is necessary, because the '.' is used to +# separate method or field names from classes) +# +# - In case refers to a class, only the class itself will be +# included in the resulting binary, NOT necessarily all its methods +# and fields. If you want to refer to all methods and fields, you can +# write class.* as an abbreviation. +# +# - Abbreviations for packages are also possible: my/package/* means all +# methods and fields of all classes in my/package. +# +# - A line with a trailing '\' continues in the next line. + +java/net/InetAddress: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/net/UnknownHostException.(Ljava/lang/String;)V + +java/net/DatagramSocketImpl: \ + java/net/DatagramSocketImpl.fd(Ljava/io/FileDescriptor;) \ + java/net/DatagramSocketImpl.localPort(I) + +java/net/PlainDatagramSocketImpl: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/io/IOException.(Ljava/lang/String;)V \ + java/io/FileDescriptor.()V \ + java/lang/Boolean.(Z)V \ + java/lang/Integer.(I)V \ + java/net/InetAddress.getByName(Ljava/lang/String;)Ljava/net/InetAddress; \ + java/net/InetAddress.getAddress()[B \ + java/lang/Boolean.booleanValue()Z \ + java/lang/Integer.intValue()I \ + java/net/SocketException.(Ljava/lang/String;)V \ + java/net/DatagramPacket.getData()[B \ + java/net/SocketImpl.address(Ljava/net/InetAddress;) \ + java/net/PlainSocketImpl.native_fd(I) \ + java/net/SocketImpl.fd(Ljava/io/FileDescriptor;) \ + java/net/SocketImpl.address(Ljava/net/InetAddress;) \ + java/net/PlainDatagramSocketImpl.native_fd(I) \ + java/net/SocketImpl.localport(I) \ + java/net/SocketImpl.port(I) + +java/net/PlainSocketImpl: \ + java/lang/ClassNotFoundException.(Ljava/lang/String;)V \ + java/lang/InternalError.(Ljava/lang/String;)V \ + java/io/IOException.(Ljava/lang/String;)V \ + java/io/FileDescriptor.()V \ + java/lang/Boolean.(Z)V \ + java/lang/Integer.(I)V \ + java/net/InetAddress.getByName(Ljava/lang/String;)Ljava/net/InetAddress; \ + java/net/InetAddress.getAddress()[B \ + java/lang/Boolean.booleanValue()Z \ + java/lang/Integer.intValue()I \ + java/net/SocketException.(Ljava/lang/String;)V \ + java/net/DatagramPacket.getData()[B \ + java/net/SocketImpl.address(Ljava/net/InetAddress;) \ + java/net/PlainSocketImpl.native_fd(I) \ + java/net/SocketImpl.fd(Ljava/io/FileDescriptor;) \ + java/net/SocketImpl.address(Ljava/net/InetAddress;) \ + java/net/PlainDatagramSocketImpl.native_fd(I) \ + java/net/SocketImpl.localport(I) \ + java/net/SocketImpl.port(I) + +# All protocols supported are loaded via URL.getURLStreamHandler from +# class gnu.java.net.protocol..Handler. +# +# This introduces a dependency for all protocols. To allow an easy selection +# and addition of protocols, the library variable {protocols} can be set to +# the set of supported protocols. +# +{protocols}: http file jar + +java/net/URL.getURLStreamHandler(Ljava/lang/String;)Ljava/net/URLStreamHandler;: \ + gnu/java/net/protocol/{protocols}/Handler.* \ + com/aicas/java/net/protocol/rom/Handler.* + +# end of file diff --git a/libjava/classpath/java/net/package.html b/libjava/classpath/java/net/package.html new file mode 100644 index 0000000..133ee71 --- /dev/null +++ b/libjava/classpath/java/net/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.net + + +

    Network communication through TCP and UDP sockets or URLs.

    + + + diff --git a/libjava/classpath/java/nio/Buffer.java b/libjava/classpath/java/nio/Buffer.java new file mode 100644 index 0000000..47dabf2 --- /dev/null +++ b/libjava/classpath/java/nio/Buffer.java @@ -0,0 +1,361 @@ +/* Buffer.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 java.nio; + +import gnu.classpath.RawData; + +/** + * @since 1.4 + */ +public abstract class Buffer +{ + int cap = 0; + int limit = 0; + int pos = 0; + int mark = -1; + RawData address; + + /** + * Creates a new Buffer. + * + * Should be package private. + */ + Buffer (int capacity, int limit, int position, int mark) + { + if (capacity < 0) + throw new IllegalArgumentException (); + + cap = capacity; + limit (limit); + position (position); + + if (mark >= 0) + { + if (mark > pos) + throw new IllegalArgumentException (); + + this.mark = mark; + } + } + + /** + * Retrieves the capacity of the buffer. + * + * @return the capacity of the buffer + */ + public final int capacity () + { + return cap; + } + + /** + * Clears the buffer. + * + * @return this buffer + */ + public final Buffer clear () + { + limit = cap; + pos = 0; + mark = -1; + return this; + } + + /** + * Flips the buffer. + * + * @return this buffer + */ + public final Buffer flip () + { + limit = pos; + pos = 0; + mark = -1; + return this; + } + + /** + * Tells whether the buffer has remaining data to read or not. + * + * @return true if the buffer contains remaining data to read, + * false otherwise + */ + public final boolean hasRemaining () + { + return remaining() > 0; + } + + /** + * Tells whether this buffer is read only or not. + * + * @return true if the buffer is read only, false otherwise + */ + public abstract boolean isReadOnly (); + + /** + * Retrieves the current limit of the buffer. + * + * @return the limit of the buffer + */ + public final int limit () + { + return limit; + } + + /** + * Sets this buffer's limit. + * + * @param newLimit The new limit value; must be non-negative and no larger + * than this buffer's capacity. + * + * @return this buffer + * + * @exception IllegalArgumentException If the preconditions on newLimit + * do not hold. + */ + public final Buffer limit (int newLimit) + { + if ((newLimit < 0) || (newLimit > cap)) + throw new IllegalArgumentException (); + + if (newLimit < mark) + mark = -1; + + if (pos > newLimit) + pos = newLimit; + + limit = newLimit; + return this; + } + + /** + * Sets this buffer's mark at its position. + * + * @return this buffer + */ + public final Buffer mark () + { + mark = pos; + return this; + } + + /** + * Retrieves the current position of this buffer. + * + * @return the current position of this buffer + */ + public final int position () + { + return pos; + } + + /** + * Sets this buffer's position. If the mark is defined and larger than the + * new position then it is discarded. + * + * @param newPosition The new position value; must be non-negative and no + * larger than the current limit. + * + * @return this buffer + * + * @exception IllegalArgumentException If the preconditions on newPosition + * do not hold + */ + public final Buffer position (int newPosition) + { + if ((newPosition < 0) || (newPosition > limit)) + throw new IllegalArgumentException (); + + if (newPosition <= mark) + mark = -1; + + pos = newPosition; + return this; + } + + /** + * Returns the number of elements between the current position and the limit. + * + * @return the number of remaining elements + */ + public final int remaining() + { + return limit - pos; + } + + /** + * Resets this buffer's position to the previously-marked position. + * + * @return this buffer + * + * @exception InvalidMarkException If the mark has not been set. + */ + public final Buffer reset() + { + if (mark == -1) + throw new InvalidMarkException (); + + pos = mark; + return this; + } + + /** + * Rewinds this buffer. The position is set to zero and the mark + * is discarded. + * + * @return this buffer + */ + public final Buffer rewind() + { + pos = 0; + mark = -1; + return this; + } + + /** + * Checks for underflow. This method is used internally to check + * whether a buffer has enough elements left to satisfy a read + * request. + * + * @exception BufferUnderflowException If there are no remaining + * elements in this buffer. + */ + final void checkForUnderflow() + { + if (!hasRemaining()) + throw new BufferUnderflowException(); + } + + /** + * Checks for underflow. This method is used internally to check + * whether a buffer has enough elements left to satisfy a read + * request for a given number of elements. + * + * @param length The length of a sequence of elements. + * + * @exception BufferUnderflowException If there are not enough + * remaining elements in this buffer. + */ + final void checkForUnderflow(int length) + { + if (remaining() < length) + throw new BufferUnderflowException(); + } + + /** + * Checks for overflow. This method is used internally to check + * whether a buffer has enough space left to satisfy a write + * request. + * + * @exception BufferOverflowException If there is no remaining + * space in this buffer. + */ + final void checkForOverflow() + { + if (!hasRemaining()) + throw new BufferOverflowException(); + } + + /** + * Checks for overflow. This method is used internally to check + * whether a buffer has enough space left to satisfy a write + * request for a given number of elements. + * + * @param length The length of a sequence of elements. + * + * @exception BufferUnderflowException If there is not enough + * remaining space in this buffer. + */ + final void checkForOverflow(int length) + { + if (remaining() < length) + throw new BufferOverflowException(); + } + + /** + * Checks if index is negative or not smaller than the buffer's + * limit. This method is used internally to check whether + * an indexed request can be fulfilled. + * + * @param index The requested position in the buffer. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + final void checkIndex(int index) + { + if (index < 0 + || index >= limit ()) + throw new IndexOutOfBoundsException (); + } + + /** + * Checks if buffer is read-only. This method is used internally to + * check if elements can be put into a buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + final void checkIfReadOnly() + { + if (isReadOnly()) + throw new ReadOnlyBufferException (); + } + + /** + * Checks whether an array is large enough to hold the given number of + * elements at the given offset. This method is used internally to + * check if an array is big enough. + * + * @param arraylength The length of the array. + * @param offset The offset within the array of the first byte to be read; + * must be non-negative and no larger than arraylength. + * @param length The number of bytes to be read from the given array; + * must be non-negative and no larger than arraylength - offset. + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + static final void checkArraySize(int arraylength, int offset, int length) + { + if ((offset < 0) || + (length < 0) || + (arraylength < length + offset)) + throw new IndexOutOfBoundsException (); + } +} diff --git a/libjava/classpath/java/nio/BufferOverflowException.java b/libjava/classpath/java/nio/BufferOverflowException.java new file mode 100644 index 0000000..588c032 --- /dev/null +++ b/libjava/classpath/java/nio/BufferOverflowException.java @@ -0,0 +1,51 @@ +/* BufferOverflowException.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 java.nio; + +/** + * @since 1.4 + */ +public class BufferOverflowException extends RuntimeException +{ + /** + * Creates the exception + */ + public BufferOverflowException () + { + } +} diff --git a/libjava/classpath/java/nio/BufferUnderflowException.java b/libjava/classpath/java/nio/BufferUnderflowException.java new file mode 100644 index 0000000..4b4161c --- /dev/null +++ b/libjava/classpath/java/nio/BufferUnderflowException.java @@ -0,0 +1,51 @@ +/* BufferUnderflowException.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 java.nio; + +/** + * @since 1.4 + */ +public class BufferUnderflowException extends RuntimeException +{ + /** + * Creates the exception + */ + public BufferUnderflowException () + { + } +} diff --git a/libjava/classpath/java/nio/ByteBuffer.java b/libjava/classpath/java/nio/ByteBuffer.java new file mode 100644 index 0000000..0ccf766 --- /dev/null +++ b/libjava/classpath/java/nio/ByteBuffer.java @@ -0,0 +1,651 @@ +/* ByteBuffer.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 java.nio; + +/** + * @since 1.4 + */ +public abstract class ByteBuffer extends Buffer + implements Comparable +{ + ByteOrder endian = ByteOrder.BIG_ENDIAN; + + int array_offset; + byte[] backing_buffer; + + ByteBuffer (int capacity, int limit, int position, int mark) + { + super (capacity, limit, position, mark); + } + + /** + * Allocates a new direct byte buffer. + */ + public static ByteBuffer allocateDirect (int capacity) + { + return DirectByteBufferImpl.allocate (capacity); + } + + /** + * Allocates a new ByteBuffer object with a given capacity. + */ + public static ByteBuffer allocate (int capacity) + { + return wrap(new byte[capacity], 0, capacity); + } + + /** + * Wraps a byte array into a ByteBuffer + * object. + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + public static final ByteBuffer wrap (byte[] array, int offset, int length) + { + // FIXME: In GCJ and other implementations where arrays may not + // move we might consider, at least when offset==0: + // return new DirectByteBufferImpl(array, + // address_of_data(array) + offset, + // length, length, 0, false); + // This may be more efficient, mainly because we can then use the + // same logic for all ByteBuffers. + + return new ByteBufferImpl (array, 0, array.length, offset + length, offset, -1, false); + } + + /** + * Wraps a byte array into a ByteBuffer + * object. + */ + public static final ByteBuffer wrap (byte[] array) + { + return wrap (array, 0, array.length); + } + + /** + * This method transfers bytes from this buffer into the given + * destination array. Before the transfer, it checks if there are fewer than + * length bytes remaining in this buffer. + * + * @param dst The destination array + * @param offset The offset within the array of the first byte + * to be written; must be non-negative and no larger than dst.length. + * @param length The maximum number of bytes to be written to the given array; + * must be non-negative and no larger than dst.length - offset. + * + * @exception BufferUnderflowException If there are fewer than length + * bytes remaining in this buffer. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold. + */ + public ByteBuffer get (byte[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + for (int i = offset; i < offset + length; i++) + { + dst [i] = get (); + } + + return this; + } + + /** + * This method transfers bytes from this buffer into the given + * destination array. + * + * @param dst The byte array to write into. + * + * @exception BufferUnderflowException If there are fewer than dst.length + * bytes remaining in this buffer. + */ + public ByteBuffer get (byte[] dst) + { + return get (dst, 0, dst.length); + } + + /** + * Writes the content of the the ByteBUFFER src + * into the buffer. Before the transfer, it checks if there is fewer than + * src.remaining() space remaining in this buffer. + * + * @param src The source data. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining bytes in the source buffer. + * @exception IllegalArgumentException If the source buffer is this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public ByteBuffer put (ByteBuffer src) + { + if (src == this) + throw new IllegalArgumentException (); + + checkForOverflow(src.remaining()); + + if (src.remaining () > 0) + { + byte[] toPut = new byte [src.remaining ()]; + src.get (toPut); + put (toPut); + } + + return this; + } + + /** + * Writes the content of the the byte array src + * into the buffer. Before the transfer, it checks if there is fewer than + * length space remaining in this buffer. + * + * @param src The array to copy into the buffer. + * @param offset The offset within the array of the first byte to be read; + * must be non-negative and no larger than src.length. + * @param length The number of bytes to be read from the given array; + * must be non-negative and no larger than src.length - offset. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining bytes in the source array. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public ByteBuffer put (byte[] src, int offset, int length) + { + checkArraySize(src.length, offset, length); + checkForOverflow(length); + + for (int i = offset; i < offset + length; i++) + put (src [i]); + + return this; + } + + /** + * Writes the content of the the byte array src + * into the buffer. + * + * @param src The array to copy into the buffer. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining bytes in the source array. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public final ByteBuffer put (byte[] src) + { + return put (src, 0, src.length); + } + + /** + * Tells whether ot not this buffer is backed by an accessible + * byte array. + */ + public final boolean hasArray () + { + return (backing_buffer != null + && !isReadOnly ()); + } + + /** + * Returns the byte array that backs this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final byte[] array () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return backing_buffer; + } + + /** + * Returns the offset within this buffer's backing array of the first element. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final int arrayOffset () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return array_offset; + } + + /** + * Calculates a hash code for this buffer. + * + * This is done with int arithmetic, + * where ** represents exponentiation, by this formula:
    + * s[position()] + 31 + (s[position()+1] + 30)*31**1 + ... + + * (s[limit()-1]+30)*31**(limit()-1). + * Where s is the buffer data. Note that the hashcode is dependent + * on buffer content, and therefore is not useful if the buffer + * content may change. + * + * @return the hash code + */ + public int hashCode () + { + int hashCode = get(position()) + 31; + int multiplier = 1; + for (int i = position() + 1; i < limit(); ++i) + { + multiplier *= 31; + hashCode += (get(i) + 30)*multiplier; + } + return hashCode; + } + + /** + * Checks if this buffer is equal to obj. + */ + public boolean equals (Object obj) + { + if (obj instanceof ByteBuffer) + { + return compareTo (obj) == 0; + } + + return false; + } + + /** + * Compares two ByteBuffer objects. + * + * @exception ClassCastException If obj is not an object derived from + * ByteBuffer. + */ + public int compareTo (Object obj) + { + ByteBuffer other = (ByteBuffer) obj; + + int num = Math.min(remaining(), other.remaining()); + int pos_this = position(); + int pos_other = other.position(); + + for (int count = 0; count < num; count++) + { + byte a = get(pos_this++); + byte b = other.get(pos_other++); + + if (a == b) + continue; + + if (a < b) + return -1; + + return 1; + } + + return remaining() - other.remaining(); + } + + /** + * Returns the byte order of this buffer. + */ + public final ByteOrder order () + { + return endian; + } + + /** + * Modifies this buffer's byte order. + */ + public final ByteBuffer order (ByteOrder endian) + { + this.endian = endian; + return this; + } + + /** + * Reads the byte at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * bytes in this buffer. + */ + public abstract byte get (); + + /** + * Writes the byte at this buffer's current position, + * and then increments the position. + * + * @exception BufferOverflowException If there no remaining + * bytes in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract ByteBuffer put (byte b); + + /** + * Absolute get method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public abstract byte get (int index); + + /** + * Absolute put method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract ByteBuffer put (int index, byte b); + + /** + * Compacts this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract ByteBuffer compact (); + + void shiftDown (int dst_offset, int src_offset, int count) + { + for (int i = 0; i < count; i++) + put(dst_offset + i, get(src_offset + i)); + } + + /** + * Tells whether or not this buffer is direct. + */ + public abstract boolean isDirect (); + + /** + * Creates a new ByteBuffer whose content is a shared + * subsequence of this buffer's content. + */ + public abstract ByteBuffer slice (); + + /** + * Creates a new ByteBuffer that shares this buffer's + * content. + */ + public abstract ByteBuffer duplicate (); + + /** + * Creates a new read-only ByteBuffer that shares this + * buffer's content. + */ + public abstract ByteBuffer asReadOnlyBuffer (); + + /** + * Creates a view of this byte buffer as a short buffer. + */ + public abstract ShortBuffer asShortBuffer (); + + /** + * Creates a view of this byte buffer as a char buffer. + */ + public abstract CharBuffer asCharBuffer (); + + /** + * Creates a view of this byte buffer as an integer buffer. + */ + public abstract IntBuffer asIntBuffer (); + + /** + * Creates a view of this byte buffer as a long buffer. + */ + public abstract LongBuffer asLongBuffer (); + + /** + * Creates a view of this byte buffer as a float buffer. + */ + public abstract FloatBuffer asFloatBuffer (); + + /** + * Creates a view of this byte buffer as a double buffer. + */ + public abstract DoubleBuffer asDoubleBuffer (); + + /** + * Relative get method for reading a character value. + * + * @exception BufferUnderflowException If there are fewer than two bytes + * remaining in this buffer. + */ + public abstract char getChar (); + + /** + * Relative put method for writing a character value. + * + * @exception BufferOverflowException If this buffer's current position is + * not smaller than its limit. + */ + public abstract ByteBuffer putChar (char value); + + /** + * Absolute get method for reading a character value. + * + * @exception IndexOutOfBoundsException If there are fewer than two bytes + * remaining in this buffer + */ + public abstract char getChar (int index); + + /** + * Absolute put method for writing a character value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus one. + */ + public abstract ByteBuffer putChar (int index, char value); + + /** + * Relative get method for reading a short value. + * + * @exception BufferUnderflowException If index is negative or not smaller + * than the buffer's limit, minus one. + */ + public abstract short getShort (); + + /** + * Relative put method for writing a short value. + * + * @exception BufferOverflowException If this buffer's current position is + * not smaller than its limit. + */ + public abstract ByteBuffer putShort (short value); + + /** + * Absolute get method for reading a short value. + * + * @exception IndexOutOfBoundsException If there are fewer than two bytes + * remaining in this buffer + */ + public abstract short getShort (int index); + + /** + * Absolute put method for writing a short value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus one. + */ + public abstract ByteBuffer putShort (int index, short value); + + /** + * Relative get method for reading an integer value. + * + * @exception BufferUnderflowException If there are fewer than four bytes + * remaining in this buffer. + */ + public abstract int getInt (); + + /** + * Relative put method for writing an integer value. + * + * @exception BufferOverflowException If this buffer's current position is + * not smaller than its limit. + */ + public abstract ByteBuffer putInt (int value); + + /** + * Absolute get method for reading an integer value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus three. + */ + public abstract int getInt (int index); + + /** + * Absolute put method for writing an integer value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus three. + */ + public abstract ByteBuffer putInt (int index, int value); + + /** + * Relative get method for reading a long value. + * + * @exception BufferUnderflowException If there are fewer than eight bytes + * remaining in this buffer. + */ + public abstract long getLong (); + + /** + * Relative put method for writing a long value. + * + * @exception BufferOverflowException If this buffer's current position is + * not smaller than its limit. + */ + public abstract ByteBuffer putLong (long value); + + /** + * Absolute get method for reading a long value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus seven. + */ + public abstract long getLong (int index); + + /** + * Absolute put method for writing a float value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus seven. + */ + public abstract ByteBuffer putLong (int index, long value); + + /** + * Relative get method for reading a float value. + * + * @exception BufferUnderflowException If there are fewer than four bytes + * remaining in this buffer. + */ + public abstract float getFloat (); + + /** + * Relative put method for writing a float value. + * + * @exception BufferOverflowException If there are fewer than four bytes + * remaining in this buffer. + */ + public abstract ByteBuffer putFloat (float value); + + /** + * Absolute get method for reading a float value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus three. + */ + public abstract float getFloat (int index); + + /** + * Relative put method for writing a float value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus three. + */ + public abstract ByteBuffer putFloat (int index, float value); + + /** + * Relative get method for reading a double value. + * + * @exception BufferUnderflowException If there are fewer than eight bytes + * remaining in this buffer. + */ + public abstract double getDouble (); + + /** + * Relative put method for writing a double value. + * + * @exception BufferOverflowException If this buffer's current position is + * not smaller than its limit. + */ + public abstract ByteBuffer putDouble (double value); + + /** + * Absolute get method for reading a double value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus seven. + */ + public abstract double getDouble (int index); + + /** + * Absolute put method for writing a double value. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit, minus seven. + */ + public abstract ByteBuffer putDouble (int index, double value); + + /** + * Returns a string summarizing the state of this buffer. + */ + public String toString () + { + return getClass ().getName () + + "[pos=" + position () + + " lim=" + limit () + + " cap=" + capacity () + "]"; + } +} diff --git a/libjava/classpath/java/nio/ByteBufferHelper.java b/libjava/classpath/java/nio/ByteBufferHelper.java new file mode 100644 index 0000000..6c46ca5 --- /dev/null +++ b/libjava/classpath/java/nio/ByteBufferHelper.java @@ -0,0 +1,344 @@ +/* ByteBufferImpl.java -- + 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 java.nio; + +/** + * @author Michael Koch (konqueror@gmx.de) + */ +final class ByteBufferHelper +{ + public static char getChar (ByteBuffer buffer, ByteOrder order) + { + return (char) getShort (buffer, order); + } + + public static void putChar (ByteBuffer buffer, char value, ByteOrder order) + { + putShort (buffer, (short) value, order); + } + + public static char getChar (ByteBuffer buffer, int index, ByteOrder order) + { + return (char) getShort (buffer, index, order); + } + + public static void putChar (ByteBuffer buffer, int index, + char value, ByteOrder order) + { + putShort (buffer, index, (short) value, order); + } + + public static short getShort (ByteBuffer buffer, ByteOrder order) + { + buffer.checkForUnderflow(2); + + if (order == ByteOrder.LITTLE_ENDIAN) + { + return (short) ((buffer.get() & 0xff) + + (buffer.get() << 8)); + } + + return (short) ((buffer.get() << 8) + + (buffer.get() & 0xff)); + } + + public static void putShort (ByteBuffer buffer, short value, ByteOrder order) + { + buffer.checkForOverflow(2); + + if (order == ByteOrder.LITTLE_ENDIAN) + { + buffer.put ((byte) value); + buffer.put ((byte) (value >> 8)); + } + else + { + buffer.put ((byte) (value >> 8)); + buffer.put ((byte) value); + } + } + + public static short getShort (ByteBuffer buffer, + int index, ByteOrder order) + { + if (order == ByteOrder.LITTLE_ENDIAN) + { + return (short) ((buffer.get (index) & 0xff) + + (buffer.get (++index) << 8)); + } + + return (short) ((buffer.get (index) << 8) + + (buffer.get (++index) & 0xff)); + } + + public static void putShort (ByteBuffer buffer, int index, + short value, ByteOrder order) + { + if (order == ByteOrder.LITTLE_ENDIAN) + { + buffer.put (index, (byte) value); + buffer.put (++index, (byte) (value >> 8)); + } + else + { + buffer.put (index, (byte) (value >> 8)); + buffer.put (++index, (byte) value); + } + } + + public static int getInt (ByteBuffer buffer, ByteOrder order) + { + buffer.checkForUnderflow(4); + + if (order == ByteOrder.LITTLE_ENDIAN) + { + return ((buffer.get() & 0xff) + + ((buffer.get() & 0xff) << 8) + + ((buffer.get() & 0xff) << 16) + + (buffer.get() << 24)); + } + + return (int) ((buffer.get() << 24) + + ((buffer.get() & 0xff) << 16) + + ((buffer.get() & 0xff) << 8) + + (buffer.get() & 0xff)); + } + + public static void putInt (ByteBuffer buffer, int value, ByteOrder order) + { + buffer.checkForOverflow(4); + + if (order == ByteOrder.LITTLE_ENDIAN) + { + buffer.put ((byte) value); + buffer.put ((byte) (value >> 8)); + buffer.put ((byte) (value >> 16)); + buffer.put ((byte) (value >> 24)); + } + else + { + buffer.put ((byte) (value >> 24)); + buffer.put ((byte) (value >> 16)); + buffer.put ((byte) (value >> 8)); + buffer.put ((byte) value); + } + } + + public static int getInt (ByteBuffer buffer, int index, ByteOrder order) + { + if (order == ByteOrder.LITTLE_ENDIAN) + { + return ((buffer.get (index) & 0xff) + + ((buffer.get (++index) & 0xff) << 8) + + ((buffer.get (++index) & 0xff) << 16) + + (buffer.get (++index) << 24)); + } + + return ((buffer.get (index) << 24) + + ((buffer.get (++index) & 0xff) << 16) + + ((buffer.get (++index) & 0xff) << 8) + + (buffer.get (++index) & 0xff)); + } + + public static void putInt (ByteBuffer buffer, int index, + int value, ByteOrder order) + { + if (order == ByteOrder.LITTLE_ENDIAN) + { + buffer.put (index, (byte) value); + buffer.put (++index, (byte) (value >> 8)); + buffer.put (++index, (byte) (value >> 16)); + buffer.put (++index, (byte) (value >> 24)); + } + else + { + buffer.put (index, (byte) (value >> 24)); + buffer.put (++index, (byte) (value >> 16)); + buffer.put (++index, (byte) (value >> 8)); + buffer.put (++index, (byte) value); + } + } + + public static long getLong (ByteBuffer buffer, ByteOrder order) + { + buffer.checkForUnderflow(8); + + if (order == ByteOrder.LITTLE_ENDIAN) + { + return ((buffer.get() & 0xff) + + (((buffer.get() & 0xff)) << 8) + + (((buffer.get() & 0xff)) << 16) + + (((buffer.get() & 0xffL)) << 24) + + (((buffer.get() & 0xffL)) << 32) + + (((buffer.get() & 0xffL)) << 40) + + (((buffer.get() & 0xffL)) << 48) + + (((long) buffer.get()) << 56)); + } + + return ((((long) buffer.get()) << 56) + + ((buffer.get() & 0xffL) << 48) + + ((buffer.get() & 0xffL) << 40) + + ((buffer.get() & 0xffL) << 32) + + ((buffer.get() & 0xffL) << 24) + + ((buffer.get() & 0xff) << 16) + + ((buffer.get() & 0xff) << 8) + + (buffer.get() & 0xff)); + } + + public static void putLong (ByteBuffer buffer, long value, ByteOrder order) + { + buffer.checkForOverflow(8); + + if (order == ByteOrder.LITTLE_ENDIAN) + { + buffer.put ((byte) value); + buffer.put ((byte) (value >> 8)); + buffer.put ((byte) (value >> 16)); + buffer.put ((byte) (value >> 24)); + buffer.put ((byte) (value >> 32)); + buffer.put ((byte) (value >> 40)); + buffer.put ((byte) (value >> 48)); + buffer.put ((byte) (value >> 56)); + } + else + { + buffer.put ((byte) (value >> 56)); + buffer.put ((byte) (value >> 48)); + buffer.put ((byte) (value >> 40)); + buffer.put ((byte) (value >> 32)); + buffer.put ((byte) (value >> 24)); + buffer.put ((byte) (value >> 16)); + buffer.put ((byte) (value >> 8)); + buffer.put ((byte) value); + } + } + + public static long getLong (ByteBuffer buffer, int index, ByteOrder order) + { + if (order == ByteOrder.LITTLE_ENDIAN) + { + return ((buffer.get (index) & 0xff) + + ((buffer.get (++index) & 0xff) << 8) + + ((buffer.get (++index) & 0xff) << 16) + + ((buffer.get (++index) & 0xffL) << 24) + + ((buffer.get (++index) & 0xffL) << 32) + + ((buffer.get (++index) & 0xffL) << 40) + + ((buffer.get (++index) & 0xffL) << 48) + + (((long) buffer.get (++index)) << 56)); + } + + return ((((long) buffer.get (index)) << 56) + + ((buffer.get (++index) & 0xffL) << 48) + + ((buffer.get (++index) & 0xffL) << 40) + + ((buffer.get (++index) & 0xffL) << 32) + + ((buffer.get (++index) & 0xffL) << 24) + + ((buffer.get (++index) & 0xff) << 16) + + ((buffer.get (++index) & 0xff) << 8) + + (buffer.get (++index) & 0xff)); + } + + public static void putLong (ByteBuffer buffer, int index, + long value, ByteOrder order) + { + if (order == ByteOrder.LITTLE_ENDIAN) + { + buffer.put (index, (byte) value); + buffer.put (++index, (byte) (value >> 8)); + buffer.put (++index, (byte) (value >> 16)); + buffer.put (++index, (byte) (value >> 24)); + buffer.put (++index, (byte) (value >> 32)); + buffer.put (++index, (byte) (value >> 40)); + buffer.put (++index, (byte) (value >> 48)); + buffer.put (++index, (byte) (value >> 56)); + } + else + { + buffer.put (index, (byte) (value >> 56)); + buffer.put (++index, (byte) (value >> 48)); + buffer.put (++index, (byte) (value >> 40)); + buffer.put (++index, (byte) (value >> 32)); + buffer.put (++index, (byte) (value >> 24)); + buffer.put (++index, (byte) (value >> 16)); + buffer.put (++index, (byte) (value >> 8)); + buffer.put (++index, (byte) value); + } + } + + public static float getFloat (ByteBuffer buffer, ByteOrder order) + { + return Float.intBitsToFloat (getInt (buffer, order)); + } + + public static void putFloat (ByteBuffer buffer, float value, ByteOrder order) + { + putInt (buffer, Float.floatToRawIntBits (value), order); + } + + public static float getFloat (ByteBuffer buffer, int index, ByteOrder order) + { + return Float.intBitsToFloat (getInt (buffer, index, order)); + } + + public static void putFloat (ByteBuffer buffer, int index, + float value, ByteOrder order) + { + putInt (buffer, index, Float.floatToRawIntBits (value), order); + } + + public static double getDouble (ByteBuffer buffer, ByteOrder order) + { + return Double.longBitsToDouble (getLong (buffer, order)); + } + + public static void putDouble (ByteBuffer buffer, double value, ByteOrder order) + { + putLong (buffer, Double.doubleToRawLongBits (value), order); + } + + public static double getDouble (ByteBuffer buffer, int index, ByteOrder order) + { + return Double.longBitsToDouble (getLong (buffer, index, order)); + } + + public static void putDouble (ByteBuffer buffer, int index, + double value, ByteOrder order) + { + putLong (buffer, index, Double.doubleToRawLongBits (value), order); + } +} // ByteBufferHelper + diff --git a/libjava/classpath/java/nio/ByteBufferImpl.java b/libjava/classpath/java/nio/ByteBufferImpl.java new file mode 100644 index 0000000..48d7152 --- /dev/null +++ b/libjava/classpath/java/nio/ByteBufferImpl.java @@ -0,0 +1,379 @@ +/* ByteBufferImpl.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 java.nio; + +/** + * This is a Heap memory implementation + */ +final class ByteBufferImpl extends ByteBuffer +{ + private boolean readOnly; + + ByteBufferImpl (byte[] buffer, int offset, int capacity, int limit, int position, int mark, boolean readOnly) + { + super (capacity, limit, position, mark); + this.backing_buffer = buffer; + this.array_offset = offset; + this.readOnly = readOnly; + } + + public CharBuffer asCharBuffer () + { + return new CharViewBufferImpl (this, remaining() >> 1); + } + + public ShortBuffer asShortBuffer () + { + return new ShortViewBufferImpl (this, remaining() >> 1); + } + + public IntBuffer asIntBuffer () + { + return new IntViewBufferImpl (this, remaining() >> 2); + } + + public LongBuffer asLongBuffer () + { + return new LongViewBufferImpl (this, remaining() >> 3); + } + + public FloatBuffer asFloatBuffer () + { + return new FloatViewBufferImpl (this, remaining() >> 2); + } + + public DoubleBuffer asDoubleBuffer () + { + return new DoubleViewBufferImpl (this, remaining() >> 3); + } + + public boolean isReadOnly () + { + return readOnly; + } + + public ByteBuffer slice () + { + return new ByteBufferImpl (backing_buffer, array_offset + position (), remaining (), remaining (), 0, -1, isReadOnly ()); + } + + public ByteBuffer duplicate () + { + return new ByteBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, isReadOnly ()); + } + + public ByteBuffer asReadOnlyBuffer () + { + return new ByteBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, true); + } + + void shiftDown (int dst_offset, int src_offset, int count) + { + System.arraycopy(backing_buffer, array_offset + src_offset, + backing_buffer, array_offset + dst_offset, + count); + } + + public ByteBuffer compact () + { + checkIfReadOnly(); + mark = -1; + int pos = position(); + if (pos > 0) + { + int count = remaining(); + shiftDown(0, pos, count); + position(count); + limit(capacity()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public boolean isDirect () + { + return false; + } + + /** + * Reads the byte at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * bytes in this buffer. + */ + public byte get () + { + if (pos >= limit) + throw new BufferUnderflowException(); + + return backing_buffer [(pos++) + array_offset]; + } + + /** + * Bulk get + */ + public ByteBuffer get (byte[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + if ( (limit - pos) < length) // check for overflow + throw new BufferUnderflowException(); + + System.arraycopy(backing_buffer, pos + array_offset, + dst, offset, length); + pos += length; + + return this; + } + + /** + * Relative bulk put(), overloads the ByteBuffer impl. + */ + public ByteBuffer put (byte[] src, int offset, int length) + { + if ( (limit - pos) < length) // check for overflow + throw new BufferOverflowException(); + checkArraySize(src.length, offset, length); + + System.arraycopy(src, offset, backing_buffer, pos + array_offset, length); + pos += length; + + return this; + } + + /** + * Relative put method. Writes value to the next position + * in the buffer. + * + * @exception BufferOverflowException If there is no remaining + * space in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public ByteBuffer put (byte value) + { + if (readOnly) + throw new ReadOnlyBufferException(); + if (pos >= limit) + throw new BufferOverflowException(); + + backing_buffer [(pos++) + array_offset] = value; + return this; + } + + /** + * Absolute get method. Reads the byte at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public byte get (int index) + { + checkIndex(index); + + return backing_buffer [index + array_offset]; + } + + /** + * Absolute put method. Writes value to position + * index in the buffer. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public ByteBuffer put (int index, byte value) + { + checkIfReadOnly(); + checkIndex(index); + + backing_buffer [index + array_offset] = value; + return this; + } + + public char getChar () + { + return ByteBufferHelper.getChar(this, order()); + } + + public ByteBuffer putChar (char value) + { + if (readOnly) + throw new ReadOnlyBufferException (); + if ( (limit-pos) < 2) + throw new BufferOverflowException(); + + if (endian == ByteOrder.LITTLE_ENDIAN) + { + backing_buffer [(pos++) + array_offset] = (byte)(value&0xFF); + backing_buffer [(pos++) + array_offset] = (byte)(value>>8); + } + else + { + backing_buffer [(pos++) + array_offset] = (byte)(value>>8); + backing_buffer [(pos++) + array_offset] = (byte)(value&0xFF); + } + return this; + } + + public char getChar (int index) + { + return ByteBufferHelper.getChar(this, index, order()); + } + + public ByteBuffer putChar (int index, char value) + { + ByteBufferHelper.putChar(this, index, value, order()); + return this; + } + + public short getShort () + { + return ByteBufferHelper.getShort(this, order()); + } + + public ByteBuffer putShort (short value) + { + ByteBufferHelper.putShort(this, value, order()); + return this; + } + + public short getShort (int index) + { + return ByteBufferHelper.getShort(this, index, order()); + } + + public ByteBuffer putShort (int index, short value) + { + ByteBufferHelper.putShort(this, index, value, order()); + return this; + } + + public int getInt () + { + return ByteBufferHelper.getInt(this, order()); + } + + public ByteBuffer putInt (int value) + { + ByteBufferHelper.putInt(this, value, order()); + return this; + } + + public int getInt (int index) + { + return ByteBufferHelper.getInt(this, index, order()); + } + + public ByteBuffer putInt (int index, int value) + { + ByteBufferHelper.putInt(this, index, value, order()); + return this; + } + + public long getLong () + { + return ByteBufferHelper.getLong(this, order()); + } + + public ByteBuffer putLong (long value) + { + ByteBufferHelper.putLong (this, value, order()); + return this; + } + + public long getLong (int index) + { + return ByteBufferHelper.getLong (this, index, order()); + } + + public ByteBuffer putLong (int index, long value) + { + ByteBufferHelper.putLong (this, index, value, order()); + return this; + } + + public float getFloat () + { + return ByteBufferHelper.getFloat (this, order()); + } + + public ByteBuffer putFloat (float value) + { + ByteBufferHelper.putFloat (this, value, order()); + return this; + } + + public float getFloat (int index) + { + return ByteBufferHelper.getFloat (this, index, order()); + } + + public ByteBuffer putFloat (int index, float value) + { + ByteBufferHelper.putFloat (this, index, value, order()); + return this; + } + + public double getDouble () + { + return ByteBufferHelper.getDouble (this, order()); + } + + public ByteBuffer putDouble (double value) + { + ByteBufferHelper.putDouble (this, value, order()); + return this; + } + + public double getDouble (int index) + { + return ByteBufferHelper.getDouble (this, index, order()); + } + + public ByteBuffer putDouble (int index, double value) + { + ByteBufferHelper.putDouble (this, index, value, order()); + return this; + } +} diff --git a/libjava/classpath/java/nio/ByteOrder.java b/libjava/classpath/java/nio/ByteOrder.java new file mode 100644 index 0000000..39a3ff8 --- /dev/null +++ b/libjava/classpath/java/nio/ByteOrder.java @@ -0,0 +1,82 @@ +/* ByteOrder.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.4 + */ +public final class ByteOrder +{ + /** + * Constant indicating big endian byte order. + */ + public static final ByteOrder BIG_ENDIAN = new ByteOrder(); + + /** + * Constant indicating little endian byte order. + */ + public static final ByteOrder LITTLE_ENDIAN = new ByteOrder(); + + /** + * Returns the native byte order of the platform currently running. + * + * @return the native byte order + */ + public static ByteOrder nativeOrder() + { + return (System.getProperty ("gnu.cpu.endian").equals("big") + ? BIG_ENDIAN : LITTLE_ENDIAN); + } + + /** + * Returns a string representation of the byte order. + * + * @return the string + */ + public String toString() + { + return this == BIG_ENDIAN ? "BIG_ENDIAN" : "LITTLE_ENDIAN"; + } + + // This class can only be instantiated here. + private ByteOrder() + { + } +} diff --git a/libjava/classpath/java/nio/CharBuffer.java b/libjava/classpath/java/nio/CharBuffer.java new file mode 100644 index 0000000..6551555 --- /dev/null +++ b/libjava/classpath/java/nio/CharBuffer.java @@ -0,0 +1,508 @@ +/* CharBuffer.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 java.nio; + +/** + * @since 1.4 + */ +public abstract class CharBuffer extends Buffer + implements Comparable, CharSequence +{ + int array_offset; + char[] backing_buffer; + + CharBuffer (int capacity, int limit, int position, int mark) + { + super (capacity, limit, position, mark); + array_offset = 0; + } + + /** + * Allocates a new CharBuffer object with a given capacity. + */ + public static CharBuffer allocate (int capacity) + { + return new CharBufferImpl (capacity); + } + + /** + * Wraps a char array into a CharBuffer + * object. + * + * @param array the array to wrap + * @param offset the offset of the region in the array to wrap + * @param length the length of the region in the array to wrap + * + * @return a new CharBuffer object + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + public static final CharBuffer wrap(char[] array, int offset, int length) + { + return new CharBufferImpl(array, 0, array.length, offset + length, offset, -1, false); + } + + /** + * Wraps a character sequence into a CharBuffer object. + * + * @param seq the sequence to wrap + * + * @return a new CharBuffer object + */ + public static final CharBuffer wrap(CharSequence seq) + { + return wrap(seq, 0, seq.length()); + } + + /** + * Wraps a character sequence into a CharBuffer object. + * + * @param seq the sequence to wrap + * @param start the index of the first character to wrap + * @param end the index of the first character not to wrap + * + * @return a new CharBuffer object + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + public static final CharBuffer wrap(CharSequence seq, int start, int end) + { + // FIXME: implement better handling of java.lang.String. + // Probably share data with String via reflection. + + if ((start < 0) + || (start > seq.length()) + || (end < start) + || (end > (seq.length() - start))) + throw new IndexOutOfBoundsException(); + + int len = end - start; + char[] buffer = new char[len]; + + for (int i = 0; i < len; i++) + buffer[i] = seq.charAt(i + start); + + return wrap(buffer, 0, len).asReadOnlyBuffer(); + } + + /** + * Wraps a char array into a CharBuffer + * object. + * + * @param array the array to wrap + * + * @return a new CharBuffer object + */ + public static final CharBuffer wrap(char[] array) + { + return wrap(array, 0, array.length); + } + + /** + * This method transfers chars from this buffer into the given + * destination array. Before the transfer, it checks if there are fewer than + * length chars remaining in this buffer. + * + * @param dst The destination array + * @param offset The offset within the array of the first char + * to be written; must be non-negative and no larger than dst.length. + * @param length The maximum number of bytes to be written to the given array; + * must be non-negative and no larger than dst.length - offset. + * + * @exception BufferUnderflowException If there are fewer than length + * chars remaining in this buffer. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold. + */ + public CharBuffer get (char[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + for (int i = offset; i < offset + length; i++) + { + dst [i] = get (); + } + + return this; + } + + /** + * This method transfers chars from this buffer into the given + * destination array. + * + * @param dst The byte array to write into. + * + * @exception BufferUnderflowException If there are fewer than dst.length + * chars remaining in this buffer. + */ + public CharBuffer get (char[] dst) + { + return get (dst, 0, dst.length); + } + + /** + * Writes the content of the the CharBUFFER src + * into the buffer. Before the transfer, it checks if there is fewer than + * src.remaining() space remaining in this buffer. + * + * @param src The source data. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining chars in the source buffer. + * @exception IllegalArgumentException If the source buffer is this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public CharBuffer put (CharBuffer src) + { + if (src == this) + throw new IllegalArgumentException (); + + checkForOverflow(src.remaining()); + + if (src.remaining () > 0) + { + char[] toPut = new char [src.remaining ()]; + src.get (toPut); + put (toPut); + } + + return this; + } + + /** + * Writes the content of the the char array src + * into the buffer. Before the transfer, it checks if there is fewer than + * length space remaining in this buffer. + * + * @param src The array to copy into the buffer. + * @param offset The offset within the array of the first byte to be read; + * must be non-negative and no larger than src.length. + * @param length The number of bytes to be read from the given array; + * must be non-negative and no larger than src.length - offset. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining chars in the source array. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public CharBuffer put (char[] src, int offset, int length) + { + checkArraySize(src.length, offset, length); + checkForOverflow(length); + + for (int i = offset; i < offset + length; i++) + put (src [i]); + + return this; + } + + /** + * Writes the content of the the char array src + * into the buffer. + * + * @param src The array to copy into the buffer. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining chars in the source array. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public final CharBuffer put (char[] src) + { + return put (src, 0, src.length); + } + + /** + * Tells whether ot not this buffer is backed by an accessible + * char array. + */ + public final boolean hasArray () + { + return (backing_buffer != null + && !isReadOnly ()); + } + + /** + * Returns the char array that backs this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final char[] array () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return backing_buffer; + } + + /** + * Returns the offset within this buffer's backing array of the first element. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final int arrayOffset () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return array_offset; + } + + /** + * Calculates a hash code for this buffer. + * + * This is done with int arithmetic, + * where ** represents exponentiation, by this formula:
    + * s[position()] + 31 + (s[position()+1] + 30)*31**1 + ... + + * (s[limit()-1]+30)*31**(limit()-1). + * Where s is the buffer data. Note that the hashcode is dependent + * on buffer content, and therefore is not useful if the buffer + * content may change. + */ + public int hashCode () + { + int hashCode = get(position()) + 31; + int multiplier = 1; + for (int i = position() + 1; i < limit(); ++i) + { + multiplier *= 31; + hashCode += (get(i) + 30)*multiplier; + } + return hashCode; + } + + /** + * Checks if this buffer is equal to obj. + */ + public boolean equals (Object obj) + { + if (obj instanceof CharBuffer) + { + return compareTo (obj) == 0; + } + + return false; + } + + /** + * Compares two CharBuffer objects. + * + * @exception ClassCastException If obj is not an object derived from + * CharBuffer. + */ + public int compareTo (Object obj) + { + CharBuffer other = (CharBuffer) obj; + + int num = Math.min(remaining(), other.remaining()); + int pos_this = position(); + int pos_other = other.position(); + + for (int count = 0; count < num; count++) + { + char a = get(pos_this++); + char b = other.get(pos_other++); + + if (a == b) + continue; + + if (a < b) + return -1; + + return 1; + } + + return remaining() - other.remaining(); + } + + /** + * Returns the byte order of this buffer. + */ + public abstract ByteOrder order (); + + /** + * Reads the char at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * chars in this buffer. + */ + public abstract char get (); + + /** + * Writes the char at this buffer's current position, + * and then increments the position. + * + * @exception BufferOverflowException If there no remaining + * chars in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract CharBuffer put (char b); + + /** + * Absolute get method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public abstract char get (int index); + + /** + * Absolute put method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract CharBuffer put (int index, char b); + + /** + * Compacts this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract CharBuffer compact (); + + /** + * Tells wether or not this buffer is direct. + */ + public abstract boolean isDirect (); + + /** + * Creates a new CharBuffer whose content is a shared + * subsequence of this buffer's content. + */ + public abstract CharBuffer slice (); + + /** + * Creates a new CharBuffer that shares this buffer's + * content. + */ + public abstract CharBuffer duplicate (); + + /** + * Creates a new read-only CharBuffer that shares this + * buffer's content. + */ + public abstract CharBuffer asReadOnlyBuffer (); + + /** + * Returns the remaining content of the buffer as a string. + */ + public String toString () + { + if (hasArray ()) + return new String (array (), position (), length ()); + + char[] buf = new char [length ()]; + int pos = position (); + get (buf, 0, buf.length); + position (pos); + return new String (buf); + } + + /** + * Returns the length of the remaining chars in this buffer. + */ + public final int length () + { + return remaining (); + } + + /** + * Creates a new character buffer that represents the specified subsequence + * of this buffer, relative to the current position. + * + * @exception IndexOutOfBoundsException If the preconditions on start and + * end do not hold. + */ + public abstract CharSequence subSequence (int start, int length); + + /** + * Relative put method. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer. + * @exception IndexOutOfBoundsException If the preconditions on the start + * and end parameters do not hold. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public CharBuffer put (String str, int start, int length) + { + return put (str.toCharArray (), start, length); + } + + /** + * Relative put method. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public final CharBuffer put (String str) + { + return put (str.toCharArray (), 0, str.length ()); + } + + /** + * Returns the character at position() + index. + * + * @exception IndexOutOfBoundsException If index is negative not smaller than + * remaining(). + */ + public final char charAt (int index) + { + if (index < 0 + || index >= remaining ()) + throw new IndexOutOfBoundsException (); + + return get (position () + index); + } +} diff --git a/libjava/classpath/java/nio/CharBufferImpl.java b/libjava/classpath/java/nio/CharBufferImpl.java new file mode 100644 index 0000000..33f8dab --- /dev/null +++ b/libjava/classpath/java/nio/CharBufferImpl.java @@ -0,0 +1,219 @@ +/* CharBufferImpl.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 java.nio; + +/** + * This is a Heap memory implementation + */ +final class CharBufferImpl extends CharBuffer +{ + private boolean readOnly; + + CharBufferImpl (int capacity) + { + this (new char [capacity], 0, capacity, capacity, 0, -1, false); + } + + CharBufferImpl (char[] buffer, int offset, int capacity, int limit, int position, int mark, boolean readOnly) + { + super (capacity, limit, position, mark); + this.backing_buffer = buffer; + this.array_offset = offset; + this.readOnly = readOnly; + } + + public CharBufferImpl (CharBufferImpl copy) + { + super (copy.capacity (), copy.limit (), copy.position (), 0); + backing_buffer = copy.backing_buffer; + array_offset = copy.array_offset; + readOnly = copy.isReadOnly (); + } + + public boolean isReadOnly () + { + return readOnly; + } + + public CharBuffer slice () + { + return new CharBufferImpl (backing_buffer, array_offset + position (), remaining (), remaining (), 0, -1, isReadOnly ()); + } + + public CharBuffer duplicate () + { + return new CharBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, isReadOnly ()); + } + + public CharBuffer asReadOnlyBuffer () + { + return new CharBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, true); + } + + public CharBuffer compact () + { + checkIfReadOnly(); + mark = -1; + int copied = 0; + + while (remaining () > 0) + { + put (copied, get ()); + copied++; + } + + position (copied); + limit(capacity()); + return this; + } + + public boolean isDirect () + { + return false; + } + + public CharSequence subSequence (int start, int end) + { + if (start < 0 + || start > length () + || end < start + || end > length ()) + throw new IndexOutOfBoundsException (); + + return new CharBufferImpl (backing_buffer, array_offset, capacity (), position () + end, position () + start, -1, isReadOnly ()); + } + + /** + * Reads the char at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * chars in this buffer. + */ + public char get () + { + if (pos >= limit) + throw new BufferUnderflowException(); + + return backing_buffer [(pos++) + array_offset]; + } + + /** + * Relative put method. Writes value to the next position + * in the buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public CharBuffer put (char value) + { + if (readOnly) + throw new ReadOnlyBufferException(); + if (pos >= limit) + throw new BufferOverflowException(); + + backing_buffer [(pos++) + array_offset] = value; + return this; + } + + /** + * Absolute get method. Reads the char at position + * index. + * + * @param index Position to read the char from. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public char get (int index) + { + checkIndex(index); + + return backing_buffer [index + array_offset]; + } + + /** + * Bulk get, overloaded for speed. + */ + public CharBuffer get (char[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + System.arraycopy(backing_buffer, pos + array_offset, + dst, offset, length); + pos += length; + return this; + } + + /** + * Bulk put, overloaded for speed. + */ + public CharBuffer put (char[] src, int offset, int length) + { + checkArraySize(src.length, offset, length); + checkForOverflow(length); + + System.arraycopy(src, offset, + backing_buffer, pos + array_offset, length); + pos += length; + return this; + } + + /** + * Absolute put method. Writes value to position + * index in the buffer. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public CharBuffer put (int index, char value) + { + checkIndex(index); + checkIfReadOnly(); + + backing_buffer [index + array_offset] = value; + return this; + } + + public ByteOrder order () + { + return ByteOrder.nativeOrder (); + } +} diff --git a/libjava/classpath/java/nio/CharViewBufferImpl.java b/libjava/classpath/java/nio/CharViewBufferImpl.java new file mode 100644 index 0000000..3198315 --- /dev/null +++ b/libjava/classpath/java/nio/CharViewBufferImpl.java @@ -0,0 +1,187 @@ +/* CharViewBufferImpl.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 java.nio; + +class CharViewBufferImpl extends CharBuffer +{ + /** Position in bb (i.e. a byte offset) where this buffer starts. */ + private int offset; + private ByteBuffer bb; + private boolean readOnly; + private ByteOrder endian; + + CharViewBufferImpl (ByteBuffer bb, int capacity) + { + super (capacity, capacity, 0, -1); + this.bb = bb; + this.offset = bb.position(); + this.readOnly = bb.isReadOnly(); + this.endian = bb.order(); + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + public CharViewBufferImpl (ByteBuffer bb, int offset, int capacity, + int limit, int position, int mark, + boolean readOnly, ByteOrder endian) + { + super (capacity, limit, position, mark); + this.bb = bb; + this.offset = offset; + this.readOnly = readOnly; + this.endian = endian; + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + /** + * Reads the char at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * chars in this buffer. + */ + public char get () + { + int p = position(); + char result = ByteBufferHelper.getChar(bb, (p << 1) + offset, endian); + position(p + 1); + return result; + } + + /** + * Absolute get method. Reads the char at position + * index. + * + * @param index Position to read the char from. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public char get (int index) + { + return ByteBufferHelper.getChar(bb, (index << 1) + offset, endian); + } + + public CharBuffer put (char value) + { + int p = position(); + ByteBufferHelper.putChar(bb, (p << 1) + offset, value, endian); + position(p + 1); + return this; + } + + public CharBuffer put (int index, char value) + { + ByteBufferHelper.putChar(bb, (index << 1) + offset, value, endian); + return this; + } + + public CharBuffer compact () + { + if (position () > 0) + { + int count = limit () - position (); + bb.shiftDown(offset, offset + 2 * position(), 2 * count); + position (count); + limit (capacity ()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public CharBuffer slice () + { + // Create a sliced copy of this object that shares its content. + return new CharViewBufferImpl (bb, (position () >> 1) + offset, + remaining (), remaining (), 0, -1, + isReadOnly (), endian); + } + + CharBuffer duplicate (boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + return new CharViewBufferImpl (bb, offset, capacity(), limit(), + pos, mark, readOnly, endian); + } + + public CharBuffer duplicate () + { + return duplicate(readOnly); + } + + public CharBuffer asReadOnlyBuffer () + { + return duplicate(true); + } + + public CharSequence subSequence (int start, int end) + { + if (start < 0 + || end < start + || end > length ()) + throw new IndexOutOfBoundsException (); + + return new CharViewBufferImpl (bb, array_offset, capacity (), + position () + end, position () + start, + -1, isReadOnly (), endian); + } + + public boolean isReadOnly () + { + return readOnly; + } + + public boolean isDirect () + { + return bb.isDirect (); + } + + public ByteOrder order () + { + return endian; + } +} diff --git a/libjava/classpath/java/nio/DirectByteBufferImpl.java b/libjava/classpath/java/nio/DirectByteBufferImpl.java new file mode 100644 index 0000000..1667299 --- /dev/null +++ b/libjava/classpath/java/nio/DirectByteBufferImpl.java @@ -0,0 +1,419 @@ +/* DirectByteBufferImpl.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 java.nio; + +import gnu.classpath.RawData; + +abstract class DirectByteBufferImpl extends ByteBuffer +{ + /** + * The owner is used to keep alive the object that actually owns the + * memory. There are three possibilities: + * 1) owner == this: We allocated the memory and we should free it, + * but *only* in finalize (if we've been sliced + * other objects will also have access to the + * memory). + * 2) owner == null: The byte buffer was created thru + * JNI.NewDirectByteBuffer. The JNI code is + * responsible for freeing the memory. + * 3) owner == some other object: The other object allocated the + * memory and should free it. + */ + private final Object owner; + + static final class ReadOnly extends DirectByteBufferImpl + { + ReadOnly(Object owner, RawData address, + int capacity, int limit, + int position) + { + super(owner, address, capacity, limit, position); + } + + public ByteBuffer put(byte value) + { + throw new ReadOnlyBufferException (); + } + + public ByteBuffer put(int index, byte value) + { + throw new ReadOnlyBufferException (); + } + + public boolean isReadOnly() + { + return true; + } + } + + static final class ReadWrite extends DirectByteBufferImpl + { + ReadWrite(int capacity) + { + super(capacity); + } + + ReadWrite(Object owner, RawData address, + int capacity, int limit, + int position) + { + super(owner, address, capacity, limit, position); + } + + public boolean isReadOnly() + { + return false; + } + } + + DirectByteBufferImpl(int capacity) + { + super(capacity, capacity, 0, -1); + this.owner = this; + this.address = VMDirectByteBuffer.allocate(capacity); + } + + DirectByteBufferImpl(Object owner, RawData address, + int capacity, int limit, + int position) + { + super(capacity, limit, position, -1); + this.owner = owner; + this.address = address; + } + + /** + * Allocates a new direct byte buffer. + */ + public static ByteBuffer allocate(int capacity) + { + return new DirectByteBufferImpl.ReadWrite(capacity); + } + + protected void finalize() throws Throwable + { + if (owner == this) + VMDirectByteBuffer.free(address); + } + + public byte get() + { + checkForUnderflow(); + + int pos = position(); + byte result = VMDirectByteBuffer.get(address, pos); + position(pos + 1); + return result; + } + + public byte get(int index) + { + checkIndex(index); + + return VMDirectByteBuffer.get(address, index); + } + + public ByteBuffer get(byte[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + int index = position(); + VMDirectByteBuffer.get(address, index, dst, offset, length); + position(index+length); + + return this; + } + + public ByteBuffer put(byte value) + { + checkForOverflow(); + + int pos = position(); + VMDirectByteBuffer.put(address, pos, value); + position(pos + 1); + return this; + } + + public ByteBuffer put(int index, byte value) + { + checkIndex(index); + + VMDirectByteBuffer.put(address, index, value); + return this; + } + + void shiftDown(int dst_offset, int src_offset, int count) + { + VMDirectByteBuffer.shiftDown(address, dst_offset, src_offset, count); + } + + public ByteBuffer compact() + { + checkIfReadOnly(); + mark = -1; + int pos = position(); + if (pos > 0) + { + int count = remaining(); + VMDirectByteBuffer.shiftDown(address, 0, pos, count); + position(count); + limit(capacity()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public ByteBuffer slice() + { + int rem = remaining(); + if (isReadOnly()) + return new DirectByteBufferImpl.ReadOnly + (owner, VMDirectByteBuffer.adjustAddress(address, position()), + rem, rem, 0); + else + return new DirectByteBufferImpl.ReadWrite + (owner, VMDirectByteBuffer.adjustAddress(address, position()), + rem, rem, 0); + } + + private ByteBuffer duplicate(boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + DirectByteBufferImpl result; + if (readOnly) + result = new DirectByteBufferImpl.ReadOnly(owner, address, capacity(), + limit(), pos); + else + result = new DirectByteBufferImpl.ReadWrite(owner, address, capacity(), + limit(), pos); + + if (mark != pos) + { + result.position(mark); + result.mark(); + result.position(pos); + } + return result; + } + + public ByteBuffer duplicate() + { + return duplicate(isReadOnly()); + } + + public ByteBuffer asReadOnlyBuffer() + { + return duplicate(true); + } + + public boolean isDirect() + { + return true; + } + + public CharBuffer asCharBuffer() + { + return new CharViewBufferImpl(this, remaining() >> 1); + } + + public ShortBuffer asShortBuffer() + { + return new ShortViewBufferImpl(this, remaining() >> 1); + } + + public IntBuffer asIntBuffer() + { + return new IntViewBufferImpl(this, remaining() >> 2); + } + + public LongBuffer asLongBuffer() + { + return new LongViewBufferImpl(this, remaining() >> 3); + } + + public FloatBuffer asFloatBuffer() + { + return new FloatViewBufferImpl(this, remaining() >> 2); + } + + public DoubleBuffer asDoubleBuffer() + { + return new DoubleViewBufferImpl(this, remaining() >> 3); + } + + public char getChar() + { + return ByteBufferHelper.getChar(this, order()); + } + + public ByteBuffer putChar(char value) + { + ByteBufferHelper.putChar(this, value, order()); + return this; + } + + public char getChar(int index) + { + return ByteBufferHelper.getChar(this, index, order()); + } + + public ByteBuffer putChar(int index, char value) + { + ByteBufferHelper.putChar(this, index, value, order()); + return this; + } + + public short getShort() + { + return ByteBufferHelper.getShort(this, order()); + } + + public ByteBuffer putShort(short value) + { + ByteBufferHelper.putShort(this, value, order()); + return this; + } + + public short getShort(int index) + { + return ByteBufferHelper.getShort(this, index, order()); + } + + public ByteBuffer putShort(int index, short value) + { + ByteBufferHelper.putShort(this, index, value, order()); + return this; + } + + public int getInt() + { + return ByteBufferHelper.getInt(this, order()); + } + + public ByteBuffer putInt(int value) + { + ByteBufferHelper.putInt(this, value, order()); + return this; + } + + public int getInt(int index) + { + return ByteBufferHelper.getInt(this, index, order()); + } + + public ByteBuffer putInt(int index, int value) + { + ByteBufferHelper.putInt(this, index, value, order()); + return this; + } + + public long getLong() + { + return ByteBufferHelper.getLong(this, order()); + } + + public ByteBuffer putLong(long value) + { + ByteBufferHelper.putLong(this, value, order()); + return this; + } + + public long getLong(int index) + { + return ByteBufferHelper.getLong(this, index, order()); + } + + public ByteBuffer putLong(int index, long value) + { + ByteBufferHelper.putLong(this, index, value, order()); + return this; + } + + public float getFloat() + { + return ByteBufferHelper.getFloat(this, order()); + } + + public ByteBuffer putFloat(float value) + { + ByteBufferHelper.putFloat(this, value, order()); + return this; + } + + public float getFloat(int index) + { + return ByteBufferHelper.getFloat(this, index, order()); + } + + public ByteBuffer putFloat(int index, float value) + { + ByteBufferHelper.putFloat(this, index, value, order()); + return this; + } + + public double getDouble() + { + return ByteBufferHelper.getDouble(this, order()); + } + + public ByteBuffer putDouble(double value) + { + ByteBufferHelper.putDouble(this, value, order()); + return this; + } + + public double getDouble(int index) + { + return ByteBufferHelper.getDouble(this, index, order()); + } + + public ByteBuffer putDouble(int index, double value) + { + ByteBufferHelper.putDouble(this, index, value, order()); + return this; + } +} diff --git a/libjava/classpath/java/nio/DoubleBuffer.java b/libjava/classpath/java/nio/DoubleBuffer.java new file mode 100644 index 0000000..381bb71 --- /dev/null +++ b/libjava/classpath/java/nio/DoubleBuffer.java @@ -0,0 +1,383 @@ +/* DoubleBuffer.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 java.nio; + +/** + * @since 1.4 + */ +public abstract class DoubleBuffer extends Buffer + implements Comparable +{ + int array_offset; + double[] backing_buffer; + + DoubleBuffer (int capacity, int limit, int position, int mark) + { + super (capacity, limit, position, mark); + array_offset = 0; + } + + /** + * Allocates a new DoubleBuffer object with a given capacity. + */ + public static DoubleBuffer allocate (int capacity) + { + return new DoubleBufferImpl (capacity); + } + + /** + * Wraps a double array into a DoubleBuffer + * object. + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + public static final DoubleBuffer wrap (double[] array, int offset, int length) + { + return new DoubleBufferImpl (array, 0, array.length, offset + length, offset, -1, false); + } + + /** + * Wraps a double array into a DoubleBuffer + * object. + */ + public static final DoubleBuffer wrap (double[] array) + { + return wrap (array, 0, array.length); + } + + /** + * This method transfers doubles from this buffer into the given + * destination array. Before the transfer, it checks if there are fewer than + * length doubles remaining in this buffer. + * + * @param dst The destination array + * @param offset The offset within the array of the first double + * to be written; must be non-negative and no larger than dst.length. + * @param length The maximum number of bytes to be written to the given array; + * must be non-negative and no larger than dst.length - offset. + * + * @exception BufferUnderflowException If there are fewer than length + * doubles remaining in this buffer. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold. + */ + public DoubleBuffer get (double[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + for (int i = offset; i < offset + length; i++) + { + dst [i] = get (); + } + + return this; + } + + /** + * This method transfers doubles from this buffer into the given + * destination array. + * + * @param dst The byte array to write into. + * + * @exception BufferUnderflowException If there are fewer than dst.length + * doubles remaining in this buffer. + */ + public DoubleBuffer get (double[] dst) + { + return get (dst, 0, dst.length); + } + + /** + * Writes the content of the the DoubleBUFFER src + * into the buffer. Before the transfer, it checks if there is fewer than + * src.remaining() space remaining in this buffer. + * + * @param src The source data. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining doubles in the source buffer. + * @exception IllegalArgumentException If the source buffer is this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public DoubleBuffer put (DoubleBuffer src) + { + if (src == this) + throw new IllegalArgumentException (); + + checkForOverflow(src.remaining ()); + + if (src.remaining () > 0) + { + double[] toPut = new double [src.remaining ()]; + src.get (toPut); + put (toPut); + } + + return this; + } + + /** + * Writes the content of the the double array src + * into the buffer. Before the transfer, it checks if there is fewer than + * length space remaining in this buffer. + * + * @param src The array to copy into the buffer. + * @param offset The offset within the array of the first byte to be read; + * must be non-negative and no larger than src.length. + * @param length The number of bytes to be read from the given array; + * must be non-negative and no larger than src.length - offset. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining doubles in the source array. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public DoubleBuffer put (double[] src, int offset, int length) + { + checkArraySize(src.length, offset, length); + checkForOverflow(length); + + for (int i = offset; i < offset + length; i++) + put (src [i]); + + return this; + } + + /** + * Writes the content of the the double array src + * into the buffer. + * + * @param src The array to copy into the buffer. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining doubles in the source array. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public final DoubleBuffer put (double[] src) + { + return put (src, 0, src.length); + } + + /** + * Tells whether ot not this buffer is backed by an accessible + * double array. + */ + public final boolean hasArray () + { + return (backing_buffer != null + && !isReadOnly ()); + } + + /** + * Returns the double array that backs this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final double[] array () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return backing_buffer; + } + + /** + * Returns the offset within this buffer's backing array of the first element. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final int arrayOffset () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return array_offset; + } + + /** + * Calculates a hash code for this buffer. + * + * This is done with long arithmetic, + * where ** represents exponentiation, by this formula:
    + * s[position()] + 31 + (s[position()+1] + 30)*31**1 + ... + + * (s[limit()-1]+30)*31**(limit()-1). + * Where s is the buffer data, in Double.doubleToLongBits() form + * Note that the hashcode is dependent on buffer content, + * and therefore is not useful if the buffer content may change. + * + * @return the hash code (casted to int) + */ + public int hashCode () + { + long hashCode = Double.doubleToLongBits(get(position())) + 31; + long multiplier = 1; + for (int i = position() + 1; i < limit(); ++i) + { + multiplier *= 31; + hashCode += (Double.doubleToLongBits(get(i)) + 30)*multiplier; + } + return ((int)hashCode); + } + + /** + * Checks if this buffer is equal to obj. + */ + public boolean equals (Object obj) + { + if (obj instanceof DoubleBuffer) + { + return compareTo (obj) == 0; + } + + return false; + } + + /** + * Compares two DoubleBuffer objects. + * + * @exception ClassCastException If obj is not an object derived from + * DoubleBuffer. + */ + public int compareTo (Object obj) + { + DoubleBuffer other = (DoubleBuffer) obj; + + int num = Math.min(remaining(), other.remaining()); + int pos_this = position(); + int pos_other = other.position(); + + for (int count = 0; count < num; count++) + { + double a = get(pos_this++); + double b = other.get(pos_other++); + + if (a == b) + continue; + + if (a < b) + return -1; + + return 1; + } + + return remaining() - other.remaining(); + } + + /** + * Returns the byte order of this buffer. + */ + public abstract ByteOrder order (); + + /** + * Reads the double at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * doubles in this buffer. + */ + public abstract double get (); + + /** + * Writes the double at this buffer's current position, + * and then increments the position. + * + * @exception BufferOverflowException If there no remaining + * doubles in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract DoubleBuffer put (double b); + + /** + * Absolute get method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public abstract double get (int index); + + /** + * Absolute put method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract DoubleBuffer put (int index, double b); + + /** + * Compacts this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract DoubleBuffer compact (); + + /** + * Tells wether or not this buffer is direct. + */ + public abstract boolean isDirect (); + + /** + * Creates a new DoubleBuffer whose content is a shared + * subsequence of this buffer's content. + */ + public abstract DoubleBuffer slice (); + + /** + * Creates a new DoubleBuffer that shares this buffer's + * content. + */ + public abstract DoubleBuffer duplicate (); + + /** + * Creates a new read-only DoubleBuffer that shares this + * buffer's content. + */ + public abstract DoubleBuffer asReadOnlyBuffer (); +} diff --git a/libjava/classpath/java/nio/DoubleBufferImpl.java b/libjava/classpath/java/nio/DoubleBufferImpl.java new file mode 100644 index 0000000..248ab45e --- /dev/null +++ b/libjava/classpath/java/nio/DoubleBufferImpl.java @@ -0,0 +1,172 @@ +/* DoubleBufferImpl.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 java.nio; + +/** + * This is a Heap memory implementation + */ +final class DoubleBufferImpl extends DoubleBuffer +{ + private boolean readOnly; + + DoubleBufferImpl (int capacity) + { + this (new double [capacity], 0, capacity, capacity, 0, -1, false); + } + + DoubleBufferImpl (double[] buffer, int offset, int capacity, int limit, int position, int mark, boolean readOnly) + { + super (capacity, limit, position, mark); + this.backing_buffer = buffer; + this.array_offset = offset; + this.readOnly = readOnly; + } + + public boolean isReadOnly () + { + return readOnly; + } + + public DoubleBuffer slice () + { + return new DoubleBufferImpl (backing_buffer, array_offset + position (), remaining (), remaining (), 0, -1, isReadOnly ()); + } + + public DoubleBuffer duplicate () + { + return new DoubleBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, isReadOnly ()); + } + + public DoubleBuffer asReadOnlyBuffer () + { + return new DoubleBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, true); + } + + public DoubleBuffer compact () + { + checkIfReadOnly(); + mark = -1; + int copied = 0; + + while (remaining () > 0) + { + put (copied, get ()); + copied++; + } + + position (copied); + limit(capacity()); + return this; + } + + public boolean isDirect () + { + return false; + } + + /** + * Reads the double at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * doubles in this buffer. + */ + public double get () + { + checkForUnderflow(); + + double result = backing_buffer [position ()]; + position (position () + 1); + return result; + } + + /** + * Relative put method. Writes value to the next position + * in the buffer. + * + * @exception BufferOverflowException If there no remaining + * space in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public DoubleBuffer put (double value) + { + checkIfReadOnly(); + checkForOverflow(); + + backing_buffer [position ()] = value; + position (position () + 1); + return this; + } + + /** + * Absolute get method. Reads the double at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public double get (int index) + { + checkIndex(index); + + return backing_buffer [index]; + } + + /** + * Absolute put method. Writes value to position + * index in the buffer. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public DoubleBuffer put (int index, double value) + { + checkIfReadOnly(); + checkIndex(index); + + backing_buffer [index] = value; + return this; + } + + public ByteOrder order () + { + return ByteOrder.nativeOrder (); + } +} diff --git a/libjava/classpath/java/nio/DoubleViewBufferImpl.java b/libjava/classpath/java/nio/DoubleViewBufferImpl.java new file mode 100644 index 0000000..e860f2f --- /dev/null +++ b/libjava/classpath/java/nio/DoubleViewBufferImpl.java @@ -0,0 +1,172 @@ +/* DoubleViewBufferImpl.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 java.nio; + +final class DoubleViewBufferImpl extends DoubleBuffer +{ + /** Position in bb (i.e. a byte offset) where this buffer starts. */ + private int offset; + private ByteBuffer bb; + private boolean readOnly; + private ByteOrder endian; + + DoubleViewBufferImpl (ByteBuffer bb, int capacity) + { + super (capacity, capacity, 0, -1); + this.bb = bb; + this.offset = bb.position(); + this.readOnly = bb.isReadOnly(); + this.endian = bb.order(); + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + public DoubleViewBufferImpl (ByteBuffer bb, int offset, int capacity, + int limit, int position, int mark, + boolean readOnly, ByteOrder endian) + { + super (capacity, limit, position, mark); + this.bb = bb; + this.offset = offset; + this.readOnly = readOnly; + this.endian = endian; + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + /** + * Reads the double at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * doubles in this buffer. + */ + public double get () + { + int p = position(); + double result = ByteBufferHelper.getDouble(bb, (p << 3) + offset, endian); + position(p + 1); + return result; + } + + /** + * Absolute get method. Reads the double at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public double get (int index) + { + return ByteBufferHelper.getDouble(bb, (index << 3) + offset, endian); + } + + public DoubleBuffer put (double value) + { + int p = position(); + ByteBufferHelper.putDouble(bb, (p << 3) + offset, value, endian); + position(p + 1); + return this; + } + + public DoubleBuffer put (int index, double value) + { + ByteBufferHelper.putDouble(bb, (index << 3) + offset, value, endian); + return this; + } + + public DoubleBuffer compact () + { + if (position () > 0) + { + int count = limit () - position (); + bb.shiftDown(offset, offset + 8 * position(), 8 * count); + position (count); + limit (capacity ()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public DoubleBuffer slice () + { + return new DoubleViewBufferImpl (bb, (position () >> 3) + offset, + remaining(), remaining(), 0, -1, + readOnly, endian); + } + + DoubleBuffer duplicate (boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + return new DoubleViewBufferImpl (bb, offset, capacity(), limit(), + pos, mark, readOnly, endian); + } + + public DoubleBuffer duplicate () + { + return duplicate(readOnly); + } + + public DoubleBuffer asReadOnlyBuffer () + { + return duplicate(true); + } + + public boolean isReadOnly () + { + return readOnly; + } + + public boolean isDirect () + { + return bb.isDirect (); + } + + public ByteOrder order () + { + return endian; + } +} diff --git a/libjava/classpath/java/nio/FloatBuffer.java b/libjava/classpath/java/nio/FloatBuffer.java new file mode 100644 index 0000000..8042333 --- /dev/null +++ b/libjava/classpath/java/nio/FloatBuffer.java @@ -0,0 +1,383 @@ +/* FloatBuffer.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 java.nio; + +/** + * @since 1.4 + */ +public abstract class FloatBuffer extends Buffer + implements Comparable +{ + int array_offset; + float[] backing_buffer; + + FloatBuffer (int capacity, int limit, int position, int mark) + { + super (capacity, limit, position, mark); + array_offset = 0; + } + + /** + * Allocates a new FloatBuffer object with a given capacity. + */ + public static FloatBuffer allocate (int capacity) + { + return new FloatBufferImpl (capacity); + } + + /** + * Wraps a float array into a FloatBuffer + * object. + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + public static final FloatBuffer wrap (float[] array, int offset, int length) + { + return new FloatBufferImpl (array, 0, array.length, offset + length, offset, -1, false); + } + + /** + * Wraps a float array into a FloatBuffer + * object. + */ + public static final FloatBuffer wrap (float[] array) + { + return wrap (array, 0, array.length); + } + + /** + * This method transfers floats from this buffer into the given + * destination array. Before the transfer, it checks if there are fewer than + * length floats remaining in this buffer. + * + * @param dst The destination array + * @param offset The offset within the array of the first float + * to be written; must be non-negative and no larger than dst.length. + * @param length The maximum number of bytes to be written to the given array; + * must be non-negative and no larger than dst.length - offset. + * + * @exception BufferUnderflowException If there are fewer than length + * floats remaining in this buffer. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold. + */ + public FloatBuffer get (float[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + for (int i = offset; i < offset + length; i++) + { + dst [i] = get (); + } + + return this; + } + + /** + * This method transfers floats from this buffer into the given + * destination array. + * + * @param dst The byte array to write into. + * + * @exception BufferUnderflowException If there are fewer than dst.length + * floats remaining in this buffer. + */ + public FloatBuffer get (float[] dst) + { + return get (dst, 0, dst.length); + } + + /** + * Writes the content of the the FloatBUFFER src + * into the buffer. Before the transfer, it checks if there is fewer than + * src.remaining() space remaining in this buffer. + * + * @param src The source data. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining floats in the source buffer. + * @exception IllegalArgumentException If the source buffer is this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public FloatBuffer put (FloatBuffer src) + { + if (src == this) + throw new IllegalArgumentException (); + + checkForOverflow(src.remaining()); + + if (src.remaining () > 0) + { + float[] toPut = new float [src.remaining ()]; + src.get (toPut); + put (toPut); + } + + return this; + } + + /** + * Writes the content of the the float array src + * into the buffer. Before the transfer, it checks if there is fewer than + * length space remaining in this buffer. + * + * @param src The array to copy into the buffer. + * @param offset The offset within the array of the first byte to be read; + * must be non-negative and no larger than src.length. + * @param length The number of bytes to be read from the given array; + * must be non-negative and no larger than src.length - offset. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining floats in the source array. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public FloatBuffer put (float[] src, int offset, int length) + { + checkArraySize(src.length, offset, length); + checkForOverflow(length); + + for (int i = offset; i < offset + length; i++) + put (src [i]); + + return this; + } + + /** + * Writes the content of the the float array src + * into the buffer. + * + * @param src The array to copy into the buffer. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining floats in the source array. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public final FloatBuffer put (float[] src) + { + return put (src, 0, src.length); + } + + /** + * Tells whether ot not this buffer is backed by an accessible + * float array. + */ + public final boolean hasArray () + { + return (backing_buffer != null + && !isReadOnly ()); + } + + /** + * Returns the float array that backs this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final float[] array () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return backing_buffer; + } + + /** + * Returns the offset within this buffer's backing array of the first element. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final int arrayOffset () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return array_offset; + } + + /** + * Calculates a hash code for this buffer. + * + * This is done with int arithmetic, + * where ** represents exponentiation, by this formula:
    + * s[position()] + 31 + (s[position()+1] + 30)*31**1 + ... + + * (s[limit()-1]+30)*31**(limit()-1). + * Where s is the buffer data, in Float.floatToIntBits() form + * Note that the hashcode is dependent on buffer content, + * and therefore is not useful if the buffer content may change. + * + * @return the hash code + */ + public int hashCode () + { + int hashCode = Float.floatToIntBits(get(position())) + 31; + int multiplier = 1; + for (int i = position() + 1; i < limit(); ++i) + { + multiplier *= 31; + hashCode += (Float.floatToIntBits(get(i)) + 30)*multiplier; + } + return hashCode; + } + + /** + * Checks if this buffer is equal to obj. + */ + public boolean equals (Object obj) + { + if (obj instanceof FloatBuffer) + { + return compareTo (obj) == 0; + } + + return false; + } + + /** + * Compares two FloatBuffer objects. + * + * @exception ClassCastException If obj is not an object derived from + * FloatBuffer. + */ + public int compareTo (Object obj) + { + FloatBuffer other = (FloatBuffer) obj; + + int num = Math.min(remaining(), other.remaining()); + int pos_this = position(); + int pos_other = other.position(); + + for (int count = 0; count < num; count++) + { + float a = get(pos_this++); + float b = other.get(pos_other++); + + if (a == b) + continue; + + if (a < b) + return -1; + + return 1; + } + + return remaining() - other.remaining(); + } + + /** + * Returns the byte order of this buffer. + */ + public abstract ByteOrder order (); + + /** + * Reads the float at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * floats in this buffer. + */ + public abstract float get (); + + /** + * Writes the float at this buffer's current position, + * and then increments the position. + * + * @exception BufferOverflowException If there no remaining + * floats in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract FloatBuffer put (float b); + + /** + * Absolute get method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public abstract float get (int index); + + /** + * Absolute put method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract FloatBuffer put (int index, float b); + + /** + * Compacts this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract FloatBuffer compact (); + + /** + * Tells wether or not this buffer is direct. + */ + public abstract boolean isDirect (); + + /** + * Creates a new FloatBuffer whose content is a shared + * subsequence of this buffer's content. + */ + public abstract FloatBuffer slice (); + + /** + * Creates a new FloatBuffer that shares this buffer's + * content. + */ + public abstract FloatBuffer duplicate (); + + /** + * Creates a new read-only FloatBuffer that shares this + * buffer's content. + */ + public abstract FloatBuffer asReadOnlyBuffer (); +} diff --git a/libjava/classpath/java/nio/FloatBufferImpl.java b/libjava/classpath/java/nio/FloatBufferImpl.java new file mode 100644 index 0000000..b486878 --- /dev/null +++ b/libjava/classpath/java/nio/FloatBufferImpl.java @@ -0,0 +1,172 @@ +/* FloatBufferImpl.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 java.nio; + +/** + * This is a Heap memory implementation + */ +final class FloatBufferImpl extends FloatBuffer +{ + private boolean readOnly; + + FloatBufferImpl (int capacity) + { + this (new float [capacity], 0, capacity, capacity, 0, -1, false); + } + + FloatBufferImpl (float[] buffer, int offset, int capacity, int limit, int position, int mark, boolean readOnly) + { + super (capacity, limit, position, mark); + this.backing_buffer = buffer; + this.array_offset = offset; + this.readOnly = readOnly; + } + + public boolean isReadOnly () + { + return readOnly; + } + + public FloatBuffer slice () + { + return new FloatBufferImpl (backing_buffer, array_offset + position (), remaining (), remaining (), 0, -1, isReadOnly ()); + } + + public FloatBuffer duplicate () + { + return new FloatBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, isReadOnly ()); + } + + public FloatBuffer asReadOnlyBuffer () + { + return new FloatBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, true); + } + + public FloatBuffer compact () + { + checkIfReadOnly(); + mark = -1; + int copied = 0; + + while (remaining () > 0) + { + put (copied, get ()); + copied++; + } + + position (copied); + limit(capacity()); + return this; + } + + public boolean isDirect () + { + return false; + } + + /** + * Reads the float at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * floats in this buffer. + */ + public float get () + { + checkForUnderflow(); + + float result = backing_buffer [position ()]; + position (position () + 1); + return result; + } + + /** + * Relative put method. Writes value to the next position + * in the buffer. + * + * @exception BufferOverflowException If there no remaining + * space in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public FloatBuffer put (float value) + { + checkIfReadOnly(); + checkForOverflow(); + + backing_buffer [position ()] = value; + position (position () + 1); + return this; + } + + /** + * Absolute get method. Reads the float at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public float get (int index) + { + checkIndex(index); + + return backing_buffer [index]; + } + + /** + * Absolute put method. Writes value to position + * index in the buffer. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public FloatBuffer put (int index, float value) + { + checkIfReadOnly(); + checkIndex(index); + + backing_buffer [index] = value; + return this; + } + + public ByteOrder order () + { + return ByteOrder.nativeOrder (); + } +} diff --git a/libjava/classpath/java/nio/FloatViewBufferImpl.java b/libjava/classpath/java/nio/FloatViewBufferImpl.java new file mode 100644 index 0000000..55770d5 --- /dev/null +++ b/libjava/classpath/java/nio/FloatViewBufferImpl.java @@ -0,0 +1,173 @@ +/* FloatViewBufferImpl.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 java.nio; + +final class FloatViewBufferImpl extends FloatBuffer +{ + /** Position in bb (i.e. a byte offset) where this buffer starts. */ + private int offset; + private ByteBuffer bb; + private boolean readOnly; + private ByteOrder endian; + + FloatViewBufferImpl (ByteBuffer bb, int capacity) + { + super (capacity, capacity, 0, -1); + this.bb = bb; + this.offset = bb.position(); + this.readOnly = bb.isReadOnly(); + this.endian = bb.order(); + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + public FloatViewBufferImpl (ByteBuffer bb, int offset, int capacity, + int limit, int position, int mark, + boolean readOnly, ByteOrder endian) + { + super (capacity, limit, position, mark); + this.bb = bb; + this.offset = offset; + this.readOnly = readOnly; + this.endian = endian; + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + /** + * Reads the float at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * floats in this buffer. + */ + public float get () + { + int p = position(); + float result = ByteBufferHelper.getFloat(bb, (p << 2) + offset, endian); + position(p + 1); + return result; + } + + /** + * Absolute get method. Reads the float at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public float get (int index) + { + return ByteBufferHelper.getFloat(bb, (index << 2) + offset, endian); + } + + public FloatBuffer put (float value) + { + int p = position(); + ByteBufferHelper.putFloat(bb, (p << 2) + offset, value, endian); + position(p + 1); + return this; + } + + public FloatBuffer put (int index, float value) + { + ByteBufferHelper.putFloat(bb, (index << 2) + offset, value, endian); + return this; + } + + public FloatBuffer compact () + { + if (position () > 0) + { + int count = limit () - position (); + bb.shiftDown(offset, offset + 4 * position(), 4 * count); + position (count); + limit (capacity ()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public FloatBuffer slice () + { + // Create a sliced copy of this object that shares its content. + return new FloatViewBufferImpl (bb, (position () >> 2) + offset, + remaining(), remaining(), 0, -1, + readOnly, endian); + } + + FloatBuffer duplicate (boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + return new FloatViewBufferImpl (bb, offset, capacity(), limit(), + pos, mark, readOnly, endian); + } + + public FloatBuffer duplicate () + { + return duplicate(readOnly); + } + + public FloatBuffer asReadOnlyBuffer () + { + return duplicate(true); + } + + public boolean isReadOnly () + { + return readOnly; + } + + public boolean isDirect () + { + return bb.isDirect (); + } + + public ByteOrder order () + { + return endian; + } +} diff --git a/libjava/classpath/java/nio/IntBuffer.java b/libjava/classpath/java/nio/IntBuffer.java new file mode 100644 index 0000000..1e1fe9c --- /dev/null +++ b/libjava/classpath/java/nio/IntBuffer.java @@ -0,0 +1,383 @@ +/* IntBuffer.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 java.nio; + +/** + * @since 1.4 + */ +public abstract class IntBuffer extends Buffer + implements Comparable +{ + int array_offset; + int[] backing_buffer; + + IntBuffer (int capacity, int limit, int position, int mark) + { + super (capacity, limit, position, mark); + array_offset = 0; + } + + /** + * Allocates a new IntBuffer object with a given capacity. + */ + public static IntBuffer allocate (int capacity) + { + return new IntBufferImpl (capacity); + } + + /** + * Wraps a int array into a IntBuffer + * object. + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + public static final IntBuffer wrap (int[] array, int offset, int length) + { + return new IntBufferImpl (array, 0, array.length, offset + length, offset, -1, false); + } + + /** + * Wraps a int array into a IntBuffer + * object. + */ + public static final IntBuffer wrap (int[] array) + { + return wrap (array, 0, array.length); + } + + /** + * This method transfers ints from this buffer into the given + * destination array. Before the transfer, it checks if there are fewer than + * length ints remaining in this buffer. + * + * @param dst The destination array + * @param offset The offset within the array of the first int + * to be written; must be non-negative and no larger than dst.length. + * @param length The maximum number of bytes to be written to the given array; + * must be non-negative and no larger than dst.length - offset. + * + * @exception BufferUnderflowException If there are fewer than length + * ints remaining in this buffer. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold. + */ + public IntBuffer get (int[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + for (int i = offset; i < offset + length; i++) + { + dst [i] = get (); + } + + return this; + } + + /** + * This method transfers ints from this buffer into the given + * destination array. + * + * @param dst The byte array to write into. + * + * @exception BufferUnderflowException If there are fewer than dst.length + * ints remaining in this buffer. + */ + public IntBuffer get (int[] dst) + { + return get (dst, 0, dst.length); + } + + /** + * Writes the content of the the IntBUFFER src + * into the buffer. Before the transfer, it checks if there is fewer than + * src.remaining() space remaining in this buffer. + * + * @param src The source data. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining ints in the source buffer. + * @exception IllegalArgumentException If the source buffer is this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public IntBuffer put (IntBuffer src) + { + if (src == this) + throw new IllegalArgumentException (); + + checkForOverflow(src.remaining ()); + + if (src.remaining () > 0) + { + int[] toPut = new int [src.remaining ()]; + src.get (toPut); + put (toPut); + } + + return this; + } + + /** + * Writes the content of the the int array src + * into the buffer. Before the transfer, it checks if there is fewer than + * length space remaining in this buffer. + * + * @param src The array to copy into the buffer. + * @param offset The offset within the array of the first byte to be read; + * must be non-negative and no larger than src.length. + * @param length The number of bytes to be read from the given array; + * must be non-negative and no larger than src.length - offset. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining ints in the source array. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public IntBuffer put (int[] src, int offset, int length) + { + checkArraySize(src.length, offset, length); + checkForOverflow(length); + + for (int i = offset; i < offset + length; i++) + put (src [i]); + + return this; + } + + /** + * Writes the content of the the int array src + * into the buffer. + * + * @param src The array to copy into the buffer. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining ints in the source array. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public final IntBuffer put (int[] src) + { + return put (src, 0, src.length); + } + + /** + * Tells whether ot not this buffer is backed by an accessible + * int array. + */ + public final boolean hasArray () + { + return (backing_buffer != null + && !isReadOnly ()); + } + + /** + * Returns the int array that backs this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final int[] array () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return backing_buffer; + } + + /** + * Returns the offset within this buffer's backing array of the first element. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final int arrayOffset () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return array_offset; + } + + /** + * Calculates a hash code for this buffer. + * + * This is done with int arithmetic, + * where ** represents exponentiation, by this formula:
    + * s[position()] + 31 + (s[position()+1] + 30)*31**1 + ... + + * (s[limit()-1]+30)*31**(limit()-1). + * Where s is the buffer data. Note that the hashcode is dependent + * on buffer content, and therefore is not useful if the buffer + * content may change. + * + * @return the hash code + */ + public int hashCode () + { + int hashCode = get(position()) + 31; + int multiplier = 1; + for (int i = position() + 1; i < limit(); ++i) + { + multiplier *= 31; + hashCode += (get(i) + 30)*multiplier; + } + return hashCode; + } + + /** + * Checks if this buffer is equal to obj. + */ + public boolean equals (Object obj) + { + if (obj instanceof IntBuffer) + { + return compareTo (obj) == 0; + } + + return false; + } + + /** + * Compares two IntBuffer objects. + * + * @exception ClassCastException If obj is not an object derived from + * IntBuffer. + */ + public int compareTo (Object obj) + { + IntBuffer other = (IntBuffer) obj; + + int num = Math.min(remaining(), other.remaining()); + int pos_this = position(); + int pos_other = other.position(); + + for (int count = 0; count < num; count++) + { + int a = get(pos_this++); + int b = other.get(pos_other++); + + if (a == b) + continue; + + if (a < b) + return -1; + + return 1; + } + + return remaining() - other.remaining(); + } + + /** + * Returns the byte order of this buffer. + */ + public abstract ByteOrder order (); + + /** + * Reads the int at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * ints in this buffer. + */ + public abstract int get (); + + /** + * Writes the int at this buffer's current position, + * and then increments the position. + * + * @exception BufferOverflowException If there no remaining + * ints in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract IntBuffer put (int b); + + /** + * Absolute get method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public abstract int get (int index); + + /** + * Absolute put method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract IntBuffer put (int index, int b); + + /** + * Compacts this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract IntBuffer compact (); + + /** + * Tells wether or not this buffer is direct. + */ + public abstract boolean isDirect (); + + /** + * Creates a new IntBuffer whose content is a shared + * subsequence of this buffer's content. + */ + public abstract IntBuffer slice (); + + /** + * Creates a new IntBuffer that shares this buffer's + * content. + */ + public abstract IntBuffer duplicate (); + + /** + * Creates a new read-only IntBuffer that shares this + * buffer's content. + */ + public abstract IntBuffer asReadOnlyBuffer (); +} diff --git a/libjava/classpath/java/nio/IntBufferImpl.java b/libjava/classpath/java/nio/IntBufferImpl.java new file mode 100644 index 0000000..2265748 --- /dev/null +++ b/libjava/classpath/java/nio/IntBufferImpl.java @@ -0,0 +1,172 @@ +/* IntBufferImpl.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 java.nio; + +/** + * This is a Heap memory implementation + */ +final class IntBufferImpl extends IntBuffer +{ + private boolean readOnly; + + IntBufferImpl (int capacity) + { + this (new int [capacity], 0, capacity, capacity, 0, -1, false); + } + + IntBufferImpl (int[] buffer, int offset, int capacity, int limit, int position, int mark, boolean readOnly) + { + super (capacity, limit, position, mark); + this.backing_buffer = buffer; + this.array_offset = offset; + this.readOnly = readOnly; + } + + public boolean isReadOnly () + { + return readOnly; + } + + public IntBuffer slice () + { + return new IntBufferImpl (backing_buffer, array_offset + position (), remaining (), remaining (), 0, -1, isReadOnly ()); + } + + public IntBuffer duplicate () + { + return new IntBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, isReadOnly ()); + } + + public IntBuffer asReadOnlyBuffer () + { + return new IntBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, true); + } + + public IntBuffer compact () + { + checkIfReadOnly(); + mark = -1; + int copied = 0; + + while (remaining () > 0) + { + put (copied, get ()); + copied++; + } + + position (copied); + limit(capacity()); + return this; + } + + public boolean isDirect () + { + return false; + } + + /** + * Reads the int at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * ints in this buffer. + */ + public int get () + { + checkForUnderflow(); + + int result = backing_buffer [position ()]; + position (position () + 1); + return result; + } + + /** + * Relative put method. Writes value to the next position + * in the buffer. + * + * @exception BufferOverflowException If there no remaining + * space in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public IntBuffer put (int value) + { + checkIfReadOnly(); + checkForOverflow(); + + backing_buffer [position ()] = value; + position (position () + 1); + return this; + } + + /** + * Absolute get method. Reads the int at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public int get (int index) + { + checkIndex(index); + + return backing_buffer [index]; + } + + /** + * Absolute put method. Writes value to position + * index in the buffer. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public IntBuffer put (int index, int value) + { + checkIfReadOnly(); + checkIndex(index); + + backing_buffer [index] = value; + return this; + } + + public ByteOrder order () + { + return ByteOrder.nativeOrder (); + } +} diff --git a/libjava/classpath/java/nio/IntViewBufferImpl.java b/libjava/classpath/java/nio/IntViewBufferImpl.java new file mode 100644 index 0000000..d0b0057 --- /dev/null +++ b/libjava/classpath/java/nio/IntViewBufferImpl.java @@ -0,0 +1,173 @@ +/* IntViewBufferImpl.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 java.nio; + +final class IntViewBufferImpl extends IntBuffer +{ + /** Position in bb (i.e. a byte offset) where this buffer starts. */ + private int offset; + private ByteBuffer bb; + private boolean readOnly; + private ByteOrder endian; + + IntViewBufferImpl (ByteBuffer bb, int capacity) + { + super (capacity, capacity, 0, -1); + this.bb = bb; + this.offset = bb.position(); + this.readOnly = bb.isReadOnly(); + this.endian = bb.order(); + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + public IntViewBufferImpl (ByteBuffer bb, int offset, int capacity, + int limit, int position, int mark, + boolean readOnly, ByteOrder endian) + { + super (capacity, limit, position, mark); + this.bb = bb; + this.offset = offset; + this.readOnly = readOnly; + this.endian = endian; + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + /** + * Reads the int at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * ints in this buffer. + */ + public int get () + { + int p = position(); + int result = ByteBufferHelper.getInt(bb, (p << 2) + offset, endian); + position(p + 1); + return result; + } + + /** + * Absolute get method. Reads the int at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public int get (int index) + { + return ByteBufferHelper.getInt(bb, (index << 2) + offset, endian); + } + + public IntBuffer put (int value) + { + int p = position(); + ByteBufferHelper.putInt(bb, (p << 2) + offset, value, endian); + position(p + 1); + return this; + } + + public IntBuffer put (int index, int value) + { + ByteBufferHelper.putInt(bb, (index << 2) + offset, value, endian); + return this; + } + + public IntBuffer compact () + { + if (position () > 0) + { + int count = limit () - position (); + bb.shiftDown(offset, offset + 4 * position(), 4 * count); + position (count); + limit (capacity ()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public IntBuffer slice () + { + // Create a sliced copy of this object that shares its content. + return new IntViewBufferImpl (bb, (position () >> 2) + offset, + remaining(), remaining(), 0, -1, + readOnly, endian); + } + + IntBuffer duplicate (boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + return new IntViewBufferImpl (bb, offset, capacity(), limit(), + pos, mark, readOnly, endian); + } + + public IntBuffer duplicate () + { + return duplicate(readOnly); + } + + public IntBuffer asReadOnlyBuffer () + { + return duplicate(true); + } + + public boolean isReadOnly () + { + return readOnly; + } + + public boolean isDirect () + { + return bb.isDirect (); + } + + public ByteOrder order () + { + return endian; + } +} diff --git a/libjava/classpath/java/nio/InvalidMarkException.java b/libjava/classpath/java/nio/InvalidMarkException.java new file mode 100644 index 0000000..937d417 --- /dev/null +++ b/libjava/classpath/java/nio/InvalidMarkException.java @@ -0,0 +1,52 @@ +/* InvalidMarkException.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 java.nio; + +/** + * @author Michael Koch + * @since 1.4 + */ +public class InvalidMarkException extends IllegalStateException +{ + /** + * Creates the exception + */ + public InvalidMarkException () + { + } +} diff --git a/libjava/classpath/java/nio/LongBuffer.java b/libjava/classpath/java/nio/LongBuffer.java new file mode 100644 index 0000000..b3d3557 --- /dev/null +++ b/libjava/classpath/java/nio/LongBuffer.java @@ -0,0 +1,383 @@ +/* LongBuffer.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 java.nio; + +/** + * @since 1.4 + */ +public abstract class LongBuffer extends Buffer + implements Comparable +{ + int array_offset; + long[] backing_buffer; + + LongBuffer (int capacity, int limit, int position, int mark) + { + super (capacity, limit, position, mark); + array_offset = 0; + } + + /** + * Allocates a new LongBuffer object with a given capacity. + */ + public static LongBuffer allocate (int capacity) + { + return new LongBufferImpl (capacity); + } + + /** + * Wraps a long array into a LongBuffer + * object. + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + public static final LongBuffer wrap (long[] array, int offset, int length) + { + return new LongBufferImpl (array, 0, array.length, offset + length, offset, -1, false); + } + + /** + * Wraps a long array into a LongBuffer + * object. + */ + public static final LongBuffer wrap (long[] array) + { + return wrap (array, 0, array.length); + } + + /** + * This method transfers longs from this buffer into the given + * destination array. Before the transfer, it checks if there are fewer than + * length longs remaining in this buffer. + * + * @param dst The destination array + * @param offset The offset within the array of the first long + * to be written; must be non-negative and no larger than dst.length. + * @param length The maximum number of bytes to be written to the given array; + * must be non-negative and no larger than dst.length - offset. + * + * @exception BufferUnderflowException If there are fewer than length + * longs remaining in this buffer. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold. + */ + public LongBuffer get (long[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + for (int i = offset; i < offset + length; i++) + { + dst [i] = get (); + } + + return this; + } + + /** + * This method transfers longs from this buffer into the given + * destination array. + * + * @param dst The byte array to write into. + * + * @exception BufferUnderflowException If there are fewer than dst.length + * longs remaining in this buffer. + */ + public LongBuffer get (long[] dst) + { + return get (dst, 0, dst.length); + } + + /** + * Writes the content of the the LongBUFFER src + * into the buffer. Before the transfer, it checks if there is fewer than + * src.remaining() space remaining in this buffer. + * + * @param src The source data. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining longs in the source buffer. + * @exception IllegalArgumentException If the source buffer is this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public LongBuffer put (LongBuffer src) + { + if (src == this) + throw new IllegalArgumentException (); + + checkForOverflow(src.remaining ()); + + if (src.remaining () > 0) + { + long[] toPut = new long [src.remaining ()]; + src.get (toPut); + put (toPut); + } + + return this; + } + + /** + * Writes the content of the the long array src + * into the buffer. Before the transfer, it checks if there is fewer than + * length space remaining in this buffer. + * + * @param src The array to copy into the buffer. + * @param offset The offset within the array of the first byte to be read; + * must be non-negative and no larger than src.length. + * @param length The number of bytes to be read from the given array; + * must be non-negative and no larger than src.length - offset. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining longs in the source array. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public LongBuffer put (long[] src, int offset, int length) + { + checkArraySize(src.length, offset, length); + checkForOverflow(length); + + for (int i = offset; i < offset + length; i++) + put (src [i]); + + return this; + } + + /** + * Writes the content of the the long array src + * into the buffer. + * + * @param src The array to copy into the buffer. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining longs in the source array. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public final LongBuffer put (long[] src) + { + return put (src, 0, src.length); + } + + /** + * Tells whether ot not this buffer is backed by an accessible + * long array. + */ + public final boolean hasArray () + { + return (backing_buffer != null + && !isReadOnly ()); + } + + /** + * Returns the long array that backs this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final long[] array () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return backing_buffer; + } + + /** + * Returns the offset within this buffer's backing array of the first element. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final int arrayOffset () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return array_offset; + } + + /** + * Calculates a hash code for this buffer. + * + * This is done with long arithmetic, + * where ** represents exponentiation, by this formula:
    + * s[position()] + 31 + (s[position()+1] + 30)*31**1 + ... + + * (s[limit()-1]+30)*31**(limit()-1). + * Where s is the buffer data. Note that the hashcode is dependent + * on buffer content, and therefore is not useful if the buffer + * content may change. + * + * @return the hash code (casted to int) + */ + public int hashCode () + { + long hashCode = get(position()) + 31; + long multiplier = 1; + for (int i = position() + 1; i < limit(); ++i) + { + multiplier *= 31; + hashCode += (get(i) + 30)*multiplier; + } + return ((int)hashCode); + } + + /** + * Checks if this buffer is equal to obj. + */ + public boolean equals (Object obj) + { + if (obj instanceof LongBuffer) + { + return compareTo (obj) == 0; + } + + return false; + } + + /** + * Compares two LongBuffer objects. + * + * @exception ClassCastException If obj is not an object derived from + * LongBuffer. + */ + public int compareTo (Object obj) + { + LongBuffer other = (LongBuffer) obj; + + int num = Math.min(remaining(), other.remaining()); + int pos_this = position(); + int pos_other = other.position(); + + for (int count = 0; count < num; count++) + { + long a = get(pos_this++); + long b = other.get(pos_other++); + + if (a == b) + continue; + + if (a < b) + return -1; + + return 1; + } + + return remaining() - other.remaining(); + } + + /** + * Returns the byte order of this buffer. + */ + public abstract ByteOrder order (); + + /** + * Reads the long at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * longs in this buffer. + */ + public abstract long get (); + + /** + * Writes the long at this buffer's current position, + * and then increments the position. + * + * @exception BufferOverflowException If there no remaining + * longs in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract LongBuffer put (long b); + + /** + * Absolute get method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public abstract long get (int index); + + /** + * Absolute put method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract LongBuffer put (int index, long b); + + /** + * Compacts this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract LongBuffer compact (); + + /** + * Tells wether or not this buffer is direct. + */ + public abstract boolean isDirect (); + + /** + * Creates a new LongBuffer whose content is a shared + * subsequence of this buffer's content. + */ + public abstract LongBuffer slice (); + + /** + * Creates a new LongBuffer that shares this buffer's + * content. + */ + public abstract LongBuffer duplicate (); + + /** + * Creates a new read-only LongBuffer that shares this + * buffer's content. + */ + public abstract LongBuffer asReadOnlyBuffer (); +} diff --git a/libjava/classpath/java/nio/LongBufferImpl.java b/libjava/classpath/java/nio/LongBufferImpl.java new file mode 100644 index 0000000..8772f61 --- /dev/null +++ b/libjava/classpath/java/nio/LongBufferImpl.java @@ -0,0 +1,172 @@ +/* LongBufferImpl.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 java.nio; + +/** + * This is a Heap memory implementation + */ +final class LongBufferImpl extends LongBuffer +{ + private boolean readOnly; + + LongBufferImpl (int capacity) + { + this (new long [capacity], 0, capacity, capacity, 0, -1, false); + } + + LongBufferImpl (long[] buffer, int offset, int capacity, int limit, int position, int mark, boolean readOnly) + { + super (capacity, limit, position, mark); + this.backing_buffer = buffer; + this.array_offset = offset; + this.readOnly = readOnly; + } + + public boolean isReadOnly () + { + return readOnly; + } + + public LongBuffer slice () + { + return new LongBufferImpl (backing_buffer, array_offset + position (), remaining (), remaining (), 0, -1, isReadOnly ()); + } + + public LongBuffer duplicate () + { + return new LongBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, isReadOnly ()); + } + + public LongBuffer asReadOnlyBuffer () + { + return new LongBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, true); + } + + public LongBuffer compact () + { + checkIfReadOnly(); + mark = -1; + int copied = 0; + + while (remaining () > 0) + { + put (copied, get ()); + copied++; + } + + position (copied); + limit(capacity()); + return this; + } + + public boolean isDirect () + { + return false; + } + + /** + * Reads the long at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * longs in this buffer. + */ + public long get () + { + checkForUnderflow(); + + long result = backing_buffer [position ()]; + position (position () + 1); + return result; + } + + /** + * Relative put method. Writes value to the next position + * in the buffer. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public LongBuffer put (long value) + { + checkIfReadOnly(); + checkForOverflow(); + + backing_buffer [position ()] = value; + position (position () + 1); + return this; + } + + /** + * Absolute get method. Reads the long at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public long get (int index) + { + checkIndex(index); + + return backing_buffer [index]; + } + + /** + * Absolute put method. Writes value to position + * index in the buffer. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public LongBuffer put (int index, long value) + { + checkIfReadOnly(); + checkIndex(index); + + backing_buffer [index] = value; + return this; + } + + public ByteOrder order () + { + return ByteOrder.nativeOrder (); + } +} diff --git a/libjava/classpath/java/nio/LongViewBufferImpl.java b/libjava/classpath/java/nio/LongViewBufferImpl.java new file mode 100644 index 0000000..9c3452a --- /dev/null +++ b/libjava/classpath/java/nio/LongViewBufferImpl.java @@ -0,0 +1,173 @@ +/* LongViewBufferImpl.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 java.nio; + +final class LongViewBufferImpl extends LongBuffer +{ + /** Position in bb (i.e. a byte offset) where this buffer starts. */ + private int offset; + private ByteBuffer bb; + private boolean readOnly; + private ByteOrder endian; + + LongViewBufferImpl (ByteBuffer bb, int capacity) + { + super (capacity, capacity, 0, -1); + this.bb = bb; + this.offset = bb.position(); + this.readOnly = bb.isReadOnly(); + this.endian = bb.order(); + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + public LongViewBufferImpl (ByteBuffer bb, int offset, int capacity, + int limit, int position, int mark, + boolean readOnly, ByteOrder endian) + { + super (capacity, limit, position, mark); + this.bb = bb; + this.offset = offset; + this.readOnly = readOnly; + this.endian = endian; + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + /** + * Reads the long at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * longs in this buffer. + */ + public long get () + { + int p = position(); + long result = ByteBufferHelper.getLong(bb, (p << 3) + offset, endian); + position(p + 1); + return result; + } + + /** + * Absolute get method. Reads the long at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public long get (int index) + { + return ByteBufferHelper.getLong(bb, (index << 3) + offset, endian); + } + + public LongBuffer put (long value) + { + int p = position(); + ByteBufferHelper.putLong(bb, (p << 3) + offset, value, endian); + position(p + 1); + return this; + } + + public LongBuffer put (int index, long value) + { + ByteBufferHelper.putLong(bb, (index << 3) + offset, value, endian); + return this; + } + + public LongBuffer compact () + { + if (position () > 0) + { + int count = limit () - position (); + bb.shiftDown(offset, offset + 8 * position(), 8 * count); + position (count); + limit (capacity ()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public LongBuffer slice () + { + // Create a sliced copy of this object that shares its content. + return new LongViewBufferImpl (bb, (position () >> 3) + offset, + remaining(), remaining(), 0, -1, + readOnly, endian); + } + + LongBuffer duplicate (boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + return new LongViewBufferImpl (bb, offset, capacity(), limit(), + pos, mark, readOnly, endian); + } + + public LongBuffer duplicate () + { + return duplicate(readOnly); + } + + public LongBuffer asReadOnlyBuffer () + { + return duplicate(true); + } + + public boolean isReadOnly () + { + return readOnly; + } + + public boolean isDirect () + { + return bb.isDirect (); + } + + public ByteOrder order () + { + return endian; + } +} diff --git a/libjava/classpath/java/nio/MappedByteBuffer.java b/libjava/classpath/java/nio/MappedByteBuffer.java new file mode 100644 index 0000000..fa25bb7 --- /dev/null +++ b/libjava/classpath/java/nio/MappedByteBuffer.java @@ -0,0 +1,93 @@ +/* MappedByteBuffer.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.4 + */ +public abstract class MappedByteBuffer extends ByteBuffer +{ + MappedByteBuffer (int capacity, int limit, int position, int mark) + { + super (capacity, limit, position, mark); + } + + void forceImpl() + { + } + + public final MappedByteBuffer force () + { + forceImpl(); + return this; + } + + boolean isLoadedImpl() + { + load(); + return true; + } + + public final boolean isLoaded () + { + return isLoadedImpl(); + } + + void loadImpl() + { + } + + public final MappedByteBuffer load () + { + loadImpl(); + return this; + } + + void unmapImpl () + { + forceImpl(); + } + + public void finalize() + throws Throwable + { + unmapImpl(); + } +} diff --git a/libjava/classpath/java/nio/MappedByteBufferImpl.java b/libjava/classpath/java/nio/MappedByteBufferImpl.java new file mode 100644 index 0000000..1b075d8 --- /dev/null +++ b/libjava/classpath/java/nio/MappedByteBufferImpl.java @@ -0,0 +1,360 @@ +/* MappedByteBufferImpl.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 java.nio; + +import gnu.classpath.RawData; + +import java.io.IOException; + +final class MappedByteBufferImpl extends MappedByteBuffer +{ + boolean readOnly; + + /** Posix uses this for the pointer returned by mmap; + * Win32 uses it for the pointer returned by MapViewOfFile. */ + public RawData implPtr; + /** Posix uses this for the actual length passed to mmap; + * Win32 uses it for the pointer returned by CreateFileMapping. */ + public long implLen; + + public MappedByteBufferImpl(RawData address, int size, boolean readOnly) + throws IOException + { + super(size, size, 0, -1); + this.address = address; + this.readOnly = readOnly; + } + + public boolean isReadOnly() + { + return readOnly; + } + + public byte get() + { + checkForUnderflow(); + + int pos = position(); + byte result = VMDirectByteBuffer.get(address, pos); + position(pos + 1); + return result; + } + + public ByteBuffer put(byte value) + { + checkIfReadOnly(); + checkForOverflow(); + + int pos = position(); + VMDirectByteBuffer.put(address, pos, value); + position(pos + 1); + return this; + } + + public byte get(int index) + { + checkIndex(index); + + return VMDirectByteBuffer.get(address, index); + } + + public ByteBuffer get(byte[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + int index = position(); + VMDirectByteBuffer.get(address, index, dst, offset, length); + position(index+length); + + return this; + } + + public ByteBuffer put(int index, byte value) + { + checkIfReadOnly(); + checkIndex(index); + + VMDirectByteBuffer.put(address, index, value); + return this; + } + + public ByteBuffer compact() + { + checkIfReadOnly(); + mark = -1; + int pos = position(); + if (pos > 0) + { + int count = remaining(); + // Call shiftDown method optimized for direct buffers. + VMDirectByteBuffer.shiftDown(address, 0, pos, count); + position(count); + limit(capacity()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public boolean isDirect() + { + return true; + } + + public ByteBuffer slice() + { + int rem = remaining(); + if (isReadOnly()) + return new DirectByteBufferImpl.ReadOnly + (this, VMDirectByteBuffer.adjustAddress(address, position()), + rem, rem, 0); + else + return new DirectByteBufferImpl.ReadWrite + (this, VMDirectByteBuffer.adjustAddress(address, position()), + rem, rem, 0); + } + + private ByteBuffer duplicate(boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + DirectByteBufferImpl result; + if (readOnly) + result = new DirectByteBufferImpl.ReadOnly(this, address, capacity(), + limit(), pos); + else + result = new DirectByteBufferImpl.ReadWrite(this, address, capacity(), + limit(), pos); + + if (mark != pos) + { + result.position(mark); + result.mark(); + result.position(pos); + } + return result; + } + + public ByteBuffer duplicate() + { + return duplicate(isReadOnly()); + } + + public ByteBuffer asReadOnlyBuffer() + { + return duplicate(true); + } + + public CharBuffer asCharBuffer() + { + return new CharViewBufferImpl(this, remaining() >> 1); + } + + public ShortBuffer asShortBuffer() + { + return new ShortViewBufferImpl(this, remaining() >> 1); + } + + public IntBuffer asIntBuffer() + { + return new IntViewBufferImpl(this, remaining() >> 2); + } + + public LongBuffer asLongBuffer() + { + return new LongViewBufferImpl(this, remaining() >> 3); + } + + public FloatBuffer asFloatBuffer() + { + return new FloatViewBufferImpl(this, remaining() >> 2); + } + + public DoubleBuffer asDoubleBuffer() + { + return new DoubleViewBufferImpl(this, remaining() >> 3); + } + + public char getChar() + { + return ByteBufferHelper.getChar(this, order()); + } + + public ByteBuffer putChar(char value) + { + ByteBufferHelper.putChar(this, value, order()); + return this; + } + + public char getChar(int index) + { + return ByteBufferHelper.getChar(this, index, order()); + } + + public ByteBuffer putChar(int index, char value) + { + ByteBufferHelper.putChar(this, index, value, order()); + return this; + } + + public short getShort() + { + return ByteBufferHelper.getShort(this, order()); + } + + public ByteBuffer putShort(short value) + { + ByteBufferHelper.putShort(this, value, order()); + return this; + } + + public short getShort(int index) + { + return ByteBufferHelper.getShort(this, index, order()); + } + + public ByteBuffer putShort(int index, short value) + { + ByteBufferHelper.putShort(this, index, value, order()); + return this; + } + + public int getInt() + { + return ByteBufferHelper.getInt(this, order()); + } + + public ByteBuffer putInt(int value) + { + ByteBufferHelper.putInt(this, value, order()); + return this; + } + + public int getInt(int index) + { + return ByteBufferHelper.getInt(this, index, order()); + } + + public ByteBuffer putInt(int index, int value) + { + ByteBufferHelper.putInt(this, index, value, order()); + return this; + } + + public long getLong() + { + return ByteBufferHelper.getLong(this, order()); + } + + public ByteBuffer putLong(long value) + { + ByteBufferHelper.putLong(this, value, order()); + return this; + } + + public long getLong(int index) + { + return ByteBufferHelper.getLong(this, index, order()); + } + + public ByteBuffer putLong(int index, long value) + { + ByteBufferHelper.putLong(this, index, value, order()); + return this; + } + + public float getFloat() + { + return ByteBufferHelper.getFloat(this, order()); + } + + public ByteBuffer putFloat(float value) + { + ByteBufferHelper.putFloat(this, value, order()); + return this; + } + + public float getFloat(int index) + { + return ByteBufferHelper.getFloat(this, index, order()); + } + + public ByteBuffer putFloat(int index, float value) + { + ByteBufferHelper.putFloat(this, index, value, order()); + return this; + } + + public double getDouble() + { + return ByteBufferHelper.getDouble(this, order()); + } + + public ByteBuffer putDouble(double value) + { + ByteBufferHelper.putDouble(this, value, order()); + return this; + } + + public double getDouble(int index) + { + return ByteBufferHelper.getDouble(this, index, order()); + } + + public ByteBuffer putDouble(int index, double value) + { + ByteBufferHelper.putDouble(this, index, value, order()); + return this; + } + + // NOTE: In libgcj these methods are implemented in natFileChannelXxx.cc, + // because they're small, and to put them next to FileChannelImpl::mapImpl. + native void unmapImpl(); + native boolean isLoadedImpl(); + // FIXME: Try to load all pages into memory. + native void loadImpl(); + + native void forceImpl(); +} diff --git a/libjava/classpath/java/nio/ReadOnlyBufferException.java b/libjava/classpath/java/nio/ReadOnlyBufferException.java new file mode 100644 index 0000000..d710e1b --- /dev/null +++ b/libjava/classpath/java/nio/ReadOnlyBufferException.java @@ -0,0 +1,52 @@ +/* ReadOnlyBufferException.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 java.nio; + +/** + * @author Michael Koch + * @since 1.4 + */ +public class ReadOnlyBufferException extends UnsupportedOperationException +{ + /** + * Creates the exception + */ + public ReadOnlyBufferException () + { + } +} diff --git a/libjava/classpath/java/nio/ShortBuffer.java b/libjava/classpath/java/nio/ShortBuffer.java new file mode 100644 index 0000000..958fe8c --- /dev/null +++ b/libjava/classpath/java/nio/ShortBuffer.java @@ -0,0 +1,383 @@ +/* ShortBuffer.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 java.nio; + +/** + * @since 1.4 + */ +public abstract class ShortBuffer extends Buffer + implements Comparable +{ + int array_offset; + short[] backing_buffer; + + ShortBuffer (int capacity, int limit, int position, int mark) + { + super (capacity, limit, position, mark); + array_offset = 0; + } + + /** + * Allocates a new ShortBuffer object with a given capacity. + */ + public static ShortBuffer allocate (int capacity) + { + return new ShortBufferImpl (capacity); + } + + /** + * Wraps a short array into a ShortBuffer + * object. + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + public static final ShortBuffer wrap (short[] array, int offset, int length) + { + return new ShortBufferImpl (array, 0, array.length, offset + length, offset, -1, false); + } + + /** + * Wraps a short array into a ShortBuffer + * object. + */ + public static final ShortBuffer wrap (short[] array) + { + return wrap (array, 0, array.length); + } + + /** + * This method transfers shorts from this buffer into the given + * destination array. Before the transfer, it checks if there are fewer than + * length shorts remaining in this buffer. + * + * @param dst The destination array + * @param offset The offset within the array of the first short + * to be written; must be non-negative and no larger than dst.length. + * @param length The maximum number of bytes to be written to the given array; + * must be non-negative and no larger than dst.length - offset. + * + * @exception BufferUnderflowException If there are fewer than length + * shorts remaining in this buffer. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold. + */ + public ShortBuffer get (short[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + for (int i = offset; i < offset + length; i++) + { + dst [i] = get (); + } + + return this; + } + + /** + * This method transfers shorts from this buffer into the given + * destination array. + * + * @param dst The byte array to write into. + * + * @exception BufferUnderflowException If there are fewer than dst.length + * shorts remaining in this buffer. + */ + public ShortBuffer get (short[] dst) + { + return get (dst, 0, dst.length); + } + + /** + * Writes the content of the the ShortBUFFER src + * into the buffer. Before the transfer, it checks if there is fewer than + * src.remaining() space remaining in this buffer. + * + * @param src The source data. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining shorts in the source buffer. + * @exception IllegalArgumentException If the source buffer is this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public ShortBuffer put (ShortBuffer src) + { + if (src == this) + throw new IllegalArgumentException (); + + checkForOverflow(src.remaining ()); + + if (src.remaining () > 0) + { + short[] toPut = new short [src.remaining ()]; + src.get (toPut); + put (toPut); + } + + return this; + } + + /** + * Writes the content of the the short array src + * into the buffer. Before the transfer, it checks if there is fewer than + * length space remaining in this buffer. + * + * @param src The array to copy into the buffer. + * @param offset The offset within the array of the first byte to be read; + * must be non-negative and no larger than src.length. + * @param length The number of bytes to be read from the given array; + * must be non-negative and no larger than src.length - offset. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining shorts in the source array. + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public ShortBuffer put (short[] src, int offset, int length) + { + checkArraySize(src.length, offset, length); + checkForOverflow(length); + + for (int i = offset; i < offset + length; i++) + put (src [i]); + + return this; + } + + /** + * Writes the content of the the short array src + * into the buffer. + * + * @param src The array to copy into the buffer. + * + * @exception BufferOverflowException If there is insufficient space in this + * buffer for the remaining shorts in the source array. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public final ShortBuffer put (short[] src) + { + return put (src, 0, src.length); + } + + /** + * Tells whether ot not this buffer is backed by an accessible + * short array. + */ + public final boolean hasArray () + { + return (backing_buffer != null + && !isReadOnly ()); + } + + /** + * Returns the short array that backs this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final short[] array () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return backing_buffer; + } + + /** + * Returns the offset within this buffer's backing array of the first element. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + * @exception UnsupportedOperationException If this buffer is not backed + * by an accessible array. + */ + public final int arrayOffset () + { + if (backing_buffer == null) + throw new UnsupportedOperationException (); + + checkIfReadOnly(); + + return array_offset; + } + + /** + * Calculates a hash code for this buffer. + * + * This is done with int arithmetic, + * where ** represents exponentiation, by this formula:
    + * s[position()] + 31 + (s[position()+1] + 30)*31**1 + ... + + * (s[limit()-1]+30)*31**(limit()-1). + * Where s is the buffer data. Note that the hashcode is dependent + * on buffer content, and therefore is not useful if the buffer + * content may change. + * + * @return the hash code + */ + public int hashCode () + { + int hashCode = get(position()) + 31; + int multiplier = 1; + for (int i = position() + 1; i < limit(); ++i) + { + multiplier *= 31; + hashCode += (get(i) + 30)*multiplier; + } + return hashCode; + } + + /** + * Checks if this buffer is equal to obj. + */ + public boolean equals (Object obj) + { + if (obj instanceof ShortBuffer) + { + return compareTo (obj) == 0; + } + + return false; + } + + /** + * Compares two ShortBuffer objects. + * + * @exception ClassCastException If obj is not an object derived from + * ShortBuffer. + */ + public int compareTo (Object obj) + { + ShortBuffer other = (ShortBuffer) obj; + + int num = Math.min(remaining(), other.remaining()); + int pos_this = position(); + int pos_other = other.position(); + + for (int count = 0; count < num; count++) + { + short a = get(pos_this++); + short b = other.get(pos_other++); + + if (a == b) + continue; + + if (a < b) + return -1; + + return 1; + } + + return remaining() - other.remaining(); + } + + /** + * Returns the byte order of this buffer. + */ + public abstract ByteOrder order (); + + /** + * Reads the short at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * shorts in this buffer. + */ + public abstract short get (); + + /** + * Writes the short at this buffer's current position, + * and then increments the position. + * + * @exception BufferOverflowException If there no remaining + * shorts in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract ShortBuffer put (short b); + + /** + * Absolute get method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public abstract short get (int index); + + /** + * Absolute put method. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract ShortBuffer put (int index, short b); + + /** + * Compacts this buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public abstract ShortBuffer compact (); + + /** + * Tells wether or not this buffer is direct. + */ + public abstract boolean isDirect (); + + /** + * Creates a new ShortBuffer whose content is a shared + * subsequence of this buffer's content. + */ + public abstract ShortBuffer slice (); + + /** + * Creates a new ShortBuffer that shares this buffer's + * content. + */ + public abstract ShortBuffer duplicate (); + + /** + * Creates a new read-only ShortBuffer that shares this + * buffer's content. + */ + public abstract ShortBuffer asReadOnlyBuffer (); +} diff --git a/libjava/classpath/java/nio/ShortBufferImpl.java b/libjava/classpath/java/nio/ShortBufferImpl.java new file mode 100644 index 0000000..ee5bff2 --- /dev/null +++ b/libjava/classpath/java/nio/ShortBufferImpl.java @@ -0,0 +1,172 @@ +/* ShortBufferImpl.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 java.nio; + +/** + * This is a Heap memory implementation + */ +final class ShortBufferImpl extends ShortBuffer +{ + private boolean readOnly; + + ShortBufferImpl (int capacity) + { + this (new short [capacity], 0, capacity, capacity, 0, -1, false); + } + + ShortBufferImpl (short[] buffer, int offset, int capacity, int limit, int position, int mark, boolean readOnly) + { + super (capacity, limit, position, mark); + this.backing_buffer = buffer; + this.array_offset = offset; + this.readOnly = readOnly; + } + + public boolean isReadOnly () + { + return readOnly; + } + + public ShortBuffer slice () + { + return new ShortBufferImpl (backing_buffer, array_offset + position (), remaining (), remaining (), 0, -1, isReadOnly ()); + } + + public ShortBuffer duplicate () + { + return new ShortBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, isReadOnly ()); + } + + public ShortBuffer asReadOnlyBuffer () + { + return new ShortBufferImpl (backing_buffer, array_offset, capacity (), limit (), position (), mark, true); + } + + public ShortBuffer compact () + { + checkIfReadOnly(); + mark = -1; + int copied = 0; + + while (remaining () > 0) + { + put (copied, get ()); + copied++; + } + + position (copied); + limit(capacity()); + return this; + } + + public boolean isDirect () + { + return false; + } + + /** + * Reads the short at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * shorts in this buffer. + */ + public short get () + { + checkForUnderflow(); + + short result = backing_buffer [position ()]; + position (position () + 1); + return result; + } + + /** + * Relative put method. Writes value to the next position + * in the buffer. + * + * @exception BufferOverflowException If there no remaining + * space in this buffer. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public ShortBuffer put (short value) + { + checkIfReadOnly(); + checkForOverflow(); + + backing_buffer [position ()] = value; + position (position () + 1); + return this; + } + + /** + * Absolute get method. Reads the short at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public short get (int index) + { + checkIndex(index); + + return backing_buffer [index]; + } + + /** + * Absolute put method. Writes value to position + * index in the buffer. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + public ShortBuffer put (int index, short value) + { + checkIfReadOnly(); + checkIndex(index); + + backing_buffer [index] = value; + return this; + } + + public ByteOrder order () + { + return ByteOrder.nativeOrder (); + } +} diff --git a/libjava/classpath/java/nio/ShortViewBufferImpl.java b/libjava/classpath/java/nio/ShortViewBufferImpl.java new file mode 100644 index 0000000..cdd5595 --- /dev/null +++ b/libjava/classpath/java/nio/ShortViewBufferImpl.java @@ -0,0 +1,173 @@ +/* ShortViewBufferImpl.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 java.nio; + +final class ShortViewBufferImpl extends ShortBuffer +{ + /** Position in bb (i.e. a byte offset) where this buffer starts. */ + private int offset; + private ByteBuffer bb; + private boolean readOnly; + private ByteOrder endian; + + ShortViewBufferImpl (ByteBuffer bb, int capacity) + { + super (capacity, capacity, 0, -1); + this.bb = bb; + this.offset = bb.position(); + this.readOnly = bb.isReadOnly(); + this.endian = bb.order(); + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + public ShortViewBufferImpl (ByteBuffer bb, int offset, int capacity, + int limit, int position, int mark, + boolean readOnly, ByteOrder endian) + { + super (capacity, limit, position, mark); + this.bb = bb; + this.offset = offset; + this.readOnly = readOnly; + this.endian = endian; + if (bb.isDirect()) + this.address = VMDirectByteBuffer.adjustAddress(bb.address, offset); + } + + /** + * Reads the short at this buffer's current position, + * and then increments the position. + * + * @exception BufferUnderflowException If there are no remaining + * shorts in this buffer. + */ + public short get () + { + int p = position(); + short result = ByteBufferHelper.getShort(bb, (p << 1) + offset, endian); + position(p + 1); + return result; + } + + /** + * Absolute get method. Reads the short at position + * index. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + public short get (int index) + { + return ByteBufferHelper.getShort(bb, (index << 1) + offset, endian); + } + + public ShortBuffer put (short value) + { + int p = position(); + ByteBufferHelper.putShort(bb, (p << 1) + offset, value, endian); + position(p + 1); + return this; + } + + public ShortBuffer put (int index, short value) + { + ByteBufferHelper.putShort(bb, (index << 1) + offset, value, endian); + return this; + } + + public ShortBuffer compact () + { + if (position () > 0) + { + int count = limit () - position (); + bb.shiftDown(offset, offset + 2 * position(), 2 * count); + position (count); + limit (capacity ()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public ShortBuffer slice () + { + // Create a sliced copy of this object that shares its content. + return new ShortViewBufferImpl (bb, (position () >> 1) + offset, + remaining(), remaining(), 0, -1, + readOnly, endian); + } + + ShortBuffer duplicate (boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + return new ShortViewBufferImpl (bb, offset, capacity(), limit(), + pos, mark, readOnly, endian); + } + + public ShortBuffer duplicate () + { + return duplicate(readOnly); + } + + public ShortBuffer asReadOnlyBuffer () + { + return duplicate(true); + } + + public boolean isReadOnly () + { + return readOnly; + } + + public boolean isDirect () + { + return bb.isDirect (); + } + + public ByteOrder order () + { + return endian; + } +} diff --git a/libjava/classpath/java/nio/channels/AlreadyConnectedException.java b/libjava/classpath/java/nio/channels/AlreadyConnectedException.java new file mode 100644 index 0000000..133547e --- /dev/null +++ b/libjava/classpath/java/nio/channels/AlreadyConnectedException.java @@ -0,0 +1,48 @@ +/* AlreadyConnectedException.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 java.nio.channels; + +public class AlreadyConnectedException extends IllegalStateException +{ + /** + * Creates the exception + */ + public AlreadyConnectedException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/AsynchronousCloseException.java b/libjava/classpath/java/nio/channels/AsynchronousCloseException.java new file mode 100644 index 0000000..f45fdd8 --- /dev/null +++ b/libjava/classpath/java/nio/channels/AsynchronousCloseException.java @@ -0,0 +1,53 @@ +/* AsynchronousCloseException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class AsynchronousCloseException extends ClosedChannelException +{ + /** + * Creates the exception + */ + public AsynchronousCloseException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/ByteChannel.java b/libjava/classpath/java/nio/channels/ByteChannel.java new file mode 100644 index 0000000..d7d7a45 --- /dev/null +++ b/libjava/classpath/java/nio/channels/ByteChannel.java @@ -0,0 +1,43 @@ +/* ByteChannel.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 java.nio.channels; + +public interface ByteChannel extends ReadableByteChannel, + WritableByteChannel +{ +} diff --git a/libjava/classpath/java/nio/channels/CancelledKeyException.java b/libjava/classpath/java/nio/channels/CancelledKeyException.java new file mode 100644 index 0000000..02108f6 --- /dev/null +++ b/libjava/classpath/java/nio/channels/CancelledKeyException.java @@ -0,0 +1,53 @@ +/* CancelledKeyException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class CancelledKeyException extends IllegalStateException +{ + /** + * Creates the exception + */ + public CancelledKeyException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/Channel.java b/libjava/classpath/java/nio/channels/Channel.java new file mode 100644 index 0000000..d488bd2 --- /dev/null +++ b/libjava/classpath/java/nio/channels/Channel.java @@ -0,0 +1,59 @@ +/* Channel.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 java.nio.channels; + +import java.io.IOException; + +public interface Channel +{ + /** + * Tells whether this channel is open or not + * + * @return trueif channel is open, + * false otherwise + */ + boolean isOpen(); + + /** + * Closes this channel + * + * @exception IOException If an error occurs + */ + void close() throws IOException; +} diff --git a/libjava/classpath/java/nio/channels/Channels.java b/libjava/classpath/java/nio/channels/Channels.java new file mode 100644 index 0000000..cdb2e83 --- /dev/null +++ b/libjava/classpath/java/nio/channels/Channels.java @@ -0,0 +1,143 @@ +/* Channels.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 java.nio.channels; + +import gnu.java.nio.ChannelReader; +import gnu.java.nio.InputStreamChannel; +import gnu.java.nio.OutputStreamChannel; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + + +/** + * @since 1.4 + */ +public final class Channels +{ + /** + * This class isn't intended to be instantiated. + */ + private Channels() + { + // Do nothing here. + } + + /** + * Constructs a stream that reads bytes from the given channel. + */ + public static InputStream newInputStream(ReadableByteChannel ch) + { + return VMChannels.newInputStream(ch); + } + + /** + * Constructs a stream that writes bytes to the given channel. + */ + public static OutputStream newOutputStream(WritableByteChannel ch) + { + return VMChannels.newOutputStream(ch); + } + + /** + * Constructs a channel that reads bytes from the given stream. + */ + public static ReadableByteChannel newChannel(InputStream in) + { + return new InputStreamChannel(in); + } + + /** + * Constructs a channel that writes bytes to the given stream. + */ + public static WritableByteChannel newChannel(OutputStream out) + { + return new OutputStreamChannel(out); + } + + /** + * Constructs a reader that decodes bytes from the given channel using the + * given decoder. + */ + public static Reader newReader(ReadableByteChannel ch, CharsetDecoder dec, + int minBufferCap) + { + return new ChannelReader(ch, dec, minBufferCap); + } + + /** + * Constructs a reader that decodes bytes from the given channel according to + * the named charset. + * + * @exception UnsupportedCharsetException If no support for the named charset + * is available in this instance of the Java virtual machine. + */ + public static Reader newReader(ReadableByteChannel ch, String csName) + { + return newReader(ch, Charset.forName(csName).newDecoder(), -1); + } + + /** + * Constructs a writer that encodes characters using the given encoder and + * writes the resulting bytes to the given channel. + */ + public static Writer newWriter(WritableByteChannel ch, CharsetEncoder enc, + int minBufferCap) + { + // FIXME: implement java.nio.channels.Channel.newWriter(WritableByteChannel, CharsetEncoder, int) + throw new Error("not implemented"); + } + + /** + * Constructs a writer that encodes characters according to the named charset + * and writes the resulting bytes to the given channel. + * + * @exception UnsupportedCharsetException If no support for the named charset + * is available in this instance of the Java virtual machine. + */ + public static Writer newWriter(WritableByteChannel ch, String csName) + { + return newWriter(ch, Charset.forName(csName).newEncoder(), -1); + } +} diff --git a/libjava/classpath/java/nio/channels/ClosedByInterruptException.java b/libjava/classpath/java/nio/channels/ClosedByInterruptException.java new file mode 100644 index 0000000..17858f6 --- /dev/null +++ b/libjava/classpath/java/nio/channels/ClosedByInterruptException.java @@ -0,0 +1,53 @@ +/* ClosedByInterruptException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class ClosedByInterruptException extends AsynchronousCloseException +{ + /** + * Creates the exception + */ + public ClosedByInterruptException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/ClosedChannelException.java b/libjava/classpath/java/nio/channels/ClosedChannelException.java new file mode 100644 index 0000000..0f8df9b --- /dev/null +++ b/libjava/classpath/java/nio/channels/ClosedChannelException.java @@ -0,0 +1,55 @@ +/* ClosedChannelException.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 java.nio.channels; + +import java.io.IOException; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class ClosedChannelException extends IOException +{ + /** + * Creates the exception + */ + public ClosedChannelException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/ClosedSelectorException.java b/libjava/classpath/java/nio/channels/ClosedSelectorException.java new file mode 100644 index 0000000..e1b7a8c --- /dev/null +++ b/libjava/classpath/java/nio/channels/ClosedSelectorException.java @@ -0,0 +1,53 @@ +/* ClosedSelectorException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class ClosedSelectorException extends IllegalStateException +{ + /** + * Creates the exception + */ + public ClosedSelectorException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/ConnectionPendingException.java b/libjava/classpath/java/nio/channels/ConnectionPendingException.java new file mode 100644 index 0000000..b0b7129 --- /dev/null +++ b/libjava/classpath/java/nio/channels/ConnectionPendingException.java @@ -0,0 +1,53 @@ +/* ConnectionPendingException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class ConnectionPendingException extends IllegalStateException +{ + /** + * Creates the exception + */ + public ConnectionPendingException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/DatagramChannel.java b/libjava/classpath/java/nio/channels/DatagramChannel.java new file mode 100644 index 0000000..d257ff3 --- /dev/null +++ b/libjava/classpath/java/nio/channels/DatagramChannel.java @@ -0,0 +1,210 @@ +/* DatagramChannel.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 java.nio.channels; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.SelectorProvider; + + +/** + * @since 1.4 + */ +public abstract class DatagramChannel extends AbstractSelectableChannel + implements ByteChannel, ScatteringByteChannel, GatheringByteChannel +{ + /** + * Initializes the channel. + */ + protected DatagramChannel(SelectorProvider provider) + { + super(provider); + } + + /** + * Opens a datagram channel. + * + * @exception IOException If an error occurs + */ + public static DatagramChannel open() throws IOException + { + return SelectorProvider.provider().openDatagramChannel(); + } + + /** + * Reads data from this channel. + */ + public final long read(ByteBuffer[] dsts) throws IOException + { + long b = 0; + + for (int i = 0; i < dsts.length; i++) + b += read(dsts[i]); + + return b; + } + + /** + * Writes data to this channel. + * + * @exception IOException If an error occurs + * @exception NotYetConnectedException The channel's socket is not connected. + */ + public final long write(ByteBuffer[] srcs) throws IOException + { + long b = 0; + + for (int i = 0; i < srcs.length; i++) + b += write(srcs[i]); + + return b; + } + + /** + * Connects this channel's socket. + * + * @exception AsynchronousCloseException If another thread closes this channel + * while the connect operation is in progress. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the read operation is in progress, thereby closing the + * channel and setting the current thread's interrupt status. + * @exception ClosedChannelException If this channel is closed. + * @exception IOException If an error occurs. + * @exception SecurityException If a security manager has been installed and + * it does not permit datagrams to be sent to the given address. + */ + public abstract DatagramChannel connect(SocketAddress remote) + throws IOException; + + /** + * Disonnects this channel's socket. + * + * @exception IOException If an error occurs + */ + public abstract DatagramChannel disconnect() throws IOException; + + /** + * Tells whether or not this channel's socket is connected. + * + * @exception IOException If an error occurs. + * @exception NotYetConnectedException The channel's socket is not connected. + */ + public abstract boolean isConnected(); + + /** + * Reads data from this channel. + */ + public abstract int read(ByteBuffer dst) throws IOException; + + /** + * Reads data from this channel. + * + * @exception IOException If an error occurs. + * @exception NotYetConnectedException The channel's socket is not connected. + */ + public abstract long read(ByteBuffer[] dsts, int offset, int length) + throws IOException; + + /** + * Receives a datagram via this channel. + * + * @exception AsynchronousCloseException If another thread closes this channel + * while the connect operation is in progress. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the read operation is in progress, thereby closing the + * channel and setting the current thread's interrupt status. + * @exception ClosedChannelException If this channel is closed. + * @exception IOException If an error occurs + * @exception SecurityException If a security manager has been installed and + * it does not permit datagrams to be sent to the given address. + */ + public abstract SocketAddress receive(ByteBuffer dst) + throws IOException; + + /** + * Sends a datagram via this channel. + * + * @exception AsynchronousCloseException If another thread closes this channel + * while the connect operation is in progress. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the read operation is in progress, thereby closing the + * channel and setting the current thread's interrupt status. + * @exception ClosedChannelException If this channel is closed. + * @exception IOException If an error occurs + * @exception SecurityException If a security manager has been installed and + * it does not permit datagrams to be sent to the given address. + */ + public abstract int send(ByteBuffer src, SocketAddress target) + throws IOException; + + /** + * Retrieves the channel's socket. + */ + public abstract DatagramSocket socket(); + + /** + * Writes data to this channel. + * + * @exception IOException If an error occurs. + * @exception NotYetConnectedException The channel's socket is not connected. + */ + public abstract int write(ByteBuffer src) throws IOException; + + /** + * Writes data to this channel. + * + * @exception IOException If an error occurs. + * @exception NotYetConnectedException The channel's socket is not connected. + */ + public abstract long write(ByteBuffer[] srcs, int offset, int length) + throws IOException; + + /** + * Retrieves the valid operations for this channel. + * + * @exception IOException If an error occurs. + * @exception NotYetConnectedException The channel's socket is not connected. + */ + public final int validOps() + { + return SelectionKey.OP_READ | SelectionKey.OP_WRITE; + } +} diff --git a/libjava/classpath/java/nio/channels/FileChannel.java b/libjava/classpath/java/nio/channels/FileChannel.java new file mode 100644 index 0000000..944ec0b --- /dev/null +++ b/libjava/classpath/java/nio/channels/FileChannel.java @@ -0,0 +1,367 @@ +/* FileChannel.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 java.nio.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.spi.AbstractInterruptibleChannel; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public abstract class FileChannel extends AbstractInterruptibleChannel + implements ByteChannel, GatheringByteChannel, ScatteringByteChannel +{ + public static class MapMode + { + int m; + public static final MapMode READ_ONLY = new MapMode(0); + public static final MapMode READ_WRITE = new MapMode(1); + public static final MapMode PRIVATE = new MapMode(2); + + /** + * Initializes the MapMode. + */ + MapMode(int a) + { + m = a; + } + + /** + * Returns a string representation of the MapMode object. + */ + public String toString() + { + if (this == READ_ONLY) + return "READ_ONLY"; + else if (this == READ_WRITE) + return "READ_WRITE"; + + return "PRIVATE"; + } + } + + /** + * Initializes the channel. + */ + protected FileChannel() + { + } + + /** + * Maps the file into the memory. + * + * @exception IllegalArgumentException If the preconditions on the parameters + * do not hold. + * @exception IOException If an I/O error occurs. + * @exception NonReadableChannelException If mode is READ_ONLY but this channel was + * not opened for reading. + * @exception NonWritableChannelException If mode is READ_WRITE or PRIVATE but this + * channel was not opened for writing. + */ + public abstract MappedByteBuffer map(MapMode mode, long position, long size) + throws IOException; + + /** + * Return the size of the file thus far + * + * @exception ClosedChannelException If this channel is closed. + */ + public abstract long size() throws IOException; + + /** + * Writes data to the channel. + * + * @exception IOException If an I/O error occurs. + */ + public final long write(ByteBuffer[] srcs) throws IOException + { + long result = 0; + + for (int i = 0; i < srcs.length; i++) + result += write(srcs[i]); + + return result; + } + + /** + * Writes data to the channel. + * + * @exception IOException If an I/O error occurs. + */ + public abstract int write(ByteBuffer src) throws IOException; + + /** + * Writes data to the channel. + * + * @exception AsynchronousCloseException If another thread closes this channel + * while the transfer is in progress. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the transfer is in progress, thereby closing both + * channels and setting the current thread's interrupt status. + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalArgumentException If position is negative. + * @exception IOException If an I/O error occurs. + * @exception NonWritableChannelException If this channel was not opened for + * writing. + */ + public abstract int write(ByteBuffer srcs, long position) + throws IOException; + + /** + * Writes data to the channel. + * + * @exception IOException If an I/O error occurs. + */ + public abstract long write(ByteBuffer[] srcs, int offset, int length) + throws IOException; + + /** + * Reads data from the channel. + * + * @exception IOException If an I/O error occurs. + */ + public abstract long read(ByteBuffer[] dsts, int offset, int length) + throws IOException; + + /** + * Reads data from the channel. + * + * @exception IOException If an I/O error occurs. + */ + public final long read(ByteBuffer[] dsts) throws IOException + { + long result = 0; + + for (int i = 0; i < dsts.length; i++) + read(dsts[i]); + + return result; + } + + /** + * Reads data from the channel. + * + * @exception IOException If an I/O error occurs. + */ + public abstract int read(ByteBuffer dst) throws IOException; + + /** + * Reads data from the channel. + * + * @exception AsynchronousCloseException If another thread closes this channel + * while the transfer is in progress. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the transfer is in progress, thereby closing both + * channels and setting the current thread's interrupt status. + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalArgumentException If position is negative. + * @exception IOException If an I/O error occurs. + * @exception NonReadableChannelException If this channel was not opened for + * reading. + */ + public abstract int read(ByteBuffer dst, long position) + throws IOException; + + /** + * Closes the channel. + * + * This is called from @see close. + * + * @exception IOException If an I/O error occurs. + */ + protected abstract void implCloseChannel() throws IOException; + + /** + * msync with the disk + * + * @exception ClosedChannelException If this channel is closed. + * @exception IOException If an I/O error occurs. + */ + public abstract void force(boolean metaData) throws IOException; + + /** + * Creates a file lock for the whole assoziated file. + * + * @exception AsynchronousCloseException If another thread closes this channel + * while the transfer is in progress. + * @exception ClosedChannelException If this channel is closed. + * @exception FileLockInterruptionException If the invoking thread is + * interrupted while blocked in this method. + * @exception IOException If an I/O error occurs. + * @exception NonReadableChannelException If shared is true and this channel + * was not opened for reading. + * @exception NonWritableChannelException If shared is false and this channel + * was not opened for writing. + * @exception OverlappingFileLockException If a lock that overlaps the + * requested region is already held by this Java virtual machine, or if + * another thread is already blocked in this method and is attempting to lock + * an overlapping region. + */ + public final FileLock lock() throws IOException + { + return lock(0, Long.MAX_VALUE, false); + } + + /** + * Creates a file lock for a region of the assoziated file. + * + * @exception AsynchronousCloseException If another thread closes this channel + * while the transfer is in progress. + * @exception ClosedChannelException If this channel is closed. + * @exception FileLockInterruptionException If the invoking thread is + * interrupted while blocked in this method. + * @exception IllegalArgumentException If the preconditions on the parameters + * do not hold. + * @exception IOException If an I/O error occurs. + * @exception OverlappingFileLockException If a lock that overlaps the + * requested region is already held by this Java virtual machine, or if + * another thread is already blocked in this method and is attempting to lock + * an overlapping region. + * @exception NonReadableChannelException If shared is true and this channel + * was not opened for reading. + * @exception NonWritableChannelException If shared is false and this channel + * was not opened for writing. + */ + public abstract FileLock lock(long position, long size, boolean shared) + throws IOException; + + /** + * Tries to aqquire alock on the whole assoziated file. + * + * @exception ClosedChannelException If this channel is closed. + * @exception IOException If an I/O error occurs. + * @exception OverlappingFileLockException If a lock that overlaps the + * requested region is already held by this Java virtual machine, or if + * another thread is already blocked in this method and is attempting to lock + * an overlapping region. + */ + public final FileLock tryLock() throws IOException + { + return tryLock(0, Long.MAX_VALUE, false); + } + + /** + * Tries to aqquire a lock on a region of the assoziated file. + * + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalArgumentException If the preconditions on the parameters + * do not hold. + * @exception IOException If an I/O error occurs. + * @exception OverlappingFileLockException If a lock that overlaps the + * requested region is already held by this Java virtual machine, or if + * another thread is already blocked in this method and is attempting to lock + * an overlapping region. + */ + public abstract FileLock tryLock(long position, long size, boolean shared) + throws IOException; + + /** + * Returns the current position on the file. + * + * @exception ClosedChannelException If this channel is closed. + * @exception IOException If an I/O error occurs. + */ + public abstract long position() throws IOException; + + /** + * Sets the position of the channel on the assoziated file. + * + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalArgumentException If newPosition is negative. + * @exception IOException If an I/O error occurs. + */ + public abstract FileChannel position(long newPosition) + throws IOException; + + /** + * Transfers bytes from this channel's file to the given writable byte + * channel. + * + * @exception AsynchronousCloseException If another thread closes this channel + * while the transfer is in progress. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the transfer is in progress, thereby closing both + * channels and setting the current thread's interrupt status. + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalArgumentException If the preconditions on the parameters + * do not hold. + * @exception IOException If an I/O error occurs. + * @exception NonReadableChannelException If this channel was not opened for + * reading. + * @exception NonWritableChannelException If the target channel was not + * opened for writing. + */ + public abstract long transferTo(long position, long count, + WritableByteChannel target) + throws IOException; + + /** + * Transfers bytes from the given readable channel into this channel. + * + * @exception AsynchronousCloseException If another thread closes this channel + * while the transfer is in progress. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the transfer is in progress, thereby closing both + * channels and setting the current thread's interrupt status. + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalArgumentException If the preconditions on the parameters + * do not hold. + * @exception IOException If an I/O error occurs. + * @exception NonReadableChannelException If the source channel was not + * opened for reading. + * @exception NonWritableChannelException If this channel was not opened for + * writing. + */ + public abstract long transferFrom(ReadableByteChannel src, long position, + long count) throws IOException; + + /** + * Truncates the channel's file at size. + * + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalArgumentException If size is negative. + * @exception IOException If an I/O error occurs. + * @exception NonWritableChannelException If this channel was not opened for + * writing. + */ + public abstract FileChannel truncate(long size) throws IOException; +} diff --git a/libjava/classpath/java/nio/channels/FileLock.java b/libjava/classpath/java/nio/channels/FileLock.java new file mode 100644 index 0000000..151c23f --- /dev/null +++ b/libjava/classpath/java/nio/channels/FileLock.java @@ -0,0 +1,150 @@ +/* FileLock.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 java.nio.channels; + +import java.io.IOException; + + +/** + * @since 1.4 + */ +public abstract class FileLock +{ + FileChannel channel; + long position; + long size; + boolean shared; + + /** + * Initializes the file lock. + * + * @exception IllegalArgumentException If the preconditions on the parameters do not hold + */ + protected FileLock(FileChannel channel, long position, long size, + boolean shared) + { + if (position < 0 || size < 0) + throw new IllegalArgumentException(); + + this.channel = channel; + this.position = position; + this.size = size; + this.shared = shared; + } + + /** + * Tells whether or not this lock is valid. + */ + public abstract boolean isValid(); + + /** + * Releases this lock. + * + * @exception IOException If an error occurs + * @exception ClosedChannelException If the locked channel is no longer open. + */ + public abstract void release() throws IOException; + + /** + * Returns the file channel upon whose file this lock is held. + */ + public final FileChannel channel() + { + return channel; + } + + /** + * Tells whether this lock is shared. + */ + public final boolean isShared() + { + return shared; + } + + /** + * Tells whether or not this lock overlaps the given lock range. + */ + public final boolean overlaps(long position, long size) + { + if (position > this.position + this.size) + return false; + + if (position + size < this.position) + return false; + + return true; + } + + /** + * Returns the position within the file of the first byte of the + * locked region. + */ + public final long position() + { + return position; + } + + /** + * Returns the size of the locked region in bytes. + */ + public final long size() + { + return size; + } + + /** + * Returns a string describing the range, type, and validity of this lock. + */ + public final String toString() + { + StringBuffer buf = new StringBuffer(getClass().getName()); + buf.append("["); + buf.append(position); + buf.append(":"); + buf.append(size); + if (shared) + buf.append(" shared"); + else + buf.append(" exclusive"); + if (isValid()) + buf.append(" valid]"); + else + buf.append(" invalid]"); + return buf.toString(); + } +} diff --git a/libjava/classpath/java/nio/channels/FileLockInterruptionException.java b/libjava/classpath/java/nio/channels/FileLockInterruptionException.java new file mode 100644 index 0000000..7d9e620 --- /dev/null +++ b/libjava/classpath/java/nio/channels/FileLockInterruptionException.java @@ -0,0 +1,55 @@ +/* FileLockInterruptionException.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 java.nio.channels; + +import java.io.IOException; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class FileLockInterruptionException extends IOException +{ + /** + * Creates the exception + */ + public FileLockInterruptionException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/GatheringByteChannel.java b/libjava/classpath/java/nio/channels/GatheringByteChannel.java new file mode 100644 index 0000000..822ea23 --- /dev/null +++ b/libjava/classpath/java/nio/channels/GatheringByteChannel.java @@ -0,0 +1,79 @@ +/* GatheringByteChannel.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 java.nio.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; + + +public interface GatheringByteChannel extends WritableByteChannel +{ + /** + * Writes a sequence of bytes to this channel from a subsequence of + * the given buffers + * + * @exception AsynchronousCloseException If another thread closes this + * channel while the write operation is in progress + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the write operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status + * @exception ClosedChannelException If this channel is closed + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception IOException If an error occurs + * @exception NonWritableChannelException If this channel was not opened for + * writing + */ + long write(ByteBuffer[] srcs, int offset, int length) + throws IOException; + + /** + * Writes a sequence of bytes to this channel from the given buffers + * + * @exception AsynchronousCloseException If another thread closes this + * channel while the write operation is in progress + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the write operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status + * @exception ClosedChannelException If this channel is closed + * @exception IOException If an error occurs + * @exception NonWritableChannelException If this channel was not opened for + * writing + */ + long write(ByteBuffer[] srcs) throws IOException; +} diff --git a/libjava/classpath/java/nio/channels/IllegalBlockingModeException.java b/libjava/classpath/java/nio/channels/IllegalBlockingModeException.java new file mode 100644 index 0000000..7352b54 --- /dev/null +++ b/libjava/classpath/java/nio/channels/IllegalBlockingModeException.java @@ -0,0 +1,57 @@ +/* IllegalBlockingModeException.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 java.nio.channels; + + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.4 + * + * Written using JDK 1.4.1 Online API from Sun + * Status: JDK 1.4 complete + */ +public class IllegalBlockingModeException extends IllegalStateException +{ + /** + * Creates the exception + */ + public IllegalBlockingModeException() + { + super(); + } +} diff --git a/libjava/classpath/java/nio/channels/IllegalSelectorException.java b/libjava/classpath/java/nio/channels/IllegalSelectorException.java new file mode 100644 index 0000000..049a8d5 --- /dev/null +++ b/libjava/classpath/java/nio/channels/IllegalSelectorException.java @@ -0,0 +1,53 @@ +/* IllegalSelectorException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class IllegalSelectorException extends IllegalArgumentException +{ + /** + * Creates the exception + */ + public IllegalSelectorException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/InterruptibleChannel.java b/libjava/classpath/java/nio/channels/InterruptibleChannel.java new file mode 100644 index 0000000..54122ce --- /dev/null +++ b/libjava/classpath/java/nio/channels/InterruptibleChannel.java @@ -0,0 +1,51 @@ +/* InterruptibleChannel.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 java.nio.channels; + +import java.io.IOException; + + +public interface InterruptibleChannel extends Channel +{ + /** + * Closes this channel + * + * @exception IOException If an error occurs + */ + void close() throws IOException; +} diff --git a/libjava/classpath/java/nio/channels/NoConnectionPendingException.java b/libjava/classpath/java/nio/channels/NoConnectionPendingException.java new file mode 100644 index 0000000..afefebf --- /dev/null +++ b/libjava/classpath/java/nio/channels/NoConnectionPendingException.java @@ -0,0 +1,53 @@ +/* NoConnectionPendingException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class NoConnectionPendingException extends IllegalStateException +{ + /** + * Creates the exception + */ + public NoConnectionPendingException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/NonReadableChannelException.java b/libjava/classpath/java/nio/channels/NonReadableChannelException.java new file mode 100644 index 0000000..e6852a7 --- /dev/null +++ b/libjava/classpath/java/nio/channels/NonReadableChannelException.java @@ -0,0 +1,53 @@ +/* NonReadableChannelException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class NonReadableChannelException extends IllegalStateException +{ + /** + * Creates the exception + */ + public NonReadableChannelException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/NonWritableChannelException.java b/libjava/classpath/java/nio/channels/NonWritableChannelException.java new file mode 100644 index 0000000..61d40bb --- /dev/null +++ b/libjava/classpath/java/nio/channels/NonWritableChannelException.java @@ -0,0 +1,53 @@ +/* NonWritableChannelException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class NonWritableChannelException extends IllegalStateException +{ + /** + * Creates the exception + */ + public NonWritableChannelException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/NotYetBoundException.java b/libjava/classpath/java/nio/channels/NotYetBoundException.java new file mode 100644 index 0000000..7d0c663 --- /dev/null +++ b/libjava/classpath/java/nio/channels/NotYetBoundException.java @@ -0,0 +1,53 @@ +/* NotYetBoundException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class NotYetBoundException extends IllegalStateException +{ + /** + * Creates the exception + */ + public NotYetBoundException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/NotYetConnectedException.java b/libjava/classpath/java/nio/channels/NotYetConnectedException.java new file mode 100644 index 0000000..463e059 --- /dev/null +++ b/libjava/classpath/java/nio/channels/NotYetConnectedException.java @@ -0,0 +1,53 @@ +/* NotYetConnectedException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class NotYetConnectedException extends IllegalStateException +{ + /** + * Creates the exception + */ + public NotYetConnectedException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/OverlappingFileLockException.java b/libjava/classpath/java/nio/channels/OverlappingFileLockException.java new file mode 100644 index 0000000..ce0900c --- /dev/null +++ b/libjava/classpath/java/nio/channels/OverlappingFileLockException.java @@ -0,0 +1,53 @@ +/* OverlappingFileLockException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class OverlappingFileLockException extends IllegalStateException +{ + /** + * Creates the exception + */ + public OverlappingFileLockException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/Pipe.java b/libjava/classpath/java/nio/channels/Pipe.java new file mode 100644 index 0000000..c7b04c8 --- /dev/null +++ b/libjava/classpath/java/nio/channels/Pipe.java @@ -0,0 +1,121 @@ +/* Pipe.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 java.nio.channels; + +import java.io.IOException; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.SelectorProvider; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public abstract class Pipe +{ + public abstract static class SinkChannel extends AbstractSelectableChannel + implements WritableByteChannel, GatheringByteChannel + { + /** + * Initializes the channel. + */ + protected SinkChannel(SelectorProvider provider) + { + super(provider); + } + + /** + * Returns an operation set that is valid on this channel. + * + * The only valid operation on this channel is @see SelectionKey.OP_WRITE. + */ + public final int validOps() + { + return SelectionKey.OP_WRITE; + } + } + + public abstract static class SourceChannel extends AbstractSelectableChannel + implements ReadableByteChannel, ScatteringByteChannel + { + /** + * Initializes the channel. + */ + protected SourceChannel(SelectorProvider provider) + { + super(provider); + } + + /** + * Returns an operation set that is valid on this channel. + * + * The only valid operation on this channel is @see SelectionKey.OP_READ. + */ + public final int validOps() + { + return SelectionKey.OP_READ; + } + } + + /** + * Initializes the pipe. + */ + protected Pipe() + { + } + + /** + * Opens a pipe. + * + * @exception IOException If an error occurs + */ + public static Pipe open() throws IOException + { + return SelectorProvider.provider().openPipe(); + } + + /** + * Returns a pipe's sink channel. + */ + public abstract Pipe.SinkChannel sink(); + + /** + * Returns a pipe's source channel + */ + public abstract Pipe.SourceChannel source(); +} diff --git a/libjava/classpath/java/nio/channels/ReadableByteChannel.java b/libjava/classpath/java/nio/channels/ReadableByteChannel.java new file mode 100644 index 0000000..889662d --- /dev/null +++ b/libjava/classpath/java/nio/channels/ReadableByteChannel.java @@ -0,0 +1,64 @@ +/* ReadableByteChannel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.nio.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; + + +public interface ReadableByteChannel extends Channel +{ + /** + * Reads a sequence of bytes from this channel into the given buffer + * + * @param dst the buffer to put the read data into + * + * @return the numer of bytes read + * + * @exception AsynchronousCloseException If another thread closes this + * channel while the read operation is in progress + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the read operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status + * @exception ClosedChannelException If this channel is closed + * @exception IOException If an error occurs + * @exception NonReadableChannelException If this channel was not opened for + * reading + */ + int read(ByteBuffer dst) throws IOException; +} diff --git a/libjava/classpath/java/nio/channels/ScatteringByteChannel.java b/libjava/classpath/java/nio/channels/ScatteringByteChannel.java new file mode 100644 index 0000000..5437ea1 --- /dev/null +++ b/libjava/classpath/java/nio/channels/ScatteringByteChannel.java @@ -0,0 +1,79 @@ +/* ScatteringByteChannel.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 java.nio.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; + + +public interface ScatteringByteChannel extends ReadableByteChannel +{ + /** + * Reads a sequence of bytes from this channel into a subsequence of the + * given buffers + * + * @exception AsynchronousCloseException If another thread closes this + * channel while the write operation is in progress + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the write operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status + * @exception ClosedChannelException If this channel is closed + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception IOException If an error occurs + * @exception NonReadableChannelException If this channel was not opened for + * reading + */ + long read(ByteBuffer[] srcs, int offset, int length) + throws IOException; + + /** + * Reads a sequence of bytes from this channel into the given buffers + * + * @exception AsynchronousCloseException If another thread closes this + * channel while the write operation is in progress + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the write operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status + * @exception ClosedChannelException If this channel is closed + * @exception IOException If an error occurs + * @exception NonReadableChannelException If this channel was not opened for + * reading + */ + long read(ByteBuffer[] srcs) throws IOException; +} diff --git a/libjava/classpath/java/nio/channels/SelectableChannel.java b/libjava/classpath/java/nio/channels/SelectableChannel.java new file mode 100644 index 0000000..70fa785 --- /dev/null +++ b/libjava/classpath/java/nio/channels/SelectableChannel.java @@ -0,0 +1,140 @@ +/* SelectableChannel.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 java.nio.channels; + +import java.io.IOException; +import java.nio.channels.spi.AbstractInterruptibleChannel; +import java.nio.channels.spi.SelectorProvider; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public abstract class SelectableChannel extends AbstractInterruptibleChannel +{ + /** + * Initializes the channel. + */ + protected SelectableChannel() + { + } + + /** + * Returns the lock of this channel. + */ + public abstract Object blockingLock(); + + /** + * Adjusts this channel's blocking mode. + * + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalBlockingModeException If block is true and this channel + * is registered with one or more selectors. + * @exception IOException If an error occurs. + */ + public abstract SelectableChannel configureBlocking(boolean block) + throws IOException; + + /** + * Tells whether this channel is blocking or not. + */ + public abstract boolean isBlocking(); + + /** + * Tells whether or not this channel is currently registered with + * any selectors. + */ + public abstract boolean isRegistered(); + + /** + * Retrieves the key representing the channel's registration with + * the given selector. + */ + public abstract SelectionKey keyFor(Selector sel); + + /** + * Returns the provider that created this channel. + */ + public abstract SelectorProvider provider(); + + /** + * Registers this channel with the given selector, + * returning a selection key. + * + * @exception CancelledKeyException If this channel is currently registered + * with the given selector but the corresponding key has already been cancelled + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalArgumentException If a bit in ops does not correspond + * to an operation that is supported by this channel, that is, if + * set & ~validOps() != 0. + * @exception IllegalBlockingModeException If block is true and this channel + * is registered with one or more selectors. + * @exception IllegalSelectorException If this channel was not created by + * the same provider as the given selector. + */ + public final SelectionKey register(Selector sel, int ops) + throws ClosedChannelException + { + return register(sel, ops, null); + } + + /** + * Registers this channel with the given selector, + * returning a selection key. + * + * @exception CancelledKeyException If this channel is currently registered + * with the given selector but the corresponding key has already been + * cancelled. + * @exception ClosedChannelException If this channel is closed. + * @exception IllegalArgumentException If a bit in ops does not correspond + * to an operation that is supported by this channel, that is, if + * set & ~validOps() != 0. + * @exception IllegalBlockingModeException If block is true and this channel + * is registered with one or more selectors. + * @exception IllegalSelectorException If this channel was not created by + * the same provider as the given selector. + */ + public abstract SelectionKey register(Selector sel, int ops, Object att) + throws ClosedChannelException; + + /** + * Returns a set of valid operations on this channel. + */ + public abstract int validOps(); +} diff --git a/libjava/classpath/java/nio/channels/SelectionKey.java b/libjava/classpath/java/nio/channels/SelectionKey.java new file mode 100644 index 0000000..5219b6b --- /dev/null +++ b/libjava/classpath/java/nio/channels/SelectionKey.java @@ -0,0 +1,164 @@ +/* SelectionKey.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public abstract class SelectionKey +{ + public static final int OP_ACCEPT = 16; + public static final int OP_CONNECT = 8; + public static final int OP_READ = 1; + public static final int OP_WRITE = 4; + Object attached; + + /** + * Initializes the selection key. + */ + protected SelectionKey() + { + } + + /** + * Attaches obj to the key and returns the old attached object. + */ + public final Object attach(Object obj) + { + Object old = attached; + attached = obj; + return old; + } + + /** + * Returns the object attached to the key. + */ + public final Object attachment() + { + return attached; + } + + /** + * Tests if the channel attached to this key is ready to accept + * a new socket connection. + * + * @exception CancelledKeyException If this key has been cancelled + */ + public final boolean isAcceptable() + { + return (readyOps() & OP_ACCEPT) != 0; + } + + /** + * Tests whether this key's channel has either finished, + * or failed to finish, its socket-connection operation. + * + * @exception CancelledKeyException If this key has been cancelled + */ + public final boolean isConnectable() + { + return (readyOps() & OP_CONNECT) != 0; + } + + /** + * Tests if the channel attached to the key is readable. + * + * @exception CancelledKeyException If this key has been cancelled + */ + public final boolean isReadable() + { + return (readyOps() & OP_READ) != 0; + } + + /** + * Tests if the channel attached to the key is writable. + * + * @exception CancelledKeyException If this key has been cancelled + */ + public final boolean isWritable() + { + return (readyOps() & OP_WRITE) != 0; + } + + /** + * Requests that the registration of this key's channel with + * its selector be cancelled. + */ + public abstract void cancel(); + + /** + * return the channel attached to the key. + */ + public abstract SelectableChannel channel(); + + /** + * Returns the key's interest set. + * + * @exception CancelledKeyException If this key has been cancelled + */ + public abstract int interestOps(); + + /** + * Sets this key's interest set to the given value. + * + * @exception CancelledKeyException If this key has been cancelled + * @exception IllegalArgumentException If a bit in the set does not + * correspond to an operation that is supported by this key's channel, + * that is, if set & ~(channel().validOps()) != 0 + */ + public abstract SelectionKey interestOps(int ops); + + /** + * Tells whether or not this key is valid. + */ + public abstract boolean isValid(); + + /** + * Retrieves this key's ready-operation set. + * + * @exception CancelledKeyException If this key has been cancelled + */ + public abstract int readyOps(); + + /** + * Returns the selector for which this key was created. + */ + public abstract Selector selector(); +} diff --git a/libjava/classpath/java/nio/channels/Selector.java b/libjava/classpath/java/nio/channels/Selector.java new file mode 100644 index 0000000..2c883ef --- /dev/null +++ b/libjava/classpath/java/nio/channels/Selector.java @@ -0,0 +1,134 @@ +/* Selector.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 java.nio.channels; + +import java.io.IOException; +import java.nio.channels.spi.SelectorProvider; +import java.util.Set; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public abstract class Selector +{ + /** + * Initializes the selector. + */ + protected Selector() + { + } + + /** + * Opens a selector. + * + * @exception IOException If an error occurs + */ + public static Selector open() throws IOException + { + return SelectorProvider.provider().openSelector(); + } + + /** + * Closes the selector. + * + * @exception IOException If an error occurs + */ + public abstract void close() throws IOException; + + /** + * Tells whether the selector is open or not. + */ + public abstract boolean isOpen(); + + /** + * Returns this selector's key set. + * + * @exception ClosedSelectorException If this selector is closed. + */ + public abstract Set keys(); + + /** + * Returns the SelectorProvider that created the selector. + */ + public abstract SelectorProvider provider(); + + /** + * Selects a set of keys whose corresponding channels are ready + * for I/O operations. + * + * @exception ClosedSelectorException If this selector is closed. + * @exception IOException If an error occurs + */ + public abstract int select() throws IOException; + + /** + * Selects a set of keys whose corresponding channels are ready + * for I/O operations. + * + * @param timeout The timeout to use. + * + * @exception ClosedSelectorException If this selector is closed. + * @exception IllegalArgumentException If the timeout value is negative. + * @exception IOException If an error occurs + */ + public abstract int select(long timeout) throws IOException; + + /** + * Returns this selector's selected-key set. + * + * @exception ClosedSelectorException If this selector is closed. + */ + public abstract Set selectedKeys(); + + /** + * Selects a set of keys whose corresponding channels are ready + * for I/O operations. + * + * @exception ClosedSelectorException If this selector is closed. + * @exception IOException If an error occurs + */ + public abstract int selectNow() throws IOException; + + /** + * Causes the first selection operation that has not yet returned to + * return immediately. + */ + public abstract Selector wakeup(); +} diff --git a/libjava/classpath/java/nio/channels/ServerSocketChannel.java b/libjava/classpath/java/nio/channels/ServerSocketChannel.java new file mode 100644 index 0000000..105d17f --- /dev/null +++ b/libjava/classpath/java/nio/channels/ServerSocketChannel.java @@ -0,0 +1,98 @@ +/* ServerSocketChannel.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 java.nio.channels; + +import java.io.IOException; +import java.net.ServerSocket; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.SelectorProvider; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public abstract class ServerSocketChannel extends AbstractSelectableChannel +{ + /** + * Initializes this channel. + */ + protected ServerSocketChannel(SelectorProvider provider) + { + super(provider); + } + + /** + * Accepts a connection made to this channel's socket. + * + * @exception IOException If an error occurs + * @exception AsynchronousCloseException If another thread closes this + * channel while the accept operation is in progress. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the accept operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status. + * @exception ClosedChannelException If the channel is closed. + * @exception NotYetBoundException If the channel's socket is not yet bound. + * @exception SecurityException If a security manager has been installed and + * it does not permit access to the remote endpoint of the new connection. + */ + public abstract SocketChannel accept() throws IOException; + + /** + * Retrieves the channels socket. + */ + public abstract ServerSocket socket(); + + /** + * Opens a server socket channel. + * + * @exception IOException If an error occurs + */ + public static ServerSocketChannel open() throws IOException + { + return SelectorProvider.provider().openServerSocketChannel(); + } + + /** + * Retrieves the valid operations for this channel. + */ + public final int validOps() + { + return SelectionKey.OP_ACCEPT; + } +} diff --git a/libjava/classpath/java/nio/channels/SocketChannel.java b/libjava/classpath/java/nio/channels/SocketChannel.java new file mode 100644 index 0000000..50f2136 --- /dev/null +++ b/libjava/classpath/java/nio/channels/SocketChannel.java @@ -0,0 +1,248 @@ +/* SocketChannel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio.channels; + +import java.io.IOException; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.SelectorProvider; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.4 + */ +public abstract class SocketChannel extends AbstractSelectableChannel + implements ByteChannel, ScatteringByteChannel, GatheringByteChannel +{ + /** + * Initializes this socket channel. + */ + protected SocketChannel(SelectorProvider provider) + { + super(provider); + } + + /** + * Opens a socket channel. + * + * @return the new SocketChannel object + * + * @exception IOException If an error occurs + */ + public static SocketChannel open() throws IOException + { + return SelectorProvider.provider().openSocketChannel(); + } + + /** + * Opens a channel and connects it to a remote address. + * + * @return the new SocketChannel object + * + * @exception AsynchronousCloseException If this channel is already connected. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the connect operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status. + * @exception IOException If an error occurs + * @exception SecurityException If a security manager has been installed and + * it does not permit access to the given remote endpoint. + * @exception UnresolvedAddressException If the given remote address is not + * fully resolved. + * @exception UnsupportedAddressTypeException If the type of the given remote + * address is not supported. + */ + public static SocketChannel open(SocketAddress remote) + throws IOException + { + SocketChannel ch = open(); + ch.connect(remote); + return ch; + } + + /** + * Reads data from the channel. + * + * @return the number of bytes read, zero is valid too, -1 if end of stream + * is reached + * + * @exception IOException If an error occurs + * @exception NotYetConnectedException If this channel is not yet connected. + */ + public final long read(ByteBuffer[] dsts) throws IOException + { + long b = 0; + + for (int i = 0; i < dsts.length; i++) + b += read(dsts[i]); + + return b; + } + + /** + * Writes data to the channel. + * + * @return the number of bytes written, zero is valid too + * + * @exception IOException If an error occurs + * @exception NotYetConnectedException If this channel is not yet connected. + */ + public final long write(ByteBuffer[] dsts) throws IOException + { + long b = 0; + + for (int i = 0; i < dsts.length; i++) + b += write(dsts[i]); + + return b; + } + + /** + * Retrieves the valid operations for this channel. + * + * @return the valid operations + */ + public final int validOps() + { + return SelectionKey.OP_CONNECT | SelectionKey.OP_READ + | SelectionKey.OP_WRITE; + } + + /** + * Reads data from the channel. + * + * @return the number of bytes read, zero is valid too, -1 if end of stream + * is reached + * + * @exception IOException If an error occurs + * @exception NotYetConnectedException If this channel is not yet connected. + */ + public abstract int read(ByteBuffer dst) throws IOException; + + /** + * Connects the channel's socket to the remote address. + * + * @return true if the channel got successfully connected, + * false if the channel is in non-blocking mode and connection + * operation is still in progress. + * + * @exception AlreadyConnectedException If this channel is already connected. + * @exception AsynchronousCloseException If this channel is already connected. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the connect operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status. + * @exception ClosedChannelException If this channel is closed. + * @exception ConnectionPendingException If a non-blocking connection + * operation is already in progress on this channel. + * @exception IOException If an error occurs + * @exception SecurityException If a security manager has been installed and + * it does not permit access to the given remote endpoint. + * @exception UnresolvedAddressException If the given remote address is not + * fully resolved. + * @exception UnsupportedAddressTypeException If the type of the given remote + * address is not supported. + */ + public abstract boolean connect(SocketAddress remote) + throws IOException; + + /** + * Finishes the process of connecting a socket channel. + * + * @exception AsynchronousCloseException If this channel is already connected. + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the connect operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status. + * @exception ClosedChannelException If this channel is closed. + * @exception IOException If an error occurs + * @exception NoConnectionPendingException If this channel is not connected + * and a connection operation has not been initiated. + */ + public abstract boolean finishConnect() throws IOException; + + /** + * Tells whether or not the channel's socket is connected. + */ + public abstract boolean isConnected(); + + /** + * Tells whether or not a connection operation is in progress on this channel. + */ + public abstract boolean isConnectionPending(); + + /** + * Reads data from the channel. + * + * @return the number of bytes read, zero is valid too, -1 if end of stream + * is reached + * + * @exception IOException If an error occurs + * @exception NotYetConnectedException If this channel is not yet connected. + */ + public abstract long read(ByteBuffer[] dsts, int offset, int length) + throws IOException; + + /** + * Retrieves the channel's socket. + * + * @return the socket + */ + public abstract Socket socket(); + + /** + * Writes data to the channel. + * + * @return the number of bytes written, zero is valid too + * + * @exception IOException If an error occurs + * @exception NotYetConnectedException If this channel is not yet connected. + */ + public abstract int write(ByteBuffer src) throws IOException; + + /** + * Writes data to the channel. + * + * @return the number of bytes written, zero is valid too + * + * @exception IOException If an error occurs + * @exception NotYetConnectedException If this channel is not yet connected. + */ + public abstract long write(ByteBuffer[] srcs, int offset, int length) + throws IOException; +} diff --git a/libjava/classpath/java/nio/channels/UnresolvedAddressException.java b/libjava/classpath/java/nio/channels/UnresolvedAddressException.java new file mode 100644 index 0000000..4db95a7 --- /dev/null +++ b/libjava/classpath/java/nio/channels/UnresolvedAddressException.java @@ -0,0 +1,53 @@ +/* UnresolvedAddressException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class UnresolvedAddressException extends IllegalArgumentException +{ + /** + * Creates the exception + */ + public UnresolvedAddressException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/UnsupportedAddressTypeException.java b/libjava/classpath/java/nio/channels/UnsupportedAddressTypeException.java new file mode 100644 index 0000000..7c16c81 --- /dev/null +++ b/libjava/classpath/java/nio/channels/UnsupportedAddressTypeException.java @@ -0,0 +1,53 @@ +/* UnsupportedAddressTypeException.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 java.nio.channels; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public class UnsupportedAddressTypeException extends IllegalArgumentException +{ + /** + * Creates the exception + */ + public UnsupportedAddressTypeException() + { + } +} diff --git a/libjava/classpath/java/nio/channels/WritableByteChannel.java b/libjava/classpath/java/nio/channels/WritableByteChannel.java new file mode 100644 index 0000000..3845723 --- /dev/null +++ b/libjava/classpath/java/nio/channels/WritableByteChannel.java @@ -0,0 +1,60 @@ +/* WritableByteChannel.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 java.nio.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; + + +public interface WritableByteChannel extends Channel +{ + /** + * Writes a sequence of bytes to this channel from the given buffer + * + * @exception AsynchronousCloseException If another thread closes this + * channel while the write operation is in progress + * @exception ClosedByInterruptException If another thread interrupts the + * current thread while the write operation is in progress, thereby closing + * the channel and setting the current thread's interrupt status + * @exception ClosedChannelException If this channel is closed + * @exception IOException If an error occurs + * @exception NonWritableChannelException If this channel was not opened for + * writing + */ + int write(ByteBuffer src) throws IOException; +} diff --git a/libjava/classpath/java/nio/channels/package.html b/libjava/classpath/java/nio/channels/package.html new file mode 100644 index 0000000..4e2bbc9 --- /dev/null +++ b/libjava/classpath/java/nio/channels/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - java.nio.channels + + +

    Classes for creating, selecting and non-blocking reading and writing of +buffers from files and sockets.

    + + + diff --git a/libjava/classpath/java/nio/channels/spi/AbstractInterruptibleChannel.java b/libjava/classpath/java/nio/channels/spi/AbstractInterruptibleChannel.java new file mode 100644 index 0000000..25e8785 --- /dev/null +++ b/libjava/classpath/java/nio/channels/spi/AbstractInterruptibleChannel.java @@ -0,0 +1,119 @@ +/* AbstractInterruptibleChannel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.nio.channels.spi; + +import java.io.IOException; +import java.nio.channels.AsynchronousCloseException; +import java.nio.channels.Channel; +import java.nio.channels.InterruptibleChannel; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public abstract class AbstractInterruptibleChannel + implements Channel, InterruptibleChannel +{ + private boolean closed; + + /** + * Initializes the channel. + */ + protected AbstractInterruptibleChannel() + { + } + + /** + * Marks the beginning of an I/O operation that might block indefinitely. + */ + protected final void begin() + { + } + + /** + * Closes the channel. + * + * @exception IOException If an error occurs + */ + public final void close() throws IOException + { + if (! closed) + { + closed = true; + implCloseChannel(); + } + } + + /** + * Marks the end of an I/O operation that might block indefinitely. + * + * @param completed true if the task completed successfully, + * false otherwise + * + * @exception IOException if an error occurs + * @exception AsynchronousCloseException If the channel was asynchronously + * closed. + * @exception ClosedByInterruptException If the thread blocked in the + * I/O operation was interrupted. + */ + protected final void end(boolean completed) + throws AsynchronousCloseException + { + // FIXME: check more here. + + if (closed) throw new AsynchronousCloseException(); + } + + /** + * Closes the channel. + * + * @exception IOException If an error occurs + */ + protected abstract void implCloseChannel() throws IOException; + + /** + * Tells whether or not this channel is open. + * + * @return true if the channel is open, false otherwise + */ + public final boolean isOpen() + { + return ! closed; + } +} diff --git a/libjava/classpath/java/nio/channels/spi/AbstractSelectableChannel.java b/libjava/classpath/java/nio/channels/spi/AbstractSelectableChannel.java new file mode 100644 index 0000000..42ceab7 --- /dev/null +++ b/libjava/classpath/java/nio/channels/spi/AbstractSelectableChannel.java @@ -0,0 +1,256 @@ +/* AbstractSelectableChannel.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 java.nio.channels.spi; + +import java.io.IOException; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.util.LinkedList; +import java.util.ListIterator; + +public abstract class AbstractSelectableChannel extends SelectableChannel +{ + private boolean blocking = true; + private Object LOCK = new Object(); + private SelectorProvider provider; + private LinkedList keys = new LinkedList(); + + /** + * Initializes the channel + * + * @param provider the provider that created this channel + */ + protected AbstractSelectableChannel(SelectorProvider provider) + { + this.provider = provider; + } + + /** + * Retrieves the object upon which the configureBlocking and register + * methods synchronize. + * + * @return the blocking lock + */ + public final Object blockingLock() + { + return LOCK; + } + + /** + * Adjusts this channel's blocking mode. + * + * @param blocking true if blocking should be enabled, false otherwise + * + * @return this channel + * + * @exception IOException If an error occurs + */ + public final SelectableChannel configureBlocking(boolean blocking) + throws IOException + { + synchronized (blockingLock()) + { + if (this.blocking != blocking) + { + implConfigureBlocking(blocking); + this.blocking = blocking; + } + } + + return this; + } + + /** + * Closes this channel. + * + * @exception IOException If an error occurs + */ + protected final void implCloseChannel() throws IOException + { + implCloseSelectableChannel(); + } + + /** + * Closes this selectable channel. + * + * @exception IOException If an error occurs + */ + protected abstract void implCloseSelectableChannel() + throws IOException; + + /** + * Adjusts this channel's blocking mode. + * + * @param blocking true if blocking should be enabled, false otherwise + * + * @exception IOException If an error occurs + */ + protected abstract void implConfigureBlocking(boolean blocking) + throws IOException; + + /** + * Tells whether or not every I/O operation on this channel will block + * until it completes. + * + * @return true of this channel is blocking, false otherwise + */ + public final boolean isBlocking() + { + return blocking; + } + + /** + * Tells whether or not this channel is currently registered with + * any selectors. + * + * @return true if this channel is registered, false otherwise + */ + public final boolean isRegistered() + { + return ! keys.isEmpty(); + } + + /** + * Retrieves the key representing the channel's registration with the + * given selector. + * + * @param selector the selector to get a selection key for + * + * @return the selection key this channel is registered with + */ + public final SelectionKey keyFor(Selector selector) + { + if (! isOpen()) + return null; + + try + { + synchronized (blockingLock()) + { + return locate(selector); + } + } + catch (Exception e) + { + return null; + } + } + + /** + * Returns the provider that created this channel. + * + * @return the selector provider that created this channel + */ + public final SelectorProvider provider() + { + return provider; + } + + private SelectionKey locate(Selector selector) + { + ListIterator it = keys.listIterator(); + + while (it.hasNext()) + { + SelectionKey key = (SelectionKey) it.next(); + + if (key.selector() == selector) + return key; + } + + return null; + } + + /** + * Registers this channel with the given selector, returning a selection key. + * + * @param selin the seletor to use + * @param ops the interested operations + * @param att an attachment for the returned selection key + * + * @return the registered selection key + * + * @exception ClosedChannelException If the channel is already closed. + */ + public final SelectionKey register(Selector selin, int ops, Object att) + throws ClosedChannelException + { + if (! isOpen()) + throw new ClosedChannelException(); + + if ((ops & ~validOps()) != 0) + throw new IllegalArgumentException(); + + SelectionKey key = null; + AbstractSelector selector = (AbstractSelector) selin; + + synchronized (blockingLock()) + { + key = locate(selector); + + if (key != null && key.isValid()) + { + if (att != null) + key.attach(att); + } + else + { + key = selector.register(this, ops, att); + + if (key != null) + addSelectionKey(key); + } + } + + return key; + } + + void addSelectionKey(SelectionKey key) + { + keys.add(key); + } + + // This method gets called by AbstractSelector.deregister(). + void removeSelectionKey(SelectionKey key) + { + keys.remove(key); + } +} diff --git a/libjava/classpath/java/nio/channels/spi/AbstractSelectionKey.java b/libjava/classpath/java/nio/channels/spi/AbstractSelectionKey.java new file mode 100644 index 0000000..5ab8468 --- /dev/null +++ b/libjava/classpath/java/nio/channels/spi/AbstractSelectionKey.java @@ -0,0 +1,78 @@ +/* AbstractSelectionKey.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 java.nio.channels.spi; + +import java.nio.channels.SelectionKey; + + +/** + * @since 1.4 + */ +public abstract class AbstractSelectionKey extends SelectionKey +{ + private boolean cancelled; + + /** + * Initializes the key. + */ + protected AbstractSelectionKey() + { + } + + /** + * Cancels this key. + */ + public final void cancel() + { + if (isValid()) + { + ((AbstractSelector) selector()).cancelKey(this); + cancelled = true; + } + } + + /** + * Tells whether this key is valid or not. + * + * @return true if this key is valid, false otherwise + */ + public final boolean isValid() + { + return ! cancelled; + } +} diff --git a/libjava/classpath/java/nio/channels/spi/AbstractSelector.java b/libjava/classpath/java/nio/channels/spi/AbstractSelector.java new file mode 100644 index 0000000..7838073 --- /dev/null +++ b/libjava/classpath/java/nio/channels/spi/AbstractSelector.java @@ -0,0 +1,167 @@ +/* AbstractSelector.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 java.nio.channels.spi; + +import java.io.IOException; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.util.HashSet; +import java.util.Set; + + +public abstract class AbstractSelector extends Selector +{ + private boolean closed; + private SelectorProvider provider; + private HashSet cancelledKeys; + + /** + * Initializes the slector. + * + * @param provider the provider that created this selector + */ + protected AbstractSelector(SelectorProvider provider) + { + this.provider = provider; + this.cancelledKeys = new HashSet(); + } + + /** + * Closes the channel. + * + * @exception IOException If an error occurs + */ + public final synchronized void close() throws IOException + { + if (closed) + return; + + implCloseSelector(); + closed = true; + } + + /** + * Tells whether this channel is open or not. + * + * @return true if channel is open, false otherwise. + */ + public final boolean isOpen() + { + return ! closed; + } + + /** + * Marks the beginning of an I/O operation that might block indefinitely. + */ + protected final void begin() + { + } + + /** + * Marks the end of an I/O operation that might block indefinitely. + */ + protected final void end() + { + } + + /** + * Returns the provider for this selector object. + * + * @return the SelectorProvider object that created this seletor + */ + public final SelectorProvider provider() + { + return provider; + } + + /** + * Returns the cancelled keys set. + * + * @return the cancelled keys set + */ + protected final Set cancelledKeys() + { + if (! isOpen()) + throw new ClosedSelectorException(); + + return cancelledKeys; + } + + /** + * Cancels a selection key. + */ + + // This method is only called by AbstractSelectionKey.cancel(). + final void cancelKey(AbstractSelectionKey key) + { + synchronized (cancelledKeys) + { + cancelledKeys.add(key); + } + } + + /** + * Closes the channel. + * + * @exception IOException if an error occurs + */ + protected abstract void implCloseSelector() throws IOException; + + /** + * Registers a channel for the selection process. + * + * @param ch the channel register + * @param ops the interested operations + * @param att an attachement to the selection key + * + * @return the registered selection key + */ + protected abstract SelectionKey register(AbstractSelectableChannel ch, + int ops, Object att); + + /** + * Deregisters the given selection key. + * + * @param key the key to deregister + */ + protected final void deregister(AbstractSelectionKey key) + { + ((AbstractSelectableChannel) key.channel()).removeSelectionKey(key); + } +} diff --git a/libjava/classpath/java/nio/channels/spi/SelectorProvider.java b/libjava/classpath/java/nio/channels/spi/SelectorProvider.java new file mode 100644 index 0000000..db4e65f --- /dev/null +++ b/libjava/classpath/java/nio/channels/spi/SelectorProvider.java @@ -0,0 +1,151 @@ +/* SelectorProvider.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 java.nio.channels.spi; + +import gnu.java.nio.SelectorProviderImpl; + +import java.io.IOException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.Pipe; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; + + +/** + * @author Michael Koch + * @since 1.4 + */ +public abstract class SelectorProvider +{ + private static SelectorProvider systemDefaultProvider; + + /** + * Initializes the selector provider. + * + * @exception SecurityException If a security manager has been installed and + * it denies @see RuntimePermission ("selectorProvider"). + */ + protected SelectorProvider() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("selectorProvider")); + } + + /** + * Opens a datagram channel. + * + * @return a new datagram channel object + * + * @exception IOException if an error occurs + */ + public abstract DatagramChannel openDatagramChannel() + throws IOException; + + /** + * Opens a pipe. + * + * @return a new pipe object + * + * @exception IOException if an error occurs + */ + public abstract Pipe openPipe() throws IOException; + + /** + * Opens a selector. + * + * @return a new selector object + * + * @exception IOException if an error occurs + */ + public abstract AbstractSelector openSelector() throws IOException; + + /** + * Opens a server socket channel. + * + * @return a new server socket channel object + * + * @exception IOException if an error occurs + */ + public abstract ServerSocketChannel openServerSocketChannel() + throws IOException; + + /** + * Opens a socket channel. + * + * @return a new socket channel object + * + * @exception IOException if an error occurs + */ + public abstract SocketChannel openSocketChannel() throws IOException; + + /** + * Returns the system-wide default selector provider for this invocation + * of the Java virtual machine. + * + * @return the default seletor provider + */ + public static synchronized SelectorProvider provider() + { + if (systemDefaultProvider == null) + { + String propertyValue = + System.getProperty("java.nio.channels.spi.SelectorProvider"); + + if (propertyValue == null || propertyValue.equals("")) + systemDefaultProvider = new SelectorProviderImpl(); + else + { + try + { + systemDefaultProvider = + (SelectorProvider) Class.forName(propertyValue) + .newInstance(); + } + catch (Exception e) + { + System.err.println("Could not instantiate class: " + + propertyValue); + systemDefaultProvider = new SelectorProviderImpl(); + } + } + } + + return systemDefaultProvider; + } +} diff --git a/libjava/classpath/java/nio/channels/spi/package.html b/libjava/classpath/java/nio/channels/spi/package.html new file mode 100644 index 0000000..133fb04 --- /dev/null +++ b/libjava/classpath/java/nio/channels/spi/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.nio.channels.spi + + +

    Utility classes and interfaces for implementing channels.

    + + + diff --git a/libjava/classpath/java/nio/charset/CharacterCodingException.java b/libjava/classpath/java/nio/charset/CharacterCodingException.java new file mode 100644 index 0000000..6812ebb --- /dev/null +++ b/libjava/classpath/java/nio/charset/CharacterCodingException.java @@ -0,0 +1,53 @@ +/* CharacterCodingException.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 java.nio.charset; + +import java.io.IOException; + +/** + * @since 1.4 + */ +public class CharacterCodingException extends IOException +{ + /** + * Creates the exception + */ + public CharacterCodingException() + { + } +} diff --git a/libjava/classpath/java/nio/charset/Charset.java b/libjava/classpath/java/nio/charset/Charset.java new file mode 100644 index 0000000..6de2917 --- /dev/null +++ b/libjava/classpath/java/nio/charset/Charset.java @@ -0,0 +1,406 @@ +/* Charset.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 java.nio.charset; + +import gnu.classpath.SystemProperties; + +import gnu.java.nio.charset.Provider; +import gnu.java.nio.charset.iconv.IconvProvider; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.spi.CharsetProvider; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * @author Jesse Rosenstock + * @since 1.4 + * @status updated to 1.5 + */ +public abstract class Charset implements Comparable +{ + private CharsetEncoder cachedEncoder; + private CharsetDecoder cachedDecoder; + + /** + * Charset providers. + */ + private static CharsetProvider[] providers; + + private final String canonicalName; + private final String[] aliases; + + protected Charset (String canonicalName, String[] aliases) + { + checkName (canonicalName); + if (aliases != null) + { + int n = aliases.length; + for (int i = 0; i < n; ++i) + checkName (aliases[i]); + } + + cachedEncoder = null; + cachedDecoder = null; + this.canonicalName = canonicalName; + this.aliases = aliases; + } + + /** + * @throws IllegalCharsetNameException if the name is illegal + */ + private static void checkName (String name) + { + int n = name.length (); + + if (n == 0) + throw new IllegalCharsetNameException (name); + + char ch = name.charAt (0); + if (!(('A' <= ch && ch <= 'Z') + || ('a' <= ch && ch <= 'z') + || ('0' <= ch && ch <= '9'))) + throw new IllegalCharsetNameException (name); + + for (int i = 1; i < n; ++i) + { + ch = name.charAt (i); + if (!(('A' <= ch && ch <= 'Z') + || ('a' <= ch && ch <= 'z') + || ('0' <= ch && ch <= '9') + || ch == '-' || ch == '.' || ch == ':' || ch == '_')) + throw new IllegalCharsetNameException (name); + } + } + + /** + * Returns the system default charset. + * + * This may be set by the user or VM with the file.encoding + * property. + */ + public static Charset defaultCharset() + { + String encoding; + + try + { + encoding = SystemProperties.getProperty("file.encoding"); + } + catch(SecurityException e) + { + // Use fallback. + encoding = "ISO-8859-1"; + } + catch(IllegalArgumentException e) + { + // Use fallback. + encoding = "ISO-8859-1"; + } + + try + { + return forName(encoding); + } + catch(UnsupportedCharsetException e) + { + // Ignore. + } + catch(IllegalCharsetNameException e) + { + // Ignore. + } + catch(IllegalArgumentException e) + { + // Ignore. + } + + throw new IllegalStateException("Can't get default charset!"); + } + + public static boolean isSupported (String charsetName) + { + return charsetForName (charsetName) != null; + } + + /** + * Returns the Charset instance for the charset of the given name. + * + * @param charsetName + * @return + * @throws UnsupportedCharsetException if this VM does not support + * the charset of the given name. + * @throws IllegalCharsetNameException if the given charset name is + * legal. + * @throws IllegalArgumentException if charsetName is null. + */ + public static Charset forName (String charsetName) + { + // Throws IllegalArgumentException as the JDK does. + if(charsetName == null) + throw new IllegalArgumentException("Charset name must not be null."); + + Charset cs = charsetForName (charsetName); + if (cs == null) + throw new UnsupportedCharsetException (charsetName); + return cs; + } + + /** + * Retrieves a charset for the given charset name. + * + * @return A charset object for the charset with the specified name, or + * null if no such charset exists. + * + * @throws IllegalCharsetNameException if the name is illegal + */ + private static Charset charsetForName(String charsetName) + { + checkName (charsetName); + Charset cs = null; + CharsetProvider[] providers = providers2(); + for (int i = 0; i < providers.length; i++) + { + cs = providers[i].charsetForName(charsetName); + if (cs != null) + break; + } + return cs; + } + + public static SortedMap availableCharsets() + { + TreeMap charsets = new TreeMap(String.CASE_INSENSITIVE_ORDER); + + CharsetProvider[] providers = providers2(); + for (int j = 0; j < providers.length; j++) + { + for (Iterator i = providers[j].charsets(); i.hasNext(); ) + { + Charset cs = (Charset) i.next(); + charsets.put(cs.name(), cs); + } + } + + return Collections.unmodifiableSortedMap(charsets); + } + + private static CharsetProvider provider() + { + String useIconv = SystemProperties.getProperty + ("gnu.classpath.nio.charset.provider.iconv"); + + if (useIconv != null) + return IconvProvider.provider(); + + return Provider.provider(); + } + + /** + * We need to support multiple providers, reading them from + * java.nio.charset.spi.CharsetProvider in the resource directory + * META-INF/services. + */ + private static CharsetProvider[] providers2() + { + if (providers == null) + { + try + { + Enumeration en = ClassLoader.getSystemResources + ("META-INF/services/java.nio.charset.spi.CharsetProvider"); + LinkedHashSet set = new LinkedHashSet(); + set.add(provider()); + while (en.hasMoreElements()) + { + BufferedReader rdr = new BufferedReader(new InputStreamReader + (((URL) (en.nextElement())).openStream())); + while (true) + { + String s = rdr.readLine(); + if (s == null) + break; + CharsetProvider p = + (CharsetProvider) ((Class.forName(s)).newInstance()); + set.add(p); + } + } + + providers = new CharsetProvider[set.size()]; + set.toArray(providers); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + return providers; + } + + public final String name () + { + return canonicalName; + } + + public final Set aliases () + { + if (aliases == null) + return Collections.EMPTY_SET; + + // should we cache the aliasSet instead? + int n = aliases.length; + HashSet aliasSet = new HashSet (n); + for (int i = 0; i < n; ++i) + aliasSet.add (aliases[i]); + return Collections.unmodifiableSet (aliasSet); + } + + public String displayName () + { + return canonicalName; + } + + public String displayName (Locale locale) + { + return canonicalName; + } + + public final boolean isRegistered () + { + return (!canonicalName.startsWith ("x-") + && !canonicalName.startsWith ("X-")); + } + + public abstract boolean contains (Charset cs); + + public abstract CharsetDecoder newDecoder (); + + public abstract CharsetEncoder newEncoder (); + + public boolean canEncode () + { + return true; + } + + // NB: This implementation serializes different threads calling + // Charset.encode(), a potential performance problem. It might + // be better to remove the cache, or use ThreadLocal to cache on + // a per-thread basis. + public final synchronized ByteBuffer encode (CharBuffer cb) + { + try + { + if (cachedEncoder == null) + { + cachedEncoder = newEncoder () + .onMalformedInput (CodingErrorAction.REPLACE) + .onUnmappableCharacter (CodingErrorAction.REPLACE); + } else + cachedEncoder.reset(); + return cachedEncoder.encode (cb); + } + catch (CharacterCodingException e) + { + throw new AssertionError (e); + } + } + + public final ByteBuffer encode (String str) + { + return encode (CharBuffer.wrap (str)); + } + + // NB: This implementation serializes different threads calling + // Charset.decode(), a potential performance problem. It might + // be better to remove the cache, or use ThreadLocal to cache on + // a per-thread basis. + public final synchronized CharBuffer decode (ByteBuffer bb) + { + try + { + if (cachedDecoder == null) + { + cachedDecoder = newDecoder () + .onMalformedInput (CodingErrorAction.REPLACE) + .onUnmappableCharacter (CodingErrorAction.REPLACE); + } else + cachedDecoder.reset(); + + return cachedDecoder.decode (bb); + } + catch (CharacterCodingException e) + { + throw new AssertionError (e); + } + } + + public final int compareTo (Object ob) + { + return canonicalName.compareToIgnoreCase (((Charset) ob).canonicalName); + } + + public final int hashCode () + { + return canonicalName.hashCode (); + } + + public final boolean equals (Object ob) + { + if (ob instanceof Charset) + return canonicalName.equalsIgnoreCase (((Charset) ob).canonicalName); + else + return false; + } + + public final String toString () + { + return canonicalName; + } +} diff --git a/libjava/classpath/java/nio/charset/CharsetDecoder.java b/libjava/classpath/java/nio/charset/CharsetDecoder.java new file mode 100644 index 0000000..c86f1c8 --- /dev/null +++ b/libjava/classpath/java/nio/charset/CharsetDecoder.java @@ -0,0 +1,317 @@ +/* CharsetDecoder.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 java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; + +/** + * @author Jesse Rosenstock + * @since 1.4 + */ +public abstract class CharsetDecoder +{ + private static final int STATE_RESET = 0; + private static final int STATE_CODING = 1; + private static final int STATE_END = 2; + private static final int STATE_FLUSHED = 3; + + private static final String DEFAULT_REPLACEMENT = "\uFFFD"; + + private final Charset charset; + private final float averageCharsPerByte; + private final float maxCharsPerByte; + private String replacement; + + private int state = STATE_RESET; + + private CodingErrorAction malformedInputAction + = CodingErrorAction.REPORT; + private CodingErrorAction unmappableCharacterAction + = CodingErrorAction.REPORT; + + private CharsetDecoder (Charset cs, float averageCharsPerByte, + float maxCharsPerByte, String replacement) + { + if (averageCharsPerByte <= 0.0f) + throw new IllegalArgumentException ("Non-positive averageCharsPerByte"); + if (maxCharsPerByte <= 0.0f) + throw new IllegalArgumentException ("Non-positive maxCharsPerByte"); + + this.charset = cs; + this.averageCharsPerByte + = averageCharsPerByte; + this.maxCharsPerByte + = maxCharsPerByte; + this.replacement = replacement; + implReplaceWith (replacement); + } + + protected CharsetDecoder (Charset cs, float averageCharsPerByte, + float maxCharsPerByte) + { + this (cs, averageCharsPerByte, maxCharsPerByte, DEFAULT_REPLACEMENT); + } + + public final float averageCharsPerByte () + { + return averageCharsPerByte; + } + + public final Charset charset () + { + return charset; + } + + public final CharBuffer decode (ByteBuffer in) + throws CharacterCodingException + { + // XXX: Sun's Javadoc seems to contradict itself saying an + // IllegalStateException is thrown "if a decoding operation is already + // in progress" and also that "it resets this Decoder". + // Should we check to see that the state is reset, or should we + // call reset()? + if (state != STATE_RESET) + throw new IllegalStateException (); + + // REVIEW: Using max instead of average may allocate a very large + // buffer. Maybe we should do something more efficient? + int remaining = in.remaining (); + int n = (int) (remaining * maxCharsPerByte ()); + CharBuffer out = CharBuffer.allocate (n); + + if (remaining == 0) + { + state = STATE_FLUSHED; + return out; + } + + CoderResult cr = decode (in, out, true); + if (cr.isError ()) + cr.throwException (); + + cr = flush (out); + if (cr.isError ()) + cr.throwException (); + + reset(); + out.flip (); + + // Unfortunately, resizing the actual charbuffer array is required. + char[] resized = new char[out.remaining()]; + out.get(resized); + return CharBuffer.wrap(resized); + } + + public final CoderResult decode (ByteBuffer in, CharBuffer out, + boolean endOfInput) + { + int newState = endOfInput ? STATE_END : STATE_CODING; + // XXX: Need to check for "previous step was an invocation [not] of + // this method with a value of true for the endOfInput parameter but + // a return value indicating an incomplete decoding operation" + // XXX: We will not check the previous return value, just + // that the previous call passed true for endOfInput + if (state != STATE_RESET && state != STATE_CODING + && !(endOfInput && state == STATE_END)) + throw new IllegalStateException (); + state = newState; + + for (;;) + { + CoderResult cr; + try + { + cr = decodeLoop (in, out); + } + catch (RuntimeException e) + { + throw new CoderMalfunctionError (e); + } + + if (cr.isOverflow ()) + return cr; + + if (cr.isUnderflow ()) + { + if (endOfInput && in.hasRemaining ()) + cr = CoderResult.malformedForLength (in.remaining ()); + else + return cr; + } + + CodingErrorAction action = cr.isMalformed () + ? malformedInputAction + : unmappableCharacterAction; + + if (action == CodingErrorAction.REPORT) + return cr; + + if (action == CodingErrorAction.REPLACE) + { + if (out.remaining () < replacement.length ()) + return CoderResult.OVERFLOW; + out.put (replacement); + } + + in.position (in.position () + cr.length ()); + } + } + + protected abstract CoderResult decodeLoop (ByteBuffer in, CharBuffer out); + + public Charset detectedCharset () + { + throw new UnsupportedOperationException (); + } + + public final CoderResult flush (CharBuffer out) + { + // It seems weird that you can flush after reset, but Sun's javadoc + // says an IllegalStateException is thrown "If the previous step of the + // current decoding operation was an invocation neither of the reset + // method nor ... of the three-argument decode method with a value of + // true for the endOfInput parameter." + // Further note that flush() only requires that there not be + // an IllegalStateException if the previous step was a call to + // decode with true as the last argument. It does not require + // that the call succeeded. decode() does require that it succeeded. + // XXX: test this to see if reality matches javadoc + if (state != STATE_RESET && state != STATE_END) + throw new IllegalStateException (); + + state = STATE_FLUSHED; + return implFlush (out); + } + + protected CoderResult implFlush (CharBuffer out) + { + return CoderResult.UNDERFLOW; + } + + public final CharsetDecoder onMalformedInput (CodingErrorAction newAction) + { + if (newAction == null) + throw new IllegalArgumentException ("Null action"); + + malformedInputAction = newAction; + implOnMalformedInput (newAction); + return this; + } + + protected void implOnMalformedInput (CodingErrorAction newAction) + { + // default implementation does nothing + } + + protected void implOnUnmappableCharacter (CodingErrorAction newAction) + { + // default implementation does nothing + } + + protected void implReplaceWith (String newReplacement) + { + // default implementation does nothing + } + + protected void implReset () + { + // default implementation does nothing + } + + public boolean isAutoDetecting () + { + return false; + } + + public boolean isCharsetDetected () + { + throw new UnsupportedOperationException (); + } + + public CodingErrorAction malformedInputAction () + { + return malformedInputAction; + } + + public final float maxCharsPerByte () + { + return maxCharsPerByte; + } + + public final CharsetDecoder onUnmappableCharacter + (CodingErrorAction newAction) + { + if (newAction == null) + throw new IllegalArgumentException ("Null action"); + + unmappableCharacterAction = newAction; + implOnUnmappableCharacter (newAction); + return this; + } + + public final String replacement () + { + return replacement; + } + + public final CharsetDecoder replaceWith (String newReplacement) + { + if (newReplacement == null) + throw new IllegalArgumentException ("Null replacement"); + if (newReplacement.length () == 0) + throw new IllegalArgumentException ("Empty replacement"); + // XXX: what about maxCharsPerByte? + + this.replacement = newReplacement; + implReplaceWith (newReplacement); + return this; + } + + public final CharsetDecoder reset () + { + state = STATE_RESET; + implReset (); + return this; + } + + public CodingErrorAction unmappableCharacterAction () + { + return unmappableCharacterAction; + } +} diff --git a/libjava/classpath/java/nio/charset/CharsetEncoder.java b/libjava/classpath/java/nio/charset/CharsetEncoder.java new file mode 100644 index 0000000..932fe35 --- /dev/null +++ b/libjava/classpath/java/nio/charset/CharsetEncoder.java @@ -0,0 +1,369 @@ +/* CharsetEncoder.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 java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; + +/** + * @author Jesse Rosenstock + * @since 1.4 + */ +public abstract class CharsetEncoder +{ + private static final int STATE_RESET = 0; + private static final int STATE_CODING = 1; + private static final int STATE_END = 2; + private static final int STATE_FLUSHED = 3; + + private static final byte[] DEFAULT_REPLACEMENT = {(byte)'?'}; + + private final Charset charset; + private final float averageBytesPerChar; + private final float maxBytesPerChar; + private byte[] replacement; + + private int state = STATE_RESET; + + private CodingErrorAction malformedInputAction + = CodingErrorAction.REPORT; + private CodingErrorAction unmappableCharacterAction + = CodingErrorAction.REPORT; + + protected CharsetEncoder (Charset cs, float averageBytesPerChar, + float maxBytesPerChar) + { + this (cs, averageBytesPerChar, maxBytesPerChar, DEFAULT_REPLACEMENT); + } + + protected CharsetEncoder (Charset cs, float averageBytesPerChar, + float maxBytesPerChar, byte[] replacement) + { + if (averageBytesPerChar <= 0.0f) + throw new IllegalArgumentException ("Non-positive averageBytesPerChar"); + if (maxBytesPerChar <= 0.0f) + throw new IllegalArgumentException ("Non-positive maxBytesPerChar"); + + this.charset = cs; + this.averageBytesPerChar + = averageBytesPerChar; + this.maxBytesPerChar + = maxBytesPerChar; + this.replacement = replacement; + implReplaceWith (replacement); + } + + public final float averageBytesPerChar () + { + return averageBytesPerChar; + } + + public boolean canEncode (char c) + { + CharBuffer cb = CharBuffer.allocate (1).put (c); + cb.flip (); + return canEncode (cb); + } + + public boolean canEncode (CharSequence cs) + { + CharBuffer cb; + if (cs instanceof CharBuffer) + cb = ((CharBuffer) cs).duplicate (); + else + cb = CharBuffer.wrap (cs); + return canEncode (cb); + } + + private boolean canEncode (CharBuffer cb) + { + // It is an error if a coding operation is "in progress" + // I take that to mean the state is not reset or flushed. + // XXX: check "in progress" everywhere + if (state == STATE_FLUSHED) + reset (); + else if (state != STATE_RESET) + throw new IllegalStateException (); + + CodingErrorAction oldMalformedInputAction = malformedInputAction; + CodingErrorAction oldUnmappableCharacterAction + = unmappableCharacterAction; + + try + { + if (oldMalformedInputAction != CodingErrorAction.REPORT) + onMalformedInput (CodingErrorAction.REPORT); + if (oldUnmappableCharacterAction != CodingErrorAction.REPORT) + onUnmappableCharacter (CodingErrorAction.REPORT); + } + catch (Exception e) + { + return false; + } + finally + { + if (oldMalformedInputAction != CodingErrorAction.REPORT) + onMalformedInput (oldMalformedInputAction); + if (oldUnmappableCharacterAction != CodingErrorAction.REPORT) + onUnmappableCharacter (oldUnmappableCharacterAction); + } + + return true; + } + + public final Charset charset () + { + return charset; + } + + public final ByteBuffer encode (CharBuffer in) + throws CharacterCodingException + { + // XXX: Sun's Javadoc seems to contradict itself saying an + // IllegalStateException is thrown "if a decoding operation is already + // in progress" and also that "it resets this Encoder". + // Should we check to see that the state is reset, or should we + // call reset()? + if (state != STATE_RESET) + throw new IllegalStateException (); + + // REVIEW: Using max instead of average may allocate a very large + // buffer. Maybe we should do something more efficient? + int remaining = in.remaining (); + int n = (int) (remaining * maxBytesPerChar ()); + ByteBuffer out = ByteBuffer.allocate (n); + + if (remaining == 0) + { + state = STATE_FLUSHED; + return out; + } + + CoderResult cr = encode (in, out, true); + if (cr.isError ()) + cr.throwException (); + + cr = flush (out); + if (cr.isError ()) + cr.throwException (); + + out.flip (); + + // Unfortunately, resizing the actual bytebuffer array is required. + byte[] resized = new byte[out.remaining()]; + out.get(resized); + return ByteBuffer.wrap(resized); + } + + public final CoderResult encode (CharBuffer in, ByteBuffer out, + boolean endOfInput) + { + int newState = endOfInput ? STATE_END : STATE_CODING; + // XXX: Need to check for "previous step was an invocation [not] of + // this method with a value of true for the endOfInput parameter but + // a return value indicating an incomplete decoding operation" + // XXX: We will not check the previous return value, just + // that the previous call passed true for endOfInput + if (state != STATE_RESET && state != STATE_CODING + && !(endOfInput && state == STATE_END)) + throw new IllegalStateException (); + state = newState; + + for (;;) + { + CoderResult cr; + try + { + cr = encodeLoop (in, out); + } + catch (RuntimeException e) + { + throw new CoderMalfunctionError (e); + } + + if (cr.isOverflow ()) + return cr; + + if (cr.isUnderflow ()) + { + if (endOfInput && in.hasRemaining ()) + cr = CoderResult.malformedForLength (in.remaining ()); + else + return cr; + } + + CodingErrorAction action = cr.isMalformed () + ? malformedInputAction + : unmappableCharacterAction; + + if (action == CodingErrorAction.REPORT) + return cr; + + if (action == CodingErrorAction.REPLACE) + { + if (out.remaining () < replacement.length) + return CoderResult.OVERFLOW; + out.put (replacement); + } + + in.position (in.position () + cr.length ()); + } + } + + protected abstract CoderResult encodeLoop (CharBuffer in, ByteBuffer out); + + public final CoderResult flush (ByteBuffer out) + { + // It seems weird that you can flush after reset, but Sun's javadoc + // says an IllegalStateException is thrown "If the previous step of the + // current decoding operation was an invocation neither of the reset + // method nor ... of the three-argument encode method with a value of + // true for the endOfInput parameter." + // Further note that flush() only requires that there not be + // an IllegalStateException if the previous step was a call to + // encode with true as the last argument. It does not require + // that the call succeeded. encode() does require that it succeeded. + // XXX: test this to see if reality matches javadoc + if (state != STATE_RESET && state != STATE_END) + throw new IllegalStateException (); + + state = STATE_FLUSHED; + return implFlush (out); + } + + protected CoderResult implFlush (ByteBuffer out) + { + return CoderResult.UNDERFLOW; + } + + protected void implOnMalformedInput (CodingErrorAction newAction) + { + // default implementation does nothing + } + + protected void implOnUnmappableCharacter (CodingErrorAction newAction) + { + // default implementation does nothing + } + + protected void implReplaceWith (byte[] newReplacement) + { + // default implementation does nothing + } + + protected void implReset () + { + // default implementation does nothing + } + + public boolean isLegalReplacement (byte[] replacement) + { + // TODO: cache the decoder + // error actions will be REPORT after construction + CharsetDecoder decoder = charset.newDecoder (); + ByteBuffer bb = ByteBuffer.wrap (replacement); + CharBuffer cb + = CharBuffer.allocate ((int) (replacement.length + * decoder.maxCharsPerByte ())); + return !decoder.decode (bb, cb, true).isError (); + } + + public CodingErrorAction malformedInputAction () + { + return malformedInputAction; + } + + public final float maxBytesPerChar () + { + return maxBytesPerChar; + } + + public final CharsetEncoder onMalformedInput (CodingErrorAction newAction) + { + if (newAction == null) + throw new IllegalArgumentException ("Null action"); + + malformedInputAction = newAction; + implOnMalformedInput (newAction); + return this; + } + + public CodingErrorAction unmappableCharacterAction () + { + return unmappableCharacterAction; + } + + public final CharsetEncoder onUnmappableCharacter + (CodingErrorAction newAction) + { + if (newAction == null) + throw new IllegalArgumentException ("Null action"); + + unmappableCharacterAction = newAction; + implOnUnmappableCharacter (newAction); + return this; + } + + public final byte[] replacement () + { + return replacement; + } + + public final CharsetEncoder replaceWith (byte[] newReplacement) + { + if (newReplacement == null) + throw new IllegalArgumentException ("Null replacement"); + if (newReplacement.length == 0) + throw new IllegalArgumentException ("Empty replacement"); + // XXX: what about maxBytesPerChar? + + if (!isLegalReplacement (newReplacement)) + throw new IllegalArgumentException ("Illegal replacement"); + + this.replacement = newReplacement; + implReplaceWith (newReplacement); + return this; + } + + public final CharsetEncoder reset () + { + state = STATE_RESET; + implReset (); + return this; + } +} diff --git a/libjava/classpath/java/nio/charset/CoderMalfunctionError.java b/libjava/classpath/java/nio/charset/CoderMalfunctionError.java new file mode 100644 index 0000000..08294ca --- /dev/null +++ b/libjava/classpath/java/nio/charset/CoderMalfunctionError.java @@ -0,0 +1,52 @@ +/* CoderMalfunctionError.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 java.nio.charset; + +/** + * @since 1.4 + */ +public class CoderMalfunctionError extends Error +{ + /** + * Creates the error + */ + public CoderMalfunctionError(Exception cause) + { + super (cause); + } +} diff --git a/libjava/classpath/java/nio/charset/CoderResult.java b/libjava/classpath/java/nio/charset/CoderResult.java new file mode 100644 index 0000000..664215d --- /dev/null +++ b/libjava/classpath/java/nio/charset/CoderResult.java @@ -0,0 +1,189 @@ +/* CoderResult.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.nio.charset; + +import java.lang.ref.WeakReference; +import java.nio.BufferOverflowException; +import java.nio.BufferUnderflowException; +import java.util.HashMap; + +/** + * @author Jesse Rosenstock + * @since 1.4 + */ +public class CoderResult +{ + private static final int TYPE_MALFORMED = 0; + private static final int TYPE_OVERFLOW = 1; + private static final int TYPE_UNDERFLOW = 2; + private static final int TYPE_UNMAPPABLE = 3; + + public static final CoderResult OVERFLOW + = new CoderResult (TYPE_OVERFLOW, 0); + public static final CoderResult UNDERFLOW + = new CoderResult (TYPE_UNDERFLOW, 0); + + private static final String[] names + = { "MALFORMED", "OVERFLOW", "UNDERFLOW", "UNMAPPABLE" }; + + private static final Cache malformedCache + = new Cache () + { + protected CoderResult make (int length) + { + return new CoderResult (TYPE_MALFORMED, length); + } + }; + + private static final Cache unmappableCache + = new Cache () + { + protected CoderResult make (int length) + { + return new CoderResult (TYPE_UNMAPPABLE, length); + } + }; + + private final int type; + private final int length; + + // Package-private to avoid a trampoline constructor. + CoderResult (int type, int length) + { + this.type = type; + this.length = length; + } + + public boolean isError () + { + return length > 0; + } + + public boolean isMalformed () + { + return type == TYPE_MALFORMED; + } + + public boolean isOverflow () + { + return type == TYPE_OVERFLOW; + } + + public boolean isUnderflow () + { + return type == TYPE_UNDERFLOW; + } + + public boolean isUnmappable () + { + return type == TYPE_UNMAPPABLE; + } + + public int length () + { + if (length <= 0) + throw new UnsupportedOperationException (); + else + return length; + } + + public static CoderResult malformedForLength (int length) + { + return malformedCache.get (length); + } + + public void throwException () + throws CharacterCodingException + { + switch (type) + { + case TYPE_MALFORMED: + throw new MalformedInputException (length); + case TYPE_OVERFLOW: + throw new BufferOverflowException (); + case TYPE_UNDERFLOW: + throw new BufferUnderflowException (); + case TYPE_UNMAPPABLE: + throw new UnmappableCharacterException (length); + } + } + + public String toString () + { + String name = names[type]; + return (length > 0) ? name + '[' + length + ']' : name; + } + + public static CoderResult unmappableForLength (int length) + { + return unmappableCache.get (length); + } + + private abstract static class Cache + { + private final HashMap cache; + + // Package-private to avoid a trampoline constructor. + Cache () + { + cache = new HashMap (); + } + + // Package-private to avoid a trampoline. + synchronized CoderResult get (int length) + { + if (length <= 0) + throw new IllegalArgumentException ("Non-positive length"); + + Integer len = new Integer (length); + CoderResult cr = null; + Object o; + if ((o = cache.get (len)) != null) + cr = (CoderResult) ((WeakReference) o).get (); + if (cr == null) + { + cr = make (length); + cache.put (len, new WeakReference (cr)); + } + + return cr; + } + + protected abstract CoderResult make (int length); + } +} diff --git a/libjava/classpath/java/nio/charset/CodingErrorAction.java b/libjava/classpath/java/nio/charset/CodingErrorAction.java new file mode 100644 index 0000000..592c159 --- /dev/null +++ b/libjava/classpath/java/nio/charset/CodingErrorAction.java @@ -0,0 +1,66 @@ +/* CodingErrorAction.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 java.nio.charset; + +public class CodingErrorAction +{ + public static final CodingErrorAction IGNORE + = new CodingErrorAction("ignore"); + public static final CodingErrorAction REPLACE + = new CodingErrorAction("replace"); + public static final CodingErrorAction REPORT + = new CodingErrorAction("report"); + + private final String name; + + /** + * Private constructor only used to create the constant CodingErrorActions. + */ + private CodingErrorAction(String name) + { + this.name = name; + } + + /** + * Returns the name of the CodingErrorAction. + */ + public String toString () + { + return name; + } +} diff --git a/libjava/classpath/java/nio/charset/IllegalCharsetNameException.java b/libjava/classpath/java/nio/charset/IllegalCharsetNameException.java new file mode 100644 index 0000000..7baeac3 --- /dev/null +++ b/libjava/classpath/java/nio/charset/IllegalCharsetNameException.java @@ -0,0 +1,73 @@ +/* IllegalCharsetNameException.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 java.nio.charset; + +/** + * @author Michael Koch + * @since 1.4 + */ +public class IllegalCharsetNameException extends IllegalArgumentException +{ + /** + * Compatible with JDK 1.4+ + */ + private static final long serialVersionUID = 1457525358470002989L; + + private String charsetName; + + /** + * Creates the exception + * + * @param charsetName name of the illegal charset + */ + public IllegalCharsetNameException (String charsetName) + { + super (); + this.charsetName = charsetName; + } + + /** + * Retrieves the illegal charset name + * + * @return the illegal charset name + */ + public String getCharsetName () + { + return charsetName; + } +} diff --git a/libjava/classpath/java/nio/charset/MalformedInputException.java b/libjava/classpath/java/nio/charset/MalformedInputException.java new file mode 100644 index 0000000..0beceb4 --- /dev/null +++ b/libjava/classpath/java/nio/charset/MalformedInputException.java @@ -0,0 +1,77 @@ +/* MalformedInputException.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 java.nio.charset; + +/** + * @since 1.4 + */ +public class MalformedInputException extends CharacterCodingException +{ + private int inputLength; + + /** + * Creates the exception + * + * @param inputLength the position of malformed input in the input stream + */ + public MalformedInputException (int inputLength) + { + super (); + this.inputLength = inputLength; + } + + /** + * Retrieves the position of the malformed input in the input stream. + * + * @return the position + */ + public int getInputLength () + { + return inputLength; + } + + /** + * Returns the detail message string of this throwable + * + * @return the message + */ + public String getMessage () + { + return "Input length = " + inputLength; + } +} diff --git a/libjava/classpath/java/nio/charset/UnmappableCharacterException.java b/libjava/classpath/java/nio/charset/UnmappableCharacterException.java new file mode 100644 index 0000000..7190651 --- /dev/null +++ b/libjava/classpath/java/nio/charset/UnmappableCharacterException.java @@ -0,0 +1,71 @@ +/* UnmappableCharacterException.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 java.nio.charset; + +/** + * @since 1.4 + */ +public class UnmappableCharacterException extends CharacterCodingException +{ + private int inputLength; + + /** + * Creates the exception + */ + public UnmappableCharacterException (int inputLength) + { + super (); + this.inputLength = inputLength; + } + + /** + * Retrieves the illegal charset name + */ + public int getInputLength () + { + return inputLength; + } + + /** + * Returns the detail message string of this throwable + */ + public String getMessage () + { + return "Input length = " + inputLength; + } +} diff --git a/libjava/classpath/java/nio/charset/UnsupportedCharsetException.java b/libjava/classpath/java/nio/charset/UnsupportedCharsetException.java new file mode 100644 index 0000000..39536ba --- /dev/null +++ b/libjava/classpath/java/nio/charset/UnsupportedCharsetException.java @@ -0,0 +1,69 @@ +/* UnsupportedCharsetException.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 java.nio.charset; + +/** + * @author Michael Koch + * @since 1.4 + */ +public class UnsupportedCharsetException extends IllegalArgumentException +{ + /** + * Compatible with JDK 1.4+ + */ + private static final long serialVersionUID = 1490765524727386367L; + + String charsetName; + + /** + * Creates the exception + */ + public UnsupportedCharsetException (String charsetName) + { + super (); + this.charsetName = charsetName; + } + + /** + * Retrieves the illegal charset name + */ + public String getCharsetName () + { + return charsetName; + } +} diff --git a/libjava/classpath/java/nio/charset/package.html b/libjava/classpath/java/nio/charset/package.html new file mode 100644 index 0000000..acc7c02 --- /dev/null +++ b/libjava/classpath/java/nio/charset/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - java.nio.charset + + +

    Classes to manipulate, encode and decode different character sets from +and to bytes.

    + + + diff --git a/libjava/classpath/java/nio/charset/spi/CharsetProvider.java b/libjava/classpath/java/nio/charset/spi/CharsetProvider.java new file mode 100644 index 0000000..f0d40ab --- /dev/null +++ b/libjava/classpath/java/nio/charset/spi/CharsetProvider.java @@ -0,0 +1,91 @@ +/* CharsetProvider.java -- charset service provider interface + Copyright (C) 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 java.nio.charset.spi; + +import java.nio.charset.Charset; +import java.util.Iterator; + + +/** + * This class allows an implementor to provide additional character sets. The + * subclass must have a nullary constructor, and be attached to charset + * implementation classes. These extensions are loaded via the context class + * loader. To provide the charset extension, all files named + * META-INF/services/java.nio.charset.spi.CharsetProvider are + * read from the classpath. Each one should be a UTF-8 encoded list of + * fully-qualified names of concrete subclasses of this class; whitespace is + * ignored, and '#' starts comments. Duplicates are ignored. The + * implementations must be accessible to the classloader that requests them. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Charset + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class CharsetProvider +{ + /** + * Initialize a new charset provider. This performs a security check on + * RuntimePermission("charsetProvider"). + * + * @throws SecurityException if building a new set is not allowed + */ + protected CharsetProvider() + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new RuntimePermission("charsetProvider")); + } + + /** + * Returns an iterator over the charsets defined by this provider. + * + * @return the iterator + * @see Charset#availableCharsets() + */ + public abstract Iterator charsets(); + + /** + * Returns the named charset, by canonical name or alias. + * + * @param name the name of the character + * + * @return the charset, or null if not supported + */ + public abstract Charset charsetForName(String name); +} // class CharsetProvider diff --git a/libjava/classpath/java/nio/charset/spi/package.html b/libjava/classpath/java/nio/charset/spi/package.html new file mode 100644 index 0000000..dd47a25 --- /dev/null +++ b/libjava/classpath/java/nio/charset/spi/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.nio.charset.spi + + +

    Classes to provide new character sets.

    + + + diff --git a/libjava/classpath/java/nio/class-dependencies.conf b/libjava/classpath/java/nio/class-dependencies.conf new file mode 100644 index 0000000..4fbf75e --- /dev/null +++ b/libjava/classpath/java/nio/class-dependencies.conf @@ -0,0 +1,58 @@ +# This property file contains dependencies of classes, methods, and +# field on other methods or classes. +# +# Syntax: +# +# : [... ] +# +# means that when is included, (... ) must +# be included as well. +# +# and are of the form +# +# +# +# or just +# +# +# +# Within dependencies, variables can be used. A variable is defined as +# follows: +# +# {variable}: value1 value2 ... value +# +# variables can be used on the right side of dependencies as follows: +# +# : com.bla.blu.{variable}.Class.m()V +# +# The use of the variable will expand to dependencies of the form +# +# : com.bla.blu.value1.Class.m()V +# : com.bla.blu.value2.Class.m()V +# ... +# : com.bla.blu.value.Class.m()V +# +# Variables can be redefined when building a system to select the +# required support for features like encodings, protocols, etc. +# +# Hints: +# +# - For methods and fields, the signature is mandatory. For +# specification, please see the Java Virtual Machine Specification by +# SUN. Unlike in the spec, field signatures (types) are in brackets. +# +# - Package names must be separated by '/' (and not '.'). E.g., +# java/lang/Class (this is necessary, because the '.' is used to +# separate method or field names from classes) +# +# - In case refers to a class, only the class itself will be +# included in the resulting binary, NOT necessarily all its methods +# and fields. If you want to refer to all methods and fields, you can +# write class.* as an abbreviation. +# +# - Abbreviations for packages are also possible: my/package/* means all +# methods and fields of all classes in my/package. +# +# - A line with a trailing '\' continues in the next line. + +# end of file diff --git a/libjava/classpath/java/nio/package.html b/libjava/classpath/java/nio/package.html new file mode 100644 index 0000000..274498b --- /dev/null +++ b/libjava/classpath/java/nio/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.nio + + +

    Abstract classes for manipulating buffers of different primitive types.

    + + + diff --git a/libjava/classpath/java/rmi/AccessException.java b/libjava/classpath/java/rmi/AccessException.java new file mode 100644 index 0000000..b470780 --- /dev/null +++ b/libjava/classpath/java/rmi/AccessException.java @@ -0,0 +1,76 @@ +/* AccessException.java -- thrown if the caller does not have access + 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 java.rmi; + +/** + * Thrown to indicate that the caller does not have permission to access + * certain data, such as bind in an ActivationSystem. + * + * @author unknown + * @see Naming + * @see ActivationSystem + * @since 1.1 + */ +public class AccessException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 6314925228044966088l; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public AccessException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public AccessException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/AlreadyBoundException.java b/libjava/classpath/java/rmi/AlreadyBoundException.java new file mode 100644 index 0000000..091c0ee --- /dev/null +++ b/libjava/classpath/java/rmi/AlreadyBoundException.java @@ -0,0 +1,73 @@ +/* AlreadyBoundException.java -- thrown if a binding is already bound + 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 java.rmi; + +/** + * Thrown on an attempt to bind an object in the registry that is already + * bound. + * + * @author unknown + * @see Naming#bind(String, Remote) + * @see Registry#bind(String, Remote) + * @since 1.1 + * @status updated to 1.4 + */ +public class AlreadyBoundException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 9218657361741657110L; + + /** + * Create an exception with no message. + */ + public AlreadyBoundException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public AlreadyBoundException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/rmi/ConnectException.java b/libjava/classpath/java/rmi/ConnectException.java new file mode 100644 index 0000000..dc3abd1 --- /dev/null +++ b/libjava/classpath/java/rmi/ConnectException.java @@ -0,0 +1,74 @@ +/* ConnectException.java -- thrown if a connection is refused + 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 java.rmi; + +/** + * Thrown if a connection is refused for a remote call. + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class ConnectException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 4863550261346652506L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ConnectException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public ConnectException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/ConnectIOException.java b/libjava/classpath/java/rmi/ConnectIOException.java new file mode 100644 index 0000000..dde753a --- /dev/null +++ b/libjava/classpath/java/rmi/ConnectIOException.java @@ -0,0 +1,74 @@ +/* ConnectIOException.java -- thrown if an IO exception occurs during connect + 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 java.rmi; + +/** + * Wraps an I/O Exception thrown while connecting for a remote call. + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class ConnectIOException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -8087809532704668744L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ConnectIOException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public ConnectIOException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/MarshalException.java b/libjava/classpath/java/rmi/MarshalException.java new file mode 100644 index 0000000..e5c10a4 --- /dev/null +++ b/libjava/classpath/java/rmi/MarshalException.java @@ -0,0 +1,76 @@ +/* MarshalException.java -- wraps error while marshalling parameters + 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 java.rmi; + +/** + * Thrown if an exception occurs while marshalling data to send in a remote + * call. The call may not be retransmitted, if the "at most once" semantics + * are to be preserved. + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class MarshalException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 6223554758134037936L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public MarshalException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public MarshalException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/MarshalledObject.java b/libjava/classpath/java/rmi/MarshalledObject.java new file mode 100644 index 0000000..9ec0ace --- /dev/null +++ b/libjava/classpath/java/rmi/MarshalledObject.java @@ -0,0 +1,113 @@ +/* MarshalledObject.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 java.rmi; + +import gnu.java.rmi.RMIMarshalledObjectInputStream; +import gnu.java.rmi.RMIMarshalledObjectOutputStream; + +import java.io.ByteArrayOutputStream; +import java.io.Serializable; + +/** + * FIXME - doc missing + */ +public final class MarshalledObject implements Serializable +{ + //The following fields are from Java API Documentation "Serialized form" + private static final long serialVersionUID = 8988374069173025854L; + byte[] objBytes; + byte[] locBytes; + int hash; + + public MarshalledObject(Object obj) throws java.io.IOException + { + ByteArrayOutputStream objStream = new ByteArrayOutputStream(); + RMIMarshalledObjectOutputStream stream = new RMIMarshalledObjectOutputStream(objStream); + stream.writeObject(obj); + stream.flush(); + objBytes = objStream.toByteArray(); + locBytes = stream.getLocBytes(); + + //The following algorithm of calculating hashCode is similar to String + hash = 0; + for (int i = 0; i < objBytes.length; i++) + hash = hash * 31 + objBytes[i]; + if(locBytes != null) + for (int i = 0; i < locBytes.length; i++) + hash = hash * 31 + locBytes[i]; + } + + public boolean equals(Object obj) + { + if (! (obj instanceof MarshalledObject)) + return false; + + // hashCode even differs, don't do the time-consuming comparisons + if (obj.hashCode() != hash) + return false; + + MarshalledObject aobj = (MarshalledObject)obj; + if (objBytes == null || aobj.objBytes == null) + return objBytes == aobj.objBytes; + if (objBytes.length != aobj.objBytes.length) + return false; + for (int i = 0; i < objBytes.length; i++) + { + if (objBytes[i] != aobj.objBytes[i]) + return false; + } + // Ignore comparison of locBytes(annotation) + return true; + } + +public Object get() + throws java.io.IOException, java.lang.ClassNotFoundException +{ + if(objBytes == null) + return null; + RMIMarshalledObjectInputStream stream = + new RMIMarshalledObjectInputStream(objBytes, locBytes); + return stream.readObject(); +} + + public int hashCode() { + return hash; + } + +} diff --git a/libjava/classpath/java/rmi/Naming.java b/libjava/classpath/java/rmi/Naming.java new file mode 100644 index 0000000..d48df06 --- /dev/null +++ b/libjava/classpath/java/rmi/Naming.java @@ -0,0 +1,220 @@ +/* Naming.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 java.rmi; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; + +/** + *

    + * The Naming class handles interactions with RMI registries. + * Each method takes a URL in String form, which points to + * the RMI registry. The scheme of the URL is irrelevant. The relevant + * part is: + *

    + *

    + * //host:port/name + *

    + *

    + * which tells the method how to locate and access the registry. The host + * and port are both optional, and default to `localhost' and the standard + * RMI registry port (1099) respectively. The name is simply a string + * used to refer to a particular service hosted by the registry. The + * registry does not attempt to interpret this further. + *

    + *

    + * RMI services are registered using one of these names, and the same name + * is later used by the client to lookup the service and access its methods. + * Registries can be shared by multiple services, or a service can create + * its own registry using createRegistry(). + *

    + * + * @author Original author unknown. + * @author Ingo Proetel (proetel@aicas.com) + * @author Guilhem Lavaux (guilhem@kaffe.org) + * @author Jeroen Frijters (jeroen@frijters.net) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.1 + */ +public final class Naming { + + /** + * This class isn't intended to be instantiated. + */ + private Naming() {} + +/** + * Looks for the remote object that is associated with the named service. + * Name and location is given in form of a URL without a scheme: + * + *
    + * //host:port/service-name
    + * 
    + * + * The port is optional. + * + * @param name the service name and location + * @return Remote-object that implements the named service + * @throws NotBoundException if no object implements the service + * @throws MalformedURLException + * @throws RemoteException + */ +public static Remote lookup(String name) throws NotBoundException, MalformedURLException, RemoteException { + URL u = parseURL(name); + String serviceName = getName(u); + return (getRegistry(u).lookup(serviceName)); +} + +/** + * Try to bind the given object to the given service name. + * @param name + * @param obj + * @throws AlreadyBoundException + * @throws MalformedURLException + * @throws RemoteException + */ +public static void bind(String name, Remote obj) throws AlreadyBoundException, MalformedURLException, RemoteException { + URL u = parseURL(name); + String serviceName = getName(u); + getRegistry(u).bind(serviceName, obj); +} + +/** + * Remove a binding for a given service name. + * @param name + * @throws RemoteException + * @throws NotBoundException + * @throws MalformedURLException + */ +public static void unbind(String name) throws RemoteException, NotBoundException, MalformedURLException { + URL u = parseURL(name); + String serviceName = getName(u); + getRegistry(u).unbind(serviceName); +} + +/** + * Forces the binding between the given Remote-object and the given service name, even + * if there was already an object bound to this name. + * @param name + * @param obj + * @throws RemoteException + * @throws MalformedURLException + */ +public static void rebind(String name, Remote obj) throws RemoteException, MalformedURLException { + URL u = parseURL(name); + String serviceName = getName(u); + getRegistry(u).rebind(serviceName, obj); +} + +/** + * Lists all services at the named registry. + * @param name url that specifies the registry + * @return list of services at the name registry + * @throws RemoteException + * @throws MalformedURLException + */ +public static String[] list(String name) throws RemoteException, MalformedURLException { + return (getRegistry(parseURL(name)).list()); +} + +private static Registry getRegistry(URL u) throws RemoteException { + if (u.getPort() == -1) { + return (LocateRegistry.getRegistry(u.getHost())); + } + else { + return (LocateRegistry.getRegistry(u.getHost(), u.getPort())); + } +} + + /** + * Parses the supplied URL and converts it to use the HTTP + * protocol. From an RMI perspective, the scheme is irrelevant + * and we want to be able to create a URL for which a handler is + * available. + * + * @param name the URL in String form. + * @throws MalformedURLException if the URL is invalid. + */ + private static URL parseURL(String name) + throws MalformedURLException + { + try + { + URI uri = new URI(name); + String host = uri.getHost(); + int port = uri.getPort(); + String query = uri.getQuery(); + String path = uri.getPath(); + return new URL("http", + (host == null ? "localhost" : host), + (port == -1 ? 1099 : port), + uri.getPath() + (query == null ? "" : query)); + } + catch (URISyntaxException e) + { + throw new MalformedURLException("The URL syntax was invalid: " + + e.getMessage()); + } + } + + /** + * Checks that the URL contains a name, and removes any leading + * slashes. + * + * @param url the URL to check. + * @throws MalformedURLException if no name is specified. + */ + private static String getName(URL url) + throws MalformedURLException + { + String filename = url.getFile(); + if (filename.length() == 0) + throw new MalformedURLException("No path specified: " + url); + // If the filename begins with a slash we must cut it for + // name resolution. + if (filename.charAt(0) == '/') + return filename.substring(1); + return filename; + } + +} diff --git a/libjava/classpath/java/rmi/NoSuchObjectException.java b/libjava/classpath/java/rmi/NoSuchObjectException.java new file mode 100644 index 0000000..69f7d6c --- /dev/null +++ b/libjava/classpath/java/rmi/NoSuchObjectException.java @@ -0,0 +1,68 @@ +/* NoSuchObjectException.java -- thrown if the remote object no longer exists + 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 java.rmi; + +/** + * Thrown on an attempt to invoke a call on an object that no longer exists + * in the remote Virtual Machine. The call may be retransmitted and still + * obey the semantics of "at most once". + * + * @author unknown + * @see RemoteObject#toStub(Remote) + * @see UnicastRemoteObject#unexportObject(Remote, boolean) + * @see Activatable#unexportObject(Remote, boolean) + * @since 1.1 + * @status updated to 1.4 + */ +public class NoSuchObjectException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 6619395951570472985L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public NoSuchObjectException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/rmi/NotBoundException.java b/libjava/classpath/java/rmi/NotBoundException.java new file mode 100644 index 0000000..b8bc0a5 --- /dev/null +++ b/libjava/classpath/java/rmi/NotBoundException.java @@ -0,0 +1,75 @@ +/* NotBoundException.java -- attempt to use a registry name with no binding + 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 java.rmi; + +/** + * Thrown on an attempt to lookup or unbind a registry name that has no + * associated binding. + * + * @author unknown + * @see Naming#lookup(String) + * @see Naming#unbind(String) + * @see Registry#lookup(String) + * @see Registry#unbind(String) + * @since 1.1 + * @status updated to 1.4 + */ +public class NotBoundException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -1857741824849069317l; + + /** + * Create an exception with no message. + */ + public NotBoundException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public NotBoundException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/rmi/RMISecurityException.java b/libjava/classpath/java/rmi/RMISecurityException.java new file mode 100644 index 0000000..a44a67e --- /dev/null +++ b/libjava/classpath/java/rmi/RMISecurityException.java @@ -0,0 +1,77 @@ +/* RMISecurityException.java -- deprecated version of SecurityException + 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 java.rmi; + +/** + * Never thrown, but originally intended to wrap a java.lang.SecurityException. + * + * @author unknown + * @since 1.1 + * @deprecated use {@link SecurityException} instead + * @status updated to 1.4 + */ +public class RMISecurityException extends SecurityException +{ + /** + * Compatible with JDK 1.1. + */ + private static final long serialVersionUID = -8433406075740433514L; + + /** + * Create an exception with a message. + * + * @param s the message + * @deprecated no longer needed + */ + public RMISecurityException(String n) + { + super(n); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + * @deprecated no longer needed + */ + public RMISecurityException(String n, String a) + { + super(n); + } +} diff --git a/libjava/classpath/java/rmi/RMISecurityManager.java b/libjava/classpath/java/rmi/RMISecurityManager.java new file mode 100644 index 0000000..a8eb13e --- /dev/null +++ b/libjava/classpath/java/rmi/RMISecurityManager.java @@ -0,0 +1,48 @@ +/* RMISecurityManager.java -- + Copyright (c) 1996, 1997, 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 java.rmi; + +/** + * @since 1.1 + */ +public class RMISecurityManager extends SecurityManager +{ + public RMISecurityManager() + { + } +} diff --git a/libjava/classpath/java/rmi/Remote.java b/libjava/classpath/java/rmi/Remote.java new file mode 100644 index 0000000..93c8d0a --- /dev/null +++ b/libjava/classpath/java/rmi/Remote.java @@ -0,0 +1,41 @@ +/* Remote.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 java.rmi; + +public interface Remote { +} diff --git a/libjava/classpath/java/rmi/RemoteException.java b/libjava/classpath/java/rmi/RemoteException.java new file mode 100644 index 0000000..cbbb262 --- /dev/null +++ b/libjava/classpath/java/rmi/RemoteException.java @@ -0,0 +1,127 @@ +/* RemoteException.java -- common superclass for exceptions in java.rmi + 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 java.rmi; + +import java.io.IOException; + +/** + * The superclass of exceptions related to RMI (remote method invocation). + * Classes that implement java.rmi.Remote should list this + * exception in their throws clause. + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class RemoteException extends IOException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -5148567311918794206l; + + /** + * The cause of this exception. This pre-dates the exception chaining + * of Throwable; and although you can change this field, you are wiser + * to leave it alone. + * + * @serial the exception cause + */ + public Throwable detail; + + /** + * Create an exception with no message, and cause initialized to null. + */ + public RemoteException() + { + this(null, null); + } + + /** + * Create an exception with the given message, and cause initialized to null. + * + * @param s the message + */ + public RemoteException(String s) + { + this(s, null); + } + + /** + * Create an exception with the given message and cause. + * + * @param s the message + * @param ex the cause + */ + public RemoteException(String s, Throwable e) + { + super(s); + initCause(e); + detail = e; + } + + /** + * This method returns a message indicating what went wrong, in this + * format: + * super.getMessage() + (detail == null ? "" + * : "; nested exception is:\n\t" + detail). + * + * @return the chained message + */ + public String getMessage() + { + if (detail == this || detail == null) + return super.getMessage(); + return super.getMessage() + "; nested exception is:\n\t" + detail; + } + + /** + * Returns the cause of this exception. Note that this may not be the + * original cause, thanks to the detail field being public + * and non-final (yuck). However, to avoid violating the contract of + * Throwable.getCause(), this returns null if detail == this, + * as no exception can be its own cause. + * + * @return the cause + * @since 1.4 + */ + public Throwable getCause() + { + return detail == this ? null : detail; + } +} diff --git a/libjava/classpath/java/rmi/ServerError.java b/libjava/classpath/java/rmi/ServerError.java new file mode 100644 index 0000000..b1a15b0 --- /dev/null +++ b/libjava/classpath/java/rmi/ServerError.java @@ -0,0 +1,64 @@ +/* ServerError.java -- wraps an error while creating the server + 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 java.rmi; + +/** + * Wraps any error thrown while processing the server of a remote call. + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class ServerError extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 8455284893909696482L; + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public ServerError(String s, Error e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/ServerException.java b/libjava/classpath/java/rmi/ServerException.java new file mode 100644 index 0000000..5170aa7 --- /dev/null +++ b/libjava/classpath/java/rmi/ServerException.java @@ -0,0 +1,74 @@ +/* ServerException.java -- wraps an exception while creating the server + 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 java.rmi; + +/** + * Wraps any exception thrown while processing the server of a remote call. + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class ServerException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -4775845313121906682l; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ServerException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public ServerException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/ServerRuntimeException.java b/libjava/classpath/java/rmi/ServerRuntimeException.java new file mode 100644 index 0000000..1f08137 --- /dev/null +++ b/libjava/classpath/java/rmi/ServerRuntimeException.java @@ -0,0 +1,67 @@ +/* ServerRuntimeException.java -- wraps an exception while creating the server + 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 java.rmi; + +/** + * Wraps any runtime exception thrown while processing the server of a + * remote call. Note, this exception is no longer used. + * + * @author unknown + * @since 1.1 + * @deprecated no replacement + * @status updated to 1.4 + */ +public class ServerRuntimeException extends RemoteException +{ + /** + * Compatible with JDK 1.1. + */ + private static final long serialVersionUID = 7054464920481467219L; + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + * @deprecated no longer needed + */ + public ServerRuntimeException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/StubNotFoundException.java b/libjava/classpath/java/rmi/StubNotFoundException.java new file mode 100644 index 0000000..2f9e0f5 --- /dev/null +++ b/libjava/classpath/java/rmi/StubNotFoundException.java @@ -0,0 +1,77 @@ +/* StubNotFoundException.java -- thrown if a valid stub is not found + 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 java.rmi; + +/** + * Thrown if a valid stub class is not found for an object when it is exported. + * + * @author unknown + * @see UnicastRemoteObject + * @see Activatable + * @since 1.1 + * @status updated to 1.4 + */ +public class StubNotFoundException extends RemoteException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -7088199405468872373L; + + + /** + * Create an exception with a message. + * + * @param s the message + */ + public StubNotFoundException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public StubNotFoundException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/UnexpectedException.java b/libjava/classpath/java/rmi/UnexpectedException.java new file mode 100644 index 0000000..e9e0d6a --- /dev/null +++ b/libjava/classpath/java/rmi/UnexpectedException.java @@ -0,0 +1,75 @@ +/* UnexpectedException.java -- an unexpected checked exception was received + 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 java.rmi; + +/** + * Thrown if an unexpected checked exception was received in a remote + * procedure call. + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class UnexpectedException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 1800467484195073863L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public UnexpectedException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public UnexpectedException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/UnknownHostException.java b/libjava/classpath/java/rmi/UnknownHostException.java new file mode 100644 index 0000000..e21b994 --- /dev/null +++ b/libjava/classpath/java/rmi/UnknownHostException.java @@ -0,0 +1,75 @@ +/* UnknownHostException.java -- wraps java.net.UnknownHostException in RMI + 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 java.rmi; + +/** + * Thrown if a java.net.UnknownHostException occurs during a remote + * procedure call. + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class UnknownHostException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -8152710247442114228L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public UnknownHostException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public UnknownHostException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/UnmarshalException.java b/libjava/classpath/java/rmi/UnmarshalException.java new file mode 100644 index 0000000..6567062 --- /dev/null +++ b/libjava/classpath/java/rmi/UnmarshalException.java @@ -0,0 +1,88 @@ +/* UnmarshalException.java -- wraps error while unmarshalling parameters + 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 java.rmi; + +/** + * Thrown if an exception occurs while unmarshalling parameters or results + * of a remote method call. This includes:
      + *
    • if an exception occurs while unmarshalling the call header
    • + *
    • if the protocol for the return value is invalid
    • + *
    • if a java.io.IOException occurs unmarshalling parameters (on the + * server side) or the return value (on the client side).
    • + *
    • if a java.lang.ClassNotFoundException occurs during unmarshalling + * parameters or return values
    • + *
    • if no skeleton can be loaded on the server-side; note that skeletons + * are required in the 1.1 stub protocol, but not in the 1.2 stub + * protocol.
    • + *
    • if the method hash is invalid (i.e., missing method).
    • + *
    • if there is a failure to create a remote reference object for a remote + * object's stub when it is unmarshalled.
    • + *
    + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class UnmarshalException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 594380845140740218l; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public UnmarshalException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public UnmarshalException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/activation/Activatable.java b/libjava/classpath/java/rmi/activation/Activatable.java new file mode 100644 index 0000000..b4c38bf --- /dev/null +++ b/libjava/classpath/java/rmi/activation/Activatable.java @@ -0,0 +1,105 @@ +/* Activatable.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 java.rmi.activation; + +import java.rmi.MarshalledObject; +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.RemoteServer; + +public abstract class Activatable extends RemoteServer +{ +static final long serialVersionUID = -3120617863591563455L; + +protected Activatable(String location, MarshalledObject data, boolean restart, int port) throws ActivationException, RemoteException { + throw new Error("Not implemented"); +} + +protected Activatable(String location, MarshalledObject data, boolean restart, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws ActivationException, RemoteException { + throw new Error("Not implemented"); +} + +protected Activatable(ActivationID id, int port) throws RemoteException { + throw new Error("Not implemented"); +} + +protected Activatable(ActivationID id, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { + throw new Error("Not implemented"); +} + +protected ActivationID getID() { + throw new Error("Not implemented"); +} + +public static Remote register(ActivationDesc desc) throws UnknownGroupException, ActivationException, RemoteException { + throw new Error("Not implemented"); +} + +public static boolean inactive(ActivationID id) throws UnknownObjectException, ActivationException, RemoteException { + throw new Error("Not implemented"); +} + +public static void unregister(ActivationID id) throws UnknownObjectException, ActivationException, RemoteException { + throw new Error("Not implemented"); +} + +public static ActivationID exportObject(Remote obj, String location, MarshalledObject data, boolean restart, int port) throws ActivationException, RemoteException { + throw new Error("Not implemented"); +} + +public static ActivationID exportObject(Remote obj, String location, MarshalledObject data, boolean restart, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws ActivationException, RemoteException { + throw new Error("Not implemented"); +} + +public static Remote exportObject(Remote obj, ActivationID id, int port) throws RemoteException { + throw new Error("Not implemented"); +} + +public static Remote exportObject(Remote obj, ActivationID id, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { + throw new Error("Not implemented"); +} + +public static boolean unexportObject(Remote obj, boolean force) throws NoSuchObjectException { + throw new Error("Not implemented"); +} + +} diff --git a/libjava/classpath/java/rmi/activation/ActivateFailedException.java b/libjava/classpath/java/rmi/activation/ActivateFailedException.java new file mode 100644 index 0000000..1c2e10e --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivateFailedException.java @@ -0,0 +1,76 @@ +/* ActivateFailedException.java -- thrown when activation fails + 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 java.rmi.activation; + +import java.rmi.RemoteException; + +/** + * Thrown when activation fails on a remote call to an activatable object. + * + * @author unknown + * @since 1.2 + * @status updated to 1.4 + */ +public class ActivateFailedException extends RemoteException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 4863550261346652506L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ActivateFailedException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param ex the cause + */ + public ActivateFailedException(String s, Exception ex) + { + super(s, ex); + } +} diff --git a/libjava/classpath/java/rmi/activation/ActivationDesc.java b/libjava/classpath/java/rmi/activation/ActivationDesc.java new file mode 100644 index 0000000..65894f8 --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivationDesc.java @@ -0,0 +1,113 @@ +/* ActivationDecc.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 java.rmi.activation; + +import java.io.Serializable; +import java.rmi.MarshalledObject; + +public final class ActivationDesc implements Serializable +{ + static final long serialVersionUID = 7455834104417690957L; + +private ActivationGroupID groupid; +private String classname; +private String location; +private MarshalledObject data; +private boolean restart; + +public ActivationDesc(String className, String location, MarshalledObject data) throws ActivationException { + this(ActivationGroup.currentGroupID(), className, location, data, false); +} + +public ActivationDesc(String className, String location, MarshalledObject data, boolean restart) throws ActivationException { + this(ActivationGroup.currentGroupID(), className, location, data, restart); +} + +public ActivationDesc(ActivationGroupID groupID, String className, String location, MarshalledObject data) { + this(groupID, className, location, data, false); +} + +public ActivationDesc(ActivationGroupID groupID, String className, String location, MarshalledObject data, boolean restart) { + this.groupid = groupID; + this.classname = className; + this.location = location; + this.data = data; + this.restart = restart; +} + +public ActivationGroupID getGroupID() { + return (groupid); +} + +public String getClassName() { + return (classname); +} + +public String getLocation() { + return (location); +} + +public MarshalledObject getData() { + return (data); +} + +public boolean getRestartMode() { + return (restart); +} + +public boolean equals(Object obj) { + if (!(obj instanceof ActivationDesc)) { + return (false); + } + ActivationDesc that = (ActivationDesc)obj; + + if (this.groupid.equals(that.groupid) && + this.classname.equals(that.classname) && + this.location.equals(that.location) && + this.data.equals(that.data) && + this.restart == that.restart) { + return (true); + } + return (false); +} + +public int hashCode() { + return (groupid.hashCode() ^ classname.hashCode() ^ location.hashCode() ^ data.hashCode()); +} + +} diff --git a/libjava/classpath/java/rmi/activation/ActivationException.java b/libjava/classpath/java/rmi/activation/ActivationException.java new file mode 100644 index 0000000..418f438 --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivationException.java @@ -0,0 +1,122 @@ +/* ActivationException.java -- general Activation exception + 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 java.rmi.activation; + +/** + * General exception class for java.rmi.activation. + * + * @author unknown + * @since 1.2 + * @status updated to 1.4 + */ +public class ActivationException extends Exception +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -4320118837291406071L; + + /** + * The cause of this exception. This pre-dates the exception chaining + * of Throwable; and although you can change this field, you are wiser + * to leave it alone. + * + * @serial the exception cause + */ + public Throwable detail; + + /** + * Create an exception with no message, and cause initialized to null. + */ + public ActivationException() + { + this(null, null); + } + + /** + * Create an exception with the given message, and cause initialized to null. + * + * @param s the message + */ + public ActivationException(String s) + { + this(s, null); + } + + /** + * Create an exception with the given message and cause. + * + * @param s the message + * @param ex the cause + */ + public ActivationException(String s, Throwable ex) + { + super(s, ex); + detail = ex; + } + + /** + * This method returns a message indicating what went wrong, in this + * format: + * super.getMessage() + (detail == null ? "" + * : "; nested exception is:\n\t" + detail). + * + * @return the chained message + */ + public String getMessage() + { + if (detail == this || detail == null) + return super.getMessage(); + return super.getMessage() + "; nested exception is:\n\t" + detail; + } + + /** + * Returns the cause of this exception. Note that this may not be the + * original cause, thanks to the detail field being public + * and non-final (yuck). However, to avoid violating the contract of + * Throwable.getCause(), this returns null if detail == this, + * as no exception can be its own cause. + * + * @return the cause + * @since 1.4 + */ + public Throwable getCause() + { + return detail == this ? null : detail; + } +} diff --git a/libjava/classpath/java/rmi/activation/ActivationGroup.java b/libjava/classpath/java/rmi/activation/ActivationGroup.java new file mode 100644 index 0000000..e5774a1 --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivationGroup.java @@ -0,0 +1,85 @@ +/* ActivationGroup.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 java.rmi.activation; + +import java.rmi.MarshalledObject; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; + +public abstract class ActivationGroup extends UnicastRemoteObject + implements ActivationInstantiator +{ +static final long serialVersionUID = -7696947875314805420L; + +protected ActivationGroup(ActivationGroupID groupID) throws RemoteException { + throw new Error("Not implemented"); +} + +public boolean inactiveObject(ActivationID id) throws ActivationException, UnknownObjectException, RemoteException { + throw new Error("Not implemented"); +} + +public abstract void activeObject(ActivationID id, Remote obj) throws ActivationException, UnknownObjectException, RemoteException; + +public static ActivationGroup createGroup(ActivationGroupID id, ActivationGroupDesc desc, long incarnation) throws ActivationException { + throw new Error("Not implemented"); +} + +public static ActivationGroupID currentGroupID() { + throw new Error("Not implemented"); +} + +public static void setSystem(ActivationSystem system) throws ActivationException { + throw new Error("Not implemented"); +} + +public static ActivationSystem getSystem() throws ActivationException { + throw new Error("Not implemented"); +} + +protected void activeObject(ActivationID id, MarshalledObject mobj) throws ActivationException, UnknownObjectException, RemoteException { + throw new Error("Not implemented"); +} + +protected void inactiveGroup() throws UnknownGroupException, RemoteException { + throw new Error("Not implemented"); +} + +} diff --git a/libjava/classpath/java/rmi/activation/ActivationGroupDesc.java b/libjava/classpath/java/rmi/activation/ActivationGroupDesc.java new file mode 100644 index 0000000..35b546e --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivationGroupDesc.java @@ -0,0 +1,134 @@ +/* ActivationGroupDesc.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 java.rmi.activation; + +import java.io.Serializable; +import java.rmi.MarshalledObject; +import java.util.Properties; + +public final class ActivationGroupDesc implements Serializable +{ + static final long serialVersionUID = -4936225423168276595L; + +public static class CommandEnvironment + implements Serializable { + +static final long serialVersionUID = 6165754737887770191L; + +private String cmdpath; +private String[] argv; + +public CommandEnvironment(String cmdpath, String[] argv) { + this.cmdpath = cmdpath; + this.argv = argv; +} + +public String getCommandPath() { + return (cmdpath); +} + +public String[] getCommandOptions() { + return (argv); +} + +public boolean equals(Object obj) { + if (!(obj instanceof CommandEnvironment)) { + return (false); + } + CommandEnvironment that = (CommandEnvironment)obj; + + if (!this.cmdpath.equals(that.cmdpath)) { + return (false); + } + + int len = this.argv.length; + if (len != that.argv.length) { + return (false); + } + for (int i = 0; i < len; i++) { + if (!this.argv[i].equals(that.argv[i])) { + return (false); + } + } + return (true); +} + +public int hashCode() { + return (cmdpath.hashCode()); // Not a very good hash code. +} + +} + +public ActivationGroupDesc(Properties overrides, ActivationGroupDesc.CommandEnvironment cmd) { + throw new Error("Not implemented"); +} + +public ActivationGroupDesc(String className, String location, MarshalledObject data, Properties overrides, ActivationGroupDesc.CommandEnvironment cmd) { + throw new Error("Not implemented"); +} + +public String getClassName() { + throw new Error("Not implemented"); +} + +public String getLocation() { + throw new Error("Not implemented"); +} + +public MarshalledObject getData() { + throw new Error("Not implemented"); +} + +public Properties getPropertyOverrides() { + throw new Error("Not implemented"); +} + +public ActivationGroupDesc.CommandEnvironment getCommandEnvironment() { + throw new Error("Not implemented"); +} + +public boolean equals(Object obj) { + throw new Error("Not implemented"); +} + +public int hashCode() { + throw new Error("Not implemented"); +} + +} diff --git a/libjava/classpath/java/rmi/activation/ActivationGroupID.java b/libjava/classpath/java/rmi/activation/ActivationGroupID.java new file mode 100644 index 0000000..5e0b964 --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivationGroupID.java @@ -0,0 +1,70 @@ +/* ActivationGroupID.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 java.rmi.activation; + +import java.io.Serializable; + +public class ActivationGroupID implements Serializable +{ + static final long serialVersionUID = -1648432278909740833L; + +private ActivationSystem system; + +public ActivationGroupID(ActivationSystem system) { + this.system = system; +} + +public ActivationSystem getSystem() { + return (system); +} + +public int hashCode() { + return (system.hashCode()); +} + +public boolean equals(Object obj) { + if (obj instanceof ActivationGroupID) { + ActivationGroupID that = (ActivationGroupID)obj; + if (this.system.equals(that.system)) { + return (true); + } + } + return (false); +} + +} diff --git a/libjava/classpath/java/rmi/activation/ActivationID.java b/libjava/classpath/java/rmi/activation/ActivationID.java new file mode 100644 index 0000000..23ed853 --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivationID.java @@ -0,0 +1,72 @@ +/* ActivationID.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 java.rmi.activation; + +import java.io.Serializable; +import java.rmi.Remote; +import java.rmi.RemoteException; + +public class ActivationID implements Serializable +{ + static final long serialVersionUID = -4608673054848209235L; + +private Activator activator; + +public ActivationID(Activator activator) { + this.activator = activator; +} + +public Remote activate(boolean force) throws ActivationException, UnknownObjectException, RemoteException { + throw new Error("Not implemented"); +} + +public int hashCode() { + return (activator.hashCode()); +} + +public boolean equals(Object obj) { + if (obj instanceof ActivationID) { + ActivationID that = (ActivationID)obj; + if (this.activator.equals(that.activator)) { + return (true); + } + } + return (false); +} + +} diff --git a/libjava/classpath/java/rmi/activation/ActivationInstantiator.java b/libjava/classpath/java/rmi/activation/ActivationInstantiator.java new file mode 100644 index 0000000..0aceb7a --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivationInstantiator.java @@ -0,0 +1,50 @@ +/* ActivationInstantiator.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 java.rmi.activation; + +import java.rmi.MarshalledObject; +import java.rmi.Remote; +import java.rmi.RemoteException; + +public interface ActivationInstantiator + extends Remote +{ + MarshalledObject newInstance (ActivationID id, ActivationDesc desc) + throws ActivationException, RemoteException; +} diff --git a/libjava/classpath/java/rmi/activation/ActivationMonitor.java b/libjava/classpath/java/rmi/activation/ActivationMonitor.java new file mode 100644 index 0000000..1e64257 --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivationMonitor.java @@ -0,0 +1,55 @@ +/* ActivationMonitor.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 java.rmi.activation; + +import java.rmi.MarshalledObject; +import java.rmi.Remote; +import java.rmi.RemoteException; + +public interface ActivationMonitor extends Remote +{ + void inactiveObject (ActivationID id) + throws UnknownObjectException, RemoteException; + + void activeObject (ActivationID id, MarshalledObject obj) + throws UnknownObjectException, RemoteException; + + void inactiveGroup (ActivationGroupID id, long incarnation) + throws UnknownGroupException, RemoteException; +} diff --git a/libjava/classpath/java/rmi/activation/ActivationSystem.java b/libjava/classpath/java/rmi/activation/ActivationSystem.java new file mode 100644 index 0000000..4b92d40 --- /dev/null +++ b/libjava/classpath/java/rmi/activation/ActivationSystem.java @@ -0,0 +1,78 @@ +/* ActivationSystem.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 java.rmi.activation; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +public interface ActivationSystem extends Remote +{ + int SYSTEM_PORT = 1098; + + ActivationID registerObject (ActivationDesc desc) + throws ActivationException, UnknownGroupException, RemoteException; + + void unregisterObject (ActivationID id) + throws ActivationException, UnknownObjectException, RemoteException; + + ActivationGroupID registerGroup (ActivationGroupDesc desc) + throws ActivationException, RemoteException; + + ActivationMonitor activeGroup (ActivationGroupID id, + ActivationInstantiator group, long incarnation) + throws UnknownGroupException, ActivationException, RemoteException; + + void unregisterGroup (ActivationGroupID id) + throws ActivationException, UnknownGroupException, RemoteException; + + void shutdown() + throws RemoteException; + + ActivationDesc setActivationDesc (ActivationID id, ActivationDesc desc) + throws ActivationException, UnknownObjectException, UnknownGroupException, + RemoteException; + + ActivationGroupDesc setActivationGroupDesc (ActivationGroupID id, + ActivationGroupDesc desc) + throws ActivationException, UnknownGroupException, RemoteException; + + ActivationDesc getActivationDesc (ActivationID id) throws ActivationException, UnknownObjectException, RemoteException; + + ActivationGroupDesc getActivationGroupDesc (ActivationGroupID id) throws ActivationException, UnknownGroupException, RemoteException; +} diff --git a/libjava/classpath/java/rmi/activation/Activator.java b/libjava/classpath/java/rmi/activation/Activator.java new file mode 100644 index 0000000..2fb5a58 --- /dev/null +++ b/libjava/classpath/java/rmi/activation/Activator.java @@ -0,0 +1,50 @@ +/* Activator.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 java.rmi.activation; + +import java.rmi.MarshalledObject; +import java.rmi.Remote; +import java.rmi.RemoteException; + +public interface Activator + extends Remote +{ + MarshalledObject activate (ActivationID id, boolean force) + throws ActivationException, UnknownObjectException, RemoteException; +} diff --git a/libjava/classpath/java/rmi/activation/UnknownGroupException.java b/libjava/classpath/java/rmi/activation/UnknownGroupException.java new file mode 100644 index 0000000..91890a9 --- /dev/null +++ b/libjava/classpath/java/rmi/activation/UnknownGroupException.java @@ -0,0 +1,69 @@ +/* UnknownGroupException.java -- thrown on an invalid ActivationGroupID + 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 java.rmi.activation; + +/** + * Thrown when an ActivationGroupID parameter is invalid or + * unknown. + * + * @author unknown + * @see Activatable + * @see ActivationGroup + * @see ActivationID + * @see ActivationMonitor + * @see ActivationSystem + * @since 1.2 + * @status updated to 1.4 + */ +public class UnknownGroupException extends ActivationException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 7056094974750002460L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public UnknownGroupException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/rmi/activation/UnknownObjectException.java b/libjava/classpath/java/rmi/activation/UnknownObjectException.java new file mode 100644 index 0000000..8dbeb0e --- /dev/null +++ b/libjava/classpath/java/rmi/activation/UnknownObjectException.java @@ -0,0 +1,69 @@ +/* UnknownObjectException.java -- thrown on an invalid ActivationID + 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 java.rmi.activation; + +/** + * Thrown when an ActivationID parameter is invalid or unknown. + * + * @author unknown + * @see Activatable + * @see ActivationGroup + * @see ActivationID + * @see ActivationMonitor + * @see ActivationSystem + * @see Activator + * @since 1.2 + * @status updated to 1.4 + */ +public class UnknownObjectException extends ActivationException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 3425547551622251430L; + + /** + * Create an exception with an error message. + * + * @param s the message + */ + public UnknownObjectException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/rmi/activation/package.html b/libjava/classpath/java/rmi/activation/package.html new file mode 100644 index 0000000..444782d --- /dev/null +++ b/libjava/classpath/java/rmi/activation/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.rmi.activation + + +

    + + + diff --git a/libjava/classpath/java/rmi/dgc/DGC.java b/libjava/classpath/java/rmi/dgc/DGC.java new file mode 100644 index 0000000..e78ec2a --- /dev/null +++ b/libjava/classpath/java/rmi/dgc/DGC.java @@ -0,0 +1,51 @@ +/* DGC.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 java.rmi.dgc; + +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.server.ObjID; + +public interface DGC extends Remote +{ + Lease dirty (ObjID[] ids, long sequenceNum, Lease lease) + throws RemoteException; + + void clean (ObjID[] ids, long sequenceNum, VMID vmid, boolean strong) + throws RemoteException; +} diff --git a/libjava/classpath/java/rmi/dgc/Lease.java b/libjava/classpath/java/rmi/dgc/Lease.java new file mode 100644 index 0000000..d3d7f69 --- /dev/null +++ b/libjava/classpath/java/rmi/dgc/Lease.java @@ -0,0 +1,67 @@ +/* Lease.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 java.rmi.dgc; + +import java.io.Serializable; + +public final class Lease + implements Serializable { + +static final long serialVersionUID = -5713411624328831948L; + +private VMID vmid; +private long value; + +public Lease(VMID id, long duration) { + vmid = id; + value = duration; +} + +public VMID getVMID() { + return (vmid); +} + +public long getValue() { + return (value); +} + +public String toString() { + return ("[" + vmid.toString() + ", " + Long.toString(value) + "]"); +} + +} diff --git a/libjava/classpath/java/rmi/dgc/VMID.java b/libjava/classpath/java/rmi/dgc/VMID.java new file mode 100644 index 0000000..f960d9c --- /dev/null +++ b/libjava/classpath/java/rmi/dgc/VMID.java @@ -0,0 +1,138 @@ +/* VMID.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 java.rmi.dgc; + +import java.io.Serializable; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.rmi.server.UID; + +public final class VMID implements Serializable +{ + static final long serialVersionUID = -538642295484486218L; + + static final boolean areWeUnique; + + static byte[] localAddr; + + private byte[] addr; + + private UID uid; + + static + { + byte[] addr; + boolean awu = true; + try { + addr = InetAddress.getLocalHost().getAddress(); + if (addr[0] == 127 && addr[1] == 0 && addr[2] == 0 && addr[3] == 1) { + awu = false; + } + } + catch (UnknownHostException _) { + addr = new byte[]{ 127, 0, 0, 1 }; + awu = false; + } + localAddr = addr; + areWeUnique = awu; + } + + public VMID() + { + addr = localAddr; + uid = new UID(); + } + + /** + * @deprecated + */ + public static boolean isUnique () + { + return areWeUnique; + } + + public int hashCode () + { + return super.hashCode(); + } + + public boolean equals (Object obj) + { + if (!(obj instanceof VMID)) + { + return false; + } + + VMID other = (VMID) obj; + if (addr.length != other.addr.length) + { + return false; + } + + for (int i = addr.length - 1; i >= 0; i--) + { + if (addr[i] != other.addr[i]) + { + return false; + } + } + + return uid.equals(other.uid); + } + + public String toString () + { + StringBuffer buf = new StringBuffer ("[VMID: "); + + for (int i = 0; i < addr.length; i++) + { + if (i > 0) + { + buf.append ("."); + } + + buf.append (Integer.toString (addr [i])); + } + + buf.append (" "); + buf.append (uid.toString ()); + buf.append ("]"); + + return buf.toString(); + } +} diff --git a/libjava/classpath/java/rmi/dgc/package.html b/libjava/classpath/java/rmi/dgc/package.html new file mode 100644 index 0000000..9458d4c --- /dev/null +++ b/libjava/classpath/java/rmi/dgc/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.rmi.dgc + + +

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

    + + + diff --git a/libjava/classpath/java/rmi/registry/LocateRegistry.java b/libjava/classpath/java/rmi/registry/LocateRegistry.java new file mode 100644 index 0000000..3547a7a --- /dev/null +++ b/libjava/classpath/java/rmi/registry/LocateRegistry.java @@ -0,0 +1,87 @@ +/* LocateRegistry.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 java.rmi.registry; + +import gnu.java.rmi.registry.RegistryImpl; +import gnu.java.rmi.registry.RegistryImpl_Stub; +import gnu.java.rmi.server.UnicastRef; + +import java.rmi.RemoteException; +import java.rmi.server.ObjID; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.RMISocketFactory; +import java.rmi.server.RemoteRef; + +public final class LocateRegistry { + /** + * This class isn't intended to be instantiated. + */ + private LocateRegistry() {} + +public static Registry getRegistry() throws RemoteException { + return (getRegistry("localhost", Registry.REGISTRY_PORT)); +} + +public static Registry getRegistry(int port) throws RemoteException { + return (getRegistry("localhost", port)); +} + +public static Registry getRegistry(String host) throws RemoteException { + return (getRegistry(host, Registry.REGISTRY_PORT)); +} + +public static Registry getRegistry(String host, int port) throws RemoteException { + return (getRegistry(host, port, RMISocketFactory.getSocketFactory())); +} + +public static Registry getRegistry(String host, int port, RMIClientSocketFactory csf) throws RemoteException { + RemoteRef ref = new UnicastRef(new ObjID(ObjID.REGISTRY_ID), host, port, csf); + return (new RegistryImpl_Stub(ref)); +} + +public static Registry createRegistry(int port) throws RemoteException { + return (createRegistry(port, RMISocketFactory.getSocketFactory(), RMISocketFactory.getSocketFactory())); +} + +public static Registry createRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { + return (new RegistryImpl(port, csf, ssf)); +} + +} diff --git a/libjava/classpath/java/rmi/registry/Registry.java b/libjava/classpath/java/rmi/registry/Registry.java new file mode 100644 index 0000000..6cd2a04 --- /dev/null +++ b/libjava/classpath/java/rmi/registry/Registry.java @@ -0,0 +1,65 @@ +/* Registry.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 java.rmi.registry; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; + +public interface Registry extends Remote +{ + int REGISTRY_PORT = 1099; + + Remote lookup(String name) + throws RemoteException, NotBoundException, AccessException; + + void bind(String name, Remote obj) + throws RemoteException, AlreadyBoundException, AccessException; + + void unbind(String name) + throws RemoteException, NotBoundException, AccessException; + + void rebind(String name, Remote obj) + throws RemoteException, AccessException; + + String[] list() + throws RemoteException, AccessException; +} diff --git a/libjava/classpath/java/rmi/registry/RegistryHandler.java b/libjava/classpath/java/rmi/registry/RegistryHandler.java new file mode 100644 index 0000000..b9b4509 --- /dev/null +++ b/libjava/classpath/java/rmi/registry/RegistryHandler.java @@ -0,0 +1,58 @@ +/* RegistryHandler.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 java.rmi.registry; + +import java.rmi.RemoteException; +import java.rmi.UnknownHostException; + +/** + * @deprecated + */ +public interface RegistryHandler +{ + /** + * @deprecated + */ + Registry registryStub (String host, int port) + throws RemoteException, UnknownHostException; + + /** + * @deprecated + */ + Registry registryImpl (int port) throws RemoteException; +} diff --git a/libjava/classpath/java/rmi/registry/package.html b/libjava/classpath/java/rmi/registry/package.html new file mode 100644 index 0000000..4e16672 --- /dev/null +++ b/libjava/classpath/java/rmi/registry/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.rmi.registry + + +

    + + + diff --git a/libjava/classpath/java/rmi/server/ExportException.java b/libjava/classpath/java/rmi/server/ExportException.java new file mode 100644 index 0000000..b2d5bfc --- /dev/null +++ b/libjava/classpath/java/rmi/server/ExportException.java @@ -0,0 +1,78 @@ +/* ExportException.java -- an export attempt failed + 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 java.rmi.server; + +import java.rmi.RemoteException; + +/** + * Thrown if an attempt to export a remote object fails. + * + * @author unknown + * @see UnicastRemoteObject + * @see Activatable + * @since 1.1 + * @status updated to 1.4 + */ +public class ExportException extends RemoteException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -9155485338494060170L; + + /** + * Create an exception with the specified message. + * + * @param s the message + */ + public ExportException(String s) + { + super(s); + } + + /** + * Create an exception with the specified message and cause. + * + * @param s the message + * @param e the cause + */ + public ExportException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/server/LoaderHandler.java b/libjava/classpath/java/rmi/server/LoaderHandler.java new file mode 100644 index 0000000..1890857 --- /dev/null +++ b/libjava/classpath/java/rmi/server/LoaderHandler.java @@ -0,0 +1,66 @@ +/* LoaderHandler.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 java.rmi.server; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * @deprecated + */ +public interface LoaderHandler +{ + String packagePrefix = ""; + + /** + * @deprecated + */ + Class loadClass(String name) + throws MalformedURLException, ClassNotFoundException; + + /** + * @deprecated + */ + Class loadClass(URL codebase, String name) + throws MalformedURLException, ClassNotFoundException; + + /** + * @deprecated + */ + Object getSecurityContext(ClassLoader loader); +} diff --git a/libjava/classpath/java/rmi/server/LogStream.java b/libjava/classpath/java/rmi/server/LogStream.java new file mode 100644 index 0000000..a2dfbb4 --- /dev/null +++ b/libjava/classpath/java/rmi/server/LogStream.java @@ -0,0 +1,146 @@ +/* LogStream.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 java.rmi.server; + +import java.io.OutputStream; +import java.io.PrintStream; + +/** + * @deprecated + */ +public class LogStream extends PrintStream +{ + public static final int SILENT = 0; + public static final int BRIEF = 10; + public static final int VERBOSE = 20; + + private static PrintStream defStream; + + private LogStream (OutputStream s) + { + super (s); + } + + /** + * @deprecated + */ + public static LogStream log (String name) + { + throw new Error ("Not implemented"); + } + + /** + * @deprecated + */ + public static PrintStream getDefaultStream () + { + return defStream; + } + + /** + * @deprecated + */ + public static void setDefaultStream (PrintStream s) + { + defStream = s; + } + + /** + * @deprecated + */ + public OutputStream getOutputStream () + { + return out; + } + + /** + * @deprecated + */ + public void setOutputStream (OutputStream s) + { + out = s; + } + + /** + * @deprecated + */ + public void write (int buffer) + { + super.write (buffer); + } + + /** + * @deprecated + */ + public void write (byte[] buffer, int offset, int len) + { + super.write (buffer, offset, len); + } + + /** + * @deprecated + */ + public String toString () + { + throw new Error ("Not implemented"); + } + + /** + * @deprecated + */ + public static int parseLevel (String s) + { + if (s.equalsIgnoreCase ("silent")) + { + return SILENT; + } + + if (s.equalsIgnoreCase ("brief")) + { + return BRIEF; + } + + if (s.equalsIgnoreCase ("verbose")) + { + return VERBOSE; + } + + return SILENT; + } +} diff --git a/libjava/classpath/java/rmi/server/ObjID.java b/libjava/classpath/java/rmi/server/ObjID.java new file mode 100644 index 0000000..07cbbde --- /dev/null +++ b/libjava/classpath/java/rmi/server/ObjID.java @@ -0,0 +1,103 @@ +/* ObjID.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 java.rmi.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Serializable; + +public final class ObjID implements Serializable +{ +static final long serialVersionUID = -6386392263968365220L; + +private static long next = 0x8000000000000000L; +private static final Object lock = ObjID.class; + +public static final int REGISTRY_ID = 0; +public static final int ACTIVATOR_ID = 1; +public static final int DGC_ID = 2; + +private long objNum; +private UID space; + +public ObjID() { + synchronized (lock) { + objNum = next++; + } + space = new UID(); +} + +public ObjID(int num) { + objNum = (long)num; + space = new UID((short)0); +} + +public void write(ObjectOutput out) throws IOException { + DataOutput dout = (DataOutput)out; + dout.writeLong(objNum); + space.write(dout); +} + +public static ObjID read(ObjectInput in) throws IOException { + DataInput din = (DataInput)in; + ObjID id = new ObjID(); + id.objNum = din.readLong(); + id.space = UID.read(din); + return (id); +} + +public int hashCode() { + return ((int)objNum); +} + +public boolean equals(Object obj) { + if (obj instanceof ObjID && this.objNum == ((ObjID)obj).objNum) { + return (true); + } + return (false); +} + +public String toString() { + return ("[objNum: " + objNum + ", " + space + "]"); +} + +} diff --git a/libjava/classpath/java/rmi/server/Operation.java b/libjava/classpath/java/rmi/server/Operation.java new file mode 100644 index 0000000..64faf66 --- /dev/null +++ b/libjava/classpath/java/rmi/server/Operation.java @@ -0,0 +1,70 @@ +/* Operation.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 java.rmi.server; + +/** + * @deprecated + */ +public class Operation +{ + private String operation; + + /** + * @deprecated + */ + public Operation (String op) + { + operation = op; + } + + /** + * @deprecated + */ + public String getOperation () + { + return operation; + } + + /** + * @deprecated + */ + public String toString () + { + return operation; + } +} diff --git a/libjava/classpath/java/rmi/server/RMIClassLoader.java b/libjava/classpath/java/rmi/server/RMIClassLoader.java new file mode 100644 index 0000000..1a2e283 --- /dev/null +++ b/libjava/classpath/java/rmi/server/RMIClassLoader.java @@ -0,0 +1,339 @@ +/* RMIClassLoader.java -- + Copyright (c) 1996, 1997, 1998, 1999, 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 java.rmi.server; + +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Map; +import java.util.StringTokenizer; + + +/** + * This class provides a set of public static utility methods for supporting + * network-based class loading in RMI. These methods are called by RMI's + * internal marshal streams to implement the dynamic class loading of types for + * RMI parameters and return values. + */ +public class RMIClassLoader +{ + /** + * This class isn't intended to be instantiated. + */ + private RMIClassLoader() {} + + 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; + } + + private MyClassLoader (URL[] urls, ClassLoader parent) + { + super (urls, parent); + this.annotation = urlToAnnotation (urls); + } + + public static String urlToAnnotation (URL[] urls) + { + if (urls.length == 0) + return null; + + StringBuffer annotation = new StringBuffer (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 Map cacheLoaders; //map annotations to loaders + private static Map cacheAnnotations; //map loaders to annotations + + //defaultAnnotation is got from system property + // "java.rmi.server.defaultAnnotation" + private static String defaultAnnotation; + + //URL object for defaultAnnotation + private static URL defaultCodebase; + + //class loader for defaultAnnotation + private static MyClassLoader defaultLoader; + + 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) + { + defaultLoader = new MyClassLoader (new URL[] { defaultCodebase }, null, + defaultAnnotation); + cacheLoaders.put (new CacheKey (defaultAnnotation, + Thread.currentThread().getContextClassLoader()), + defaultLoader); + } + } + + /** + * @deprecated + */ + public static Class loadClass (String name) + throws MalformedURLException, ClassNotFoundException + { + return loadClass ("", name); + } + + public static Class loadClass (String codebases, String name) + throws MalformedURLException, ClassNotFoundException + { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + + //try context class loader first + try + { + return loader.loadClass (name); + } + catch (ClassNotFoundException e) + { + // class not found in the local classpath + } + + if (codebases.length() == 0) //=="" + { + loader = defaultLoader; + } + else + { + loader = getClassLoader(codebases); + } + + if (loader == null) + { + //do not throw NullPointerException + throw new ClassNotFoundException ("Could not find class (" + name + + ") at codebase (" + codebases + ")"); + } + + return loader.loadClass (name); + } + + /** + * Gets a classloader for the given codebase and with the current + * context classloader as parent. + * + * @param codebases + * + * @return a classloader for the given codebase + * + * @throws MalformedURLException if the codebase contains a malformed URL + */ + public static ClassLoader getClassLoader (String codebases) + throws MalformedURLException + { + ClassLoader loader; + CacheKey loaderKey = new CacheKey + (codebases, 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 (codebases, " "); + 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(), + codebases); + 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 static 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; + + StringBuffer annotation = new StringBuffer (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"); + } + + /** + * @deprecated + */ + public static Object getSecurityContext (ClassLoader loader) + { + throw new Error ("Not implemented"); + } +} diff --git a/libjava/classpath/java/rmi/server/RMIClassLoaderSpi.java b/libjava/classpath/java/rmi/server/RMIClassLoaderSpi.java new file mode 100644 index 0000000..372d818 --- /dev/null +++ b/libjava/classpath/java/rmi/server/RMIClassLoaderSpi.java @@ -0,0 +1,64 @@ +/* RMIClassLoaderSpi.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 java.rmi.server; + +import java.net.MalformedURLException; + +/** + * @author Michael Koch + * @since 1.4 + */ +public abstract class RMIClassLoaderSpi +{ + public RMIClassLoaderSpi() + { + } + + public abstract Class loadClass (String codeBase, String name, + ClassLoader defaultLoader) + throws MalformedURLException, ClassNotFoundException; + + public abstract Class loadProxyClass (String codeBase, String[] interfaces, + ClassLoader defaultLoader) + throws MalformedURLException, ClassNotFoundException; + + public abstract ClassLoader getClassLoader (String codebase) + throws MalformedURLException; + + public abstract String getClassAnnotation (Class cl); +} diff --git a/libjava/classpath/java/rmi/server/RMIClientSocketFactory.java b/libjava/classpath/java/rmi/server/RMIClientSocketFactory.java new file mode 100644 index 0000000..a54d111 --- /dev/null +++ b/libjava/classpath/java/rmi/server/RMIClientSocketFactory.java @@ -0,0 +1,47 @@ +/* RMIClientSocketFactory.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 java.rmi.server; + +import java.io.IOException; +import java.net.Socket; + +public interface RMIClientSocketFactory +{ + Socket createSocket (String host, int port) throws IOException; +} diff --git a/libjava/classpath/java/rmi/server/RMIFailureHandler.java b/libjava/classpath/java/rmi/server/RMIFailureHandler.java new file mode 100644 index 0000000..3496cd6 --- /dev/null +++ b/libjava/classpath/java/rmi/server/RMIFailureHandler.java @@ -0,0 +1,46 @@ +/* RMIFailureHandler.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 java.rmi.server; + +public interface RMIFailureHandler +{ + /** + * @exception IOException If an error occurs + */ + boolean failure (Exception ex); +} diff --git a/libjava/classpath/java/rmi/server/RMIServerSocketFactory.java b/libjava/classpath/java/rmi/server/RMIServerSocketFactory.java new file mode 100644 index 0000000..88eaff3 --- /dev/null +++ b/libjava/classpath/java/rmi/server/RMIServerSocketFactory.java @@ -0,0 +1,47 @@ +/* RMIServerSocketFactory.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 java.rmi.server; + +import java.io.IOException; +import java.net.ServerSocket; + +public interface RMIServerSocketFactory +{ + ServerSocket createServerSocket(int port) throws IOException; +} diff --git a/libjava/classpath/java/rmi/server/RMISocketFactory.java b/libjava/classpath/java/rmi/server/RMISocketFactory.java new file mode 100644 index 0000000..953f1ef --- /dev/null +++ b/libjava/classpath/java/rmi/server/RMISocketFactory.java @@ -0,0 +1,108 @@ +/* RMISocketFactory.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 java.rmi.server; + +import gnu.java.rmi.server.RMIDefaultSocketFactory; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +public abstract class RMISocketFactory + implements RMIClientSocketFactory, RMIServerSocketFactory +{ + private static RMISocketFactory defaultFactory; + private static RMISocketFactory currentFactory; + private static RMIFailureHandler currentHandler; + + static + { + defaultFactory = new RMIDefaultSocketFactory(); + currentFactory = defaultFactory; + } + + public RMISocketFactory () + { + } + + /** + * @exception IOException If an error occurs + */ + public abstract Socket createSocket (String host, int port) + throws IOException; + + /** + * @exception IOException If an error occurs + */ + public abstract ServerSocket createServerSocket (int port) + throws IOException; + + /** + * @exception IOException If an error occurs + * @exception SecurityException FIXME + */ + public static void setSocketFactory (RMISocketFactory fac) + throws IOException + { + currentFactory = fac; + } + + public static RMISocketFactory getSocketFactory () + { + return currentFactory; + } + + public static RMISocketFactory getDefaultSocketFactory () + { + return defaultFactory; + } + + /** + * @exception SecurityException FIXME + */ + public static void setFailureHandler (RMIFailureHandler fh) + { + currentHandler = fh; + } + + public static RMIFailureHandler getFailureHandler () + { + return currentHandler; + } +} diff --git a/libjava/classpath/java/rmi/server/RemoteCall.java b/libjava/classpath/java/rmi/server/RemoteCall.java new file mode 100644 index 0000000..35f3bf1 --- /dev/null +++ b/libjava/classpath/java/rmi/server/RemoteCall.java @@ -0,0 +1,86 @@ +/* RemoteCall.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 java.rmi.server; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.StreamCorruptedException; + +/** + * @deprecated + */ +public interface RemoteCall +{ + /** + * @deprecated + */ + ObjectOutput getOutputStream () throws IOException; + + /** + * @deprecated + */ + void releaseOutputStream () throws IOException; + + /** + * @deprecated + */ + ObjectInput getInputStream () throws IOException; + + /** + * @deprecated + */ + void releaseInputStream () throws IOException; + + /** + * @deprecated + */ + ObjectOutput getResultStream (boolean success) + throws IOException, StreamCorruptedException; + + /** + * @deprecated + */ + void executeCall () throws Exception; + + /** + * @deprecated + */ + void done () throws IOException; +} diff --git a/libjava/classpath/java/rmi/server/RemoteObject.java b/libjava/classpath/java/rmi/server/RemoteObject.java new file mode 100644 index 0000000..0b3c229 --- /dev/null +++ b/libjava/classpath/java/rmi/server/RemoteObject.java @@ -0,0 +1,160 @@ +/* RemoteObject.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 java.rmi.server; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.UnmarshalException; +import java.util.WeakHashMap; + +public abstract class RemoteObject + implements Remote, Serializable { + +private static final long serialVersionUID = -3215090123894869218l; + +protected transient RemoteRef ref; + +private static final WeakHashMap stubs = new WeakHashMap(); + +protected RemoteObject() { + this(null); +} + +protected RemoteObject(RemoteRef newref) { + ref = newref; +} + +public RemoteRef getRef() { + return (ref); +} + +synchronized static void addStub(Remote obj, Remote stub) +{ + stubs.put(obj, stub); +} + +synchronized static void deleteStub(Remote obj) +{ + stubs.remove(obj); +} + + public static Remote toStub(Remote obj) throws NoSuchObjectException + { + Remote stub = (Remote)stubs.get(obj); + + if (stub == null) + throw new NoSuchObjectException(obj.getClass().getName()); + + return stub; + } + +public int hashCode() { + if (ref == null) { + return (0); + } + else { + return (ref.hashCode()); + } +} + +public boolean equals(Object obj) { + // We only compare references. + return (this == obj); +} + + public String toString() + { + if (ref == null) + return getClass ().toString (); + return (ref.toString ()); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException + { + String cname = in.readUTF(); + if (!cname.equals("")) + { + if (cname.equals ("UnicastRef2")) + { + // hack for interoperating with JDK + cname = "UnicastRef"; + in.read (); //some unknown UnicastRef2 field + } + + cname = RemoteRef.packagePrefix + '.' + cname; + try + { + Class cls = Class.forName(cname); + ref = (RemoteRef)cls.newInstance(); + } + catch (InstantiationException e1) + { + throw new UnmarshalException("failed to create ref", e1); + } + catch (IllegalAccessException e2) + { + throw new UnmarshalException("failed to create ref", e2); + } + ref.readExternal(in); + } + else + { + ref = (RemoteRef)in.readObject(); + } + } + +private void writeObject(ObjectOutputStream out) throws IOException, ClassNotFoundException { + if (ref == null) { + throw new UnmarshalException("no ref to serialize"); + } + String cname = ref.getRefClass(out); + if (cname != null && cname.length() > 0) { + out.writeUTF(cname); + ref.writeExternal(out); + } + else { + out.writeUTF(""); + out.writeObject(ref); + } +} + +} diff --git a/libjava/classpath/java/rmi/server/RemoteRef.java b/libjava/classpath/java/rmi/server/RemoteRef.java new file mode 100644 index 0000000..7e34db3 --- /dev/null +++ b/libjava/classpath/java/rmi/server/RemoteRef.java @@ -0,0 +1,79 @@ +/* RemoteRef.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 java.rmi.server; + +import java.io.Externalizable; +import java.io.ObjectOutput; +import java.lang.reflect.Method; +import java.rmi.Remote; +import java.rmi.RemoteException; + +public interface RemoteRef extends Externalizable +{ + long serialVersionUID = 3632638527362204081L; + + String packagePrefix = "gnu.java.rmi.server"; + + /** + * @deprecated + */ + void invoke (RemoteCall call) throws Exception; + + Object invoke (Remote obj, Method method, Object[] params, long opnum) + throws Exception; + + /** + * @deprecated + */ + RemoteCall newCall (RemoteObject obj, Operation[] op, int opnum, long hash) + throws RemoteException; + + /** + * @deprecated + */ + void done (RemoteCall call) throws RemoteException; + + boolean remoteEquals (RemoteRef ref); + + int remoteHashCode(); + + String getRefClass (ObjectOutput out); + + String remoteToString(); +} diff --git a/libjava/classpath/java/rmi/server/RemoteServer.java b/libjava/classpath/java/rmi/server/RemoteServer.java new file mode 100644 index 0000000..9efb12a --- /dev/null +++ b/libjava/classpath/java/rmi/server/RemoteServer.java @@ -0,0 +1,76 @@ +/* RemoteServer.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 java.rmi.server; + +import gnu.java.rmi.server.RMIIncomingThread; + +import java.io.OutputStream; +import java.io.PrintStream; + +public abstract class RemoteServer extends RemoteObject +{ +private static final long serialVersionUID = -4100238210092549637L; + +protected RemoteServer() { + super(); +} + +protected RemoteServer(RemoteRef ref) { + super(ref); +} + +public static String getClientHost() throws ServerNotActiveException { + Thread currThread = Thread.currentThread(); + if (currThread instanceof RMIIncomingThread) { + RMIIncomingThread incomingThread = (RMIIncomingThread) currThread; + return incomingThread.getClientHost(); + } else { + throw new ServerNotActiveException( + "Unknown client host - current thread not instance of 'RMIIncomingThread'"); + } +} + +public static void setLog(OutputStream out) { + throw new Error("Not implemented"); +} + +public static PrintStream getLog() { + throw new Error("Not implemented"); +} + +} diff --git a/libjava/classpath/java/rmi/server/RemoteStub.java b/libjava/classpath/java/rmi/server/RemoteStub.java new file mode 100644 index 0000000..18c614b --- /dev/null +++ b/libjava/classpath/java/rmi/server/RemoteStub.java @@ -0,0 +1,61 @@ +/* RemoteStub.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 java.rmi.server; + +public abstract class RemoteStub extends RemoteObject +{ + static final long serialVersionUID = -1585587260594494182l; + + protected RemoteStub () + { + super (); + } + + protected RemoteStub (RemoteRef ref) + { + super (ref); + } + + /** + * @deprecated + */ + protected static void setRef (RemoteStub stub, RemoteRef ref) + { + stub.ref = ref; + } +} // class RemoteSub diff --git a/libjava/classpath/java/rmi/server/ServerCloneException.java b/libjava/classpath/java/rmi/server/ServerCloneException.java new file mode 100644 index 0000000..bda41b3 --- /dev/null +++ b/libjava/classpath/java/rmi/server/ServerCloneException.java @@ -0,0 +1,117 @@ +/* ServerCloneException.java -- a UnicastRemoteObject could not be cloned + 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 java.rmi.server; + +/** + * Thrown if a remote exception occurs during the cloning process of a + * UnicastRemoteObject. + * + * @author unknown + * @see UnicastRemoteObject#clone() + * @since 1.1 + * @status updated to 1.4 + */ +public class ServerCloneException extends CloneNotSupportedException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 6617456357664815945L; + + /** + * The cause of this exception. This pre-dates the exception chaining + * of Throwable; and although you can change this field, you are wiser + * to leave it alone. + * + * @serial the exception cause + */ + public Exception detail; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ServerCloneException(String s) + { + this(s, null); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message + * @param e the cause + */ + public ServerCloneException(String s, Exception e) + { + super(s); + initCause(e); + detail = e; + } + + /** + * This method returns a message indicating what went wrong, in this + * format: + * super.getMessage() + (detail == null ? "" + * : "; nested exception is:\n\t" + detail). + * + * @return the chained message + */ + public String getMessage() + { + if (detail == this || detail == null) + return super.getMessage(); + return super.getMessage() + "; nested exception is:\n\t" + detail; + } + + /** + * Returns the cause of this exception. Note that this may not be the + * original cause, thanks to the detail field being public + * and non-final (yuck). However, to avoid violating the contract of + * Throwable.getCause(), this returns null if detail == this, + * as no exception can be its own cause. + * + * @return the cause + * @since 1.4 + */ + public Throwable getCause() + { + return detail == this ? null : detail; + } +} diff --git a/libjava/classpath/java/rmi/server/ServerNotActiveException.java b/libjava/classpath/java/rmi/server/ServerNotActiveException.java new file mode 100644 index 0000000..0581b63 --- /dev/null +++ b/libjava/classpath/java/rmi/server/ServerNotActiveException.java @@ -0,0 +1,72 @@ +/* ServerNotActiveException.java -- the method is not servicing a remote call + 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 java.rmi.server; + +/** + * Thrown during RemoteServer.getClientHost if the host is + * not servicing a remote method call. + * + * @author unknown + * @see RemoteServer#getClientHost() + * @since 1.1 + * @status updated to 1.4 + */ +public class ServerNotActiveException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 4687940720827538231L; + + /** + * Create an exception with no message. + */ + public ServerNotActiveException() + { + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public ServerNotActiveException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/rmi/server/ServerRef.java b/libjava/classpath/java/rmi/server/ServerRef.java new file mode 100644 index 0000000..cf1013c --- /dev/null +++ b/libjava/classpath/java/rmi/server/ServerRef.java @@ -0,0 +1,51 @@ +/* ServerRef.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 java.rmi.server; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +public interface ServerRef extends RemoteRef +{ + long serialVersionUID = -4557750989390278438L; + + RemoteStub exportObject(Remote obj, Object data) throws RemoteException; + + String getClientHost() throws ServerNotActiveException; +} diff --git a/libjava/classpath/java/rmi/server/Skeleton.java b/libjava/classpath/java/rmi/server/Skeleton.java new file mode 100644 index 0000000..82f5d38 --- /dev/null +++ b/libjava/classpath/java/rmi/server/Skeleton.java @@ -0,0 +1,57 @@ +/* Skeleton.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 java.rmi.server; + +import java.rmi.Remote; + +/** + * @deprecated + */ +public interface Skeleton +{ + /** + * @deprecated + */ + void dispatch (Remote obj, RemoteCall theCall, int opnum, long hash) + throws Exception; + + /** + * @deprecated + */ + Operation[] getOperations(); +} diff --git a/libjava/classpath/java/rmi/server/SkeletonMismatchException.java b/libjava/classpath/java/rmi/server/SkeletonMismatchException.java new file mode 100644 index 0000000..9c0206a --- /dev/null +++ b/libjava/classpath/java/rmi/server/SkeletonMismatchException.java @@ -0,0 +1,68 @@ +/* SkeletonMismatchException.java -- thrown when stub class versions mismatch + 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 java.rmi.server; + +import java.rmi.RemoteException; + +/** + * Thrown if a call is received that does not match a Skeleton. Note that + * Skeletons are no longer required. + * + * @author unknown + * @since 1.1 + * @deprecated no replacement. Skeletons are no longer required. + * @status updated to 1.4 + */ +public class SkeletonMismatchException extends RemoteException +{ + /** + * Compatible with JDK 1.1. + */ + private static final long serialVersionUID = -7780460454818859281l; + + /** + * Create an exception with the specified message. + * + * @param s the message + * @deprecated no longer needed + */ + public SkeletonMismatchException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/rmi/server/SkeletonNotFoundException.java b/libjava/classpath/java/rmi/server/SkeletonNotFoundException.java new file mode 100644 index 0000000..596aae1 --- /dev/null +++ b/libjava/classpath/java/rmi/server/SkeletonNotFoundException.java @@ -0,0 +1,79 @@ +/* SkeletonNotFoundException.java -- thrown if a Skeleton is not found + 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 java.rmi.server; + +import java.rmi.RemoteException; + +/** + * Thrown if a Skeleton corresponding to the remote object is not found. + * Note that Skeletons are no longer required. + * + * @author unknown + * @since 1.1 + * @deprecated no replacement. Skeletons are no longer required. + * @status updated to 1.4 + */ +public class SkeletonNotFoundException extends RemoteException +{ + /** + * Compatible with JDK 1.1. + */ + private static final long serialVersionUID = -7860299673822761231L; + + /** + * Create an exception with the specified message. + * + * @param s the message + */ + public SkeletonNotFoundException(String s) + { + super(s); + } + + /** + * Create an exception with the specified message and cause. + * + * @param s the message + * @param e the cause + */ + public SkeletonNotFoundException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/server/SocketSecurityException.java b/libjava/classpath/java/rmi/server/SocketSecurityException.java new file mode 100644 index 0000000..aaf7698 --- /dev/null +++ b/libjava/classpath/java/rmi/server/SocketSecurityException.java @@ -0,0 +1,75 @@ +/* SocketSecurityException.java -- the socket could not be created + 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 java.rmi.server; + +/** + * Thrown during remote object export if the code does not have permission + * to create a java.net.ServerSocket on the specified port. + * + * @author unknown + * @since 1.1 + * @status updated to 1.4 + */ +public class SocketSecurityException extends ExportException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -7622072999407781979L; + + /** + * Create an exception with the specified message. + * + * @param s the message + */ + public SocketSecurityException(String s) + { + super(s); + } + + /** + * Create an exception with the specified message and cause. + * + * @param s the message + * @param e the cause + */ + public SocketSecurityException(String s, Exception e) + { + super(s, e); + } +} diff --git a/libjava/classpath/java/rmi/server/UID.java b/libjava/classpath/java/rmi/server/UID.java new file mode 100644 index 0000000..0f492ba --- /dev/null +++ b/libjava/classpath/java/rmi/server/UID.java @@ -0,0 +1,127 @@ +/* UID.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 java.rmi.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.Serializable; + +public final class UID implements Serializable +{ +private static final long serialVersionUID = 1086053664494604050L; + +private static final Object lock = UID.class; +private static long baseTime = System.currentTimeMillis(); +private static short nextCount = Short.MIN_VALUE; +// This is sun's algorithm - don't ask me why ... +private static final int uniqueNr = (new Object()).hashCode(); + +private int unique; +private long time; +private short count; + +/** + * This is sun's algorithm - don't ask me why ... + */ +public UID() { + synchronized (lock) { + if (nextCount == Short.MAX_VALUE) { + long newtime; + for (;;) { + newtime = System.currentTimeMillis(); + if (newtime - baseTime > 1000) { + break; + } + try { + Thread.sleep(1000); + } + catch (InterruptedException _) { + } + } + baseTime = newtime; + nextCount = Short.MIN_VALUE; + } + count = nextCount++; + unique = uniqueNr; + time = baseTime; + } +} + +public UID(short num) { + unique = (int)num; + time = 0; + count = 0; +} + +public int hashCode() { + return (unique); +} + +public boolean equals(Object obj) { + if (obj instanceof UID) { + UID uid = (UID)obj; + if (this.unique == uid.unique && + this.time == uid.time && + this.count == uid.count) { + return (true); + } + } + return (false); +} + +public String toString() { + return ("[UID: " + unique + "," + time + "," + count + "]"); +} + +public void write(DataOutput out) throws IOException { + out.writeInt(unique); + out.writeLong(time); + out.writeShort(count); +} + +public static UID read(DataInput in) throws IOException { + UID id = new UID(); + id.unique = in.readInt(); + id.time = in.readLong(); + id.count = in.readShort(); + return (id); +} + +} diff --git a/libjava/classpath/java/rmi/server/UnicastRemoteObject.java b/libjava/classpath/java/rmi/server/UnicastRemoteObject.java new file mode 100644 index 0000000..dbe25bd --- /dev/null +++ b/libjava/classpath/java/rmi/server/UnicastRemoteObject.java @@ -0,0 +1,133 @@ +/* UnicastRemoteObject.java -- + Copyright (c) 1996, 1997, 1998, 1999, 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 java.rmi.server; + +import gnu.java.rmi.server.UnicastServerRef; + +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; + +public class UnicastRemoteObject extends RemoteServer +{ +private static final long serialVersionUID = 4974527148936298033L; +//The following serialized fields are from Java API Documentation "Serialized form" +private int port = 0; +private RMIClientSocketFactory csf = null; +private RMIServerSocketFactory ssf = null; + +protected UnicastRemoteObject() throws RemoteException { + this(0); +} + +protected UnicastRemoteObject(int port) throws RemoteException { + this(port, RMISocketFactory.getSocketFactory(), RMISocketFactory.getSocketFactory()); +} + +protected UnicastRemoteObject(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { + this.port = port; + //Is RMIXXXSocketFactory serializable + //this.csf = csf; + //this.ssf = ssf; + this.ref = new UnicastServerRef(new ObjID(), port, ssf); + exportObject(this); +} + +protected UnicastRemoteObject(RemoteRef ref) throws RemoteException { + super((UnicastServerRef)ref); + exportObject(this); +} + +public Object clone() throws CloneNotSupportedException { + throw new Error("Not implemented"); +} + +public static RemoteStub exportObject(Remote obj) throws RemoteException { + UnicastServerRef sref = (UnicastServerRef)((RemoteObject)obj).getRef(); + return (sref.exportObject(obj)); +} + + public static Remote exportObject(Remote obj, int port) throws RemoteException + { + return exportObject(obj, port, null); + } + + static Remote exportObject(Remote obj, int port, RMIServerSocketFactory ssf) + throws RemoteException + { + UnicastServerRef sref = null; + if (obj instanceof RemoteObject) + sref = (UnicastServerRef)((RemoteObject)obj).getRef (); + if(sref == null) + { + sref = new UnicastServerRef(new ObjID (), port, ssf); + } + Remote stub = sref.exportObject (obj); + addStub(obj, stub); + return stub; + } + + /** + * FIXME + */ + public static Remote exportObject(Remote obj, int port, RMIClientSocketFactory csf, + RMIServerSocketFactory ssf) + throws RemoteException + { + return (exportObject(obj, port, ssf)); + } + + public static boolean unexportObject(Remote obj, boolean force) + throws NoSuchObjectException + { + if (obj instanceof RemoteObject) + { + deleteStub(obj); + UnicastServerRef sref = (UnicastServerRef)((RemoteObject)obj).getRef(); + return sref.unexportObject(obj, force); + } + else + { + //FIX ME + ; + } + return true; + } + +} diff --git a/libjava/classpath/java/rmi/server/Unreferenced.java b/libjava/classpath/java/rmi/server/Unreferenced.java new file mode 100644 index 0000000..982aa64 --- /dev/null +++ b/libjava/classpath/java/rmi/server/Unreferenced.java @@ -0,0 +1,43 @@ +/* Unreferenced.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 java.rmi.server; + +public interface Unreferenced +{ + void unreferenced(); +} diff --git a/libjava/classpath/java/rmi/server/package.html b/libjava/classpath/java/rmi/server/package.html new file mode 100644 index 0000000..54055a7 --- /dev/null +++ b/libjava/classpath/java/rmi/server/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.rmi.server + + +

    + + + diff --git a/libjava/classpath/java/security/AccessControlContext.java b/libjava/classpath/java/security/AccessControlContext.java new file mode 100644 index 0000000..9a6ad20 --- /dev/null +++ b/libjava/classpath/java/security/AccessControlContext.java @@ -0,0 +1,176 @@ +/* AccessControlContext.java --- Access Control Context Class + 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 java.security; + +import java.util.HashSet; + +/** + * AccessControlContext makes system resource access decsion + * based on permission rights. + * + * It is used for a specific context and has only one method + * checkPermission. It is similar to AccessController except + * that it makes decsions based on the current context instead + * of the the current thread. + * + * It is created by call AccessController.getContext method. + * + * @author Mark Benvenuto + * @since 1.2 + */ +public final class AccessControlContext +{ + private final ProtectionDomain[] protectionDomains; + private final DomainCombiner combiner; + + /** + * Construct a new AccessControlContext with the specified + * ProtectionDomains. context must not be + * null and duplicates will be removed. + * + * @param context The ProtectionDomains to use + */ + public AccessControlContext(ProtectionDomain[] context) + { + HashSet domains = new HashSet (context.length); + for (int i = 0; i < context.length; i++) + domains.add (context[i]); + protectionDomains = (ProtectionDomain[]) + domains.toArray (new ProtectionDomain[domains.size()]); + combiner = null; + } + + /** + * Construct a new AccessControlContext with the specified + * ProtectionDomains and DomainCombiner + * + * @since 1.3 + */ + public AccessControlContext(AccessControlContext acc, + DomainCombiner combiner) + { + // XXX check permission to call this. + AccessControlContext acc2 = AccessController.getContext(); + protectionDomains = combiner.combine (acc2.protectionDomains, + acc.protectionDomains); + this.combiner = combiner; + } + + AccessControlContext (ProtectionDomain[] domains, AccessControlContext acc, + DomainCombiner combiner) + { + protectionDomains = combiner.combine (domains, acc.protectionDomains); + this.combiner = combiner; + } + + /** + * Returns the Domain Combiner associated with the AccessControlContext + * + * @return the DomainCombiner + */ + public DomainCombiner getDomainCombiner() + { + return combiner; + } + + /** + * Determines whether or not the specific permission is granted + * depending on the context it is within. + * + * @param perm a permission to check + * + * @throws AccessControlException if the permssion is not permitted + */ + public void checkPermission(Permission perm) throws AccessControlException + { + if (protectionDomains.length == 0) + throw new AccessControlException ("permission not granted"); + for (int i = 0; i < protectionDomains.length; i++) + if (!protectionDomains[i].implies(perm)) + throw new AccessControlException ("permission not granted"); + } + + /** + * Checks if two AccessControlContexts are equal. + * + * It first checks if obj is an AccessControlContext class, and + * then checks if each ProtectionDomain matches. + * + * @param obj The object to compare this class to + * + * @return true if equal, false otherwise + */ + public boolean equals(Object obj) + { + if (obj instanceof AccessControlContext) + { + AccessControlContext acc = (AccessControlContext) obj; + + if (acc.protectionDomains.length != protectionDomains.length) + return false; + + int i, j; + for (i = 0; i < protectionDomains.length; i++) + { + for (j = 0; j < acc.protectionDomains.length; j++) + { + if (acc.protectionDomains[j].equals (protectionDomains[i])) + break; + } + if (j == acc.protectionDomains.length) + return false; + } + return true; + } + return false; + } + + /** + * Computes a hash code of this class + * + * @return a hash code representing this class + */ + public int hashCode() + { + int h = 0; + for (int i = 0; i < protectionDomains.length; i++) + h ^= protectionDomains[i].hashCode(); + + return h; + } +} diff --git a/libjava/classpath/java/security/AccessControlException.java b/libjava/classpath/java/security/AccessControlException.java new file mode 100644 index 0000000..27aee7c --- /dev/null +++ b/libjava/classpath/java/security/AccessControlException.java @@ -0,0 +1,97 @@ +/* AccessControlException.java -- Permission is denied + Copyright (C) 1998, 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 java.security; + +/** + * This exception is thrown when the AccessController denies + * an attempt to perform an operation. This often keeps track of the + * permission that was not granted. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see AccessController + * @status updated to 1.4 + */ +public class AccessControlException extends SecurityException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5138225684096988535L; + + /** + * The Permission associated with this exception. + * + * @serial the permission + */ + private final Permission perm; + + /** + * Create a new instance with a descriptive error message, and a null + * Permission object. + * + * @param msg the descriptive error message + */ + public AccessControlException(String msg) + { + this(msg, null); + } + + /** + * Create a new instance with a descriptive error message and an associated + * Permission object. + * + * @param msg the descriptive error message + * @param perm the permission that caused this + */ + public AccessControlException(String msg, Permission perm) + { + super(msg); + this.perm = perm; + } + + /** + * This method returns the Permission object that caused + * this exception to be thrown. + * + * @return the denied permission, or null + */ + public Permission getPermission() + { + return perm; + } +} diff --git a/libjava/classpath/java/security/AccessController.java b/libjava/classpath/java/security/AccessController.java new file mode 100644 index 0000000..bc9c2de --- /dev/null +++ b/libjava/classpath/java/security/AccessController.java @@ -0,0 +1,221 @@ +/* AccessController.java --- Access control context and permission checker + 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 java.security; + +/** + * Access control context and permission checker. + * Can check permissions in the access control context of the current thread + * through the checkPermission() method. + * Manipulates the access control context for code that needs to be executed + * the protection domain of the calling class (by explicitly ignoring the + * context of the calling code) in the doPrivileged() methods. + * And provides a getContext() method which gives the access + * control context of the current thread that can be used for checking + * permissions at a later time and/or in another thread. + * + * @author Mark Wielaard (mark@klomp.org) + * @since 1.2 + */ +public final class AccessController +{ + /** + * This class only has static methods so there is no public contructor. + */ + private AccessController() + { + } + + /** + * Checks wether the access control context of the current thread allows + * the given Permission. Throws an AccessControlException + * when the permission is not allowed in the current context. Otherwise + * returns silently without throwing an exception. + * + * @param perm the permission to be checked. + * @exception AccessControlException thrown if the current context does not + * allow the given permission. + */ + public static void checkPermission(Permission perm) + throws AccessControlException + { + getContext().checkPermission(perm); + } + + /** + * Calls the run() method of the given action with as + * (initial) access control context only the protection domain of the + * calling class. Calls to checkPermission() in the + * run() method ignore all earlier protection domains of + * classes in the call chain. Note that the protection domains of classes + * called by the code in the run() method are not ignored. + * + * @param action the PrivilegedAction whose run() + * should be be called. + * @return the result of the action.run() method. + */ + public static Object doPrivileged(PrivilegedAction action) + { + VMAccessController.pushContext(null); + try + { + return action.run(); + } + finally + { + VMAccessController.popContext(); + } + } + + /** + * Calls the run() method of the given action with as + * (initial) access control context the given context combined with the + * protection domain of the calling class. Calls to + * checkPermission() in the run() method ignore + * all earlier protection domains of classes in the call chain, but add + * checks for the protection domains given in the supplied context. + * + * @param action the PrivilegedAction whose run() + * should be be called. + * @param context the AccessControlContext whose protection + * domains should be added to the protection domain of the calling class. + * @return the result of the action.run() method. + */ + public static Object doPrivileged(PrivilegedAction action, + AccessControlContext context) + { + VMAccessController.pushContext(context); + try + { + return action.run(); + } + finally + { + VMAccessController.popContext(); + } + } + + /** + * Calls the run() method of the given action with as + * (initial) access control context only the protection domain of the + * calling class. Calls to checkPermission() in the + * run() method ignore all earlier protection domains of + * classes in the call chain. Note that the protection domains of classes + * called by the code in the run() method are not ignored. + * If the run() method throws an exception then this method + * will wrap that exception in an PrivilegedActionException. + * + * @param action the PrivilegedExceptionAction whose + * run() should be be called. + * @return the result of the action.run() method. + * @exception PrivilegedActionException wrapped around any exception that + * is thrown in the run() method. + */ + public static Object doPrivileged(PrivilegedExceptionAction action) + throws PrivilegedActionException + { + VMAccessController.pushContext(null); + try + { + return action.run(); + } + catch (Exception e) + { + throw new PrivilegedActionException(e); + } + finally + { + VMAccessController.popContext(); + } + } + + /** + * Calls the run() method of the given action with as + * (initial) access control context the given context combined with the + * protection domain of the calling class. Calls to + * checkPermission() in the run() method ignore + * all earlier protection domains of classes in the call chain, but add + * checks for the protection domains given in the supplied context. + * If the run() method throws an exception then this method + * will wrap that exception in an PrivilegedActionException. + * + * @param action the PrivilegedExceptionAction whose + * run() should be be called. + * @param context the AccessControlContext whose protection + * domains should be added to the protection domain of the calling class. + * @return the result of the action.run() method. + * @exception PrivilegedActionException wrapped around any exception that + * is thrown in the run() method. + */ + public static Object doPrivileged(PrivilegedExceptionAction action, + AccessControlContext context) + throws PrivilegedActionException + { + VMAccessController.pushContext(context); + try + { + return action.run(); + } + catch (Exception e) + { + throw new PrivilegedActionException(e); + } + finally + { + VMAccessController.popContext(); + } + } + + /** + * Returns the complete access control context of the current thread. + * The returned object encompasses all {@link ProtectionDomain} objects + * for all classes in the current call stack, or the set of protection + * domains until the last call to {@link + * #doPrivileged(java.security.PrivilegedAction)}. + * + *

    Additionally, if a call was made to {@link + * #doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)} + * that supplied an {@link AccessControlContext}, then that context + * will be intersected with the calculated one. + * + * @return The context. + */ + public static AccessControlContext getContext() + { + return VMAccessController.getContext(); + } +} diff --git a/libjava/classpath/java/security/AlgorithmParameterGenerator.java b/libjava/classpath/java/security/AlgorithmParameterGenerator.java new file mode 100644 index 0000000..5dc9e3b --- /dev/null +++ b/libjava/classpath/java/security/AlgorithmParameterGenerator.java @@ -0,0 +1,302 @@ +/* AlgorithmParameterGenerator.java --- Algorithm Parameter Generator + Copyright (C) 1999, 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 java.security; + +import gnu.java.security.Engine; + +import java.security.spec.AlgorithmParameterSpec; + +/** + *

    The AlgorithmParameterGenerator class is used to generate a + * set of parameters to be used with a certain algorithm. Parameter generators + * are constructed using the getInstance() factory methods (static + * methods that return instances of a given class).

    + * + *

    The object that will generate the parameters can be initialized in two + * different ways: in an algorithm-independent manner, or in an + * algorithm-specific manner:

    + * + *
      + *
    • The algorithm-independent approach uses the fact that all parameter + * generators share the concept of a "size" and a source of + * randomness. The measure of size is universally shared by all + * algorithm parameters, though it is interpreted differently for different + * algorithms. For example, in the case of parameters for the DSA + * algorithm, "size" corresponds to the size of the prime modulus (in + * bits). When using this approach, algorithm-specific parameter generation + * values - if any - default to some standard values, unless they can be + * derived from the specified size.
    • + *
    • The other approach initializes a parameter generator object using + * algorithm-specific semantics, which are represented by a set of + * algorithm-specific parameter generation values. To generate Diffie-Hellman + * system parameters, for example, the parameter generation values usually + * consist of the size of the prime modulus and the size of the random + * exponent, both specified in number of bits.
    • + *
    + * + *

    In case the client does not explicitly initialize the + * AlgorithmParameterGenerator (via a call to an init() + * method), each provider must supply (and document) a default initialization. + * For example, the GNU provider uses a default modulus prime size of + * 1024 bits for the generation of DSA parameters. + * + * @author Mark Benvenuto + * @since 1.2 + * @see AlgorithmParameters + * @see AlgorithmParameterSpec + */ +public class AlgorithmParameterGenerator +{ + /** Service name for algorithm parameter generators. */ + private static final String ALGORITHM_PARAMETER_GENERATOR = + "AlgorithmParameterGenerator"; + + private AlgorithmParameterGeneratorSpi paramGenSpi; + private Provider provider; + private String algorithm; + + /** + * Creates an AlgorithmParameterGenerator object. + * + * @param paramGenSpi the delegate. + * @param provider the provider. + * @param algorithm the algorithm. + */ + protected AlgorithmParameterGenerator(AlgorithmParameterGeneratorSpi + paramGenSpi, Provider provider, + String algorithm) + { + this.paramGenSpi = paramGenSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Returns the standard name of the algorithm this parameter generator is + * associated with. + * + * @return the string name of the algorithm. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Generates an AlgorithmParameterGenerator object that + * implements the specified digest algorithm. If the default provider package + * provides an implementation of the requested digest algorithm, an instance + * of AlgorithmParameterGenerator containing that implementation + * is returned. If the algorithm is not available in the default package, + * other packages are searched. + * + * @param algorithm the string name of the algorithm this parameter generator + * is associated with. + * @return the new AlgorithmParameterGenerator object. + * @throws NoSuchAlgorithmException if the algorithm is not available in the + * environment. + */ + public static AlgorithmParameterGenerator getInstance(String algorithm) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + for (int i = 0; i < p.length; i++) + try + { + return getInstance(algorithm, p[i]); + } + catch (NoSuchAlgorithmException e) + { + // Ignore. + } + + throw new NoSuchAlgorithmException(algorithm); + } + + /** + * Generates an AlgorithmParameterGenerator object for the + * requested algorithm, as supplied from the specified provider, if such a + * parameter generator is available from the provider. + * + * @param algorithm the string name of the algorithm. + * @param provider the string name of the provider. + * @return the new AlgorithmParameterGenerator object. + * @throws NoSuchAlgorithmException if the algorithm is not + * available from the provider. + * @throws NoSuchProviderException if the provider is not + * available in the environment. + * @throws IllegalArgumentException if the provider name is + * null or empty. + * @see Provider + */ + public static AlgorithmParameterGenerator getInstance(String algorithm, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null || provider.length() == 0) + throw new IllegalArgumentException("Illegal provider"); + + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + + return getInstance(algorithm, p); + } + + /** + * Generates an AlgorithmParameterGenerator object for the requested + * algorithm, as supplied from the specified provider, if such a parameter + * generator is available from the provider. Note: the provider + * doesn't have to be registered. + * + * @param algorithm the string name of the algorithm. + * @param provider the provider. + * @return the new AlgorithmParameterGenerator object. + * @throws NoSuchAlgorithmException if the algorithm is not available from + * the provider. + * @throws IllegalArgumentException if the provider is null. + * @since 1.4 + * @see Provider + */ + public static AlgorithmParameterGenerator getInstance(String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("Illegal provider"); + + try + { + return new AlgorithmParameterGenerator( + (AlgorithmParameterGeneratorSpi) Engine.getInstance( + ALGORITHM_PARAMETER_GENERATOR, algorithm, provider), + provider, algorithm); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new NoSuchAlgorithmException(algorithm); + } + catch (ClassCastException cce) + { + throw new NoSuchAlgorithmException(algorithm); + } + } + + /** + * Returns the provider of this algorithm parameter generator object. + * + * @return the provider of this algorithm parameter generator object. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Initializes this parameter generator for a certain size. To create + * the parameters, the {@link SecureRandom} implementation of the + * highest-priority installed provider is used as the source of randomness. + * (If none of the installed providers supply an implementation of + * {@link SecureRandom}, a system-provided source of randomness is used.) + * + * @param size the size (number of bits). + */ + public final void init(int size) + { + init(size, new SecureRandom()); + } + + /** + * Initializes this parameter generator for a certain size and source of + * randomness. + * + * @param size the size (number of bits). + * @param random the source of randomness. + */ + public final void init(int size, SecureRandom random) + { + paramGenSpi.engineInit(size, random); + } + + /** + * Initializes this parameter generator with a set of algorithm-specific + * parameter generation values. To generate the parameters, the {@link + * SecureRandom} implementation of the highest-priority installed provider is + * used as the source of randomness. (If none of the installed providers + * supply an implementation of {@link SecureRandom}, a system-provided source + * of randomness is used.) + * + * @param genParamSpec the set of algorithm-specific parameter generation + * values. + * @throws InvalidAlgorithmParameterException if the given parameter + * generation values are inappropriate for this parameter generator. + */ + public final void init(AlgorithmParameterSpec genParamSpec) + throws InvalidAlgorithmParameterException + { + init(genParamSpec, new SecureRandom()); + } + + /** + * Initializes this parameter generator with a set of algorithm-specific + * parameter generation values. + * + * @param genParamSpec the set of algorithm-specific parameter generation + * values. + * @param random the source of randomness. + * @throws InvalidAlgorithmParameterException if the given parameter + * generation values are inappropriate for this parameter generator. + */ + public final void init(AlgorithmParameterSpec genParamSpec, + SecureRandom random) + throws InvalidAlgorithmParameterException + { + paramGenSpi.engineInit(genParamSpec, random); + } + + /** + * Generates the parameters. + * + * @return the new {@link AlgorithmParameters} object. + */ + public final AlgorithmParameters generateParameters() + { + return paramGenSpi.engineGenerateParameters(); + } +} diff --git a/libjava/classpath/java/security/AlgorithmParameterGeneratorSpi.java b/libjava/classpath/java/security/AlgorithmParameterGeneratorSpi.java new file mode 100644 index 0000000..3143ea7 --- /dev/null +++ b/libjava/classpath/java/security/AlgorithmParameterGeneratorSpi.java @@ -0,0 +1,94 @@ +/* AlgorithmParameterGeneratorSpi.java --- Algorithm Parameter Generator SPI + Copyright (C) 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 java.security; +import java.security.spec.AlgorithmParameterSpec; + +/** + AlgorithmParameterGeneratorSpi is the Service Provider + Interface for the AlgorithmParameterGenerator class. + This class is used to generate the algorithm parameters + for a specific algorithm. + + @since JDK 1.2 + @author Mark Benvenuto + */ +public abstract class AlgorithmParameterGeneratorSpi +{ + + /** + Constructs a new AlgorithmParameterGeneratorSpi + */ + public AlgorithmParameterGeneratorSpi() + { + } + + /** + Initializes the parameter generator with the specified size + and SecureRandom + + @param size the size( in number of bits) + @param random the SecureRandom class to use for randomness + */ + protected abstract void engineInit(int size, SecureRandom random); + + /** + Initializes the parameter generator with the specified + AlgorithmParameterSpec and SecureRandom classes. + + If genParamSpec is an invalid AlgorithmParameterSpec for this + AlgorithmParameterGeneratorSpi then it throws + InvalidAlgorithmParameterException + + @param genParamSpec the AlgorithmParameterSpec class to use + @param random the SecureRandom class to use for randomness + + @throws InvalidAlgorithmParameterException genParamSpec is invalid + */ + protected abstract void engineInit(AlgorithmParameterSpec genParamSpec, + SecureRandom random) throws + InvalidAlgorithmParameterException; + + + /** + Generate a new set of AlgorithmParameters. + + @returns a new set of algorithm parameters + */ + protected abstract AlgorithmParameters engineGenerateParameters(); + +} diff --git a/libjava/classpath/java/security/AlgorithmParameters.java b/libjava/classpath/java/security/AlgorithmParameters.java new file mode 100644 index 0000000..038fbb4 --- /dev/null +++ b/libjava/classpath/java/security/AlgorithmParameters.java @@ -0,0 +1,340 @@ +/* AlgorithmParameters.java --- Algorithm Parameters Implementation Class + Copyright (C) 1999, 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 java.security; + +import gnu.java.security.Engine; + +import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +/** + *

    This class is used as an opaque representation of cryptographic + * parameters.

    + * + *

    An AlgorithmParameters object for managing the parameters + * for a particular algorithm can be obtained by calling one of the + * getInstance() factory methods (static methods that return + * instances of a given class).

    + * + *

    There are two ways to request such an implementation: by specifying + * either just an algorithm name, or both an algorithm name and a package + * provider.

    + * + *
      + *
    • If just an algorithm name is specified, the system will determine if + * there is an AlgorithmParameters implementation for the algorithm requested + * available in the environment, and if there is more than one, if there is + * a preferred one.
    • + *
    • If both an algorithm name and a package provider are specified, the + * system will determine if there is an implementation in the package + * requested, and throw an exception if there is not.
    • + *
    + * + *

    Once an AlgorithmParameters object is returned, it must be + * initialized via a call to init(), using an appropriate + * parameter specification or parameter encoding.

    + * + *

    A transparent parameter specification is obtained from an + * AlgorithmParameters object via a call to + * getParameterSpec(), and a byte encoding of the parameters is + * obtained via a call to getEncoded().

    + * + * @author Mark Benvenuto + * @since 1.2 + * @see AlgorithmParameterSpec + * @see java.security.spec.DSAParameterSpec + * @see KeyPairGenerator + */ +public class AlgorithmParameters +{ + /** Service name for algorithm parameters. */ + private static final String ALGORITHM_PARAMETERS = "AlgorithmParameters"; + + private AlgorithmParametersSpi paramSpi; + private Provider provider; + private String algorithm; + + /** + * Creates an AlgorithmParameters object. + * + * @param paramSpi the delegate. + * @param provider the provider. + * @param algorithm the algorithm. + */ + protected AlgorithmParameters(AlgorithmParametersSpi paramSpi, + Provider provider, String algorithm) + { + this.paramSpi = paramSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Returns the name of the algorithm associated with this parameter object. + * + * @return the algorithm name. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + *

    Generates a parameter object for the specified algorithm.

    + * + *

    If the default provider package provides an implementation of the + * requested algorithm, an instance of AlgorithmParameters + * containing that implementation is returned. If the algorithm is not + * available in the default package, other packages are searched.

    + * + *

    The returned parameter object must be initialized via a call to + * init(), using an appropriate parameter specification or + * parameter encoding.

    + * + * @param algorithm the name of the algorithm requested. + * @return the new parameter object. + * @throws NoSuchAlgorithmException if the algorithm is not available in the + * environment. + */ + public static AlgorithmParameters getInstance(String algorithm) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + + for (int i = 0; i < p.length; i++) + try + { + return getInstance(algorithm, p[i]); + } + catch (NoSuchAlgorithmException e) + { + // Ignore this. + } + + throw new NoSuchAlgorithmException(algorithm); + } + + /** + *

    Generates a parameter object for the specified algorithm, as supplied + * by the specified provider, if such an algorithm is available from the + * provider.

    + * + *

    The returned parameter object must be initialized via a call to + * init(), using an appropriate parameter specification or + * parameter encoding.

    + * + * @param algorithm the name of the algorithm requested. + * @param provider the name of the provider. + * @return the new parameter object. + * @throws NoSuchAlgorithmException if the algorithm is not available in the + * package supplied by the requested provider. + * @throws NoSuchProviderException if the provider is not available in the + * environment. + * @throws IllegalArgumentException if the provider name is null or empty. + * @see Provider + */ + public static AlgorithmParameters getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null || provider.length() == 0) + throw new IllegalArgumentException("Illegal provider"); + + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + + return getInstance(algorithm, p); + } + + /** + * Generates an AlgorithmParameterGenerator object for the + * requested algorithm, as supplied from the specified provider, if such a + * parameter generator is available from the provider. Note: the + * provider doesn't have to be registered. + * + * @param algorithm the string name of the algorithm. + * @param provider the provider. + * @return the new AlgorithmParameterGenerator object. + * @throws NoSuchAlgorithmException if the algorithm is not + * available from the provider. + * @throws IllegalArgumentException if the provider is + * null. + * @since 1.4 + */ + public static AlgorithmParameters getInstance(String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("Illegal provider"); + + try + { + return new AlgorithmParameters((AlgorithmParametersSpi) + Engine.getInstance(ALGORITHM_PARAMETERS, algorithm, provider), + provider, algorithm); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new NoSuchAlgorithmException(algorithm); + } + catch (ClassCastException cce) + { + throw new NoSuchAlgorithmException(algorithm); + } + } + + /** + * Returns the provider of this parameter object. + * + * @return the provider of this parameter object. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Initializes this parameter object using the parameters specified in + * paramSpec. + * + * @param paramSpec the parameter specification. + * @throws InvalidParameterSpecException if the given parameter specification + * is inappropriate for the initialization of this parameter object, or if + * this parameter object has already been initialized. + */ + public final void init(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + paramSpi.engineInit(paramSpec); + } + + /** + * Imports the specified parameters and decodes them according to the primary + * decoding format for parameters. The primary decoding format for parameters + * is ASN.1, if an ASN.1 specification for this type of parameters exists. + * + * @param params the encoded parameters. + * @throws IOException on decoding errors, or if this parameter object has + * already been initialized. + */ + public final void init(byte[]params) throws IOException + { + paramSpi.engineInit(params); + } + + /** + * Imports the parameters from params and decodes them according to the + * specified decoding scheme. If format is null, + * the primary decoding format for parameters is used. The primary decoding + * format is ASN.1, if an ASN.1 specification for these parameters exists. + * + * @param params the encoded parameters. + * @param format the name of the decoding scheme. + * @throws IOException on decoding errors, or if this parameter object has + * already been initialized. + */ + public final void init(byte[]params, String format) throws IOException + { + paramSpi.engineInit(params, format); + } + + /** + * Returns a (transparent) specification of this parameter object. + * paramSpec identifies the specification class in which the + * parameters should be returned. It could, for example, be + * DSAParameterSpec.class, to indicate that the parameters should + * be returned in an instance of the {@link java.security.spec.DSAParameterSpec} + * class. + * + * @param paramSpec the specification class in which the parameters should be + * returned. + * @return the parameter specification. + * @throws InvalidParameterSpecException if the requested parameter + * specification is inappropriate for this parameter object, or if this + * parameter object has not been initialized. + */ + public final AlgorithmParameterSpec getParameterSpec(Class paramSpec) + throws InvalidParameterSpecException + { + return paramSpi.engineGetParameterSpec(paramSpec); + } + + /** + * Returns the parameters in their primary encoding format. The primary + * encoding format for parameters is ASN.1, if an ASN.1 specification for + * this type of parameters exists. + * + * @return the parameters encoded using their primary encoding format. + * @throws IOException on encoding errors, or if this parameter object has not + * been initialized. + */ + public final byte[] getEncoded() throws IOException + { + return paramSpi.engineGetEncoded(); + } + + /** + * Returns the parameters encoded in the specified scheme. If format is + * null, the primary encoding format for parameters is used. The + * primary encoding format is ASN.1, if an ASN.1 specification for these + * parameters exists. + * + * @param format the name of the encoding format. + * @return the parameters encoded using the specified encoding scheme. + * @throws IOException on encoding errors, or if this parameter object has + * not been initialized. + */ + public final byte[] getEncoded(String format) throws IOException + { + return paramSpi.engineGetEncoded(format); + } + + /** + * Returns a formatted string describing the parameters. + * + * @return a formatted string describing the parameters, or null + * if this parameter object has not been initialized. + */ + public final String toString() + { + return paramSpi.engineToString(); + } +} diff --git a/libjava/classpath/java/security/AlgorithmParametersSpi.java b/libjava/classpath/java/security/AlgorithmParametersSpi.java new file mode 100644 index 0000000..a9faa15 --- /dev/null +++ b/libjava/classpath/java/security/AlgorithmParametersSpi.java @@ -0,0 +1,149 @@ +/* AlgorithmParametersSpi.java --- Algorithm Parameters SPI + 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 java.security; + +import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +/** + * AlgorithmParametersSpi is the Service Provider Interface + * for the Algorithm Parameters class. This class is used + * to manage the algorithm parameters. + * + * @since 1.2 + * @author Mark Benvenuto + */ +public abstract class AlgorithmParametersSpi +{ + /** + * Creates a new instance of AlgorithmParametersSpi + */ + public AlgorithmParametersSpi() + { + } + + /** + * Initializes the engine with the specified + * AlgorithmParameterSpec class. + * + * @param paramSpec A AlgorithmParameterSpec to initialize with + * + * @throws InvalidParameterSpecException For an inapporiate + * ParameterSpec class + */ + protected abstract void engineInit(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException; + + /** + * Initializes the engine with the specified + * parameters stored in the byte array and decodes them + * according to the ASN.1 specification. If the ASN.1 + * specification exists then it succeeds or else it throws + * IOException. + * + * @param params Parameters to initialize with + * + * @throws IOException Decoding Error + */ + protected abstract void engineInit(byte[]params) throws IOException; + + /** + * Initializes the engine with the specified + * parameters stored in the byte array and decodes them + * according to the specified decoding specification. + * If format is null, then it is decoded using the ASN.1 + * specification if it exists or else it throws + * IOException. + * + * @param params Parameters to initialize with + * @param format Name of decoding format to use + * + * @throws IOException Decoding Error + */ + protected abstract void engineInit(byte[]params, String format) + throws IOException; + + + /** + * Returns a specification of this AlgorithmParameters object. + * paramSpec identifies the class to return the AlgortihmParameters + * in. + * + * @param paramSpec Class to return AlgorithmParameters in + * + * @return the parameter specification + * + * @throws InvalidParameterSpecException if the paramSpec is an + * invalid parameter class + */ + protected abstract AlgorithmParameterSpec engineGetParameterSpec(Class + paramSpec) + throws InvalidParameterSpecException; + + + /** + * Returns the parameters in the default encoding format. + * The primary encoding format is ASN.1 format if it exists + * for the specified type. + * + * @return byte array representing the parameters + */ + protected abstract byte[] engineGetEncoded() throws IOException; + + + /** + * Returns the parameters in the specified encoding format. + * If format is null then the + * primary encoding format is used, the ASN.1 format, + * if it exists for the specified type. + * + * @return byte array representing the parameters + */ + protected abstract byte[] engineGetEncoded(String format) + throws IOException; + + /** + * Returns a string describing the parameters in the + * AlgorithmParametersSpi class. + * + * @return A string representing the format of the parameters. + */ + protected abstract String engineToString(); +} diff --git a/libjava/classpath/java/security/AllPermission.java b/libjava/classpath/java/security/AllPermission.java new file mode 100644 index 0000000..6adcd8c --- /dev/null +++ b/libjava/classpath/java/security/AllPermission.java @@ -0,0 +1,198 @@ +/* AllPermission.java -- Permission to do anything + Copyright (C) 1998, 2001, 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 java.security; + +import gnu.java.util.EmptyEnumeration; + +import java.util.Collections; +import java.util.Enumeration; + +/** + * This class is a permission that implies all other permissions. Granting + * this permission effectively grants all others. Extreme caution should + * be exercised in granting this permission. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see AccessController + * @see Permissions + * @see SecurityManager + * @since 1.1 + * @status updated to 1.4 + */ +public final class AllPermission extends Permission +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -2916474571451318075L; + + /** + * Create a new AllPermission object. + */ + public AllPermission() + { + super("*"); + } + + /** + * Create a new AllPermission object. The parameters are ignored, as all + * permission implies ALL PERMISSION. + * + * @param name ignored + * @param actions ignored + */ + public AllPermission(String name, String actions) + { + super("*"); + } + + /** + * This method always returns true to indicate that this + * permission always implies that any other permission is also granted. + * + * @param perm ignored + * @return true, the permission is implied + */ + public boolean implies(Permission perm) + { + return true; + } + + /** + * Checks an object for equality. All AllPermissions are equal. + * + * @param obj the Object to test for equality + */ + public boolean equals(Object obj) + { + return obj instanceof AllPermission; + } + + /** + * This method returns a hash code for this object. This returns 1. + * + * @return a hash value for this object + */ + public int hashCode() + { + return 1; + } + + /** + * This method returns the list of actions associated with this object. + * This will always be the empty string ("") for this class. + * + * @return the action list + */ + public String getActions() + { + return ""; + } + + /** + * Returns a PermissionCollection which can hold AllPermission. + * + * @return a permission collection + */ + public PermissionCollection newPermissionCollection() + { + return new AllPermissionCollection(); + } + + /** + * Implements AllPermission.newPermissionCollection, and obeys serialization + * of JDK. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class AllPermissionCollection extends PermissionCollection + { + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -4023755556366636806L; + + /** + * Whether an AllPermission has been added to the collection. + * + * @serial if all permission is in the collection yet + */ + private boolean all_allowed; + + /** + * Add an AllPermission. + * + * @param perm the permission to add + * @throws IllegalArgumentException if perm is not an AllPermission + * @throws SecurityException if the collection is read-only + */ + public void add(Permission perm) + { + if (isReadOnly()) + throw new SecurityException(); + if (! (perm instanceof AllPermission)) + throw new IllegalArgumentException(); + all_allowed = true; + } + + /** + * Returns true if this collection implies a permission. + * + * @param perm the permission to check + * @return true if this collection contains an AllPermission + */ + public boolean implies(Permission perm) + { + return all_allowed; + } + + /** + * Returns an enumeration of the elements in the collection. + * + * @return the elements in the collection + */ + public Enumeration elements() + { + return all_allowed + ? Collections.enumeration(Collections.singleton(new AllPermission())) + : EmptyEnumeration.getInstance(); + } + } // class AllPermissionCollection +} // class AllPermission diff --git a/libjava/classpath/java/security/BasicPermission.java b/libjava/classpath/java/security/BasicPermission.java new file mode 100644 index 0000000..267a6e2 --- /dev/null +++ b/libjava/classpath/java/security/BasicPermission.java @@ -0,0 +1,308 @@ +/* BasicPermission.java -- implements a simple named permission + Copyright (C) 1998, 1999, 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 java.security; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * This class implements a simple model for named permissions without an + * associated action list. That is, either the named permission is granted + * or it is not. + * + *

    It also supports trailing wildcards to allow the easy granting of + * permissions in a hierarchical fashion. (For example, the name "org.gnu.*" + * might grant all permissions under the "org.gnu" permissions hierarchy). + * The only valid wildcard character is a '*' which matches anything. It + * must be the rightmost element in the permission name and must follow a + * '.' or else the Permission name must consist of only a '*'. Any other + * occurrence of a '*' is not valid. + * + *

    This class ignores the action list. Subclasses can choose to implement + * actions on top of this class if desired. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Permission + * @see Permissions + * @see PermissionCollection + * @see RuntimePermission + * @see SecurityPermission + * @see PropertyPermission + * @see AWTPermission + * @see NetPermission + * @see SecurityManager + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class BasicPermission extends java.security.Permission + implements Serializable + // FIXME extends with fully qualified classname as workaround for gcj 3.3. +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 6279438298436773498L; + + /** + * Create a new instance with the specified permission name. If the + * name is empty an exception is thrown. + * + * @param name the name of this permission + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if name is invalid + */ + public BasicPermission(String name) + { + super(name); + + // This routine used to check for illegal wildcards, but no such + // requirement exists in the specification and Sun's runtime + // doesn't appear to do it. + + if ("".equals(name)) + throw new IllegalArgumentException("Empty name"); + } + + /** + * Create a new instance with the specified permission name. If the name + * is empty, or contains an illegal wildcard character, an exception is + * thrown. The actions parameter is ignored. + * + * @param name the name of this permission + * @param actions ignored + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if name is invalid + */ + public BasicPermission(String name, String actions) + { + this(name); + } + + /** + * This method tests to see if the specified permission is implied by this + * permission. This will be true if the following conditions are met:

      + *
    • The specified object is an instance of the same class as this + * object.
    • + *
    • The name of the specified permission is implied by this permission's + * name based on wildcard matching. For example, "a.*" implies "a.b".
    • + *
    + * + * @param perm the Permission object to test against + * @return true if the specified permission is implied + */ + public boolean implies(Permission perm) + { + if (! getClass().isInstance(perm)) + return false; + + String otherName = perm.getName(); + String name = getName(); + + if (name.equals(otherName)) + return true; + + int last = name.length() - 1; + return name.charAt(last) == '*' + && otherName.startsWith(name.substring(0, last)); + } + + /** + * This method tests to see if this object is equal to the specified + * Object. This will be true if and only if the specified + * object meets the following conditions:
      + *
    • It is an instance of the same class as this.
    • + *
    • It has the same name as this permission.
    • + *
    + * + * @param obj the Object to test for equality + * @return true if obj is semantically equal to this + */ + public boolean equals(Object obj) + { + return getClass().isInstance(obj) + && getName().equals(((BasicPermission) obj).getName()); + } + + /** + * This method returns a hash code for this permission object. The hash + * code returned is the value returned by calling the hashCode + * method on the String that is the name of this permission. + * + * @return a hash value for this object + */ + public int hashCode() + { + return getName().hashCode(); + } + + /** + * This method returns a list of the actions associated with this + * permission. This method always returns the empty string ("") since + * this class ignores actions. + * + * @return the action list + */ + public String getActions() + { + return ""; + } + + /** + * This method returns an instance of PermissionCollection + * suitable for storing BasicPermission objects. The + * collection returned can only store objects of the same type as this. + * Subclasses which use actions must override this method; but a class with + * no actions will work fine with this. + * + * @return a new empty PermissionCollection object + */ + public PermissionCollection newPermissionCollection() + { + return new BasicPermissionCollection(getClass()); + } + + /** + * Implements AllPermission.newPermissionCollection, and obeys serialization + * of JDK. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class BasicPermissionCollection extends PermissionCollection + { + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 739301742472979399L; + + /** + * The permissions in the collection. + * + * @serial a hash mapping name to permissions, all of type permClass + */ + private final Hashtable permissions = new Hashtable(); + + /** + * If "*" is in the collection. + * + * @serial true if a permission named "*" is in the collection + */ + private boolean all_allowed; + + /** + * The runtime class which all entries in the table must belong to. + * + * @serial the limiting subclass of this collection + */ + private final Class permClass; + + /** + * Construct a collection over the given runtime class. + * + * @param c the class + */ + BasicPermissionCollection(Class c) + { + permClass = c; + } + + /** + * Add a Permission. It must be of the same type as the permission which + * created this collection. + * + * @param perm the permission to add + * @throws IllegalArgumentException if perm is not the correct type + * @throws SecurityException if the collection is read-only + */ + public void add(Permission perm) + { + if (isReadOnly()) + throw new SecurityException("readonly"); + if (! permClass.isInstance(perm)) + throw new IllegalArgumentException("Expecting instance of " + permClass); + BasicPermission bp = (BasicPermission) perm; + String name = bp.getName(); + if (name.equals("*")) + all_allowed = true; + permissions.put(name, bp); + } + + /** + * Returns true if this collection implies the given permission. + * + * @param permission the permission to check + * @return true if it is implied by this + */ + public boolean implies(Permission permission) + { + if (! permClass.isInstance(permission)) + return false; + if (all_allowed) + return true; + BasicPermission toImply = (BasicPermission) permission; + String name = toImply.getName(); + if (name.equals("*")) + return false; + int prefixLength = name.length(); + if (name.endsWith("*")) + prefixLength -= 2; + + while (true) + { + if (permissions.get(name) != null) + return true; + prefixLength = name.lastIndexOf('.', prefixLength); + if (prefixLength < 0) + return false; + name = name.substring(0, prefixLength + 1) + '*'; + } + } + + /** + * Enumerate over the collection. + * + * @return an enumeration of the collection contents + */ + public Enumeration elements() + { + return permissions.elements(); + } + } // class BasicPermissionCollection +} // class BasicPermission diff --git a/libjava/classpath/java/security/Certificate.java b/libjava/classpath/java/security/Certificate.java new file mode 100644 index 0000000..5cdba6e --- /dev/null +++ b/libjava/classpath/java/security/Certificate.java @@ -0,0 +1,125 @@ +/* Certificate.java -- deprecated interface for modeling digital certificates + Copyright (C) 1998, 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 java.security; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * This interface models a digital certificate which verifies the + * authenticity of a party. This class simply allows certificate + * information to be queried, it does not guarantee that the certificate + * is valid. + * + *

    This class is deprecated in favor of the new java.security.cert package. + * It exists for backward compatibility only. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @deprecated use {@link java.security.cert} instead + * @status updated to 1.4 + */ +public interface Certificate +{ + /** + * This method returns the Principal that is guaranteeing + * this certificate. + * + * @return the Principal guaranteeing the certificate + */ + Principal getGuarantor(); + + /** + * This method returns the Principal being guaranteed by + * this certificate. + * + * @return the Principal guaranteed by this certificate + */ + Principal getPrincipal(); + + /** + * This method returns the public key for the Principal that + * is being guaranteed. + * + * @return the PublicKey of the Principal being guaranteed + */ + PublicKey getPublicKey(); + + /** + * This method writes the certificate to an OutputStream in + * a format that can be understood by the decode method. + * + * @param out the OutputStream to write to + * @throws KeyException if there is a problem with the certificate + * @throws IOException if an error occurs writing to the stream + * @see #decode(InputStream) + * @see #getFormat() + */ + void encode(OutputStream out) throws KeyException, IOException; + + /** + * This method reads an encoded certificate from an InputStream. + * + * @param in the InputStream to read from + * @throws KeyException if there is a problem with the certificate data + * @throws IOException if an error occurs reading from the stream + * @see #encode(OutputStream) + * @see #getFormat() + */ + void decode(InputStream in) throws KeyException, IOException; + + /** + * This method returns the encoding format of the certificate (e.g., "PGP", + * "X.509"). This format is used by the encode and + * decode methods. + * + * @return the encoding format being used + */ + String getFormat(); + + /** + * This method returns a String representation of the contents + * of this certificate. + * + * @param detail true to provided more detailed information + * @return the string representation + */ + String toString(boolean detail); +} // interface Certificate diff --git a/libjava/classpath/java/security/CodeSource.java b/libjava/classpath/java/security/CodeSource.java new file mode 100644 index 0000000..b516170 --- /dev/null +++ b/libjava/classpath/java/security/CodeSource.java @@ -0,0 +1,354 @@ +/* CodeSource.java -- Code location and certifcates + Copyright (C) 1998, 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 java.security; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.SocketPermission; +import java.net.URL; +// Note that this overrides Certificate in this package. +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; + +/** + * This class represents a location from which code is loaded (as + * represented by a URL), and the list of certificates that are used to + * check the signatures of signed code loaded from this source. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public class CodeSource implements Serializable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 4977541819976013951L; + + /** + * This is the URL that represents the code base from which code will + * be loaded. + * + * @serial the code location + */ + private final URL location; + + /** The set of certificates for this code base. */ + private transient HashSet certs; + + /** + * This creates a new instance of CodeSource that loads code + * from the specified URL location and which uses the specified certificates + * for verifying signatures. + * + * @param location the location from which code will be loaded + * @param certs the list of certificates + */ + public CodeSource(URL location, Certificate[] certs) + { + this.location = location; + if (certs != null) + this.certs = new HashSet(Arrays.asList(certs)); + } + + /** + * This method returns a hash value for this object. + * + * @return a hash value for this object + */ + public int hashCode() + { + return (location == null ? 0 : location.hashCode()) + ^ (certs == null ? 0 : certs.hashCode()); + } + + /** + * This method tests the specified Object for equality with + * this object. This will be true if and only if the locations are equal + * and the certificate sets are identical (ignoring order). + * + * @param obj the Object to test against + * @return true if the specified object is equal to this one + */ + public boolean equals(Object obj) + { + if (! (obj instanceof CodeSource)) + return false; + CodeSource cs = (CodeSource) obj; + return (certs == null ? cs.certs == null : certs.equals(cs.certs)) + && (location == null ? cs.location == null + : location.equals(cs.location)); + } + + /** + * This method returns the URL specifying the location from which code + * will be loaded under this CodeSource. + * + * @return the code location for this CodeSource + */ + public final URL getLocation() + { + return location; + } + + /** + * This method returns the list of digital certificates that can be used + * to verify the signatures of code loaded under this + * CodeSource. + * + * @return the certifcate list for this CodeSource + */ + public final Certificate[] getCertificates() + { + if (certs == null) + return null; + Certificate[] c = new Certificate[certs.size()]; + certs.toArray(c); + return c; + } + + /** + * This method tests to see if a specified CodeSource is + * implied by this object. Effectively, to meet this test, the specified + * object must have all the certifcates this object has (but may have more), + * and must have a location that is a subset of this object's. In order + * for this object to imply the specified object, the following must be + * true: + * + *

      + *
    1. codesource must not be null.
    2. + *
    3. If codesource has a certificate list, all of it's + * certificates must be present in the certificate list of this + * code source.
    4. + *
    5. If this object does not have a null location, then + * the following addtional tests must be passed. + * + *
        + *
      1. codesource must not have a null + * location.
      2. + *
      3. codesource's location must be equal to this object's + * location, or + *
          + *
        • codesource's location protocol, port, and ref (aka, + * anchor) must equal this objects
        • + *
        • codesource's location host must imply this object's + * location host, as determined by contructing + * SocketPermission objects from each with no + * action list and using that classes's implies + * method
        • + *
        • If this object's location file ends with a '/', then the + * specified object's location file must start with this + * object's location file. Otherwise, the specified object's + * location file must start with this object's location file + * with the '/' character appended to it.
        • + *
      4. + *
    6. + *
    + * + *

    For example, each of these locations imply the location + * "http://java.sun.com/classes/foo.jar":

    + * + *
    +   * http:
    +   * http://*.sun.com/classes/*
    +   * http://java.sun.com/classes/-
    +   * http://java.sun.com/classes/foo.jar
    +   * 
    + * + *

    Note that the code source with null location and null certificates implies + * all other code sources.

    + * + * @param cs the CodeSource to test against this object + * @return true if this specified CodeSource is implied + */ + public boolean implies(CodeSource cs) + { + if (cs == null) + return false; + // First check the certificate list. + if (certs != null && (cs.certs == null || ! certs.containsAll(cs.certs))) + return false; + // Next check the location. + if (location == null) + return true; + if (cs.location == null + || ! location.getProtocol().equals(cs.location.getProtocol()) + || (location.getPort() != -1 + && location.getPort() != cs.location.getPort()) + || (location.getRef() != null + && ! location.getRef().equals(cs.location.getRef()))) + return false; + if (location.getHost() != null) + { + String their_host = cs.location.getHost(); + if (their_host == null) + return false; + SocketPermission our_sockperm = + new SocketPermission(location.getHost(), "accept"); + SocketPermission their_sockperm = + new SocketPermission(their_host, "accept"); + if (! our_sockperm.implies(their_sockperm)) + return false; + } + String our_file = location.getFile(); + if (our_file != null) + { + if (! our_file.endsWith("/")) + our_file += "/"; + String their_file = cs.location.getFile(); + if (their_file == null + || ! their_file.startsWith(our_file)) + return false; + } + return true; + } + + /** + * This method returns a String that represents this object. + * The result is in the format "(" + getLocation() followed + * by a space separated list of certificates (or "<no certificates>"), + * followed by ")". + * + * @return a String for this object + */ + public String toString() + { + StringBuffer sb = new StringBuffer("(").append(location); + if (certs == null || certs.isEmpty()) + sb.append(" "); + else + { + Iterator iter = certs.iterator(); + for (int i = certs.size(); --i >= 0; ) + sb.append(' ').append(iter.next()); + } + return sb.append(")").toString(); + } + + /** + * Reads this object from a serialization stream. + * + * @param s the input stream + * @throws IOException if reading fails + * @throws ClassNotFoundException if deserialization fails + * @serialData this reads the location, then expects an int indicating the + * number of certificates. Each certificate is a String type + * followed by an int encoding length, then a byte[] encoding + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + int count = s.readInt(); + certs = new HashSet(); + while (--count >= 0) + { + String type = (String) s.readObject(); + int bytes = s.readInt(); + byte[] encoded = new byte[bytes]; + for (int i = 0; i < bytes; i++) + encoded[i] = s.readByte(); + ByteArrayInputStream stream = new ByteArrayInputStream(encoded); + try + { + CertificateFactory factory = CertificateFactory.getInstance(type); + certs.add(factory.generateCertificate(stream)); + } + catch (CertificateException e) + { + // XXX Should we ignore this certificate? + } + } + } + + /** + * Writes this object to a serialization stream. + * + * @param s the output stream + * @throws IOException if writing fails + * @serialData this writes the location, then writes an int indicating the + * number of certificates. Each certificate is a String type + * followed by an int encoding length, then a byte[] encoding + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + if (certs == null) + s.writeInt(0); + else + { + int count = certs.size(); + s.writeInt(count); + Iterator iter = certs.iterator(); + while (--count >= 0) + { + Certificate c = (Certificate) iter.next(); + s.writeObject(c.getType()); + byte[] encoded; + try + { + encoded = c.getEncoded(); + } + catch (CertificateEncodingException e) + { + // XXX Should we ignore this certificate? + encoded = null; + } + if (encoded == null) + s.writeInt(0); + else + { + s.writeInt(encoded.length); + for (int i = 0; i < encoded.length; i++) + s.writeByte(encoded[i]); + } + } + } + } +} // class CodeSource diff --git a/libjava/classpath/java/security/DigestException.java b/libjava/classpath/java/security/DigestException.java new file mode 100644 index 0000000..6393e0c --- /dev/null +++ b/libjava/classpath/java/security/DigestException.java @@ -0,0 +1,70 @@ +/* DigestException.java -- A generic message digest exception + Copyright (C) 1998, 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 java.security; + +/** + * This exception indicates that a generic message digest exception has + * occurred. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class DigestException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5821450303093652515L; + + /** + * Create a new instance with no descriptive message. + */ + public DigestException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param msg the descriptive message + */ + public DigestException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/DigestInputStream.java b/libjava/classpath/java/security/DigestInputStream.java new file mode 100644 index 0000000..0d4a9d0 --- /dev/null +++ b/libjava/classpath/java/security/DigestInputStream.java @@ -0,0 +1,167 @@ +/* DigestInputStream.java --- An Input stream tied to a message digest + Copyright (C) 1999, 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 java.security; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * DigestInputStream is a class that ties an InputStream with a + * MessageDigest. The Message Digest is used by the class to + * update it self as bytes are read from the InputStream. + * + * The updating to the digest depends on the on flag which is set + * to true by default to tell the class to update the data + * in the message digest. + * + * @version 0.0 + * @author Mark Benvenuto (ivymccough@worldnet.att.net) + */ +public class DigestInputStream extends FilterInputStream +{ + /** + * The message digest for the DigestInputStream + */ + protected MessageDigest digest; + + //Manages the on flag + private boolean state = true; + + /** + * Constructs a new DigestInputStream. + * It associates a MessageDigest with the stream to + * compute the stream as data is written. + * + * @param stream An InputStream to associate this stream with + * @param digest A MessageDigest to hash the stream with + */ + public DigestInputStream(InputStream stream, MessageDigest digest) + { + super(stream); + //this.in = stream; + this.digest = digest; + } + + /** + * Returns the MessageDigest associated with this DigestInputStream + * + * @return The MessageDigest used to hash this stream + */ + public MessageDigest getMessageDigest() + { + return digest; + } + + /** + * Sets the current MessageDigest to current parameter + * + * @param digest A MessageDigest to associate with this stream + */ + public void setMessageDigest(MessageDigest digest) + { + this.digest = digest; + } + + /** + * Reads a byte from the input stream and updates the digest. + * This method reads the underlying input stream and if the + * on flag is true then updates the message digest. + * + * @return Returns a byte from the input stream, -1 is returned to indicate that + * the end of stream was reached before this read call + * + * @throws IOException if an IO error occurs in the underlying input stream, + * this error is thrown + */ + public int read() throws IOException + { + int temp = in.read(); + + if (state == true && temp != -1) + digest.update((byte) temp); + + return temp; + } + + /** + * Reads bytes from the input stream and updates the digest. + * This method reads the underlying input stream and if the + * on flag is true then updates the message digest. + * + * @param b a byte array to store the data from the input stream + * @param off an offset to start at in the array + * @param len length of data to read + * @return Returns count of bytes read, -1 is returned to indicate that + * the end of stream was reached before this read call + * + * @throws IOException if an IO error occurs in the underlying input stream, + * this error is thrown + */ + public int read(byte[]b, int off, int len) throws IOException + { + int temp = in.read(b, off, len); + + if (state == true && temp != -1) + digest.update(b, off, temp); + + return temp; + } + + /** + * Sets the flag specifing if this DigestInputStream updates the + * digest in the write() methods. The default is on; + * + * @param on True means it digests stream, false means it does not + */ + public void on(boolean on) + { + state = on; + } + + /** + * Converts the input stream and underlying message digest to a string. + * + * @return A string representing the input stream and message digest. + */ + public String toString() + { + return "[Digest Input Stream] " + digest.toString(); + } +} diff --git a/libjava/classpath/java/security/DigestOutputStream.java b/libjava/classpath/java/security/DigestOutputStream.java new file mode 100644 index 0000000..037b39e --- /dev/null +++ b/libjava/classpath/java/security/DigestOutputStream.java @@ -0,0 +1,158 @@ +/* DigestOutputStream.java --- An output stream tied to a message digest + Copyright (C) 1999, 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 java.security; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * DigestOutputStream is a class that ties an OutputStream with a + * MessageDigest. The Message Digest is used by the class to update it + * self as bytes are written to the OutputStream. + * + * The updating to the digest depends on the on flag which is set to + * true by default that tells the class to update the data in the + * message digest. + * + * @version 0.0 + * @author Mark Benvenuto (ivymccough@worldnet.att.net) + */ +public class DigestOutputStream extends FilterOutputStream +{ + /** + * The message digest for the DigestOutputStream + */ + protected MessageDigest digest; + + //Manages the on flag + private boolean state = true; + + /** + * Constructs a new DigestOutputStream. It associates a + * MessageDigest with the stream to compute the stream as data is + * written. + * + * @param stream An OutputStream to associate this stream with + * @param digest A MessageDigest to hash the stream with + */ + public DigestOutputStream(OutputStream stream, MessageDigest digest) + { + super(stream); + this.digest = digest; + } + + /** + * Returns the MessageDigest associated with this DigestOutputStream + * + * @return The MessageDigest used to hash this stream + */ + public MessageDigest getMessageDigest() + { + return digest; + } + + /** + * Sets the current MessageDigest to current parameter + * + * @param digest A MessageDigest to associate with this stream + */ + public void setMessageDigest(MessageDigest digest) + { + this.digest = digest; + } + + + /** + * Updates the hash if the on flag is true and then writes a byte to + * the underlying output stream. + * + * @param b A byte to write to the output stream + * + * @exception IOException if the underlying output stream + * cannot write the byte, this is thrown. + */ + public void write(int b) throws IOException + { + if (state) + digest.update((byte) b); + + out.write(b); + } + + /** + * Updates the hash if the on flag is true and then writes the bytes + * to the underlying output stream. + * + * @param b Bytes to write to the output stream + * @param off Offset to start to start at in array + * @param len Length of data to write + * + * @exception IOException if the underlying output stream + * cannot write the bytes, this is thrown. + */ + public void write(byte[]b, int off, int len) throws IOException + { + if (state) + digest.update(b, off, len); + + out.write(b, off, len); + } + + /** + * Sets the flag specifying if this DigestOutputStream updates the + * digest in the write() methods. The default is on; + * + * @param on True means it digests stream, false means it does not + */ + public void on(boolean on) + { + state = on; + } + + /** + * Converts the output stream and underlying message digest to a string. + * + * @return A string representing the output stream and message digest. + */ + public String toString() + { + return "[Digest Output Stream] " + digest.toString(); + } +} diff --git a/libjava/classpath/java/security/DomainCombiner.java b/libjava/classpath/java/security/DomainCombiner.java new file mode 100644 index 0000000..9ec680c --- /dev/null +++ b/libjava/classpath/java/security/DomainCombiner.java @@ -0,0 +1,67 @@ +/* DomainCombiner.java -- Combines ProtectionDomains + Copyright (C) 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 java.security; + +/** + * A public interface used to combine two ProtectionDomains in a new + * ProtectionDomain and update the current Protection Domains + * associated with the current AccessControlContext. + * + * It can add, subtract, or update ProtectionDomains or possibly + * remove duplicates or any possible complex action but just not add + * ones that do not already exist in either array. + * + * @author Mark Benvenuto + * @see AccessControlContext + * @see AccessController + * @since 1.3 + * @status updated to 1.4 + */ +public interface DomainCombiner +{ + /** + * Combines the current ProtectionDomains of the Thread with new + * ProtectionDomains. + * + * @param currentDomains - the ProtectionDomains for the current thread. + * @param assignedDomains - ProtectionsDomains to add + * @return a new array of all the ProtectionDomains + */ + ProtectionDomain[] combine(ProtectionDomain[] currentDomains, + ProtectionDomain[] assignedDomains); +} // interface DomainCombiner diff --git a/libjava/classpath/java/security/DummyKeyPairGenerator.java b/libjava/classpath/java/security/DummyKeyPairGenerator.java new file mode 100644 index 0000000..da8c362e --- /dev/null +++ b/libjava/classpath/java/security/DummyKeyPairGenerator.java @@ -0,0 +1,75 @@ +/* DummyKeyPairGenerator.java - Wrapper for KeyPairGeneratorSpi + Copyright (C) 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 java.security; + +import java.security.spec.AlgorithmParameterSpec; + +final class DummyKeyPairGenerator extends KeyPairGenerator +{ + private KeyPairGeneratorSpi kpgSpi = null; + + public DummyKeyPairGenerator(KeyPairGeneratorSpi kpgSpi, String algorithm) + { + super(algorithm); + this.kpgSpi = kpgSpi; + } + + public Object clone() throws CloneNotSupportedException + { + KeyPairGenerator result = new DummyKeyPairGenerator + ((KeyPairGeneratorSpi) kpgSpi.clone(), this.getAlgorithm()); + result.provider = this.getProvider(); + return result; + } + + public void initialize(int keysize, SecureRandom random) + { + kpgSpi.initialize(keysize, random); + } + + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + kpgSpi.initialize(params, random); + } + + public KeyPair generateKeyPair() + { + return kpgSpi.generateKeyPair(); + } +} diff --git a/libjava/classpath/java/security/DummyMessageDigest.java b/libjava/classpath/java/security/DummyMessageDigest.java new file mode 100644 index 0000000..6cecdcf --- /dev/null +++ b/libjava/classpath/java/security/DummyMessageDigest.java @@ -0,0 +1,90 @@ +/* DummyMessageDigest.java - Wrapper for MessageDigestSpi + Copyright (C) 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 java.security; + +final class DummyMessageDigest extends MessageDigest +{ + private MessageDigestSpi mdSpi = null; + + public DummyMessageDigest(MessageDigestSpi mdSpi, String algorithm) + { + super(algorithm); + this.mdSpi = mdSpi; + } + + public Object clone() throws CloneNotSupportedException + { + MessageDigest result = new DummyMessageDigest + ((MessageDigestSpi) mdSpi.clone(), this.getAlgorithm()); + result.provider = this.getProvider(); + return result; + } + + // java.security.MessageDigestSpi abstract methods implementation --------- + + public byte[] engineDigest() + { + return mdSpi.engineDigest(); + } + + public int engineDigest(byte[] buf, int offset, int len) + throws DigestException + { + return mdSpi.engineDigest(buf, offset, len); + } + + public int engineGetDigestLength() + { + return mdSpi.engineGetDigestLength(); + } + + public void engineReset() + { + mdSpi.engineReset(); + } + + public void engineUpdate(byte input) + { + mdSpi.engineUpdate(input); + } + + public void engineUpdate(byte[] input, int offset, int len) + { + mdSpi.engineUpdate(input, offset, len); + } +} diff --git a/libjava/classpath/java/security/DummySignature.java b/libjava/classpath/java/security/DummySignature.java new file mode 100644 index 0000000..b74885c --- /dev/null +++ b/libjava/classpath/java/security/DummySignature.java @@ -0,0 +1,102 @@ +/* DummySignature.java - Signature wrapper for SignatureSpi. + Copyright (C) 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 java.security; + +final class DummySignature extends Signature +{ + private SignatureSpi sigSpi = null; + + public DummySignature(SignatureSpi sigSpi, String algorithm) + { + super(algorithm); + this.sigSpi = sigSpi; + } + + public Object clone() throws CloneNotSupportedException + { + Signature result = new DummySignature + ((SignatureSpi) sigSpi.clone(), this.getAlgorithm()); + result.provider = this.getProvider(); + return result; + } + + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException + { + sigSpi.engineInitVerify(publicKey); + } + + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException + { + sigSpi.engineInitSign(privateKey); + } + + protected void engineUpdate(byte b) throws SignatureException + { + sigSpi.engineUpdate(b); + } + + protected void engineUpdate(byte[]b, int off, int len) + throws SignatureException + { + sigSpi.engineUpdate(b, off, len); + } + + protected byte[] engineSign() throws SignatureException + { + return sigSpi.engineSign(); + } + + protected boolean engineVerify(byte[]sigBytes) throws SignatureException + { + return sigSpi.engineVerify(sigBytes); + } + + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException + { + sigSpi.engineSetParameter(param, value); + } + + protected Object engineGetParameter(String param) + throws InvalidParameterException + { + return sigSpi.engineGetParameter(param); + } +} diff --git a/libjava/classpath/java/security/GeneralSecurityException.java b/libjava/classpath/java/security/GeneralSecurityException.java new file mode 100644 index 0000000..72453ee --- /dev/null +++ b/libjava/classpath/java/security/GeneralSecurityException.java @@ -0,0 +1,75 @@ +/* GeneralSecurityException.java -- Common superclass of security exceptions + Copyright (C) 1998, 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 java.security; + +/** + * This class is the common superclass of all security exceptions. All + * exceptions in java.security extend this class with the exception (no + * pun intended) of AccessControlException and + * CertificateException (which extend + * SecurityException), ProviderException + * (RuntimeException), and InvalidParamterException + * (IllegalArgumentException). + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class GeneralSecurityException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 894798122053539237L; + + /** + * Create a new instance with no descriptive error message. + */ + public GeneralSecurityException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param msg the descriptive error message + */ + public GeneralSecurityException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/Guard.java b/libjava/classpath/java/security/Guard.java new file mode 100644 index 0000000..4f22360 --- /dev/null +++ b/libjava/classpath/java/security/Guard.java @@ -0,0 +1,60 @@ +/* Guard.java -- Check access to a guarded object + Copyright (C) 1998, 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 java.security; + +/** + * This interface specifies a mechanism for querying whether or not + * access is allowed to a guarded object. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see GuardedObject + * @since 1.1 + * @status updated to 1.4 + */ +public interface Guard +{ + /** + * This method tests whether or not access is allowed to the specified + * guarded object. Access is allowed if this method returns silently. If + * access is denied, an exception is generated. + * + * @param obj the Object to test + * @throws SecurityException if access to the object is denied + */ + void checkGuard(Object obj); +} // interface Guard diff --git a/libjava/classpath/java/security/GuardedObject.java b/libjava/classpath/java/security/GuardedObject.java new file mode 100644 index 0000000..5ca0883 --- /dev/null +++ b/libjava/classpath/java/security/GuardedObject.java @@ -0,0 +1,121 @@ +/* GuardedObject.java -- An object protected by a Guard + Copyright (C) 1998, 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 java.security; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * This class is an object that is guarded by a Guard object. + * The object that is being guarded is retrieved by a call to the only + * method in this class - getObject. That method returns the + * guarded Object after first checking with the + * Guard. If the Guard disallows access, an + * exception will be thrown. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class GuardedObject implements Serializable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -5240450096227834308L; + + /** + * This is the Guard that is protecting the object. + * + * @serial the guard + */ + private final Guard guard; + + /** + * This is the object that is being guarded. + * + * @serial the protected object + */ + private final Object object; + + /** + * This method initializes a new instance of GuardedObject + * that protects the specified Object using the specified + * Guard. A null guard means there are no restrictions on + * accessing the object. + * + * @param object the Object to guard + * @param guard the Guard that is protecting the object + */ + public GuardedObject(Object object, Guard guard) + { + this.object = object; + this.guard = guard; + } + + /** + * This method first call the checkGuard method on the + * Guard object protecting the guarded object. If the + * Guard disallows access, an exception is thrown, otherwise + * the Object is returned. + * + * @return The object being guarded + * @throws SecurityException if access is denied + */ + public Object getObject() + { + if (guard != null) + guard.checkGuard(object); + return object; + } + + /** + * Ensures that serialization is legal, by checking the guard. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + if (guard != null) + guard.checkGuard(object); + s.defaultWriteObject(); + } +} // class GuardedObject diff --git a/libjava/classpath/java/security/Identity.java b/libjava/classpath/java/security/Identity.java new file mode 100644 index 0000000..26b01a5 --- /dev/null +++ b/libjava/classpath/java/security/Identity.java @@ -0,0 +1,407 @@ +/* Identity.java --- Identity Class + 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 java.security; + +import java.io.Serializable; +import java.util.Vector; + +/** + *

    This class represents identities: real-world objects such as people, + * companies or organizations whose identities can be authenticated using their + * public keys. Identities may also be more abstract (or concrete) constructs, + * such as daemon threads or smart cards.

    + * + *

    All Identity objects have a name and a public key. Names + * are immutable. Identities may also be scoped. That is, if an + * Identity is specified to have a particular scope, then the + * name and public key of the Identity are unique within + * that scope.

    + * + *

    An Identity also has a set of certificates (all certifying + * its own public key). The Principal names specified in these + * certificates need not be the same, only the key.

    + * + *

    An Identity can be subclassed, to include postal and email + * addresses, telephone numbers, images of faces and logos, and so on.

    + * + * @author Mark Benvenuto + * @see IdentityScope + * @see Signer + * @see Principal + * @deprecated This class is no longer used. Its functionality has been replaced + * by java.security.KeyStore, the java.security.cert + * package, and java.security.Principal. + */ +public abstract class Identity implements Principal, Serializable +{ + private static final long serialVersionUID = 3609922007826600659L; + + private String name; + private IdentityScope scope; + private PublicKey publicKey; + private String info; + private Vector certificates; + + /** Constructor for serialization only. */ + protected Identity() + { + } + + /** + * Constructs an identity with the specified name and scope. + * + * @param name the identity name. + * @param scope the scope of the identity. + * @throws KeyManagementException if there is already an identity with the + * same name in the scope. + */ + public Identity(String name, IdentityScope scope) + throws KeyManagementException + { + this.name = name; + this.scope = scope; + } + + /** + * Constructs an identity with the specified name and no scope. + * + * @param name the identity name. + */ + public Identity(String name) + { + this.name = name; + this.scope = null; + } + + /** + * Returns this identity's name. + * + * @return the name of this identity. + */ + public final String getName() + { + return name; + } + + /** + * Returns this identity's scope. + * + * @return the scope of this identity. + */ + public final IdentityScope getScope() + { + return scope; + } + + /** + * Returns this identity's public key. + * + * @return the public key for this identity. + * @see #setPublicKey(java.security.PublicKey) + */ + public PublicKey getPublicKey() + { + return publicKey; + } + + /** + *

    Sets this identity's public key. The old key and all of this identity's + * certificates are removed by this operation.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with "setIdentityPublicKey" as its + * argument to see if it's ok to set the public key.

    + * + * @param key the public key for this identity. + * @throws KeyManagementException if another identity in the identity's scope + * has the same public key, or if another exception occurs. + * @throws SecurityException if a security manager exists and its + * checkSecurityAccess() method doesn't allow setting the public + * key. + * @see #getPublicKey() + * @see SecurityManager#checkSecurityAccess(String) + */ + public void setPublicKey(PublicKey key) throws KeyManagementException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("setIdentityPublicKey"); + + this.publicKey = key; + } + + /** + *

    Specifies a general information string for this identity.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with "setIdentityInfo" as its + * argument to see if it's ok to specify the information string.

    + * + * @param info the information string. + * @throws SecurityException if a security manager exists and its + * checkSecurityAccess() method doesn't allow setting the + * information string. + * @see #getInfo() + * @see SecurityManager#checkSecurityAccess(String) + */ + public void setInfo(String info) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("setIdentityInfo"); + + this.info = info; + } + + /** + * Returns general information previously specified for this identity. + * + * @return general information about this identity. + * @see #setInfo(String) + */ + public String getInfo() + { + return info; + } + + /** + *

    Adds a certificate for this identity. If the identity has a public key, + * the public key in the certificate must be the same, and if the identity + * does not have a public key, the identity's public key is set to be that + * specified in the certificate.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with "addIdentityCertificate" as its + * argument to see if it's ok to add a certificate.

    + * + * @param certificate the certificate to be added. + * @throws KeyManagementException if the certificate is not valid, if the + * public key in the certificate being added conflicts with this identity's + * public key, or if another exception occurs. + * @throws SecurityException if a security manager exists and its + * checkSecurityAccess() method doesn't allow adding a + * certificate. + * @see SecurityManager#checkSecurityAccess(String) + */ + public void addCertificate(Certificate certificate) + throws KeyManagementException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("addIdentityCertificate"); + + // Check public key of this certificate against the first one in the vector + if (certificates.size() > 0) + { + if (((Certificate) certificates.firstElement()).getPublicKey() != publicKey) + throw new KeyManagementException("Public key does not match"); + } + certificates.addElement(certificate); + } + + /** + *

    Removes a certificate from this identity.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with "removeIdentityCertificate" as + * its argument to see if it's ok to remove a certificate.

    + * + * @param certificate the certificate to be removed. + * @throws KeyManagementException if the certificate is missing, or if + * another exception occurs. + * @throws SecurityException if a security manager exists and its + * checkSecurityAccess() method doesn't allow removing a + * certificate. + * @see SecurityManager#checkSecurityAccess(String) + */ + public void removeCertificate(Certificate certificate) + throws KeyManagementException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("removeIdentityCertificate"); + + if (certificates.contains(certificate) == false) + throw new KeyManagementException("Certificate not found"); + + certificates.removeElement(certificate); + } + + /** + * Returns a copy of all the certificates for this identity. + * + * @return a copy of all the certificates for this identity. + */ + public Certificate[] certificates() + { + Certificate[] certs = new Certificate[certificates.size()]; + int max = certificates.size(); + for (int i = 0; i < max; i++) + certs[i] = (Certificate) certificates.elementAt(i); + + return certs; + } + + /** + * Tests for equality between the specified object and this identity. This + * first tests to see if the entities actually refer to the same object, in + * which case it returns true. Next, it checks to see if the + * entities have the same name and the same scope. If they do, + * the method returns true. Otherwise, it calls + * identityEquals(), which subclasses should override. + * + * @param identity the object to test for equality with this identity. + * @return true if the objects are considered equal, false + * otherwise. + * @see #identityEquals(Identity) + */ + public final boolean equals(Object identity) + { + if (identity instanceof Identity) + { + if (identity == this) + return true; + + if ((((Identity) identity).getName() == this.name) && + (((Identity) identity).getScope() == this.scope)) + return true; + + return identityEquals((Identity) identity); + } + return false; + } + + /** + * Tests for equality between the specified identity and this + * identity. This method should be overriden by subclasses to test for + * equality. The default behavior is to return true if the names + * and public keys are equal. + * + * @param identity the identity to test for equality with this identity. + * @return true if the identities are considered equal, + * false otherwise. + * @see #equals(Object) + */ + protected boolean identityEquals(Identity identity) + { + return ((identity.getName() == this.name) && + (identity.getPublicKey() == this.publicKey)); + } + + /** + *

    Returns a short string describing this identity, telling its name and + * its scope (if any).

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with "printIdentity" as its argument + * to see if it's ok to return the string.

    + * + * @return information about this identity, such as its name and the name of + * its scope (if any). + * @throws SecurityException if a security manager exists and its + * checkSecurityAccess() method doesn't allow returning a string + * describing this identity. + * @see SecurityManager#checkSecurityAccess(String) + */ + public String toString() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("printIdentity"); + + /* TODO: Insert proper format here */ + return (name + ":@" + scope + " Public Key: " + publicKey); + } + + /** + *

    Returns a string representation of this identity, with optionally more + * details than that provided by the toString() method without + * any arguments.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with "printIdentity" as its argument + * to see if it's ok to return the string.

    + * + * @param detailed whether or not to provide detailed information. + * @return information about this identity. If detailed is true, + * then this method returns more information than that provided by the + * toString() method without any arguments. + * @throws SecurityException if a security manager exists and its + * checkSecurityAccess() method doesn't allow returning a string + * describing this identity. + * @see #toString() + * @see SecurityManager#checkSecurityAccess(String) + */ + public String toString(boolean detailed) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("printIdentity"); + + if (detailed) + { + /* TODO: Insert proper detailed format here */ + return (name + ":@" + scope + " Public Key: " + publicKey); + } + else + { + /* TODO: Insert proper format here */ + return (name + ":@" + scope + " Public Key: " + publicKey); + } + } + + /** + * Returns a hashcode for this identity. + * + * @return a hashcode for this identity. + */ + public int hashCode() + { + int ret = name.hashCode(); + if (publicKey != null) + ret |= publicKey.hashCode(); + if (scope != null) + ret |= scope.hashCode(); + if (info != null) + ret |= info.hashCode(); + if (certificates != null) + ret |= certificates.hashCode(); + + return ret; + } +} diff --git a/libjava/classpath/java/security/IdentityScope.java b/libjava/classpath/java/security/IdentityScope.java new file mode 100644 index 0000000..34dd011 --- /dev/null +++ b/libjava/classpath/java/security/IdentityScope.java @@ -0,0 +1,226 @@ +/* IdentityScope.java --- IdentityScope Class + 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 java.security; + +import java.util.Enumeration; + +/** + *

    This class represents a scope for identities. It is an Identity itself, + * and therefore has a name and can have a scope. It can also optionally have a + * public key and associated certificates.

    + * + *

    An IdentityScope can contain {@link Identity} objects of all + * kinds, including {@link Signer}s. All types of Identity objects + * can be retrieved, added, and removed using the same methods. Note that it is + * possible, and in fact expected, that different types of identity scopes will + * apply different policies for their various operations on the various types of + * Identities.

    + * + *

    There is a one-to-one mapping between keys and identities, and there can + * only be one copy of one key per scope. For example, suppose Acme Software, + * Inc is a software publisher known to a user. Suppose it is an Identity, + * that is, it has a public key, and a set of associated certificates. It is + * named in the scope using the name "Acme Software". No other named Identity + * in the scope has the same public key. Of course, none has the same name + * as well.

    + * + * @author Mark Benvenuto + * @see Identity + * @see Signer + * @see Principal + * @see Key + * @deprecated This class is no longer used. Its functionality has been replaced + * by java.security.KeyStore, the java.security.cert + * package, and java.security.Principal. + */ +public abstract class IdentityScope extends Identity +{ + private static final long serialVersionUID = -2337346281189773310L; + private static IdentityScope systemScope; + + /** + * This constructor is used for serialization only and should not be used by + * subclasses. + */ + protected IdentityScope() + { + super(); + } + + /** + * Constructs a new identity scope with the specified name. + * + * @param name the scope name. + */ + public IdentityScope(String name) + { + super(name); + } + + /** + * Constructs a new identity scope with the specified name and scope. + * + * @param name the scope name. + * @param scope the scope for the new identity scope. + * @throws KeyManagementException if there is already an identity with the + * same name in the scope. + */ + public IdentityScope(String name, IdentityScope scope) + throws KeyManagementException + { + super(name, scope); + } + + /** + * Returns the system's identity scope. + * + * @return the system's identity scope. + * @see #setSystemScope(IdentityScope) + */ + public static IdentityScope getSystemScope() + { + if (systemScope == null) + { + //Load it + //systemScope; + } + return systemScope; + } + + /** + * Sets the system's identity scope. + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with "setSystemScope" as its argument + * to see if it's ok to set the identity scope.

    + * + * @param scope the scope to set. + * @throws SecurityException if a security manager exists and its + * checkSecurityAccess() method doesn't allow setting the + * identity scope. + * @see #getSystemScope() + * @see SecurityManager#checkSecurityAccess(String) + */ + protected static void setSystemScope(IdentityScope scope) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("setSystemScope"); + + systemScope = scope; + } + + /** + * Returns the number of identities within this identity scope. + * + * @return the number of identities within this identity scope. + */ + public abstract int size(); + + /** + * Returns the identity in this scope with the specified name (if any). + * + * @param name the name of the identity to be retrieved. + * @return the identity named name, or null if there are no + * identities named name in this scope. + */ + public abstract Identity getIdentity(String name); + + /** + * Retrieves the identity whose name is the same as that of the specified + * principal. (Note: Identity implements Principal.) + * + * @param principal the principal corresponding to the identity to be + * retrieved. + * @return the identity whose name is the same as that of the principal, or + * null if there are no identities of the same name in this scope. + */ + public Identity getIdentity(Principal principal) + { + return getIdentity(principal.getName()); + } + + /** + * Retrieves the identity with the specified public key. + * + * @param key the public key for the identity to be returned. + * @return the identity with the given key, or null if there are + * no identities in this scope with that key. + */ + public abstract Identity getIdentity(PublicKey key); + + /** + * Adds an identity to this identity scope. + * + * @param identity the identity to be added. + * @throws KeyManagementException if the identity is not valid, a name + * conflict occurs, another identity has the same public key as the identity + * being added, or another exception occurs. + */ + public abstract void addIdentity(Identity identity) + throws KeyManagementException; + + /** + * Removes an identity from this identity scope. + * + * @param identity the identity to be removed. + * @throws KeyManagementException if the identity is missing, or another + * exception occurs. + */ + public abstract void removeIdentity(Identity identity) + throws KeyManagementException; + + /** + * Returns an enumeration of all identities in this identity scope. + * + * @return an enumeration of all identities in this identity scope. + */ + public abstract Enumeration identities(); + + /** + * Returns a string representation of this identity scope, including its name, + * its scope name, and the number of identities in this identity scope. + * + * @return a string representation of this identity scope. + * @see SecurityManager#checkSecurityAccess(String) + */ + public String toString() + { + return (super.getName() + " " + super.getScope().getName() + " " + size()); + } +} diff --git a/libjava/classpath/java/security/IntersectingDomainCombiner.java b/libjava/classpath/java/security/IntersectingDomainCombiner.java new file mode 100644 index 0000000..2bfcfb4 --- /dev/null +++ b/libjava/classpath/java/security/IntersectingDomainCombiner.java @@ -0,0 +1,82 @@ +/* IntersectingDomainCombiner.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 java.security; + +import java.util.HashSet; + +/** + * A trivial implementation of {@link DomainCombiner} that produces the + * intersection of the supplied {@link ProtectionDomain} objects. + */ +final class IntersectingDomainCombiner implements DomainCombiner +{ + + // Contstant. + // ------------------------------------------------------------------------- + + static final IntersectingDomainCombiner SINGLETON = new IntersectingDomainCombiner(); + + // Constructor. + // ------------------------------------------------------------------------- + + private IntersectingDomainCombiner() + { + } + + // Methods. + // ------------------------------------------------------------------------- + + public ProtectionDomain[] combine (ProtectionDomain[] currentDomains, + ProtectionDomain[] assignedDomains) + { + HashSet newDomains = new HashSet (); + for (int i = 0; i < currentDomains.length; i++) + { + if (currentDomains[i] == null) + continue; + for (int j = 0; j < assignedDomains.length; j++) + { + if (currentDomains[i].equals (assignedDomains[j])) + newDomains.add (currentDomains[i]); + } + } + return (ProtectionDomain[]) + newDomains.toArray(new ProtectionDomain[newDomains.size()]); + } +} diff --git a/libjava/classpath/java/security/InvalidAlgorithmParameterException.java b/libjava/classpath/java/security/InvalidAlgorithmParameterException.java new file mode 100644 index 0000000..9b72619 --- /dev/null +++ b/libjava/classpath/java/security/InvalidAlgorithmParameterException.java @@ -0,0 +1,73 @@ +/* InvalidAlgorithmParameterException.java -- an invalid parameter to a + security algorithm + Copyright (C) 2000, 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 java.security; + +/** + * Thrown for an invalid security algorithm parameter. + * + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.2 + * @status updated to 1.4 + */ +public class InvalidAlgorithmParameterException + extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 2864672297499471472L; + + /** + * Construct an exception with no message. + */ + public InvalidAlgorithmParameterException() + { + super(); + } + + /** + * Construct an exception with a message. + * + * @param msg the message + */ + public InvalidAlgorithmParameterException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/InvalidKeyException.java b/libjava/classpath/java/security/InvalidKeyException.java new file mode 100644 index 0000000..cd5845a --- /dev/null +++ b/libjava/classpath/java/security/InvalidKeyException.java @@ -0,0 +1,69 @@ +/* InvalidKeyException -- thrown for an invalid key + 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 java.security; + +/** + * Thrown for an invalid key. + * + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class InvalidKeyException extends KeyException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5698479920593359816L; + + /** + * Construct an exception with no message. + */ + public InvalidKeyException() + { + } + + /** + * Construct an exception with a message. + * + * @param msg the message + */ + public InvalidKeyException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/InvalidParameterException.java b/libjava/classpath/java/security/InvalidParameterException.java new file mode 100644 index 0000000..c5218a0 --- /dev/null +++ b/libjava/classpath/java/security/InvalidParameterException.java @@ -0,0 +1,70 @@ +/* InvalidParameterException.java -- an invalid parameter in the JCA/JCE engine + 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 java.security; + +/** + * Thrown when an invalid parameter is passed to a method of the JCA/JCE + * engine classes. + * + * @author Warren Levy (warrenl@cygnus.com) + * @status updated to 1.4 + */ +public class InvalidParameterException extends IllegalArgumentException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -857968536935667808L; + + /** + * Construct an exception with no message. + */ + public InvalidParameterException() + { + } + + /** + * Construct an exception with a message. + * + * @param msg the message + */ + public InvalidParameterException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/Key.java b/libjava/classpath/java/security/Key.java new file mode 100644 index 0000000..23652b6 --- /dev/null +++ b/libjava/classpath/java/security/Key.java @@ -0,0 +1,94 @@ +/* Key.java -- A abstract representation of a digital key + Copyright (C) 1998, 2000, 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 java.security; + +import java.io.Serializable; + +/** + * This interfaces models the base characteristics that all keys must + * have. These are: a key algorithm, an encoded form, and a format used + * to encode the key. Specific key types inherit from this interface. + * Note that since this interface extends Serializable, all + * keys may be serialized. Keys are generally obtained through key generators, + * including {@link KeyFactory}. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see PublicKey + * @see PrivateKey + * @see KeyPair + * @see KeyPairGenerator + * @see KeyFactory + * @see KeySpec + * @see Identity + * @see Signer + * @since 1.1 + * @status updated to 1.4 + */ +public interface Key extends Serializable +{ + /** + * The version identifier used for serialization. + */ + long serialVersionUID = 6603384152749567654L; + + /** + * This method returns the name of the algorithm for this key. This is a + * String such as "RSA". + * + * @return the name of the algorithm in use + */ + String getAlgorithm(); + + /** + * This method returns the name of the encoding format for this key. This + * is the name of the ASN.1 data format used for this key, such as + * "X.509" or "PKCS#8". This method returns null if this key + * does not have an encoding format. + * + * @return the name of the encoding format for this key, or null + */ + String getFormat(); + + /** + * This method returns the encoded form of the key. If this key does not + * support encoding, this method returns null. + * + * @return the encoded form of the key, or null + */ + byte[] getEncoded(); +} // interface Key diff --git a/libjava/classpath/java/security/KeyException.java b/libjava/classpath/java/security/KeyException.java new file mode 100644 index 0000000..feaf024 --- /dev/null +++ b/libjava/classpath/java/security/KeyException.java @@ -0,0 +1,72 @@ +/* KeyException.java -- Thrown when there is a problem with a key + Copyright (C) 1998, 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 java.security; + +/** + * This exception is thrown when there is a problem with a key. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Key + * @status updated to 1.4 + */ +public class KeyException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -7483676942812432108L; + + /** + * This method initializes a new instance of KeyException + * with no descriptive message. + */ + public KeyException() + { + } + + /** + * This method initializes a new instance of KeyException + * with a descriptive message. + * + * @param msg the descriptive message + */ + public KeyException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/KeyFactory.java b/libjava/classpath/java/security/KeyFactory.java new file mode 100644 index 0000000..64ce841 --- /dev/null +++ b/libjava/classpath/java/security/KeyFactory.java @@ -0,0 +1,297 @@ +/* KeyFactory.java --- Key Factory Class + Copyright (C) 1999, 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 java.security; + +import gnu.java.security.Engine; + +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +/** + *

    Key factories are used to convert keys (opaque cryptographic keys of type + * {@link Key}) into key specifications (transparent representations of the + * underlying key material), and vice versa.

    + * + *

    Key factories are bi-directional. That is, they allow you to build an + * opaque key object from a given key specification (key material), or to + * retrieve the underlying key material of a key object in a suitable format.

    + * + *

    Multiple compatible key specifications may exist for the same key. For + * example, a DSA public key may be specified using {@link + * java.security.spec.DSAPublicKeySpec} or {@link + * java.security.spec.X509EncodedKeySpec}. A key factory can be used to + * translate between compatible key specifications.

    + * + *

    The following is an example of how to use a key factory in order to + * instantiate a DSA public key from its encoding. Assume Alice has + * received a digital signature from Bob. Bob also sent her his public key (in + * encoded format) to verify his signature. Alice then performs the following + * actions: + * + *

    + *  X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
    + *  KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    + *  PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
    + *  Signature sig = Signature.getInstance("DSA");
    + *  sig.initVerify(bobPubKey);
    + *  sig.update(data);
    + *  sig.verify(signature);
    + * 
    + * + * @since 1.2 + * @see Key + * @see PublicKey + * @see PrivateKey + * @see KeySpec + * @see java.security.spec.DSAPublicKeySpec + * @see java.security.spec.X509EncodedKeySpec + @author Mark Benvenuto + */ +public class KeyFactory +{ + /** The service name for key factories. */ + private static final String KEY_FACTORY = "KeyFactory"; + + private KeyFactorySpi keyFacSpi; + private Provider provider; + private String algorithm; + + /** + * Creates a KeyFactory object. + * + * @param keyFacSpi the delegate. + * @param provider the provider. + * @param algorithm the name of the algorithm to associate with this + * KeyFactory. + */ + protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider, + String algorithm) + { + this.keyFacSpi = keyFacSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Generates a KeyFactory object that implements the specified + * algorithm. If the default provider package provides an implementation of + * the requested algorithm, an instance of KeyFactory containing + * that implementation is returned. If the algorithm is not available in the + * default package, other packages are searched. + * + * @param algorithm the name of the requested key algorithm. See Appendix A + * in the Java Cryptography Architecture API Specification & Reference + * for information about standard algorithm names. + * @return a KeyFactory object for the specified algorithm. + * @throws NoSuchAlgorithmException if the requested algorithm is not + * available in the default provider package or any of the other provider + * packages that were searched. + */ + public static KeyFactory getInstance(String algorithm) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + for (int i = 0; i < p.length; i++) + try + { + return getInstance(algorithm, p[i]); + } + catch (NoSuchAlgorithmException e) + { + // Ignore. + } + + throw new NoSuchAlgorithmException(algorithm); + } + + /** + * Generates a KeyFactory object for the specified algorithm + * from the specified provider. + * + * @param algorithm the name of the requested key algorithm. See Appendix A + * in the Java Cryptography Architecture API Specification & Reference + * for information about standard algorithm names. + * @param provider the name of the provider. + * @return a KeyFactory object for the specified algorithm. + * @throws NoSuchAlgorithmException if the algorithm is not available from + * the specified provider. + * @throws NoSuchProviderException if the provider has not been configured. + * @throws IllegalArgumentException if the provider name is null or empty. + * @see Provider + */ + public static KeyFactory getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null || provider.length() == 0) + throw new IllegalArgumentException("Illegal provider"); + + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + + return getInstance(algorithm, p); + } + + /** + * Generates a KeyFactory object for the specified algorithm from + * the specified provider. Note: the provider doesn't have to be + * registered. + * + * @param algorithm the name of the requested key algorithm. See Appendix A + * in the Java Cryptography Architecture API Specification & Reference for + * information about standard algorithm names. + * @param provider the provider. + * @return a KeyFactory object for the specified algorithm. + * @throws NoSuchAlgorithmException if the algorithm is not available from + * the specified provider. + * @throws IllegalArgumentException if the provider is + * null. + * @since 1.4 + * @see Provider + */ + public static KeyFactory getInstance(String algorithm, Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("Illegal provider"); + + try + { + return new KeyFactory((KeyFactorySpi) + Engine.getInstance(KEY_FACTORY, algorithm, provider), + provider, algorithm); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new NoSuchAlgorithmException(algorithm); + } + catch (ClassCastException cce) + { + throw new NoSuchAlgorithmException(algorithm); + } + } + + /** + * Returns the provider of this key factory object. + * + * @return the provider of this key factory object. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Gets the name of the algorithm associated with this KeyFactory. + * + * @return the name of the algorithm associated with this + * KeyFactory. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Generates a public key object from the provided key specification (key + * material). + * + * @param keySpec the specification (key material) of the public key. + * @return the public key. + * @throws InvalidKeySpecException if the given key specification is + * inappropriate for this key factory to produce a public key. + */ + public final PublicKey generatePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + return keyFacSpi.engineGeneratePublic(keySpec); + } + + /** + * Generates a private key object from the provided key specification (key + * material). + * + * @param keySpec the specification (key material) of the private key. + * @return the private key. + * @throws InvalidKeySpecException if the given key specification is + * inappropriate for this key factory to produce a private key. + */ + public final PrivateKey generatePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + return keyFacSpi.engineGeneratePrivate(keySpec); + } + + /** + * Returns a specification (key material) of the given key object. + * keySpec identifies the specification class in which the key + * material should be returned. It could, for example, be + * DSAPublicKeySpec.class, to indicate that the key material + * should be returned in an instance of the {@link + * java.security.spec.DSAPublicKeySpec} class. + * + * @param key the key. + * @param keySpec the specification class in which the key material should be + * returned. + * @return the underlying key specification (key material) in an instance of + * the requested specification class. + * @throws InvalidKeySpecException if the requested key specification is + * inappropriate for the given key, or the given key cannot be processed + * (e.g., the given key has an unrecognized algorithm or format). + */ + public final KeySpec getKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + return keyFacSpi.engineGetKeySpec(key, keySpec); + } + + /** + * Translates a key object, whose provider may be unknown or potentially + * untrusted, into a corresponding key object of this key factory. + * + * @param key the key whose provider is unknown or untrusted. + * @return the translated key. + * @throws InvalidKeyException if the given key cannot be processed by this + * key factory. + */ + public final Key translateKey(Key key) throws InvalidKeyException + { + return keyFacSpi.engineTranslateKey(key); + } +} diff --git a/libjava/classpath/java/security/KeyFactorySpi.java b/libjava/classpath/java/security/KeyFactorySpi.java new file mode 100644 index 0000000..1894fad0 --- /dev/null +++ b/libjava/classpath/java/security/KeyFactorySpi.java @@ -0,0 +1,133 @@ +/* KeyFactorySpi.java --- Key Factory Service Provider Interface + 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 java.security; + +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +/** + * KeyFactorySpi is the Service Provider Interface (SPI) for the + * KeyFactory class. This is the interface for providers to + * supply to implement a key factory for an algorithm. + * + * Key factories are used to convert keys (opaque cryptographic + * keys of type Key) into key specifications (transparent + * representations of the underlying key material). + * + * Key factories are bi-directional. They allow a key class + * to be converted into a key specification (key material) and + * back again. + * + * For example DSA public keys can be specified as + * DSAPublicKeySpec or X509EncodedKeySpec. The key factory + * translate these key specifications. + * + * @since JDK 1.2 + * @author Mark Benvenuto + */ +public abstract class KeyFactorySpi +{ + /** + * Constucts a new KeyFactorySpi. + */ + public KeyFactorySpi() + { + } + + /** + * Generates a public key from the provided key specification. + * + * @param keySpec key specification + * + * @return the public key + * + * @throws InvalidKeySpecException invalid key specification for + * this key factory to produce a public key + */ + protected abstract PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException; + + + /** + * Generates a private key from the provided key specification. + * + * @param keySpec key specification + * + * @return the private key + * + * @throws InvalidKeySpecException invalid key specification for + * this key factory to produce a private key + */ + protected abstract PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException; + + /** + * Returns a key specification for the given key. keySpec + * identifies the specification class to return the key + * material in. + * + * @param key the key + * @param keySpec the specification class to return the + * key material in. + * + * @return the key specification in an instance of the requested + * specification class + * + * @throws InvalidKeySpecException the requested key specification + * is inappropriate for this key or the key is + * unrecognized. + */ + protected abstract KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException; + + + /** + * Translates the key from an unknown or untrusted provider + * into a key for this key factory. + * + * @param the key from an unknown or untrusted provider + * + * @return the translated key + * + * @throws InvalidKeySpecException if the key cannot be + * processed by this key factory + */ + protected abstract Key engineTranslateKey(Key key) + throws InvalidKeyException; +} diff --git a/libjava/classpath/java/security/KeyManagementException.java b/libjava/classpath/java/security/KeyManagementException.java new file mode 100644 index 0000000..694b4c2 --- /dev/null +++ b/libjava/classpath/java/security/KeyManagementException.java @@ -0,0 +1,71 @@ +/* KeyManagementException.java -- an exception in key management + Copyright (C) 1998, 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 java.security; + +/** + * This exception is thrown whenever a problem related to the management of + * security keys is encountered. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Key + * @status updated to 1.4 + */ +public class KeyManagementException extends KeyException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 947674216157062695L; + + /** + * Create a new instance with no descriptive error message. + */ + public KeyManagementException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param msg the descriptive error message + */ + public KeyManagementException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/KeyPair.java b/libjava/classpath/java/security/KeyPair.java new file mode 100644 index 0000000..bf1a40a --- /dev/null +++ b/libjava/classpath/java/security/KeyPair.java @@ -0,0 +1,87 @@ +/* KeyPair.java --- Key Pair Class + Copyright (C) 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 java.security; +import java.io.Serializable; + +/** + KeyPair serves as a simple container for public and private keys. + If properly initialized, this class should be treated like the + private key since it contains it and take approriate security + measures. + + @author Mark Benvenuto + */ +public final class KeyPair implements Serializable +{ + private static final long serialVersionUID = -7565189502268009837L; + + private PublicKey publicKey; + private PrivateKey privateKey; + + /** + Initializes the KeyPair with a pubilc and private key. + + @param publicKey Public Key to store + @param privateKey Private Key to store + */ + public KeyPair(PublicKey publicKey, PrivateKey privateKey) + { + this.publicKey = publicKey; + this.privateKey = privateKey; + } + + /** + Returns the public key stored in the KeyPair + + @return The public key + */ + public PublicKey getPublic() + { + return publicKey; + } + + /** + Returns the private key stored in the KeyPair + + @return The private key + */ + public PrivateKey getPrivate() + { + return privateKey; + } +} diff --git a/libjava/classpath/java/security/KeyPairGenerator.java b/libjava/classpath/java/security/KeyPairGenerator.java new file mode 100644 index 0000000..e6f926e --- /dev/null +++ b/libjava/classpath/java/security/KeyPairGenerator.java @@ -0,0 +1,401 @@ +/* KeyPairGenerator.java --- Key Pair Generator Class + Copyright (C) 1999, 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 java.security; + +import gnu.java.security.Engine; + +import java.security.spec.AlgorithmParameterSpec; + +/** + *

    The KeyPairGenerator class is used to generate pairs of + * public and private keys. Key pair generators are constructed using the + * getInstance() factory methods (static methods that return + * instances of a given class).

    + * + *

    A Key pair generator for a particular algorithm creates a public/private + * key pair that can be used with this algorithm. It also associates + * algorithm-specific parameters with each of the generated keys.

    + * + *

    There are two ways to generate a key pair: in an algorithm-independent + * manner, and in an algorithm-specific manner. The only difference between the + * two is the initialization of the object:

    + * + *
      + *
    • Algorithm-Independent Initialization
      + * All key pair generators share the concepts of a keysize and a + * source of randomness. The keysize is interpreted differently + * for different algorithms (e.g., in the case of the DSA algorithm, + * the keysize corresponds to the length of the modulus). There is an + * initialize() method in this KeyPairGenerator + * class that takes these two universally shared types of arguments. There + * is also one that takes just a keysize argument, and uses the + * {@link SecureRandom} implementation of the highest-priority installed + * provider as the source of randomness. (If none of the installed + * providers supply an implementation of {@link SecureRandom}, a + * system-provided source of randomness is used.) + * + *

      Since no other parameters are specified when you call the above + * algorithm-independent initialize methods, it is up to the provider what + * to do about the algorithm-specific parameters (if any) to be associated + * with each of the keys.

      + * + *

      If the algorithm is the DSA algorithm, and the keysize + * (modulus size) is 512, 768, or 1024, + * then the GNU provider uses a set of precomputed values for the + * p, q, and g parameters. If the + * modulus size is not one of the above values, the GNU + * provider creates a new set of parameters. Other providers might have + * precomputed parameter sets for more than just the three modulus sizes + * mentioned above. Still others might not have a list of precomputed + * parameters at all and instead always create new parameter sets.

    • + *
    • Algorithm-Specific Initialization
      + * For situations where a set of algorithm-specific parameters already + * exists (e.g., so-called community parameters in DSA), there + * are two initialize methods that have an {@link AlgorithmParameterSpec} + * argument. One also has a {@link SecureRandom} argument, while the the + * other uses the {@link SecureRandom} implementation of the highest-priority + * installed provider as the source of randomness. (If none of the installed + * providers supply an implementation of {@link SecureRandom}, a + * system-provided source of randomness is used.)
    • + *
    + * + *

    In case the client does not explicitly initialize the + * KeyPairGenerator (via a call to an initialize method), each + * provider must supply (and document) a default initialization. For example, + * the GNU provider uses a default modulus size (keysize) of + * 1024 bits.

    + * + *

    Note that this class is abstract and extends from {@link + * KeyPairGeneratorSpi} for historical reasons. Application developers should + * only take notice of the methods defined in this KeyPairGenerator + * class; all the methods in the superclass are intended for cryptographic + * service providers who wish to supply their own implementations of key pair + * generators.

    + * + * @see Signature + * @see KeyPair + * @see AlgorithmParameterSpec + * @author Mark Benvenuto + * @author Casey Marshall + */ +public abstract class KeyPairGenerator extends KeyPairGeneratorSpi +{ + /** The service name for key pair generators. */ + private static final String KEY_PAIR_GENERATOR = "KeyPairGenerator"; + + Provider provider; + private String algorithm; + + /** + * Creates a KeyPairGenerator object for the specified + * algorithm. + * + * @param algorithm the standard string name of the algorithm. + * See Appendix A in the Java Cryptography Architecture API + * Specification & Reference for information about standard + * algorithm names. + */ + protected KeyPairGenerator(String algorithm) + { + this.algorithm = algorithm; + this.provider = null; + } + + /** + * Returns the standard name of the algorithm for this key pair generator. + * See Appendix A in the Java Cryptography Architecture API Specification + * & Reference for information about standard algorithm names. + * + * @return the standard string name of the algorithm. + */ + public String getAlgorithm() + { + return algorithm; + } + + /** + * Generates a KeyPairGenerator object that implements the + * specified digest algorithm. If the default provider package provides an + * implementation of the requested digest algorithm, an instance of + * KeyPairGenerator containing that implementation is returned. + * If the algorithm is not available in the default package, other packages + * are searched. + * + * @param algorithm the standard string name of the algorithm. See Appendix A + * in the Java Cryptography Architecture API Specification & Reference for + * information about standard algorithm names. + * @return the new KeyPairGenerator object. + * @throws NoSuchAlgorithmException if the algorithm is not available in the + * environment. + */ + public static KeyPairGenerator getInstance(String algorithm) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(algorithm, p[i]); + } + catch (NoSuchAlgorithmException e) + { + // Ignored. + } + } + + throw new NoSuchAlgorithmException(algorithm); + } + + /** + * Generates a KeyPairGenerator object implementing the + * specified algorithm, as supplied from the specified provider, if + * such an algorithm is available from the provider. + * + * @param algorithm the standard string name of the algorithm. See + * Appendix A in the Java Cryptography Architecture API Specification + * & Reference for information about standard algorithm names. + * @param provider the string name of the provider. + * @return the new KeyPairGenerator object. + * @throws NoSuchAlgorithmException if the algorithm is not available + * from the provider. + * @throws NoSuchProviderException if the provider is not available in the + * environment. + * @throws IllegalArgumentException if the provider name is null + * or empty. + * @see Provider + */ + public static KeyPairGenerator getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + + return getInstance(algorithm, p); + } + + /** + * Generates a KeyPairGenerator object implementing the specified + * algorithm, as supplied from the specified provider, if such an algorithm is + * available from the provider. Note: the provider doesn't have to be + * registered. + * + * @param algorithm the standard string name of the algorithm. See Appendix A + * in the Java Cryptography Architecture API Specification & Reference for + * information about standard algorithm names. + * @param provider the provider. + * @return the new KeyPairGenerator object. + * @throws NoSuchAlgorithmException if the algorithm is not + * available from the provider. + * @throws IllegalArgumentException if the provider is + * null. + * @since 1.4 + * @see Provider + */ + public static KeyPairGenerator getInstance(String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("Illegal provider"); + + Object o = null; + try + { + o = Engine.getInstance(KEY_PAIR_GENERATOR, algorithm, provider); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new NoSuchAlgorithmException(algorithm); + } + + KeyPairGenerator result = null; + if (o instanceof KeyPairGeneratorSpi) + { + result = new DummyKeyPairGenerator((KeyPairGeneratorSpi) o, algorithm); + } + else if (o instanceof KeyPairGenerator) + { + result = (KeyPairGenerator) o; + result.algorithm = algorithm; + } + result.provider = provider; + return result; + } + + /** + * Returns the provider of this key pair generator object. + * + * @return the provider of this key pair generator object. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Initializes the key pair generator for a certain keysize using a default + * parameter set and the {@link SecureRandom} implementation of the + * highest-priority installed provider as the source of randomness. (If none + * of the installed providers supply an implementation of {@link SecureRandom}, + * a system-provided source of randomness is used.) + * + * @param keysize the keysize. This is an algorithm-specific metric, such as + * modulus length, specified in number of bits. + * @throws InvalidParameterException if the keysize is not supported by this + * KeyPairGenerator object. + */ + public void initialize(int keysize) + { + initialize(keysize, new SecureRandom()); + } + + /** + * Initializes the key pair generator for a certain keysize with the given + * source of randomness (and a default parameter set). + * + * @param keysize the keysize. This is an algorithm-specific metric, such as + * modulus length, specified in number of bits. + * @param random the source of randomness. + * @throws InvalidParameterException if the keysize is not + * supported by this KeyPairGenerator object. + * @since 1.2 + */ + public void initialize(int keysize, SecureRandom random) + { + initialize(keysize, random); + } + + /** + *

    Initializes the key pair generator using the specified parameter set and + * the {@link SecureRandom} implementation of the highest-priority installed + * provider as the source of randomness. (If none of the installed providers + * supply an implementation of {@link SecureRandom}, a system-provided source + * of randomness is used.)

    + * + *

    This concrete method has been added to this previously-defined abstract + * class. This method calls the + * {@link KeyPairGeneratorSpi#initialize(AlgorithmParameterSpec, SecureRandom)} + * initialize method, passing it params and a source of + * randomness (obtained from the highest-priority installed provider or + * system-provided if none of the installed providers supply one). That + * initialize method always throws an {@link UnsupportedOperationException} + * if it is not overridden by the provider.

    + * + * @param params the parameter set used to generate the keys. + * @throws InvalidAlgorithmParameterException if the given parameters are + * inappropriate for this key pair generator. + * @since 1.2 + */ + public void initialize(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException + { + initialize(params, new SecureRandom()); + } + + /** + *

    Initializes the key pair generator with the given parameter set and + * source of randomness.

    + * + *

    This concrete method has been added to this previously-defined abstract + * class. This method calls the + * {@link KeyPairGeneratorSpi#initialize(AlgorithmParameterSpec, SecureRandom)} + * initialize method, passing it params and random. + * That initialize method always throws an {@link UnsupportedOperationException} + * if it is not overridden by the provider.

    + * + * @param params the parameter set used to generate the keys. + * @param random the source of randomness. + * @throws InvalidAlgorithmParameterException if the given parameters are + * inappropriate for this key pair generator. + * @since 1.2 + */ + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + super.initialize(params, random); + } + + /** + *

    Generates a key pair.

    + * + *

    If this KeyPairGenerator has not been initialized + * explicitly, provider-specific defaults will be used for the size and other + * (algorithm-specific) values of the generated keys.

    + * + *

    This will generate a new key pair every time it is called.

    + * + *

    This method is functionally equivalent to {@link #generateKeyPair()}.

    + * + * @return the generated key pair. + * @since 1.2 + */ + public final KeyPair genKeyPair() + { + try + { + return getInstance("DSA", "GNU").generateKeyPair(); + } + catch (Exception e) + { + System.err.println("genKeyPair failed: " + e); + e.printStackTrace(); + return null; + } + } + + /** + *

    Generates a key pair.

    + * + *

    If this KeyPairGenerator has not been initialized + * explicitly, provider-specific defaults will be used for the size and other + * (algorithm-specific) values of the generated keys.

    + * + *

    This will generate a new key pair every time it is called.

    + * + *

    This method is functionally equivalent to {@link #genKeyPair()}.

    + * + * @return the generated key pair. + */ + public KeyPair generateKeyPair() + { + return genKeyPair(); + } +} diff --git a/libjava/classpath/java/security/KeyPairGeneratorSpi.java b/libjava/classpath/java/security/KeyPairGeneratorSpi.java new file mode 100644 index 0000000..689fbec --- /dev/null +++ b/libjava/classpath/java/security/KeyPairGeneratorSpi.java @@ -0,0 +1,102 @@ +/* KeyPairGeneratorSpi.java --- Key Pair Generator SPI Class + Copyright (C) 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 java.security; +import java.security.spec.AlgorithmParameterSpec; + +/** + KeyPairGeneratorSpi is the interface used to generate key pairs + for security algorithms. + + @author Mark Benvenuto + */ +public abstract class KeyPairGeneratorSpi +{ + /** + Constructs a new KeyPairGeneratorSpi + */ + public KeyPairGeneratorSpi() + { + } + + /** + Initialize the KeyPairGeneratorSpi with the specified + key size and source of randomness + + @param keysize size of the key to generate + @param random A SecureRandom source of randomness + */ + public abstract void initialize(int keysize, SecureRandom random); + + /** + Initialize the KeyPairGeneratorSpi with the specified + AlgorithmParameterSpec and source of randomness + + This is a concrete method. It may be overridden by the provider + and if the AlgorithmParameterSpec class is invalid + throw InvalidAlgorithmParameterException. By default this + method just throws UnsupportedOperationException. + + @param params A AlgorithmParameterSpec to intialize with + @param random A SecureRandom source of randomness + + @throws InvalidAlgorithmParameterException + */ + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + throw new java.lang.UnsupportedOperationException(); + } + + /** + Generates a KeyPair according the rules for the algorithm. + Unless intialized, algorithm defaults will be used. It + creates a unique key pair each time. + + @return a key pair + */ + public abstract KeyPair generateKeyPair(); + + /** + * We override clone here to make it accessible for use by + * DummyKeyPairGenerator. + */ + protected Object clone() throws CloneNotSupportedException + { + return super.clone(); + } +} diff --git a/libjava/classpath/java/security/KeyStore.java b/libjava/classpath/java/security/KeyStore.java new file mode 100644 index 0000000..6964487 --- /dev/null +++ b/libjava/classpath/java/security/KeyStore.java @@ -0,0 +1,507 @@ +/* KeyStore.java --- Key Store Class + Copyright (C) 1999, 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 java.security; + +import gnu.java.security.Engine; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.CertificateException; +import java.util.Date; +import java.util.Enumeration; + +/** + * Keystore represents an in-memory collection of keys and + * certificates. There are two types of entries: + * + *
    + *
    Key Entry
    + * + *

    This type of keystore entry store sensitive crytographic key + * information in a protected format.Typically this is a secret + * key or a private key with a certificate chain.

    + * + *
    Trusted Ceritificate Entry
    + * + *

    This type of keystore entry contains a single public key + * certificate belonging to annother entity. It is called trusted + * because the keystore owner trusts that the certificates + * belongs to the subject (owner) of the certificate.

    + *
    + * + *

    Entries in a key store are referred to by their "alias": a simple + * unique string. + * + *

    The structure and persistentence of the key store is not + * specified. Any method could be used to protect sensitive + * (private or secret) keys. Smart cards or integrated + * cryptographic engines could be used or the keystore could + * be simply stored in a file.

    + * + * @see java.security.cert.Certificate + * @see Key + */ +public class KeyStore +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** Service name for key stores. */ + private static final String KEY_STORE = "KeyStore"; + + private KeyStoreSpi keyStoreSpi; + private Provider provider; + private String type; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + Creates an instance of KeyStore + + @param keyStoreSpi A KeyStore engine to use + @param provider A provider to use + @param type The type of KeyStore + */ + protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type) + { + this.keyStoreSpi = keyStoreSpi; + this.provider = provider; + this.type = type; + } + + // Class methods. + // ------------------------------------------------------------------------ + + /** + * Gets an instance of the KeyStore class representing + * the specified keystore. If the type is not + * found then, it throws KeyStoreException. + * + * @param type the type of keystore to choose + * @return a KeyStore repesenting the desired type + * @throws KeyStoreException if the type of keystore is not implemented + * by providers or the implementation cannot be instantiated. + */ + public static KeyStore getInstance(String type) throws KeyStoreException + { + Provider[] p = Security.getProviders(); + + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(type, p[i]); + } + catch (KeyStoreException e) + { + // Ignore. + } + } + + throw new KeyStoreException(type); + } + + /** + * Gets an instance of the KeyStore class representing + * the specified key store from the specified provider. + * If the type is not found then, it throws KeyStoreException. + * If the provider is not found, then it throws + * NoSuchProviderException. + * + * @param type the type of keystore to choose + * @param provider the provider name + * @return a KeyStore repesenting the desired type + * @throws KeyStoreException if the type of keystore is not + * implemented by the given provider + * @throws NoSuchProviderException if the provider is not found + * @throws IllegalArgumentException if the provider string is + * null or empty + */ + public static KeyStore getInstance(String type, String provider) + throws KeyStoreException, NoSuchProviderException + { + if (provider == null || provider.length() == 0) + throw new IllegalArgumentException("Illegal provider"); + + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + + return getInstance(type, p); + } + + /** + * Gets an instance of the KeyStore class representing + * the specified key store from the specified provider. + * If the type is not found then, it throws KeyStoreException. + * If the provider is not found, then it throws + * NoSuchProviderException. + * + * @param type the type of keystore to choose + * @param provider the keystore provider + * @return a KeyStore repesenting the desired type + * @throws KeyStoreException if the type of keystore is not + * implemented by the given provider + * @throws IllegalArgumentException if the provider object is null + * @since 1.4 + */ + public static KeyStore getInstance(String type, Provider provider) + throws KeyStoreException + { + if (provider == null) + throw new IllegalArgumentException("Illegal provider"); + try + { + return new KeyStore( + (KeyStoreSpi) Engine.getInstance(KEY_STORE, type, provider), + provider, type); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyStoreException(type); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new KeyStoreException(type); + } + catch (ClassCastException cce) + { + throw new KeyStoreException(type); + } + } + + /** + * Returns the default KeyStore type. This method looks up the + * type in <JAVA_HOME>/lib/security/java.security with the + * property "keystore.type" or if that fails then "jks" . + */ + public static final String getDefaultType() + { + // Security reads every property in java.security so it + // will return this property if it exists. + String tmp = Security.getProperty("keystore.type"); + + if (tmp == null) + tmp = "jks"; + + return tmp; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + Gets the provider that the class is from. + + @return the provider of this class + */ + public final Provider getProvider() + { + return provider; + } + + /** + Returns the type of the KeyStore supported + + @return A string with the type of KeyStore + */ + public final String getType() + { + return type; + } + + /** + Returns the key associated with given alias using the + supplied password. + + @param alias an alias for the key to get + @param password password to access key with + + @return the requested key, or null otherwise + + @throws NoSuchAlgorithmException if there is no algorithm + for recovering the key + @throws UnrecoverableKeyException key cannot be reocovered + (wrong password). + */ + public final Key getKey(String alias, char[]password) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableKeyException + { + return keyStoreSpi.engineGetKey(alias, password); + } + + /** + Gets a Certificate chain for the specified alias. + + @param alias the alias name + + @return a chain of Certificates ( ordered from the user's + certificate to the Certificate Authority's ) or + null if the alias does not exist or there is no + certificate chain for the alias ( the alias refers + to a trusted certificate entry or there is no entry). + */ + public final java.security.cert. + Certificate[] getCertificateChain(String alias) throws KeyStoreException + { + return keyStoreSpi.engineGetCertificateChain(alias); + } + + /** + Gets a Certificate for the specified alias. + + If there is a trusted certificate entry then that is returned. + it there is a key entry with a certificate chain then the + first certificate is return or else null. + + @param alias the alias name + + @return a Certificate or null if the alias does not exist + or there is no certificate for the alias + */ + public final java.security.cert.Certificate getCertificate(String alias) + throws KeyStoreException + { + return keyStoreSpi.engineGetCertificate(alias); + } + + /** + Gets entry creation date for the specified alias. + + @param alias the alias name + + @returns the entry creation date or null + */ + public final Date getCreationDate(String alias) throws KeyStoreException + { + return keyStoreSpi.engineGetCreationDate(alias); + } + + /** + Assign the key to the alias in the keystore, protecting it + with the given password. It will overwrite an existing + entry and if the key is a PrivateKey, also add the + certificate chain representing the corresponding public key. + + @param alias the alias name + @param key the key to add + @password the password to protect with + @param chain the certificate chain for the corresponding + public key + + @throws KeyStoreException if it fails + */ + public final void setKeyEntry(String alias, Key key, char[]password, + java.security.cert. + Certificate[]chain) throws KeyStoreException + { + keyStoreSpi.engineSetKeyEntry(alias, key, password, chain); + } + + /** + Assign the key to the alias in the keystore. It will overwrite + an existing entry and if the key is a PrivateKey, also + add the certificate chain representing the corresponding + public key. + + @param alias the alias name + @param key the key to add + @param chain the certificate chain for the corresponding + public key + + @throws KeyStoreException if it fails + */ + public final void setKeyEntry(String alias, byte[]key, + java.security.cert. + Certificate[]chain) throws KeyStoreException + { + keyStoreSpi.engineSetKeyEntry(alias, key, chain); + } + + /** + Assign the certificate to the alias in the keystore. It + will overwrite an existing entry. + + @param alias the alias name + @param cert the certificate to add + + @throws KeyStoreException if it fails + */ + public final void setCertificateEntry(String alias, + java.security.cert. + Certificate cert) throws + KeyStoreException + { + keyStoreSpi.engineSetCertificateEntry(alias, cert); + } + + /** + Deletes the entry for the specified entry. + + @param alias the alias name + + @throws KeyStoreException if it fails + */ + public final void deleteEntry(String alias) throws KeyStoreException + { + keyStoreSpi.engineDeleteEntry(alias); + } + + /** + Generates a list of all the aliases in the keystore. + + @return an Enumeration of the aliases + */ + public final Enumeration aliases() throws KeyStoreException + { + return keyStoreSpi.engineAliases(); + } + + /** + Determines if the keystore contains the specified alias. + + @param alias the alias name + + @return true if it contains the alias, false otherwise + */ + public final boolean containsAlias(String alias) throws KeyStoreException + { + return keyStoreSpi.engineContainsAlias(alias); + } + + /** + Returns the number of entries in the keystore. + + @returns the number of keystore entries. + */ + public final int size() throws KeyStoreException + { + return keyStoreSpi.engineSize(); + } + + /** + Determines if the keystore contains a key entry for + the specified alias. + + @param alias the alias name + + @return true if it is a key entry, false otherwise + */ + public final boolean isKeyEntry(String alias) throws KeyStoreException + { + return keyStoreSpi.engineIsKeyEntry(alias); + } + + + /** + Determines if the keystore contains a certificate entry for + the specified alias. + + @param alias the alias name + + @return true if it is a certificate entry, false otherwise + */ + public final boolean isCertificateEntry(String alias) + throws KeyStoreException + { + return keyStoreSpi.engineIsCertificateEntry(alias); + } + + /** + Determines if the keystore contains the specified certificate + entry and returns the alias. + + It checks every entry and for a key entry checks only the + first certificate in the chain. + + @param cert Certificate to look for + + @return alias of first matching certificate, null if it + does not exist. + */ + public final String getCertificateAlias(java.security.cert.Certificate cert) + throws KeyStoreException + { + return keyStoreSpi.engineGetCertificateAlias(cert); + } + + /** + Stores the keystore in the specified output stream and it + uses the specified key it keep it secure. + + @param stream the output stream to save the keystore to + @param password the password to protect the keystore integrity with + + @throws IOException if an I/O error occurs. + @throws NoSuchAlgorithmException the data integrity algorithm + used cannot be found. + @throws CertificateException if any certificates could not be + stored in the output stream. + */ + public final void store(OutputStream stream, char[]password) + throws KeyStoreException, IOException, NoSuchAlgorithmException, + CertificateException + { + keyStoreSpi.engineStore(stream, password); + } + + /** + Loads the keystore from the specified input stream and it + uses the specified password to check for integrity if supplied. + + @param stream the input stream to load the keystore from + @param password the password to check the keystore integrity with + + @throws IOException if an I/O error occurs. + @throws NoSuchAlgorithmException the data integrity algorithm + used cannot be found. + @throws CertificateException if any certificates could not be + stored in the output stream. + */ + public final void load(InputStream stream, char[]password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + keyStoreSpi.engineLoad(stream, password); + } + +} diff --git a/libjava/classpath/java/security/KeyStoreException.java b/libjava/classpath/java/security/KeyStoreException.java new file mode 100644 index 0000000..9a0a535 --- /dev/null +++ b/libjava/classpath/java/security/KeyStoreException.java @@ -0,0 +1,70 @@ +/* KeyStoreException.java -- Indicates a problem with the key store + Copyright (C) 1998, 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 java.security; + +/** + * Indicates a problem with the key store. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.2 + * @status updated to 1.4 + */ +public class KeyStoreException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -1119353179322377262L; + + /** + * Create a new instance detailed error message. + */ + public KeyStoreException() + { + } + + /** + * Create a new instance with a detailed error message. + * + * @param msg the descriptive error message + */ + public KeyStoreException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/KeyStoreSpi.java b/libjava/classpath/java/security/KeyStoreSpi.java new file mode 100644 index 0000000..a16008f --- /dev/null +++ b/libjava/classpath/java/security/KeyStoreSpi.java @@ -0,0 +1,275 @@ +/* KeyStoreSpi.java --- Key Store Service Provider Interface + 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 java.security; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.CertificateException; +import java.util.Date; +import java.util.Enumeration; + +/** + * KeyStoreSpi is the Service Provider Interface (SPI) for the + * KeyStore class. This is the interface for providers to + * supply to implement a keystore for a particular keystore + * type. + * + * @since 1.2 + * @author Mark Benvenuto + */ +public abstract class KeyStoreSpi +{ + /** + * Constructs a new KeyStoreSpi + */ + public KeyStoreSpi() + { + } + + /** + * Returns the key associated with given alias using the + * supplied password. + * + * @param alias an alias for the key to get + * @param password password to access key with + * + * @return the requested key, or null otherwise + * + * @throws NoSuchAlgorithmException if there is no algorithm + * for recovering the key + * @throws UnrecoverableKeyException key cannot be reocovered + * (wrong password). + */ + public abstract Key engineGetKey(String alias, char[]password) + throws NoSuchAlgorithmException, UnrecoverableKeyException; + + /** + * Gets a Certificate chain for the specified alias. + * + * @param alias the alias name + * + * @return a chain of Certificates ( ordered from the user's + * certificate to the Certificate Authority's ) or + * null if the alias does not exist or there is no + * certificate chain for the alias ( the alias refers + * to a trusted certificate entry or there is no entry). + */ + public abstract java.security.cert. + Certificate[] engineGetCertificateChain(String alias); + + + /** + * Gets a Certificate for the specified alias. + * + * If there is a trusted certificate entry then that is returned. + * it there is a key entry with a certificate chain then the + * first certificate is return or else null. + * + * @param alias the alias name + * + * @return a Certificate or null if the alias does not exist + * or there is no certificate for the alias + */ + public abstract java.security.cert. + Certificate engineGetCertificate(String alias); + + /** + * Gets entry creation date for the specified alias. + * + * @param alias the alias name + * + * @returns the entry creation date or null + */ + public abstract Date engineGetCreationDate(String alias); + + /** + * Assign the key to the alias in the keystore, protecting it + * with the given password. It will overwrite an existing + * entry and if the key is a PrivateKey, also add the + * certificate chain representing the corresponding public key. + * + * @param alias the alias name + * @param key the key to add + * @password the password to protect with + * @param chain the certificate chain for the corresponding + * public key + * + * @throws KeyStoreException if it fails + */ + public abstract void engineSetKeyEntry(String alias, Key key, + char[]password, + java.security.cert. + Certificate[]chain) throws + KeyStoreException; + + /** + * Assign the key to the alias in the keystore. It will overwrite + * an existing entry and if the key is a PrivateKey, also + * add the certificate chain representing the corresponding + * public key. + * + * @param alias the alias name + * @param key the key to add + * @param chain the certificate chain for the corresponding + * public key + * + * @throws KeyStoreException if it fails + */ + public abstract void engineSetKeyEntry(String alias, byte[]key, + java.security.cert. + Certificate[]chain) throws + KeyStoreException; + + + /** + * Assign the certificate to the alias in the keystore. It + * will overwrite an existing entry. + * + * @param alias the alias name + * @param cert the certificate to add + * + * @throws KeyStoreException if it fails + */ + public abstract void engineSetCertificateEntry(String alias, + java.security.cert. + Certificate cert) throws + KeyStoreException; + + /** + * Deletes the entry for the specified entry. + * + * @param alias the alias name + * + * @throws KeyStoreException if it fails + */ + public abstract void engineDeleteEntry(String alias) + throws KeyStoreException; + + /** + * Generates a list of all the aliases in the keystore. + * + * @return an Enumeration of the aliases + */ + public abstract Enumeration engineAliases(); + + /** + * Determines if the keystore contains the specified alias. + * + * @param alias the alias name + * + * @return true if it contains the alias, false otherwise + */ + public abstract boolean engineContainsAlias(String alias); + + /** + * Returns the number of entries in the keystore. + * + * @returns the number of keystore entries. + */ + public abstract int engineSize(); + + /** + * Determines if the keystore contains a key entry for + * the specified alias. + * + * @param alias the alias name + * + * @return true if it is a key entry, false otherwise + */ + public abstract boolean engineIsKeyEntry(String alias); + + /** + * Determines if the keystore contains a certificate entry for + * the specified alias. + * + * @param alias the alias name + * + * @return true if it is a certificate entry, false otherwise + */ + public abstract boolean engineIsCertificateEntry(String alias); + + /** + * Determines if the keystore contains the specified certificate + * entry and returns the alias. + * + * It checks every entry and for a key entry checks only the + * first certificate in the chain. + * + * @param cert Certificate to look for + * + * @return alias of first matching certificate, null if it + * does not exist. + */ + public abstract String engineGetCertificateAlias(java.security.cert. + Certificate cert); + + /** + * Stores the keystore in the specified output stream and it + * uses the specified key it keep it secure. + * + * @param stream the output stream to save the keystore to + * @param password the password to protect the keystore integrity with + * + * @throws IOException if an I/O error occurs. + * @throws NoSuchAlgorithmException the data integrity algorithm + * used cannot be found. + * @throws CertificateException if any certificates could not be + * stored in the output stream. + */ + public abstract void engineStore(OutputStream stream, char[]password) + throws IOException, NoSuchAlgorithmException, CertificateException; + + + /** + * Loads the keystore from the specified input stream and it + * uses the specified password to check for integrity if supplied. + * + * @param stream the input stream to load the keystore from + * @param password the password to check the keystore integrity with + * + * @throws IOException if an I/O error occurs. + * @throws NoSuchAlgorithmException the data integrity algorithm + * used cannot be found. + * @throws CertificateException if any certificates could not be + * stored in the output stream. + */ + public abstract void engineLoad(InputStream stream, char[]password) + throws IOException, NoSuchAlgorithmException, CertificateException; +} diff --git a/libjava/classpath/java/security/MessageDigest.java b/libjava/classpath/java/security/MessageDigest.java new file mode 100644 index 0000000..8684f20 --- /dev/null +++ b/libjava/classpath/java/security/MessageDigest.java @@ -0,0 +1,413 @@ +/* MessageDigest.java --- The message digest interface. + Copyright (C) 1999, 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 java.security; + +import gnu.java.security.Engine; + +/** + *

    This MessageDigest class provides applications the + * functionality of a message digest algorithm, such as MD5 or SHA. + * Message digests are secure one-way hash functions that take arbitrary-sized + * data and output a fixed-length hash value.

    + * + *

    A MessageDigest object starts out initialized. The data is + * processed through it using the update() methods. At any point + * reset() can be called to reset the digest. Once all the data to + * be updated has been updated, one of the digest() methods should + * be called to complete the hash computation.

    + * + *

    The digest() method can be called once for a given + * number of updates. After digest() has been called, the + * MessageDigest object is reset to its initialized state. + *

    + * + *

    Implementations are free to implement the {@link Cloneable} interface. + * Client applications can test cloneability by attempting cloning and catching + * the {@link CloneNotSupportedException}: + * + *

    + *    MessageDigest md = MessageDigest.getInstance("SHA");
    + *    try
    + *      {
    + *        md.update(toChapter1);
    + *        MessageDigest tc1 = md.clone();
    + *        byte[] toChapter1Digest = tc1.digest();
    + *        md.update(toChapter2);
    + *        // ...
    + *      }
    + *    catch (CloneNotSupportedException x)
    + *      {
    + *        throw new DigestException("couldn't make digest of partial content");
    + *      }
    + * 
    + * + *

    Note that if a given implementation is not cloneable, it is still possible + * to compute intermediate digests by instantiating several instances, if the + * number of digests is known in advance.

    + * + *

    Note that this class is abstract and extends from {@link MessageDigestSpi} + * for historical reasons. Application developers should only take notice of the + * methods defined in this MessageDigest class; all the methods in + * the superclass are intended for cryptographic service providers who wish to + * supply their own implementations of message digest algorithms.

    + * + * @see MessageDigestSpi + * @see Provider + * @since JDK 1.1 + */ +public abstract class MessageDigest extends MessageDigestSpi +{ + /** The service name for message digests. */ + private static final String MESSAGE_DIGEST = "MessageDigest"; + + private String algorithm; + Provider provider; + private byte[] lastDigest; + + /** + * Creates a message digest with the specified algorithm name. + * + * @param algorithm the standard name of the digest algorithm. + * See Appendix A in the Java Cryptography Architecture API + * Specification & Reference for information about standard + * algorithm names. + */ + protected MessageDigest(String algorithm) + { + this.algorithm = algorithm; + provider = null; + } + + /** + * Generates a MessageDigest object that implements the specified + * digest algorithm. If the default provider package provides an + * implementation of the requested digest algorithm, an instance of + * MessageDigest containing that implementation is returned. If + * the algorithm is not available in the default package, other packages are + * searched. + * + * @param algorithm the name of the algorithm requested. See Appendix A in the + * Java Cryptography Architecture API Specification & Reference for + * information about standard algorithm names. + * @return a Message Digest object implementing the specified algorithm. + * @throws NoSuchAlgorithmException if the algorithm is not available in the + * caller's environment. + */ + public static MessageDigest getInstance(String algorithm) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(algorithm, p[i]); + } + catch (NoSuchAlgorithmException ignored) + { + // Ignore. + } + } + + throw new NoSuchAlgorithmException(algorithm); + } + + /** + * Generates a MessageDigest object implementing the specified + * algorithm, as supplied from the specified provider, if such an algorithm is + * available from the provider. + * + * @param algorithm the name of the algorithm requested. See Appendix A in the + * Java Cryptography Architecture API Specification & Reference for + * information about standard algorithm names. + * @param provider the name of the provider. + * @return a Message Digest object implementing the specified algorithm. + * @throws NoSuchAlgorithmException if the algorithm is not available in the + * package supplied by the requested provider. + * @throws NoSuchProviderException if the provider is not available in the + * environment. + * @throws IllegalArgumentException if the provider name is null or empty. + * @see Provider + */ + public static MessageDigest getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null || provider.length() == 0) + throw new IllegalArgumentException("Illegal provider"); + + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + + return getInstance(algorithm, p); + } + + /** + * Generates a MessageDigest object implementing the specified + * algorithm, as supplied from the specified provider, if such an algorithm + * is available from the provider. Note: the provider doesn't have to be + * registered. + * + * @param algorithm the name of the algorithm requested. See Appendix A in + * the Java Cryptography Architecture API Specification & Reference for + * information about standard algorithm names. + * @param provider the provider. + * @return a Message Digest object implementing the specified algorithm. + * @throws NoSuchAlgorithmException if the algorithm is not + * available in the package supplied by the requested provider. + * @throws IllegalArgumentException if the provider is + * null. + * @since 1.4 + * @see Provider + */ + public static MessageDigest getInstance(String algorithm, Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("Illegal provider"); + + MessageDigest result = null; + Object o = null; + try + { + o = Engine.getInstance(MESSAGE_DIGEST, algorithm, provider); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new NoSuchAlgorithmException(algorithm); + } + + if (o instanceof MessageDigestSpi) + { + result = new DummyMessageDigest((MessageDigestSpi) o, algorithm); + } + else if (o instanceof MessageDigest) + { + result = (MessageDigest) o; + result.algorithm = algorithm; + } + else + { + throw new NoSuchAlgorithmException(algorithm); + } + result.provider = provider; + return result; + } + + /** + * Returns the provider of this message digest object. + * + * @return the provider of this message digest object. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Updates the digest using the specified byte. + * + * @param input the byte with which to update the digest. + */ + public void update(byte input) + { + engineUpdate(input); + } + + /** + * Updates the digest using the specified array of bytes, starting at the + * specified offset. + * + * @param input the array of bytes. + * @param offset the offset to start from in the array of bytes. + * @param len the number of bytes to use, starting at offset. + */ + public void update(byte[] input, int offset, int len) + { + engineUpdate(input, offset, len); + } + + /** + * Updates the digest using the specified array of bytes. + * + * @param input the array of bytes. + */ + public void update(byte[] input) + { + engineUpdate(input, 0, input.length); + } + + /** + * Completes the hash computation by performing final operations such as + * padding. The digest is reset after this call is made. + * + * @return the array of bytes for the resulting hash value. + */ + public byte[] digest() + { + return lastDigest = engineDigest(); + } + + /** + * Completes the hash computation by performing final operations such as + * padding. The digest is reset after this call is made. + * + * @param buf An output buffer for the computed digest. + * @param offset The offset into the output buffer to begin storing the digest. + * @param len The number of bytes within buf allotted for the digest. + * @return The number of bytes placed into buf. + * @throws DigestException if an error occurs. + */ + public int digest(byte[] buf, int offset, int len) throws DigestException + { + return engineDigest(buf, offset, len); + } + + /** + * Performs a final update on the digest using the specified array of bytes, + * then completes the digest computation. That is, this method first calls + * update(input), passing the input array to the update() + * method, then calls digest(). + * + * @param input the input to be updated before the digest is completed. + * @return the array of bytes for the resulting hash value. + */ + public byte[] digest(byte[] input) + { + update(input); + return digest(); + } + + /** + * Returns a string representation of this message digest object. + * + * @return a string representation of the object. + */ + public String toString() + { + return (getClass()).getName() + " Message Digest <" + digestToString() + ">"; + } + + /** + * Compares two digests for equality. Does a simple byte compare. + * + * @param digesta one of the digests to compare. + * @param digestb the other digest to compare. + * @return true if the digests are equal, false + * otherwise. + */ + public static boolean isEqual(byte[] digesta, byte[] digestb) + { + if (digesta.length != digestb.length) + return false; + + for (int i = digesta.length - 1; i >= 0; --i) + if (digesta[i] != digestb[i]) + return false; + + return true; + } + + /** Resets the digest for further use. */ + public void reset() + { + engineReset(); + } + + /** + * Returns a string that identifies the algorithm, independent of + * implementation details. The name should be a standard Java Security name + * (such as "SHA", "MD5", and so on). See Appendix + * A in the Java Cryptography Architecture API Specification & Reference + * for information about standard algorithm names. + * + * @return the name of the algorithm. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Returns the length of the digest in bytes, or 0 if this + * operation is not supported by the provider and the implementation is not + * cloneable. + * + * @return the digest length in bytes, or 0 if this operation is + * not supported by the provider and the implementation is not cloneable. + * @since 1.2 + */ + public final int getDigestLength() + { + return engineGetDigestLength(); + } + + /** + * Returns a clone if the implementation is cloneable. + * + * @return a clone if the implementation is cloneable. + * @throws CloneNotSupportedException if this is called on an implementation + * that does not support {@link Cloneable}. + */ + public Object clone() throws CloneNotSupportedException + { + return super.clone(); + } + + private String digestToString() + { + byte[] digest = lastDigest; + + if (digest == null) + return "incomplete"; + + StringBuffer buf = new StringBuffer(); + int len = digest.length; + for (int i = 0; i < len; ++i) + { + byte b = digest[i]; + byte high = (byte) ((b & 0xff) >>> 4); + byte low = (byte) (b & 0xf); + + buf.append(high > 9 ? ('a' - 10) + high : '0' + high); + buf.append(low > 9 ? ('a' - 10) + low : '0' + low); + } + + return buf.toString(); + } +} diff --git a/libjava/classpath/java/security/MessageDigestSpi.java b/libjava/classpath/java/security/MessageDigestSpi.java new file mode 100644 index 0000000..df3bd3e --- /dev/null +++ b/libjava/classpath/java/security/MessageDigestSpi.java @@ -0,0 +1,155 @@ +/* MessageDigestSpi.java --- The message digest service provider interface. + Copyright (C) 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 java.security; + +/** + This is the Service Provider Interface (SPI) for MessageDigest + class in java.security. It provides the back end functionality + for the MessageDigest class so that it can compute message + hashes. The default hashes are SHA-1 and MD5. A message hash + takes data of arbitrary length and produces a unique number + representing it. + + Cryptography service providers who want to implement their + own message digest hashes need only to subclass this class. + + The implementation of a Cloneable interface is left to up to + the programmer of a subclass. + + @version 0.0 + + @author Mark Benvenuto (ivymccough@worldnet.att.net) + */ +public abstract class MessageDigestSpi +{ + /** + Default constructor of the MessageDigestSpi class + */ + public MessageDigestSpi() + { + } + + /** + Returns the length of the digest. It may be overridden by the + provider to return the length of the digest. Default is to + return 0. It is concrete for backwards compatibility with JDK1.1 + message digest classes. + + @return Length of Digest in Bytes + + @since 1.2 + */ + protected int engineGetDigestLength() + { + return 0; + } + + /** + Updates the digest with the specified byte. + + @param input the byte to update digest with + */ + protected abstract void engineUpdate(byte input); + + + /** + Updates the digest with the specified bytes starting with the + offset and proceeding for the specified length. + + @param input the byte array to update digest with + @param offset the offset of the byte to start with + @param len the number of the bytes to update with + */ + protected abstract void engineUpdate(byte[]input, int offset, int len); + + /** + Computes the final digest of the stored bytes and returns + them. It performs any necessary padding. The message digest + should reset sensitive data after performing the digest. + + @return An array of bytes containing the digest + */ + protected abstract byte[] engineDigest(); + + /** + Computes the final digest of the stored bytes and returns + them. It performs any necessary padding. The message digest + should reset sensitive data after performing the digest. This + method is left concrete for backwards compatibility with JDK1.1 + message digest classes. + + @param buf An array of bytes to store the digest + @param offset An offset to start storing the digest at + @param len The length of the buffer + @return Returns the length of the buffer + + @since 1.2 + */ + protected int engineDigest(byte[]buf, int offset, int len) + throws DigestException + { + if (engineGetDigestLength() > len) + throw new DigestException("Buffer is too small."); + + byte[] tmp = engineDigest(); + if (tmp.length > len) + throw new DigestException("Buffer is too small"); + + System.arraycopy(tmp, 0, buf, offset, tmp.length); + return tmp.length; + } + + /** + Resets the digest engine. Reinitializes internal variables + and clears sensitive data. + */ + protected abstract void engineReset(); + + /** + Returns a clone of this class. + + If cloning is not supported, then by default the class throws a + CloneNotSupportedException. The MessageDigestSpi provider + implementation has to overload this class in order to be + cloneable. + */ + public Object clone() throws CloneNotSupportedException + { + return super.clone(); + } +} diff --git a/libjava/classpath/java/security/NoSuchAlgorithmException.java b/libjava/classpath/java/security/NoSuchAlgorithmException.java new file mode 100644 index 0000000..412d14a --- /dev/null +++ b/libjava/classpath/java/security/NoSuchAlgorithmException.java @@ -0,0 +1,70 @@ +/* NoSuchAlgorithmException.java -- an algorithm was not available + Copyright (C) 1998, 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 java.security; + +/** + * This exception is thrown when the requested security algorithm is + * not available + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class NoSuchAlgorithmException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -7443947487218346562L; + + /** + * Create a new instance with no descriptive error message. + */ + public NoSuchAlgorithmException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param msg the descriptive error message + */ + public NoSuchAlgorithmException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/NoSuchProviderException.java b/libjava/classpath/java/security/NoSuchProviderException.java new file mode 100644 index 0000000..bd26df5 --- /dev/null +++ b/libjava/classpath/java/security/NoSuchProviderException.java @@ -0,0 +1,70 @@ +/* NoSuchProviderException.java -- thrown when a provider is not found + Copyright (C) 1998, 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 java.security; + +/** + * This exception is thrown when the requested security provider is + * not available. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class NoSuchProviderException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 8488111756688534474L; + + /** + * Create a new instance with no descriptive error message. + */ + public NoSuchProviderException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param msg the descriptive error message + */ + public NoSuchProviderException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/Permission.java b/libjava/classpath/java/security/Permission.java new file mode 100644 index 0000000..48f4d52 --- /dev/null +++ b/libjava/classpath/java/security/Permission.java @@ -0,0 +1,187 @@ +/* Permission.java -- The superclass for all permission objects + Copyright (C) 1998, 2001, 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 java.security; + +import java.io.Serializable; + +/** + * This class is the abstract superclass of all classes that implement + * the concept of a permission. A permission consists of a permission name + * and optionally a list of actions that relate to the permission. The + * actual meaning of the name of the permission is defined only in the + * context of a subclass. It may name a resource to which access permissions + * are granted (for example, the name of a file) or it might represent + * something else entirely. Similarly, the action list only has meaning + * within the context of a subclass. Some permission names may have no + * actions associated with them. That is, you either have the permission + * or you don't. + * + *

    The most important method in this class is implies. This + * checks whether if one has this permission, then the specified + * permission is also implied. As a conceptual example, consider the + * permissions "Read All Files" and "Read File foo". The permission + * "Read All Files" implies that the caller has permission to read the + * file foo. + * + *

    Permission's must be immutable - do not change their + * state after creation. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Permissions + * @see PermissionCollection + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class Permission implements Guard, Serializable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -5636570222231596674L; + + /** + * This is the name assigned to this permission object. + * + * @serial the name of the permission + */ + private String name; + + /** + * Create an instance with the specified name. + * + * @param name the permission name + */ + public Permission(String name) + { + this.name = name; + } + + /** + * This method implements the Guard interface for this class. + * It calls the checkPermission method in + * SecurityManager with this Permission as its + * argument. This method returns silently if the security check succeeds + * or throws an exception if it fails. + * + * @param obj the Object being guarded - ignored by this class + * @throws SecurityException if the security check fails + * @see GuardedObject + * @see SecurityManager#checkPermission(Permission) + */ + public void checkGuard(Object obj) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(this); + } + + /** + * This method tests whether this Permission implies that the + * specified Permission is also granted. + * + * @param perm the Permission to test against + * @return true if perm is implied by this + */ + public abstract boolean implies(Permission perm); + + /** + * Check to see if this object equals obj. Use implies, rather + * than equals, when making access control decisions. + * + * @param obj the object to compare to + */ + public abstract boolean equals(Object obj); + + /** + * This method returns a hash code for this Permission. It + * must satisfy the contract of Object.hashCode: it must be + * the same for all objects that equals considers to be the same. + * + * @return a hash value + */ + public abstract int hashCode(); + + /** + * Get the name of this Permission. + * + * @return the name + */ + public final String getName() + { + return name; + } + + /** + * This method returns the list of actions for this Permission + * as a String. The string should be in canonical order, for + * example, both new FilePermission(f, "write,read") and + * new FilePermission(f, "read,write") have the action list + * "read,write". + * + * @return the action list for this Permission + */ + public abstract String getActions(); + + /** + * This method returns an empty PermissionCollection object + * that can store permissions of this type, or null if no + * such collection is defined. Subclasses must override this to provide + * an appropriate collection when one is needed to accurately calculate + * implies. + * + * @return a new PermissionCollection + */ + public PermissionCollection newPermissionCollection() + { + return null; + } + + /** + * This method returns a String representation of this + * Permission object. This is in the format: + * '(' + getClass().getName() + ' ' + getName() + ' ' + getActions + * + ')'. + * + * @return this object as a String + */ + public String toString() + { + return '(' + getClass().getName() + ' ' + getName() + ' ' + + getActions() + ')'; + } +} // class Permission diff --git a/libjava/classpath/java/security/PermissionCollection.java b/libjava/classpath/java/security/PermissionCollection.java new file mode 100644 index 0000000..4e8ffe5 --- /dev/null +++ b/libjava/classpath/java/security/PermissionCollection.java @@ -0,0 +1,167 @@ +/* PermissionCollection.java -- A collection of permission objects + Copyright (C) 1998, 2001, 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 java.security; + +import java.io.Serializable; +import java.util.Enumeration; + +/** + * This class models a group of Java permissions. It has convenient + * methods for determining whether or not a given permission is implied + * by any of the permissions in this collection. + * + *

    Some care must be taken in storing permissions. First, a collection of + * the appropriate type must be created. This is done by calling the + * newPermissionCollection method on an object of the + * permission class you wish to add to the collection. If this method + * returns null, any type of PermissionCollection + * can be used to store permissions of that type. However, if a + * PermissionCollection collection object is returned, that + * type must be used. + * + *

    A PermissionCollection returned by the + * newPermissionCollection method in a subclass of + * Permission is a homogeneous collection. It only will + * hold permissions of one specified type - instances of the class that + * created it. Not all PermissionCollection subclasses + * have to hold permissions of only one type however. For example, + * the Permissions class holds permissions of many types. + * + *

    Since the newPermissionCollection in Permission + * itself returns null, by default a permission can be stored + * in any type of collection unless it overrides that method to create its + * own collection type. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Permission + * @see Permissions + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class PermissionCollection implements Serializable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -6727011328946861783L; + + /** + * Indicates whether or not this collection is read only. + * + * @serial if the collection is read-only + */ + private boolean readOnly; + + /** + * Create a new collection. + */ + public PermissionCollection() + { + } + + /** + * This method adds a new Permission object to the collection. + * + * @param perm the Permission to add + * + * @throws SecurityException if the collection is marked read only + * @throws IllegalArgumentException if perm is of the wrong type + */ + public abstract void add(Permission perm); + + /** + * This method tests whether the specified Permission object is + * implied by this collection of Permission objects. + * + * @param perm the Permission object to test + * @return true if the collection implies perm + */ + public abstract boolean implies(Permission perm); + + /** + * This method returns an Enumeration of all the objects in + * this collection. + * + * @return an Enumeration of this collection's objects + */ + public abstract Enumeration elements(); + + /** + * This method sets this PermissionCollection object to be + * read only. No further permissions can be added to it after calling this + * method. + */ + public void setReadOnly() + { + readOnly = true; + } + + /** + * This method tests whether or not this PermissionCollection + * object is read only. + * + * @return true if this collection is read only + */ + public boolean isReadOnly() + { + return readOnly; + } + + /** + * This method returns a String representation of this + * collection. It is formed by: + *

    +   * super.toString()" (\n"
    +   *   // enumerate all permissions, one per line
    +   * ")\n"
    +   * 
    + * + * @return a String representing this object + */ + public String toString() + { + StringBuffer sb = new StringBuffer(super.toString()); + + sb.append(" (\n"); + Enumeration e = elements(); + while (e.hasMoreElements()) + sb.append(' ').append(e.nextElement()).append('\n'); + return sb.append(")\n").toString(); + } +} // class PermissionCollection diff --git a/libjava/classpath/java/security/Permissions.java b/libjava/classpath/java/security/Permissions.java new file mode 100644 index 0000000..e3fd069 --- /dev/null +++ b/libjava/classpath/java/security/Permissions.java @@ -0,0 +1,254 @@ +/* Permissions.java -- a collection of permission collections + Copyright (C) 1998, 2001, 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 java.security; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.NoSuchElementException; + +/** + * This class is a heterogeneous collection of permissions. It is + * organized as a collection of PermissionCollection's stored + * in a hashtable. Each individual PermissionCollection + * contains permissions of a single type. If a specific type of + * Permission does not provide a collection type to use + * via its newPermissionCollection method, then a default + * collection type which stores its permissions in a hash table will be + * used. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + */ +public final class Permissions extends PermissionCollection + implements Serializable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 4858622370623524688L; + + /** + * Holds instances of AllPermission. + * + * @serial the permission collection for AllPermission + */ + private PermissionCollection allPermission; + + // Package-private to avoid a trampoline. + /** + * This is the Hashtable that contains our collections. + * + * @serial maps Class to PermissionCollection + */ + final Hashtable perms = new Hashtable(); + + /** + * This method initializes a new instance of Permissions. + */ + public Permissions() + { + } + + /** + * This method adds a new Permission to this collection. It + * will be stored in a PermissionCollection of the appropriate + * type, as determined by calling newPermissionCollection on + * the specified permission (if an appropriate collection does not already + * exist). If this object does not specify a particular type of collection, + * a default collection, which stores in permissions in a hash table, will + * be used. + * + * @param perm the Permission to add + * @throws SecurityException if this collection is marked as read only + */ + public void add(Permission perm) + { + if (isReadOnly()) + throw new SecurityException("PermissionCollection is read only"); + if (perm instanceof AllPermission) + { + if (allPermission == null) + { + allPermission = perm.newPermissionCollection(); + allPermission.add(perm); + perms.put(perm.getClass(), allPermission); + } + } + else + { + PermissionCollection pc + = (PermissionCollection) perms.get(perm.getClass()); + if (pc == null) + { + pc = perm.newPermissionCollection(); + if (pc == null) + pc = new PermissionsHash(); + perms.put(perm.getClass(), pc); + } + pc.add(perm); + } + } + + /** + * This method tests whether or not the specified Permission + * is implied by this PermissionCollection. + * + * @param perm the Permission to test + * @return true if the specified permission is implied by this + */ + public boolean implies(Permission perm) + { + if (allPermission != null) + return true; + PermissionCollection pc + = (PermissionCollection) perms.get(perm.getClass()); + return pc == null ? false : pc.implies(perm); + } + + /** + * This method returns an Enumeration which contains a + * list of all Permission objects contained in this + * collection. + * + * @return an Enumeration of this collection's elements + */ + public Enumeration elements() + { + return new Enumeration() + { + Enumeration main_enum = perms.elements(); + Enumeration sub_enum; + + public boolean hasMoreElements() + { + if (sub_enum == null) + { + if (main_enum == null) + return false; + if (! main_enum.hasMoreElements()) + { + main_enum = null; + return false; + } + PermissionCollection pc = + (PermissionCollection) main_enum.nextElement(); + sub_enum = pc.elements(); + } + if (! sub_enum.hasMoreElements()) + { + sub_enum = null; + return hasMoreElements(); + } + return true; + } + + public Object nextElement() + { + if (! hasMoreElements()) + throw new NoSuchElementException(); + return sub_enum.nextElement(); + } + }; + } + + /** + * Implements the permission collection for all permissions without one of + * their own, and obeys serialization of JDK. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class PermissionsHash extends PermissionCollection + { + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -8491988220802933440L; + + /** + * Hashtable where we store permissions. + * + * @serial the stored permissions, both as key and value + */ + private final Hashtable perms = new Hashtable(); + + /** + * Add a permission. We don't need to check for read-only, as this + * collection is never exposed outside of Permissions, which has already + * done that check. + * + * @param perm the permission to add + */ + public void add(Permission perm) + { + perms.put(perm, perm); + } + + /** + * Returns true if perm is in the collection. + * + * @param perm the permission to check + * @return true if it is implied + */ + // FIXME: Should this method be synchronized? + public boolean implies(Permission perm) + { + Enumeration elements = elements(); + + while (elements.hasMoreElements()) + { + Permission p = (Permission)elements.nextElement(); + if (p.implies(perm)) + return true; + } + return false; + } + + /** + * Return the elements. + * + * @return the elements + */ + public Enumeration elements() + { + return perms.elements(); + } + } // class PermissionsHash +} // class Permissions diff --git a/libjava/classpath/java/security/Policy.java b/libjava/classpath/java/security/Policy.java new file mode 100644 index 0000000..03d9bbb --- /dev/null +++ b/libjava/classpath/java/security/Policy.java @@ -0,0 +1,310 @@ +/* Policy.java --- Policy Manager Class + Copyright (C) 1999, 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 java.security; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + *

    This is an abstract class for representing the system security policy for + * a Java application environment (specifying which permissions are available + * for code from various sources). That is, the security policy is represented + * by a Policy subclass providing an implementation of the abstract + * methods in this Policy class.

    + * + *

    There is only one Policy object in effect at any given time. + *

    + * + *

    The source location for the policy information utilized by the + * Policy object is up to the Policy implementation. + * The policy configuration may be stored, for example, as a flat ASCII file, as + * a serialized binary file of the Policy class, or as a database. + *

    + * + *

    The currently-installed Policy object can be obtained by + * calling the getPolicy() method, and it can be changed by a call + * to the setPolicy() method (by code with permission to reset the + * Policy).

    + * + *

    The refresh() method causes the policy object to refresh / + * reload its current configuration.

    + * + *

    This is implementation-dependent. For example, if the policy object stores + * its policy in configuration files, calling refresh() will cause + * it to re-read the configuration policy files. The refreshed policy may not + * have an effect on classes in a particular {@link ProtectionDomain}. This is + * dependent on the Policy provider's implementation of the + * implies() method and the {@link PermissionCollection} caching + * strategy.

    + * + *

    The default Policy implementation can be changed by setting + * the value of the "policy.provider" security property (in the + * Java security properties file) to the fully qualified name of the desired + * Policy implementation class. The Java security properties file + * is located in the file named <JAVA_HOME>/lib/security/java.security + * , where <JAVA_HOME> refers to the directory where the + * SDK was installed.

    + * + *

    IMPLEMENTATION NOTE: This implementation attempts to read the + * System property named policy.provider to find the concrete + * implementation of the Policy. If/when this fails, it falls back + * to a default implementation, which allows everything. + * + * @author Mark Benvenuto + * @see CodeSource + * @see PermissionCollection + * @see SecureClassLoader + * @since 1.2 + */ +public abstract class Policy +{ + private static Policy currentPolicy; + + /** Map of ProtectionDomains to PermissionCollections for this instance. */ + private Map pd2pc = null; + + /** Constructs a new Policy object. */ + public Policy() + { + } + + /** + * Returns the installed Policy object. This value should not be + * cached, as it may be changed by a call to setPolicy(). This + * method first calls {@link SecurityManager#checkPermission(Permission)} with + * a SecurityPermission("getPolicy") permission to ensure it's ok + * to get the Policy object. + * + * @return the installed Policy. + * @throws SecurityException if a security manager exists and its + * checkPermission() method doesn't allow getting the + * Policy object. + * @see SecurityManager#checkPermission(Permission) + * @see #setPolicy(Policy) + */ + public static Policy getPolicy() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new SecurityPermission("getPolicy")); + + return getCurrentPolicy(); + } + + /** + * Sets the system-wide Policy object. This method first calls + * {@link SecurityManager#checkPermission(Permission)} with a + * SecurityPermission("setPolicy") permission to ensure it's ok + * to set the Policy. + * + * @param policy the new system Policy object. + * @throws SecurityException if a security manager exists and its + * checkPermission() method doesn't allow setting the + * Policy. + * @see SecurityManager#checkPermission(Permission) + * @see #getPolicy() + */ + public static void setPolicy(Policy policy) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new SecurityPermission("setPolicy")); + + setup(policy); + currentPolicy = policy; + } + + private static void setup(final Policy policy) + { + if (policy.pd2pc == null) + policy.pd2pc = Collections.synchronizedMap(new LinkedHashMap()); + + ProtectionDomain pd = policy.getClass().getProtectionDomain(); + if (pd.getCodeSource() != null) + { + PermissionCollection pc = null; + if (currentPolicy != null) + pc = currentPolicy.getPermissions(pd); + + if (pc == null) // assume it has all + { + pc = new Permissions(); + pc.add(new AllPermission()); + } + + policy.pd2pc.put(pd, pc); // add the mapping pd -> pc + } + } + + /** + * Ensures/forces loading of the configured policy provider, while bypassing + * the {@link SecurityManager} checks for "getPolicy" security + * permission. Needed by {@link ProtectionDomain}. + */ + static Policy getCurrentPolicy() + { + // FIXME: The class name of the Policy provider should really be sourced + // from the "java.security" configuration file. For now, just hard-code + // a stub implementation. + if (currentPolicy == null) + { + String pp = System.getProperty ("policy.provider"); + if (pp != null) + try + { + currentPolicy = (Policy) Class.forName(pp).newInstance(); + } + catch (Exception e) + { + // Ignored. + } + + if (currentPolicy == null) + currentPolicy = new gnu.java.security.provider.DefaultPolicy(); + } + return currentPolicy; + } + + /** + * Tests if currentPolicy is not null, + * thus allowing clients to not force loading of any policy + * provider; needed by {@link ProtectionDomain}. + */ + static boolean isLoaded() + { + return currentPolicy != null; + } + + /** + * Evaluates the global policy and returns a {@link PermissionCollection} + * object specifying the set of permissions allowed for code from the + * specified code source. + * + * @param codesource the {@link CodeSource} associated with the caller. This + * encapsulates the original location of the code (where the code came from) + * and the public key(s) of its signer. + * @return the set of permissions allowed for code from codesource according + * to the policy. The returned set of permissions must be a new mutable + * instance and it must support heterogeneous {@link Permission} types. + */ + public abstract PermissionCollection getPermissions(CodeSource codesource); + + /** + * Evaluates the global policy and returns a {@link PermissionCollection} + * object specifying the set of permissions allowed given the characteristics + * of the protection domain. + * + * @param domain the {@link ProtectionDomain} associated with the caller. + * @return the set of permissions allowed for the domain according to the + * policy. The returned set of permissions must be a new mutable instance and + * it must support heterogeneous {@link Permission} types. + * @since 1.4 + * @see ProtectionDomain + * @see SecureClassLoader + */ + public PermissionCollection getPermissions(ProtectionDomain domain) + { + if (domain == null) + return new Permissions(); + + if (pd2pc == null) + setup(this); + + PermissionCollection result = (PermissionCollection) pd2pc.get(domain); + if (result != null) + { + Permissions realResult = new Permissions(); + for (Enumeration e = result.elements(); e.hasMoreElements(); ) + realResult.add((Permission) e.nextElement()); + + return realResult; + } + + result = getPermissions(domain.getCodeSource()); + if (result == null) + result = new Permissions(); + + PermissionCollection pc = domain.getPermissions(); + if (pc != null) + for (Enumeration e = pc.elements(); e.hasMoreElements(); ) + result.add((Permission) e.nextElement()); + + return result; + } + + /** + * Evaluates the global policy for the permissions granted to the {@link + * ProtectionDomain} and tests whether the permission is granted. + * + * @param domain the {@link ProtectionDomain} to test. + * @param permission the {@link Permission} object to be tested for + * implication. + * @return true if permission is a proper subset of + * a permission granted to this {@link ProtectionDomain}. + * @since 1.4 + * @see ProtectionDomain + */ + public boolean implies(ProtectionDomain domain, Permission permission) + { + if (pd2pc == null) + setup(this); + + PermissionCollection pc = (PermissionCollection) pd2pc.get(domain); + if (pc != null) + return pc.implies(permission); + + boolean result = false; + pc = getPermissions(domain); + if (pc != null) + { + result = pc.implies(permission); + pd2pc.put(domain, pc); + } + + return result; + } + + /** + * Refreshes/reloads the policy configuration. The behavior of this method + * depends on the implementation. For example, calling refresh on a file-based + * policy will cause the file to be re-read. + */ + public abstract void refresh(); +} diff --git a/libjava/classpath/java/security/Principal.java b/libjava/classpath/java/security/Principal.java new file mode 100644 index 0000000..6d9de6c --- /dev/null +++ b/libjava/classpath/java/security/Principal.java @@ -0,0 +1,85 @@ +/* Principal.java -- A security entity + Copyright (C) 1998, 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 java.security; + +/** + * This interface models an entity (such as a user or a certificate authority) + * for the purposes of applying the Java security model. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see X509Certificate + * @since 1.1 + * @status updated to 1.4 + */ +public interface Principal +{ + /** + * This method tests another Principal object for equality + * with this one. + * + * @param obj the Object to test for equality + * @return true if the specified Principal is equal + */ + boolean equals(Object obj); + + /** + * This method returns a String representation of this + * Principal. + * + * @return this Principal represented as a String + */ + String toString(); + + /** + * This method returns a hash code value for this Principal. + * Remember the contract of hashCode - two objects which compare as + * equals() must have the same hashCode(). + * + * @return a hash value + */ + int hashCode(); + + /** + * This method returns a String that names this + * Principal. + * + * @return the name of this Principal + */ + String getName(); +} // interface Principal diff --git a/libjava/classpath/java/security/PrivateKey.java b/libjava/classpath/java/security/PrivateKey.java new file mode 100644 index 0000000..70607c1 --- /dev/null +++ b/libjava/classpath/java/security/PrivateKey.java @@ -0,0 +1,62 @@ +/* PrivateKey.java -- tagging interface for all private keys + Copyright (C) 1998, 2001, 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 java.security; + +/** + * This interface specified no methods. In simply provides a common + * super-interface for all algorithm specific private key values. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Key + * @see PublicKey + * @see Certificate + * @see Signature#initVerify(PublicKey) + * @see DSAPrivateKey + * @see RSAPrivateKey + * @see RSAPrivateCrtKey + * @since 1.1 + * @status updated to 1.4 + */ +public interface PrivateKey extends Key +{ + /** + * The version identifier used for serialization. + */ + long serialVersionUID = 6034044314589513430L; +} // interface PrivateKey diff --git a/libjava/classpath/java/security/PrivilegedAction.java b/libjava/classpath/java/security/PrivilegedAction.java new file mode 100644 index 0000000..c3a4134 --- /dev/null +++ b/libjava/classpath/java/security/PrivilegedAction.java @@ -0,0 +1,64 @@ +/* PrivilegedAction.java -- Perform a privileged action + 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 java.security; + +/** + * This interface specifes a single run method that + * executes a privileged operation. This method is called by + * AccessController.doPrivileged() after that method + * activiates the required privileges. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see AccessController + * @see PrivilegedExceptionAction + * @since 1.1 + * @status updated to 1.4 + */ +public interface PrivilegedAction +{ + /** + * This method performs an operation that requires higher privileges to + * perform. It is called when a section of code invokes + * AccessController.doPrivileged(). + * + * @return obj An implementation dependent return value + * @see AccessController#doPrivileged(PrivilegedAction) + * @see AccessController#doPrivileged(PrivilegedAction, AccessControlContext) + */ + Object run(); +} // interface PrivilegedAction diff --git a/libjava/classpath/java/security/PrivilegedActionException.java b/libjava/classpath/java/security/PrivilegedActionException.java new file mode 100644 index 0000000..3f08c81 --- /dev/null +++ b/libjava/classpath/java/security/PrivilegedActionException.java @@ -0,0 +1,109 @@ +/* PrivilegedActionException.java -- wrap an exception in a privileged action + Copyright (C) 1998, 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 java.security; + +/** + * This exception is thrown when an exception is thrown during a + * privileged action being performed with the + * AccessController.doPrivileged() method. It wraps the + * actual exception thrown in the privileged code. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see PrivilegedExceptionAction + * @see AccessController#doPrivileged(PrivilegedExceptionAction) + * @see AccessController#doPrivileged(PrivilegedExceptionAction, AccessControlContext) + * @status updated to 1.4 + */ +public class PrivilegedActionException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 4724086851538908602L; + + /** + * This is the actual exception that occurred. + * + * @serial the wrapped exception + */ + private Exception exception; + + /** + * Create a new instance that wraps the specified Exception. + * + * @param e the Exception to wrap + */ + public PrivilegedActionException(Exception e) + { + super(e); + exception = e; + } + + /** + * Get the underlying Exception that caused this one. This + * is a legacy method, the preferred way is {@link #getCause()}. + * + * @return the cause + */ + public Exception getException() + { + return exception; + } + + /** + * Gets the cause of this exception. + * + * @return the cause + * @since 1.4 + */ + public Throwable getCause() + { + return exception; + } + + /** + * Convert this to a String. + * + * @return the string representation + */ + public String toString() + { + return super.toString(); + } +} diff --git a/libjava/classpath/java/security/PrivilegedExceptionAction.java b/libjava/classpath/java/security/PrivilegedExceptionAction.java new file mode 100644 index 0000000..d3d0478 --- /dev/null +++ b/libjava/classpath/java/security/PrivilegedExceptionAction.java @@ -0,0 +1,65 @@ +/* PrivilegedExceptionAction.java -- Perform a privileged operation + 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 java.security; + +/** + * This interface defines a method that is called by + * AccessController.doPrivileged() in order to perform a + * privileged operation with higher privileges enabled. This interface + * differs from PrivilegedAction in that the run + * method in this interface may throw a checked exception. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public interface PrivilegedExceptionAction +{ + /** + * This method performs an operation that requires higher privileges to + * successfully complete. It is called when a section of code invokes + * AccessController.doPrivileged(). + * + * @return obj An implementation defined return value + * @throws Exception An implementation specific exception + * @see AccessController#doPrivileged(PrivilegedExceptionAction) + * @see AccessController#doPrivileged(PrivilegedExceptionAction, + * AccessControlContext) + */ + Object run() throws Exception; +} // interface PrivilegedExceptionAction diff --git a/libjava/classpath/java/security/ProtectionDomain.java b/libjava/classpath/java/security/ProtectionDomain.java new file mode 100644 index 0000000..a5851b5 --- /dev/null +++ b/libjava/classpath/java/security/ProtectionDomain.java @@ -0,0 +1,269 @@ +/* ProtectionDomain.java -- A security domain + Copyright (C) 1998, 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 java.security; + +/** + *

    This ProtectionDomain class encapsulates the characteristics + * of a domain, which encloses a set of classes whose instances are granted a + * set of permissions when being executed on behalf of a given set of + * Principals. + * + *

    A static set of permissions can be bound to a ProtectionDomain + * when it is constructed; such permissions are granted to the domain regardless + * of the {@link Policy} in force. However, to support dynamic security + * policies, a ProtectionDomain can also be constructed such that + * it is dynamically mapped to a set of permissions by the current {@link + * Policy} whenever a permission is checked.

    + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @version 0.0 + */ +public class ProtectionDomain +{ + /** This is the CodeSource for this protection domain. */ + private CodeSource code_source; + + /** This is the set of permissions granted to this domain. */ + private PermissionCollection perms; + + /** The {@link ClassLoader} associated with this domain. */ + private ClassLoader classloader; + + /** The array of Principals associated with this domain.. */ + private Principal[] principals; + + /** Post 1.4 the policy may be refreshed! use false for pre 1.4. */ + private boolean staticBinding; + + /** + * Creates a new ProtectionDomain with the given {@link + * CodeSource} and {@link Permissions}. If the permissions object is not + * null, then setReadOnly() will be called on the + * passed in {@link Permissions} object. The only permissions granted to this + * domain are the ones specified; the current {@link Policy} will not be + * consulted. + * + * @param codesource the codesource associated with this domain. + * @param permissions the permissions granted to this domain + */ + public ProtectionDomain(CodeSource codesource, PermissionCollection permissions) + { + this(codesource, permissions, null, null, true); + } + + /** + *

    Creates a new ProtectionDomain qualified by the given CodeSource, + * Permissions, ClassLoader and array of Principals. If the permissions + * object is not null, then setReadOnly() will be called on the + * passed in Permissions object. The permissions granted to this domain are + * dynamic; they include both the static permissions passed to this + * constructor, and any permissions granted to this domain by the current + * Policy at the time a permission is checked.

    + * + *

    This constructor is typically used by {@link ClassLoader}s and {@link + * DomainCombiner}s which delegate to Policy to actively + * associate the permissions granted to this domain. This constructor affords + * the Policy provider the opportunity to augment the supplied + * PermissionCollection to reflect policy changes.

    + * + * @param codesource the CodeSource associated with this domain. + * @param permissions the permissions granted to this domain. + * @param classloader the ClassLoader associated with this domain. + * @param principals the array of Principals associated with this domain. + * @since 1.4 + * @see Policy#refresh() + * @see Policy#getPermissions(ProtectionDomain) + */ + public ProtectionDomain(CodeSource codesource, + PermissionCollection permissions, + ClassLoader classloader, Principal[] principals) + { + this(codesource, permissions, classloader, principals, false); + } + + private ProtectionDomain(CodeSource codesource, + PermissionCollection permissions, + ClassLoader classloader, Principal[] principals, + boolean staticBinding) + { + super(); + + code_source = codesource; + if (permissions != null) + { + perms = permissions; + perms.setReadOnly(); + } + + this.classloader = classloader; + this.principals = + (principals != null ? (Principal[]) principals.clone() : new Principal[0]); + this.staticBinding = staticBinding; + } + + /** + * Returns the {@link CodeSource} of this domain. + * + * @return the {@link CodeSource} of this domain which may be null. + * @since 1.2 + */ + public final CodeSource getCodeSource() + { + return code_source; + } + + /** + * Returns the {@link ClassLoader} of this domain. + * + * @return the {@link ClassLoader} of this domain which may be + * null. + * @since 1.4 + */ + public final ClassLoader getClassLoader() + { + return this.classloader; + } + + /** + * Returns an array of principals for this domain. + * + * @return returns a non-null array of principals for this domain. Changes to + * this array will have no impact on the ProtectionDomain. + * @since 1.4 + */ + public final Principal[] getPrincipals() + { + return (Principal[]) principals.clone(); + } + + /** + * Returns the static permissions granted to this domain. + * + * @return the static set of permissions for this domain which may be + * null. + * @see Policy#refresh() + * @see Policy#getPermissions(ProtectionDomain) + */ + public final PermissionCollection getPermissions() + { + return perms; + } + + /** + *

    Check and see if this ProtectionDomain implies the + * permissions expressed in the Permission object.

    + * + *

    The set of permissions evaluated is a function of whether the + * ProtectionDomain was constructed with a static set of + * permissions or it was bound to a dynamically mapped set of permissions.

    + * + *

    If the ProtectionDomain was constructed to a statically + * bound {@link PermissionCollection} then the permission will only be checked + * against the {@link PermissionCollection} supplied at construction.

    + * + *

    However, if the ProtectionDomain was constructed with the + * constructor variant which supports dynamically binding permissions, then + * the permission will be checked against the combination of the + * {@link PermissionCollection} supplied at construction and the current + * {@link Policy} binding. + * + * @param permission the {@link Permission} object to check. + * @return true if permission is implicit to this + * ProtectionDomain. + */ + public boolean implies(Permission permission) + { + if (staticBinding) + return (perms == null ? false : perms.implies(permission)); + // Else dynamically bound. Do we have it? + // NOTE: this will force loading of Policy.currentPolicy + return Policy.getCurrentPolicy().implies(this, permission); + } + + /** + * Convert a ProtectionDomain to a String. + * + * @return a string representation of the object. + */ + public String toString() + { + String linesep = System.getProperty("line.separator"); + StringBuffer sb = new StringBuffer("ProtectionDomain (").append(linesep); + + if (code_source == null) + sb.append("CodeSource:null"); + else + sb.append(code_source); + + sb.append(linesep); + if (classloader == null) + sb.append("ClassLoader:null"); + else + sb.append(classloader); + + sb.append(linesep); + sb.append("Principals:"); + if (principals != null && principals.length > 0) + { + sb.append("["); + Principal pal; + for (int i = 0; i < principals.length; i++) + { + pal = principals[i]; + sb.append("'").append(pal.getName()) + .append("' of type ").append(pal.getClass().getName()); + if (i < principals.length-1) + sb.append(", "); + } + sb.append("]"); + } + else + sb.append("none"); + + sb.append(linesep); + if (!staticBinding) // include all but dont force loading Policy.currentPolicy + if (Policy.isLoaded()) + sb.append(Policy.getCurrentPolicy().getPermissions(this)); + else // fallback on this one's permissions + sb.append(perms); + else + sb.append(perms); + + return sb.append(linesep).append(")").append(linesep).toString(); + } +} diff --git a/libjava/classpath/java/security/Provider.java b/libjava/classpath/java/security/Provider.java new file mode 100644 index 0000000..4ffaa55 --- /dev/null +++ b/libjava/classpath/java/security/Provider.java @@ -0,0 +1,202 @@ +/* Provider.java -- Security provider information + Copyright (C) 1998, 1999, 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 java.security; + +import java.io.Serializable; +import java.util.Properties; + +/** + * This class represents a Java security architecture service provider. + * The services provided by a such a provider can range from security + * algorithms to key generation. + *

    + * Providers are installed by name and version number. There is one + * standard provider supplied with the class library. This is the + * "GNU" provider, which can also be accessed by the alias "SUN" for + * compatibility with the JDK. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class Provider extends Properties implements Serializable +{ + private static final long serialVersionUID = -4298000515446427739L; + + /** + * This is a textual description of the provider + */ + private String info; + + /** + * This is the name of the provider + */ + private String name; + + /** + * This is the version number of the provider + */ + private double version; + + /** + * This method initializes a new instance of Provider to have + * the specified name, version, and description information. + * + * @param name The name to assign to this Provider. + * @param version The version number for this Provider. + * @param info A textual description of this provider. + */ + protected Provider(String name, double version, String info) + { + this.name = name; + this.version = version; + this.info = info; + } + + /** + * This method returns the name assigned to this Provider. + * + * @return The Provider's name. + */ + public String getName() + { + return (name); + } + + /** + * This method retunrs the version number of this Provider. + * + * @return The Provider's version number. + */ + public double getVersion() + { + return (version); + } + + /** + * This method returns a textual description of the Provider. + * + * @return A description of the Provider. + */ + public String getInfo() + { + return (info); + } + + /** + * Sets the key property to have the specified value. + *

    + * NOT IMPLEMENTED YET[ + * First, if there is a security manager, its checkSecurityAccess + * method is called with the string "putProviderProperty."+name, where name is + * the provider name, to see if it's ok to set this provider's property + * values. + * If the default implementation of checkSecurityAccess is used + * (that is, that method is not overriden), then this results in a call to the + * security manager's checkPermission method with a + * SecurityPermission("putProviderProperty."+name) + * permission.
    ] + * + * @param key The property key. + * @param value The property value. + * + * @return The previous value of the specified property (key), + * or null if it did not have one. + * @throws SecurityException If a security manager exists and its + * {@link java.lang.SecurityManager.checkSecurityAccess(java.lang.String)} + * method denies access to set property values. + * @since Classpath 0.4+cvs, JDK 1.2 + * @see java.lang.Object.equals(Object) + * @see java.util.Hashtable.get(Object) + */ + public Object put(Object key, Object value) + { + return super.put(toCanonicalKey(key), value); + } + + // overrides same in java.util.Hashtable + public Object get(Object key) + { + return super.get(toCanonicalKey(key)); + } + + /** + * This method removes the specified key entry (and its associated value) + * from the property mapping list. + * + * @param key The key to remove + * + * @return The previous value for this key, or null if no + * previous value. + */ + public Object remove(Object key) + { + return super.remove(toCanonicalKey(key)); + } + + /** + * This method clears the entire property list such that it no longer + * contains the properties used to look up the services provided by + * the Provider. + */ + public void clear() + { + super.clear(); + } + + /** + * This method returns a String representation of this + * object. This will include the Provider name and + * version number. + * + * @return A String representation of this object. + */ + public String toString() + { + return (getClass().getName() + ": name=" + getName() + " version=" + + version); + } + + private Object toCanonicalKey(Object key) + { + if (key.getClass().isAssignableFrom(String.class)) // is it ours? + return ((String) key).toUpperCase(); // use default locale + else + return key; + } +} diff --git a/libjava/classpath/java/security/ProviderException.java b/libjava/classpath/java/security/ProviderException.java new file mode 100644 index 0000000..2dafcec --- /dev/null +++ b/libjava/classpath/java/security/ProviderException.java @@ -0,0 +1,70 @@ +/* ProviderException.java -- Generic security provider runtime exception + Copyright (C) 1998, 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 java.security; + +/** + * This exception indicates that a runtime problem was encounterd with + * a security provider. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class ProviderException extends RuntimeException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5256023526693665674L; + + /** + * Create an instance with no descriptive error message. + */ + public ProviderException() + { + } + + /** + * Create an instance with a descriptive error message. + * + * @param msg the descriptive error message + */ + public ProviderException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/PublicKey.java b/libjava/classpath/java/security/PublicKey.java new file mode 100644 index 0000000..9bf1458 --- /dev/null +++ b/libjava/classpath/java/security/PublicKey.java @@ -0,0 +1,60 @@ +/* PublicKey.java -- tagging interface for all public keys + Copyright (C) 1998, 2001, 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 java.security; + +/** + * This interface specified no methods. In simply provides a common + * super-interface for all algorithm specific public key values. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Key + * @see PrivateKey + * @see Certificate + * @see Signature#initVerify(PublicKey) + * @see DSAPublicKey + * @see RSAPublicKey + * @since 1.1 + * @status updated to 1.4 + */ +public interface PublicKey extends Key +{ + /** + * The version identifier used for serialization. + */ + long serialVersionUID = 7187392471159151072L; +} // interface PublicKey diff --git a/libjava/classpath/java/security/SecureClassLoader.java b/libjava/classpath/java/security/SecureClassLoader.java new file mode 100644 index 0000000..9d1fac7 --- /dev/null +++ b/libjava/classpath/java/security/SecureClassLoader.java @@ -0,0 +1,128 @@ +/* SecureClassLoader.java --- A Secure Class Loader + 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 java.security; + +/** + * A Secure Class Loader for loading classes with additional + * support for specifying code source and permissions when + * they are retrieved by the system policy handler. + * + * @since 1.2 + * + * @author Mark Benvenuto + */ +public class SecureClassLoader extends ClassLoader +{ + java.util.WeakHashMap protectionDomainCache = new java.util.WeakHashMap(); + + protected SecureClassLoader(ClassLoader parent) + { + super(parent); + SecurityManager sm = System.getSecurityManager(); + if(sm != null) + sm.checkCreateClassLoader(); + } + + protected SecureClassLoader() + { + SecurityManager sm = System.getSecurityManager(); + if(sm != null) + sm.checkCreateClassLoader(); + } + + /** + * Creates a class using an array of bytes and a + * CodeSource. + * + * @param name the name to give the class. null if unknown. + * @param b the data representing the classfile, in classfile format. + * @param off the offset into the data where the classfile starts. + * @param len the length of the classfile data in the array. + * @param cs the CodeSource for the class or null when unknown. + * + * @return the class that was defined and optional CodeSource. + * + * @exception ClassFormatError if the byte array is not in proper classfile format. + */ + protected final Class defineClass(String name, byte[] b, int off, int len, + CodeSource cs) + { + if (cs != null) + { + ProtectionDomain protectionDomain; + + synchronized (protectionDomainCache) + { + protectionDomain = (ProtectionDomain)protectionDomainCache.get(cs); + } + + if (protectionDomain == null) + { + protectionDomain + = new ProtectionDomain(cs, getPermissions(cs), this, null); + synchronized (protectionDomainCache) + { + ProtectionDomain domain + = (ProtectionDomain)protectionDomainCache.get(cs); + if (domain == null) + protectionDomainCache.put(cs, protectionDomain); + else + protectionDomain = domain; + } + } + return super.defineClass(name, b, off, len, protectionDomain); + } + else + return super.defineClass(name, b, off, len); + } + + /** + * Returns a PermissionCollection for the specified CodeSource. + * The default implementation invokes + * java.security.Policy.getPermissions. + * + * This method is called by defineClass that takes a CodeSource + * arguement to build a proper ProtectionDomain for the class + * being defined. + */ + protected PermissionCollection getPermissions(CodeSource cs) + { + Policy policy = Policy.getCurrentPolicy(); + return policy.getPermissions(cs); + } +} diff --git a/libjava/classpath/java/security/SecureRandom.java b/libjava/classpath/java/security/SecureRandom.java new file mode 100644 index 0000000..3ee3a84 --- /dev/null +++ b/libjava/classpath/java/security/SecureRandom.java @@ -0,0 +1,380 @@ +/* SecureRandom.java --- Secure Random class implementation + Copyright (C) 1999, 2001, 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 java.security; + +import gnu.java.security.Engine; + +import java.util.Enumeration; +import java.util.Random; + +/** + * An interface to a cryptographically secure pseudo-random number + * generator (PRNG). Random (or at least unguessable) numbers are used + * in all areas of security and cryptography, from the generation of + * keys and initialization vectors to the generation of random padding + * bytes. + * + * @author Mark Benvenuto (ivymccough@worldnet.att.net) + * @author Casey Marshall + */ +public class SecureRandom extends Random +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** Service name for PRNGs. */ + private static final String SECURE_RANDOM = "SecureRandom"; + + private static final long serialVersionUID = 4940670005562187L; + + //Serialized Field + long counter = 0; //Serialized + Provider provider = null; + byte[] randomBytes = null; //Always null + int randomBytesUsed = 0; + SecureRandomSpi secureRandomSpi = null; + byte[] state = null; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + Default constructor for SecureRandom. It constructs a + new SecureRandom by instantating the first SecureRandom + algorithm in the default security provier. + + It is not seeded and should be seeded using setSeed or else + on the first call to getnextBytes it will force a seed. + + It is maintained for backwards compatibility and programs + should use {@link #getInstance(java.lang.String)}. + */ + public SecureRandom() + { + Provider[] p = Security.getProviders(); + + //Format of Key: SecureRandom.algname + String key; + + String classname = null; + int i; + Enumeration e; + for (i = 0; i < p.length; i++) + { + e = p[i].propertyNames(); + while (e.hasMoreElements()) + { + key = (String) e.nextElement(); + if (key.startsWith("SECURERANDOM.")) + { + if ((classname = p[i].getProperty(key)) != null) + { + try + { + secureRandomSpi = (SecureRandomSpi) Class. + forName(classname).newInstance(); + provider = p[i]; + return; + } + catch (ThreadDeath death) + { + throw death; + } + catch (Throwable t) + { + // Ignore. + } + } + } + } + } + + // Nothing found. Fall back to SHA1PRNG + secureRandomSpi = new gnu.java.security.provider.SHA1PRNG(); + } + + /** + A constructor for SecureRandom. It constructs a new + SecureRandom by instantating the first SecureRandom algorithm + in the default security provier. + + It is seeded with the passed function and is useful if the user + has access to hardware random device (like a radiation detector). + + It is maintained for backwards compatibility and programs + should use getInstance. + + @param seed Seed bytes for class + */ + public SecureRandom(byte[] seed) + { + this(); + setSeed(seed); + } + + /** + A constructor for SecureRandom. It constructs a new + SecureRandom using the specified SecureRandomSpi from + the specified security provier. + + @param secureRandomSpi A SecureRandomSpi class + @param provider A Provider class + */ + protected SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider) + { + this.secureRandomSpi = secureRandomSpi; + this.provider = provider; + } + + // Class methods. + // ------------------------------------------------------------------------ + + /** + * Returns an instance of a SecureRandom. It creates the class from + * the first provider that implements it. + * + * @param algorithm The algorithm name. + * @return A new SecureRandom implementing the given algorithm. + * @throws NoSuchAlgorithmException If no installed provider implements + * the given algorithm. + */ + public static SecureRandom getInstance(String algorithm) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(algorithm, p[i]); + } + catch (NoSuchAlgorithmException e) + { + // Ignore. + } + } + + // None found. + throw new NoSuchAlgorithmException(algorithm); + } + + /** + * Returns an instance of a SecureRandom. It creates the class + * for the specified algorithm from the named provider. + * + * @param algorithm The algorithm name. + * @param provider The provider name. + * @return A new SecureRandom implementing the chosen algorithm. + * @throws NoSuchAlgorithmException If the named provider does not implement + * the algorithm, or if the implementation cannot be + * instantiated. + * @throws NoSuchProviderException If no provider named + * provider is currently installed. + * @throws IllegalArgumentException If provider is null + * or is empty. + */ + public static SecureRandom getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null || provider.length() == 0) + throw new IllegalArgumentException("Illegal provider"); + + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + + return getInstance(algorithm, p); + } + + /** + * Returns an instance of a SecureRandom. It creates the class for + * the specified algorithm from the given provider. + * + * @param algorithm The SecureRandom algorithm to create. + * @param provider The provider to get the instance from. + * @throws NoSuchAlgorithmException If the algorithm cannot be found, or + * if the class cannot be instantiated. + * @throws IllegalArgumentException If provider is null. + */ + public static SecureRandom getInstance(String algorithm, Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("Illegal provider"); + try + { + return new SecureRandom((SecureRandomSpi) + Engine.getInstance(SECURE_RANDOM, algorithm, provider), + provider); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new NoSuchAlgorithmException(algorithm); + } + catch (ClassCastException cce) + { + throw new NoSuchAlgorithmException(algorithm); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + Returns the provider being used by the current SecureRandom class. + + @return The provider from which this SecureRandom was attained + */ + public final Provider getProvider() + { + return provider; + } + + /** + Seeds the SecureRandom. The class is re-seeded for each call and + each seed builds on the previous seed so as not to weaken security. + + @param seed seed bytes to seed with + */ + public void setSeed(byte[] seed) + { + secureRandomSpi.engineSetSeed(seed); + } + + /** + Seeds the SecureRandom. The class is re-seeded for each call and + each seed builds on the previous seed so as not to weaken security. + + @param seed 8 seed bytes to seed with + */ + public void setSeed(long seed) + { + // This particular setSeed will be called by Random.Random(), via + // our own constructor, before secureRandomSpi is initialized. In + // this case we can't call a method on secureRandomSpi, and we + // definitely don't want to throw a NullPointerException. + // Therefore we test. + if (secureRandomSpi != null) + { + byte[] tmp = { (byte) (0xff & (seed >> 56)), + (byte) (0xff & (seed >> 48)), + (byte) (0xff & (seed >> 40)), + (byte) (0xff & (seed >> 32)), + (byte) (0xff & (seed >> 24)), + (byte) (0xff & (seed >> 16)), + (byte) (0xff & (seed >> 8)), + (byte) (0xff & seed) + }; + secureRandomSpi.engineSetSeed(tmp); + } + } + + /** + Generates a user specified number of bytes. This function + is the basis for all the random functions. + + @param bytes array to store generated bytes in + */ + public void nextBytes(byte[] bytes) + { + randomBytesUsed += bytes.length; + counter++; + secureRandomSpi.engineNextBytes(bytes); + } + + /** + Generates an integer containing the user specified + number of random bits. It is right justified and padded + with zeros. + + @param numBits number of random bits to get, 0 <= numBits <= 32; + + @return the random bits + */ + protected final int next(int numBits) + { + if (numBits == 0) + return 0; + + byte[] tmp = new byte[numBits / 8 + (1 * (numBits % 8))]; + + secureRandomSpi.engineNextBytes(tmp); + randomBytesUsed += tmp.length; + counter++; + + int ret = 0; + + for (int i = 0; i < tmp.length; i++) + ret |= (tmp[i] & 0xFF) << (8 * i); + + long mask = (1L << numBits) - 1; + return (int) (ret & mask); + } + + /** + Returns the given number of seed bytes. This method is + maintained only for backwards capability. + + @param numBytes number of seed bytes to get + + @return an array containing the seed bytes + */ + public static byte[] getSeed(int numBytes) + { + byte[] tmp = new byte[numBytes]; + + new Random().nextBytes(tmp); + return tmp; + //return secureRandomSpi.engineGenerateSeed( numBytes ); + } + + /** + Returns the specified number of seed bytes. + + @param numBytes number of seed bytes to get + + @return an array containing the seed bytes + */ + public byte[] generateSeed(int numBytes) + { + return secureRandomSpi.engineGenerateSeed(numBytes); + } + +} diff --git a/libjava/classpath/java/security/SecureRandomSpi.java b/libjava/classpath/java/security/SecureRandomSpi.java new file mode 100644 index 0000000..7759097 --- /dev/null +++ b/libjava/classpath/java/security/SecureRandomSpi.java @@ -0,0 +1,85 @@ +/* SecureRandomSpi.java --- Secure Random Service Provider Interface + Copyright (C) 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 java.security; +import java.io.Serializable; + +/** + SecureRandomSpi is the Service Provider Interface for SecureRandom + providers. It provides an interface for providers to the + SecureRandom engine to write their own pseudo-random number + generator. + + @since JDK 1.2 + + @author Mark Benvenuto (ivymccough@worldnet.att.net) + */ +public abstract class SecureRandomSpi implements Serializable +{ + private static final long serialVersionUID = -2991854161009191830L; + + /** + Default Constructor for SecureRandomSpi + */ + public SecureRandomSpi() + { + } + + /** + Updates the seed for SecureRandomSpi but does not reset seed. + It does to this so repeated called never decrease randomness. + */ + protected abstract void engineSetSeed(byte[] seed); + + /** + Gets a user specified number of bytes depending on the length + of the array? + + @param bytes array to fill with random bytes + */ + protected abstract void engineNextBytes(byte[] bytes); + + /** + Gets a user specified number of bytes specified by the + parameter. + + @param numBytes number of random bytes to generate + + @return an array full of random bytes + */ + protected abstract byte[] engineGenerateSeed(int numBytes); +} diff --git a/libjava/classpath/java/security/Security.java b/libjava/classpath/java/security/Security.java new file mode 100644 index 0000000..54b9792 --- /dev/null +++ b/libjava/classpath/java/security/Security.java @@ -0,0 +1,740 @@ +/* Security.java --- Java base security class implementation + Copyright (C) 1999, 2001, 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 java.security; + +import gnu.classpath.SystemProperties; + +import gnu.classpath.Configuration; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.Vector; + +/** + * This class centralizes all security properties and common security methods. + * One of its primary uses is to manage providers. + * + * @author Mark Benvenuto (ivymccough@worldnet.att.net) + */ +public final class Security +{ + private static final String ALG_ALIAS = "Alg.Alias."; + + private static Vector providers = new Vector(); + private static Properties secprops = new Properties(); + + static + { + String base = SystemProperties.getProperty("gnu.classpath.home.url"); + String vendor = SystemProperties.getProperty("gnu.classpath.vm.shortname"); + + // Try VM specific security file + boolean loaded = loadProviders (base, vendor); + + // Append classpath standard provider if possible + if (!loadProviders (base, "classpath") + && !loaded + && providers.size() == 0) + { + if (Configuration.DEBUG) + { + /* No providers found and both security files failed to + * load properly. Give a warning in case of DEBUG is + * enabled. Could be done with java.util.logging later. + */ + System.err.println + ("WARNING: could not properly read security provider files:"); + System.err.println + (" " + base + "/security/" + vendor + + ".security"); + System.err.println + (" " + base + "/security/" + "classpath" + + ".security"); + System.err.println + (" Falling back to standard GNU security provider"); + } + providers.addElement (new gnu.java.security.provider.Gnu()); + } + } + // This class can't be instantiated. + private Security() + { + } + + /** + * Tries to load the vender specific security providers from the given + * base URL. Returns true if the resource could be read and completely + * parsed successfully, false otherwise. + */ + private static boolean loadProviders(String baseUrl, String vendor) + { + if (baseUrl == null || vendor == null) + return false; + + boolean result = true; + String secfilestr = baseUrl + "/security/" + vendor + ".security"; + try + { + InputStream fin = new URL(secfilestr).openStream(); + secprops.load(fin); + + int i = 1; + String name; + while ((name = secprops.getProperty("security.provider." + i)) != null) + { + Exception exception = null; + try + { + providers.addElement(Class.forName(name).newInstance()); + } + catch (ClassNotFoundException x) + { + exception = x; + } + catch (InstantiationException x) + { + exception = x; + } + catch (IllegalAccessException x) + { + exception = x; + } + + if (exception != null) + { + System.err.println ("WARNING: Error loading security provider " + + name + ": " + exception); + result = false; + } + i++; + } + } + catch (IOException ignored) + { + result = false; + } + + return result; + } + + /** + * Gets a specified property for an algorithm. The algorithm name should be a + * standard name. See Appendix A in the Java Cryptography Architecture API + * Specification & Reference for information about standard algorithm + * names. One possible use is by specialized algorithm parsers, which may map + * classes to algorithms which they understand (much like {@link Key} parsers + * do). + * + * @param algName the algorithm name. + * @param propName the name of the property to get. + * @return the value of the specified property. + * @deprecated This method used to return the value of a proprietary property + * in the master file of the "SUN" Cryptographic Service Provider in order to + * determine how to parse algorithm-specific parameters. Use the new + * provider-based and algorithm-independent {@link AlgorithmParameters} and + * {@link KeyFactory} engine classes (introduced in the Java 2 platform) + * instead. + */ + public static String getAlgorithmProperty(String algName, String propName) + { + if (algName == null || propName == null) + return null; + + String property = String.valueOf(propName) + "." + String.valueOf(algName); + Provider p; + for (Iterator i = providers.iterator(); i.hasNext(); ) + { + p = (Provider) i.next(); + for (Iterator j = p.keySet().iterator(); j.hasNext(); ) + { + String key = (String) j.next(); + if (key.equalsIgnoreCase(property)) + return p.getProperty(key); + } + } + return null; + } + + /** + *

    Adds a new provider, at a specified position. The position is the + * preference order in which providers are searched for requested algorithms. + * Note that it is not guaranteed that this preference will be respected. The + * position is 1-based, that is, 1 is most preferred, followed by + * 2, and so on.

    + * + *

    If the given provider is installed at the requested position, the + * provider that used to be at that position, and all providers with a + * position greater than position, are shifted up one position (towards the + * end of the list of installed providers).

    + * + *

    A provider cannot be added if it is already installed.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with the string "insertProvider."+provider. + * getName() to see if it's ok to add a new provider. If the default + * implementation of checkSecurityAccess() is used (i.e., that + * method is not overriden), then this will result in a call to the security + * manager's checkPermission() method with a + * SecurityPermission("insertProvider."+provider.getName()) + * permission.

    + * + * @param provider the provider to be added. + * @param position the preference position that the caller would like for + * this provider. + * @return the actual preference position in which the provider was added, or + * -1 if the provider was not added because it is already + * installed. + * @throws SecurityException if a security manager exists and its + * {@link SecurityManager#checkSecurityAccess(String)} method denies access + * to add a new provider. + * @see #getProvider(String) + * @see #removeProvider(String) + * @see SecurityPermission + */ + public static int insertProviderAt(Provider provider, int position) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("insertProvider." + provider.getName()); + + position--; + int max = providers.size (); + for (int i = 0; i < max; i++) + { + if (((Provider) providers.elementAt(i)).getName().equals(provider.getName())) + return -1; + } + + if (position < 0) + position = 0; + if (position > max) + position = max; + + providers.insertElementAt(provider, position); + + return position + 1; + } + + /** + *

    Adds a provider to the next position available.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with the string "insertProvider."+provider. + * getName() to see if it's ok to add a new provider. If the default + * implementation of checkSecurityAccess() is used (i.e., that + * method is not overriden), then this will result in a call to the security + * manager's checkPermission() method with a + * SecurityPermission("insertProvider."+provider.getName()) + * permission.

    + * + * @param provider the provider to be added. + * @return the preference position in which the provider was added, or + * -1 if the provider was not added because it is already + * installed. + * @throws SecurityException if a security manager exists and its + * {@link SecurityManager#checkSecurityAccess(String)} method denies access + * to add a new provider. + * @see #getProvider(String) + * @see #removeProvider(String) + * @see SecurityPermission + */ + public static int addProvider(Provider provider) + { + return insertProviderAt (provider, providers.size () + 1); + } + + /** + *

    Removes the provider with the specified name.

    + * + *

    When the specified provider is removed, all providers located at a + * position greater than where the specified provider was are shifted down + * one position (towards the head of the list of installed providers).

    + * + *

    This method returns silently if the provider is not installed.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with the string "removeProvider."+name + * to see if it's ok to remove the provider. If the default implementation of + * checkSecurityAccess() is used (i.e., that method is not + * overriden), then this will result in a call to the security manager's + * checkPermission() method with a SecurityPermission( + * "removeProvider."+name) permission.

    + * + * @param name the name of the provider to remove. + * @throws SecurityException if a security manager exists and its + * {@link SecurityManager#checkSecurityAccess(String)} method denies access + * to remove the provider. + * @see #getProvider(String) + * @see #addProvider(Provider) + */ + public static void removeProvider(String name) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("removeProvider." + name); + + int max = providers.size (); + for (int i = 0; i < max; i++) + { + if (((Provider) providers.elementAt(i)).getName().equals(name)) + { + providers.remove(i); + break; + } + } + } + + /** + * Returns an array containing all the installed providers. The order of the + * providers in the array is their preference order. + * + * @return an array of all the installed providers. + */ + public static Provider[] getProviders() + { + Provider[] array = new Provider[providers.size ()]; + providers.copyInto (array); + return array; + } + + /** + * Returns the provider installed with the specified name, if any. Returns + * null if no provider with the specified name is installed. + * + * @param name the name of the provider to get. + * @return the provider of the specified name. + * @see #removeProvider(String) + * @see #addProvider(Provider) + */ + public static Provider getProvider(String name) + { + Provider p; + int max = providers.size (); + for (int i = 0; i < max; i++) + { + p = (Provider) providers.elementAt(i); + if (p.getName().equals(name)) + return p; + } + return null; + } + + /** + *

    Gets a security property value.

    + * + *

    First, if there is a security manager, its checkPermission() + * method is called with a SecurityPermission("getProperty."+key) + * permission to see if it's ok to retrieve the specified security property + * value.

    + * + * @param key the key of the property being retrieved. + * @return the value of the security property corresponding to key. + * @throws SecurityException if a security manager exists and its + * {@link SecurityManager#checkPermission(Permission)} method denies access + * to retrieve the specified security property value. + * @see #setProperty(String, String) + * @see SecurityPermission + */ + public static String getProperty(String key) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("getProperty." + key); + + return secprops.getProperty(key); + } + + /** + *

    Sets a security property value.

    + * + *

    First, if there is a security manager, its checkPermission() + * method is called with a SecurityPermission("setProperty."+key) + * permission to see if it's ok to set the specified security property value. + *

    + * + * @param key the name of the property to be set. + * @param datnum the value of the property to be set. + * @throws SecurityException if a security manager exists and its + * {@link SecurityManager#checkPermission(Permission)} method denies access + * to set the specified security property value. + * @see #getProperty(String) + * @see SecurityPermission + */ + public static void setProperty(String key, String datnum) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("setProperty." + key); + + secprops.put(key, datnum); + } + + /** + * Returns a Set of Strings containing the names of all available algorithms + * or types for the specified Java cryptographic service (e.g., Signature, + * MessageDigest, Cipher, Mac, KeyStore). Returns an empty Set if there is no + * provider that supports the specified service. For a complete list of Java + * cryptographic services, please see the Java Cryptography Architecture API + * Specification & Reference. Note: the returned set is immutable. + * + * @param serviceName the name of the Java cryptographic service (e.g., + * Signature, MessageDigest, Cipher, Mac, KeyStore). Note: this parameter is + * case-insensitive. + * @return a Set of Strings containing the names of all available algorithms + * or types for the specified Java cryptographic service or an empty set if + * no provider supports the specified service. + * @since 1.4 + */ + public static Set getAlgorithms(String serviceName) + { + HashSet result = new HashSet(); + if (serviceName == null || serviceName.length() == 0) + return result; + + serviceName = serviceName.trim(); + if (serviceName.length() == 0) + return result; + + serviceName = serviceName.toUpperCase()+"."; + Provider[] providers = getProviders(); + int ndx; + for (int i = 0; i < providers.length; i++) + for (Enumeration e = providers[i].propertyNames(); e.hasMoreElements(); ) + { + String service = ((String) e.nextElement()).trim(); + if (service.toUpperCase().startsWith(serviceName)) + { + service = service.substring(serviceName.length()).trim(); + ndx = service.indexOf(' '); // get rid of attributes + if (ndx != -1) + service = service.substring(0, ndx); + result.add(service); + } + } + return Collections.unmodifiableSet(result); + } + + /** + *

    Returns an array containing all installed providers that satisfy the + * specified selection criterion, or null if no such providers + * have been installed. The returned providers are ordered according to their + * preference order.

    + * + *

    A cryptographic service is always associated with a particular + * algorithm or type. For example, a digital signature service is always + * associated with a particular algorithm (e.g., DSA), and a + * CertificateFactory service is always associated with a particular + * certificate type (e.g., X.509).

    + * + *

    The selection criterion must be specified in one of the following two + * formats:

    + * + *
      + *
    • <crypto_service>.<algorithm_or_type>

      + *

      The cryptographic service name must not contain any dots.

      + *

      A provider satisfies the specified selection criterion iff the + * provider implements the specified algorithm or type for the specified + * cryptographic service.

      + *

      For example, "CertificateFactory.X.509" would be satisfied by any + * provider that supplied a CertificateFactory implementation for X.509 + * certificates.

    • + * + *
    • <crypto_service>.<algorithm_or_type> <attribute_name>:<attribute_value>

      + *

      The cryptographic service name must not contain any dots. There must + * be one or more space charaters between the the <algorithm_or_type> + * and the <attribute_name>.

      + *

      A provider satisfies this selection criterion iff the provider + * implements the specified algorithm or type for the specified + * cryptographic service and its implementation meets the constraint + * expressed by the specified attribute name/value pair.

      + *

      For example, "Signature.SHA1withDSA KeySize:1024" would be satisfied + * by any provider that implemented the SHA1withDSA signature algorithm + * with a keysize of 1024 (or larger).

    • + *
    + * + *

    See Appendix A in the Java Cryptogaphy Architecture API Specification + * & Reference for information about standard cryptographic service names, + * standard algorithm names and standard attribute names.

    + * + * @param filter the criterion for selecting providers. The filter is case- + * insensitive. + * @return all the installed providers that satisfy the selection criterion, + * or null if no such providers have been installed. + * @throws InvalidParameterException if the filter is not in the required + * format. + * @see #getProviders(Map) + */ + public static Provider[] getProviders(String filter) + { + if (providers == null || providers.isEmpty()) + return null; + + if (filter == null || filter.length() == 0) + return getProviders(); + + HashMap map = new HashMap(1); + int i = filter.indexOf(':'); + if (i == -1) // . + map.put(filter, ""); + else // . : + map.put(filter.substring(0, i), filter.substring(i+1)); + + return getProviders(map); + } + + /** + *

    Returns an array containing all installed providers that satisfy the + * specified selection criteria, or null if no such providers + * have been installed. The returned providers are ordered according to their + * preference order.

    + * + *

    The selection criteria are represented by a map. Each map entry + * represents a selection criterion. A provider is selected iff it satisfies + * all selection criteria. The key for any entry in such a map must be in one + * of the following two formats:

    + * + *
      + *
    • <crypto_service>.<algorithm_or_type>

      + *

      The cryptographic service name must not contain any dots.

      + *

      The value associated with the key must be an empty string.

      + *

      A provider satisfies this selection criterion iff the provider + * implements the specified algorithm or type for the specified + * cryptographic service.

    • + * + *
    • <crypto_service>.<algorithm_or_type> <attribute_name>

      + *

      The cryptographic service name must not contain any dots. There must + * be one or more space charaters between the <algorithm_or_type> and + * the <attribute_name>.

      + *

      The value associated with the key must be a non-empty string. A + * provider satisfies this selection criterion iff the provider implements + * the specified algorithm or type for the specified cryptographic service + * and its implementation meets the constraint expressed by the specified + * attribute name/value pair.

    • + *
    + * + *

    See Appendix A in the Java Cryptogaphy Architecture API Specification + * & Reference for information about standard cryptographic service names, + * standard algorithm names and standard attribute names.

    + * + * @param filter the criteria for selecting providers. The filter is case- + * insensitive. + * @return all the installed providers that satisfy the selection criteria, + * or null if no such providers have been installed. + * @throws InvalidParameterException if the filter is not in the required + * format. + * @see #getProviders(String) + */ + public static Provider[] getProviders(Map filter) + { + if (providers == null || providers.isEmpty()) + return null; + + if (filter == null) + return getProviders(); + + Set querries = filter.keySet(); + if (querries == null || querries.isEmpty()) + return getProviders(); + + LinkedHashSet result = new LinkedHashSet(providers); // assume all + int dot, ws; + String querry, service, algorithm, attribute, value; + LinkedHashSet serviceProviders = new LinkedHashSet(); // preserve insertion order + for (Iterator i = querries.iterator(); i.hasNext(); ) + { + querry = (String) i.next(); + if (querry == null) // all providers + continue; + + querry = querry.trim(); + if (querry.length() == 0) // all providers + continue; + + dot = querry.indexOf('.'); + if (dot == -1) // syntax error + throw new InvalidParameterException( + "missing dot in '" + String.valueOf(querry)+"'"); + + value = (String) filter.get(querry); + // deconstruct querry into [service, algorithm, attribute] + if (value == null || value.trim().length() == 0) // . + { + value = null; + attribute = null; + service = querry.substring(0, dot).trim(); + algorithm = querry.substring(dot+1).trim(); + } + else // . + { + ws = querry.indexOf(' '); + if (ws == -1) + throw new InvalidParameterException( + "value (" + String.valueOf(value) + + ") is not empty, but querry (" + String.valueOf(querry) + + ") is missing at least one space character"); + value = value.trim(); + attribute = querry.substring(ws+1).trim(); + // was the dot in the attribute? + if (attribute.indexOf('.') != -1) + throw new InvalidParameterException( + "attribute_name (" + String.valueOf(attribute) + + ") in querry (" + String.valueOf(querry) + ") contains a dot"); + + querry = querry.substring(0, ws).trim(); + service = querry.substring(0, dot).trim(); + algorithm = querry.substring(dot+1).trim(); + } + + // service and algorithm must not be empty + if (service.length() == 0) + throw new InvalidParameterException( + " in querry (" + String.valueOf(querry) + + ") is empty"); + + if (algorithm.length() == 0) + throw new InvalidParameterException( + " in querry (" + String.valueOf(querry) + + ") is empty"); + + selectProviders(service, algorithm, attribute, value, result, serviceProviders); + result.retainAll(serviceProviders); // eval next retaining found providers + if (result.isEmpty()) // no point continuing + break; + } + + if (result.isEmpty()) + return null; + + return (Provider[]) result.toArray(new Provider[0]); + } + + private static void selectProviders(String svc, String algo, String attr, + String val, LinkedHashSet providerSet, + LinkedHashSet result) + { + result.clear(); // ensure we start with an empty result set + for (Iterator i = providerSet.iterator(); i.hasNext(); ) + { + Provider p = (Provider) i.next(); + if (provides(p, svc, algo, attr, val)) + result.add(p); + } + } + + private static boolean provides(Provider p, String svc, String algo, + String attr, String val) + { + Iterator it; + String serviceDotAlgorithm = null; + String key = null; + String realVal; + boolean found = false; + // if . is in the set then so is . + // but it may be stored under an alias . resolve + outer: for (int r = 0; r < 3; r++) // guard against circularity + { + serviceDotAlgorithm = (svc+"."+String.valueOf(algo)).trim(); + for (it = p.keySet().iterator(); it.hasNext(); ) + { + key = (String) it.next(); + if (key.equalsIgnoreCase(serviceDotAlgorithm)) // eureka + { + found = true; + break outer; + } + // it may be there but as an alias + if (key.equalsIgnoreCase(ALG_ALIAS + serviceDotAlgorithm)) + { + algo = p.getProperty(key); + continue outer; + } + // else continue inner + } + } + + if (!found) + return false; + + // found a candidate for the querry. do we have an attr to match? + if (val == null) // . querry + return true; + + // . ; find the key entry that match + String realAttr; + int limit = serviceDotAlgorithm.length() + 1; + for (it = p.keySet().iterator(); it.hasNext(); ) + { + key = (String) it.next(); + if (key.length() <= limit) + continue; + + if (key.substring(0, limit).equalsIgnoreCase(serviceDotAlgorithm+" ")) + { + realAttr = key.substring(limit).trim(); + if (! realAttr.equalsIgnoreCase(attr)) + continue; + + // eveything matches so far. do the value + realVal = p.getProperty(key); + if (realVal == null) + return false; + + realVal = realVal.trim(); + // is it a string value? + if (val.equalsIgnoreCase(realVal)) + return true; + + // assume value is a number. cehck for greater-than-or-equal + return (new Integer(val).intValue() >= new Integer(realVal).intValue()); + } + } + + return false; + } +} diff --git a/libjava/classpath/java/security/SecurityPermission.java b/libjava/classpath/java/security/SecurityPermission.java new file mode 100644 index 0000000..6aba18f --- /dev/null +++ b/libjava/classpath/java/security/SecurityPermission.java @@ -0,0 +1,178 @@ +/* SecurityPermission.java -- Class for named security permissions + 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 java.security; + +/** + * This class provides a mechanism for specified named permissions + * related to the Java security framework. These permissions have no + * associated actions list. They are either granted or not granted. + * + *

    The list of valid permission names is:
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Permission NamePermission AllowsRisks + *
    createAccessControlContextAllows creation of an AccessControlContextThe new control context can have a rogue DomainCombiner, leading + * to a privacy leak
    getDomainCombinerGet a DomainCombiner from an AccessControlContextAccess to a DomainCombiner can lead to a privacy leak
    getPolicyAllows retrieval of the system security policyMalicious code can use information from the policy to better plan + * an attack
    setPolicyAllows the security policy to be changedMalicious code can give itself any permission it wants
    getProperty.keyRetrieve the property specified by the keyMalicious code can use information from the property to better plan + * an attack
    setProperty.keyAllows changing of the value of all properties implied by keyMalicious code can insert rogue classes to steal keys or recreate + * the security policy with whatever permissions it desires
    insertProvider.keyAllows the named provider to be addedMalicious code can insert rogue providers that steal data
    removeProvider.keyAllows the named provider to be removedA missing provider can cripple code that relies on it
    setSystemScopeAllows the system identity scope to be setMalicious code can add certificates not available in the original + * identity scope, to gain more permissions
    setIdentityPublicKeyAllows the public key of an Identity to be setMalicious code can install its own key to gain permissions not + * allowed by the original identity scope
    SetIdentityInfoAllows the description of an Identity to be setMalicious code can spoof users into trusting a fake identity
    addIdentityCertificateAllows a certificate to be set for the public key of an identityThe public key can become trusted to a wider audience than originally + * intended
    removeIdentityCertificateAllows removal of a certificate from an identity's public keyThe public key can become less trusted than it should be
    printIdentityView the name of the identity and scope, and whether they are + * trustedThe scope may include a filename, which provides an entry point for + * further security breaches
    clearProviderProperties.keyAllows the properties of the named provider to be clearedThis can disable parts of the program which depend on finding the + * provider
    putProviderProperty.keyAllows the properties of the named provider to be changedMalicious code can replace the implementation of a provider
    removeProviderProperty.keyAllows the properties of the named provider to be deletedThis can disable parts of the program which depend on finding the + * provider
    getSignerPrivateKeyAllows the retrieval of the private key for a signerAnyone that can access the private key can claim to be the + * Signer
    setSignerKeyPairAllows the public and private key of a Signer to be changedThe replacement might be a weaker encryption, or the attacker + * can use knowledge of the replaced key to decrypt an entire + * communication session
    + * + *

    There is some degree of security risk in granting any of these + * permissions. Some of them can completely compromise system security. + * Please exercise extreme caution in granting these permissions. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Permission + * @see SecurityManager + * @since 1.1 + * @status updated to 1.4 + */ +public final class SecurityPermission extends BasicPermission +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5236109936224050470L; + + /** + * Create a new instance with the specified name. + * + * @param name the name to assign to this permission + */ + public SecurityPermission(String name) + { + super(name); + } + + /** + * Create a new instance with the specified name. As SecurityPermission + * carries no actions, the second parameter is ignored. + * + * @param name the name to assign to this permission + * @param actions ignored + */ + public SecurityPermission(String name, String actions) + { + super(name); + } +} // class SecurityPermission diff --git a/libjava/classpath/java/security/Signature.java b/libjava/classpath/java/security/Signature.java new file mode 100644 index 0000000..852c959 --- /dev/null +++ b/libjava/classpath/java/security/Signature.java @@ -0,0 +1,636 @@ +/* Signature.java --- Signature Class + Copyright (C) 1999, 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 java.security; + +import gnu.java.security.Engine; + +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.spec.AlgorithmParameterSpec; + +/** + *

    This Signature class is used to provide applications the + * functionality of a digital signature algorithm. Digital signatures are used + * for authentication and integrity assurance of digital data.

    + * + *

    The signature algorithm can be, among others, the NIST standard DSS, + * using DSA and SHA-1. The DSA algorithm using the + * SHA-1 message digest algorithm can be specified as SHA1withDSA + * . In the case of RSA, there are multiple choices for the + * message digest algorithm, so the signing algorithm could be specified as, for + * example, MD2withRSA, MD5withRSA, or + * SHA1withRSA. The algorithm name must be specified, as there is + * no default.

    + * + *

    Like other algorithm-based classes in Java Security, Signature + * provides implementation-independent algorithms, whereby a caller (application + * code) requests a particular signature algorithm and is handed back a properly + * initialized Signature object. It is also possible, if desired, + * to request a particular algorithm from a particular provider. See the + * getInstance() methods.

    + * + *

    Thus, there are two ways to request a Signature algorithm + * object: by specifying either just an algorithm name, or both an algorithm + * name and a package provider.

    + * + *

    If just an algorithm name is specified, the system will determine if there + * is an implementation of the algorithm requested available in the environment, + * and if there is more than one, if there is a preferred one.

    + * + *

    If both an algorithm name and a package provider are specified, the system + * will determine if there is an implementation of the algorithm in the package + * requested, and throw an exception if there is not.

    + * + *

    A Signature object can be used to generate and verify digital + * signatures.

    + * + *

    There are three phases to the use of a Signature object for + * either signing data or verifying a signature:

    + * + *
      + *
    1. Initialization, with either + *
        + *
      • a public key, which initializes the signature for verification + * (see initVerify()), or
      • + *
      • a private key (and optionally a Secure Random Number Generator), + * which initializes the signature for signing (see + * {@link #initSign(PrivateKey)} and {@link #initSign(PrivateKey, SecureRandom)} + * ).
      • + *
    2. + *
    3. Updating
      + * Depending on the type of initialization, this will update the bytes to + * be signed or verified. See the update methods.
    4. + *
    5. Signing or Verifying a signature on all updated bytes. See the + * sign() methods and the verify() method.
    6. + *
    + * + *

    Note that this class is abstract and extends from {@link SignatureSpi} for + * historical reasons. Application developers should only take notice of the + * methods defined in this Signature class; all the methods in the + * superclass are intended for cryptographic service providers who wish to + * supply their own implementations of digital signature algorithms. + * + * @author Mark Benvenuto (ivymccough@worldnet.att.net) + */ +public abstract class Signature extends SignatureSpi +{ + /** Service name for signatures. */ + private static final String SIGNATURE = "Signature"; + + /** + * Possible state value, signifying that this signature object + * has not yet been initialized. + */ + protected static final int UNINITIALIZED = 0; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Possible state value, signifying that this signature object + * has been initialized for signing. + */ + protected static final int SIGN = 2; + + /** + * Possible state value, signifying that this signature object + * has been initialized for verification. + */ + protected static final int VERIFY = 3; + + /** Current state of this signature object. */ + protected int state = UNINITIALIZED; + + private String algorithm; + Provider provider; + + /** + * Creates a Signature object for the specified algorithm. + * + * @param algorithm the standard string name of the algorithm. See Appendix A + * in the Java Cryptography Architecture API Specification & Reference for + * information about standard algorithm names. + */ + protected Signature(String algorithm) + { + this.algorithm = algorithm; + state = UNINITIALIZED; + } + + /** + * Generates a Signature object that implements the specified + * digest algorithm. If the default provider package provides an + * implementation of the requested digest algorithm, an instance of + * Signature containing that implementation is returned. If the + * algorithm is not available in the default package, other packages are + * searched. + * + * @param algorithm the standard name of the algorithm requested. See Appendix + * A in the Java Cryptography Architecture API Specification & Reference + * for information about standard algorithm names. + * @return the new Signature object. + * @throws NoSuchAlgorithmException if the algorithm is not available in the + * environment. + */ + public static Signature getInstance(String algorithm) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(algorithm, p[i]); + } + catch (NoSuchAlgorithmException e) + { + // Ignored. + } + } + + throw new NoSuchAlgorithmException(algorithm); + } + + /** + * Generates a Signature object implementing the specified + * algorithm, as supplied from the specified provider, if such an algorithm + * is available from the provider. + * + * @param algorithm the name of the algorithm requested. See Appendix A in + * the Java Cryptography Architecture API Specification & Reference for + * information about standard algorithm names. + * @param provider the name of the provider. + * @return the new Signature object. + * @throws NoSuchAlgorithmException if the algorithm is not available in the + * package supplied by the requested provider. + * @throws NoSuchProviderException if the provider is not available in the + * environment. + * @throws IllegalArgumentException if the provider name is null + * or empty. + * @see Provider + */ + public static Signature getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null || provider.length() == 0) + throw new IllegalArgumentException("Illegal provider"); + + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + + return getInstance(algorithm, p); + } + + /** + * Generates a Signature object implementing the specified + * algorithm, as supplied from the specified provider, if such an algorithm + * is available from the provider. Note: the provider doesn't have to be + * registered. + * + * @param algorithm the name of the algorithm requested. See Appendix A in + * the Java Cryptography Architecture API Specification & Reference for + * information about standard algorithm names. + * @param provider the provider. + * @return the new Signature object. + * @throws NoSuchAlgorithmException if the algorithm is not + * available in the package supplied by the requested provider. + * @throws IllegalArgumentException if the provider is + * null. + * @since 1.4 + * @see Provider + */ + public static Signature getInstance(String algorithm, Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("Illegal provider"); + + Signature result = null; + Object o = null; + try + { + o = Engine.getInstance(SIGNATURE, algorithm, provider); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new NoSuchAlgorithmException(algorithm); + } + + if (o instanceof SignatureSpi) + { + result = new DummySignature((SignatureSpi) o, algorithm); + } + else if (o instanceof Signature) + { + result = (Signature) o; + result.algorithm = algorithm; + } + else + { + throw new NoSuchAlgorithmException(algorithm); + } + result.provider = provider; + return result; + } + + /** + * Returns the provider of this signature object. + * + * @return the provider of this signature object. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Initializes this object for verification. If this method is called again + * with a different argument, it negates the effect of this call. + * + * @param publicKey the public key of the identity whose signature is going + * to be verified. + * @throws InvalidKeyException if the key is invalid. + */ + public final void initVerify(PublicKey publicKey) throws InvalidKeyException + { + state = VERIFY; + engineInitVerify(publicKey); + } + + /** + *

    Initializes this object for verification, using the public key from the + * given certificate.

    + * + *

    If the certificate is of type X.509 and has a key usage + * extension field marked as critical, and the value of the key + * usage extension field implies that the public key in the certificate + * and its corresponding private key are not supposed to be used for digital + * signatures, an {@link InvalidKeyException} is thrown.

    + * + * @param certificate the certificate of the identity whose signature is + * going to be verified. + * @throws InvalidKeyException if the public key in the certificate is not + * encoded properly or does not include required parameter information or + * cannot be used for digital signature purposes. + */ + public final void initVerify(Certificate certificate) + throws InvalidKeyException + { + state = VERIFY; + if (certificate.getType().equals("X509")) + { + X509Certificate cert = (X509Certificate) certificate; + boolean[]array = cert.getKeyUsage(); + if (array != null && array[0] == false) + throw new InvalidKeyException( + "KeyUsage of this Certificate indicates it cannot be used for digital signing"); + } + this.initVerify(certificate.getPublicKey()); + } + + /** + * Initialize this object for signing. If this method is called again with a + * different argument, it negates the effect of this call. + * + * @param privateKey the private key of the identity whose signature is going + * to be generated. + * @throws InvalidKeyException if the key is invalid. + */ + public final void initSign(PrivateKey privateKey) throws InvalidKeyException + { + state = SIGN; + engineInitSign(privateKey); + } + + /** + * Initialize this object for signing. If this method is called again with a + * different argument, it negates the effect of this call. + * + * @param privateKey the private key of the identity whose signature is going + * to be generated. + * @param random the source of randomness for this signature. + * @throws InvalidKeyException if the key is invalid. + */ + public final void initSign(PrivateKey privateKey, SecureRandom random) + throws InvalidKeyException + { + state = SIGN; + engineInitSign(privateKey, random); + } + + /** + *

    Returns the signature bytes of all the data updated. The format of the + * signature depends on the underlying signature scheme.

    + * + *

    A call to this method resets this signature object to the state it was + * in when previously initialized for signing via a call to + * initSign(PrivateKey). That is, the object is reset and + * available to generate another signature from the same signer, if desired, + * via new calls to update() and sign().

    + * + * @return the signature bytes of the signing operation's result. + * @throws SignatureException if this signature object is not initialized + * properly. + */ + public final byte[] sign() throws SignatureException + { + if (state == SIGN) + return engineSign(); + else + throw new SignatureException(); + } + + /** + *

    Finishes the signature operation and stores the resulting signature + * bytes in the provided buffer outbuf, starting at offset + * . The format of the signature depends on the underlying signature + * scheme.

    + * + *

    This signature object is reset to its initial state (the state it was + * in after a call to one of the initSign() methods) and can be + * reused to generate further signatures with the same private key.

    + * + * @param outbuf buffer for the signature result. + * @param offset offset into outbuf where the signature is stored. + * @param len number of bytes within outbuf allotted for the signature. + * @return the number of bytes placed into outbuf. + * @throws SignatureException if an error occurs or len is less than the + * actual signature length. + * @since 1.2 + */ + public final int sign(byte[] outbuf, int offset, int len) + throws SignatureException + { + if (state == SIGN) + return engineSign(outbuf, offset, len); + else + throw new SignatureException(); + } + + /** + *

    Verifies the passed-in signature.

    + * + *

    A call to this method resets this signature object to the state it was + * in when previously initialized for verification via a call to + * initVerify(PublicKey). That is, the object is reset and + * available to verify another signature from the identity whose public key + * was specified in the call to initVerify().

    + * + * @param signature the signature bytes to be verified. + * @return true if the signature was verified, false + * if not. + * @throws SignatureException if this signature object is not initialized + * properly, or the passed-in signature is improperly encoded or of the wrong + * type, etc. + */ + public final boolean verify(byte[]signature) throws SignatureException + { + if (state == VERIFY) + return engineVerify(signature); + else + throw new SignatureException(); + } + + /** + *

    Verifies the passed-in signature in the specified array of + * bytes, starting at the specified offset.

    + * + *

    A call to this method resets this signature object to the state it was + * in when previously initialized for verification via a call to + * initVerify(PublicKey). That is, the object is reset and + * available to verify another signature from the identity whose public key + * was specified in the call to initVerify().

    + * + * @param signature the signature bytes to be verified. + * @param offset the offset to start from in the array of bytes. + * @param length the number of bytes to use, starting at offset. + * @return true if the signature was verified, false + * if not. + * @throws SignatureException if this signature object is not initialized + * properly, or the passed-in signature is improperly encoded or + * of the wrong type, etc. + * @throws IllegalArgumentException if the signature byte array + * is null, or the offset or length is + * less than 0, or the sum of the offset and + * length is greater than the length of the signature + * byte array. + */ + public final boolean verify(byte[] signature, int offset, int length) + throws SignatureException + { + if (state != VERIFY) + throw new SignatureException("illegal state"); + + if (signature == null) + throw new IllegalArgumentException("signature is null"); + if (offset < 0) + throw new IllegalArgumentException("offset is less than 0"); + if (length < 0) + throw new IllegalArgumentException("length is less than 0"); + if (offset + length < signature.length) + throw new IllegalArgumentException("range is out of bounds"); + + return engineVerify(signature, offset, length); + } + + /** + * Updates the data to be signed or verified by a byte. + * + * @param b the byte to use for the update. + * @throws SignatureException if this signature object is not initialized + * properly. + */ + public final void update(byte b) throws SignatureException + { + if (state != UNINITIALIZED) + engineUpdate(b); + else + throw new SignatureException(); + } + + /** + * Updates the data to be signed or verified, using the specified array of + * bytes. + * + * @param data the byte array to use for the update. + * @throws SignatureException if this signature object is not initialized + * properly. + */ + public final void update(byte[]data) throws SignatureException + { + if (state != UNINITIALIZED) + engineUpdate(data, 0, data.length); + else + throw new SignatureException(); + } + + /** + * Updates the data to be signed or verified, using the specified array of + * bytes, starting at the specified offset. + * + * @param data the array of bytes. + * @param off the offset to start from in the array of bytes. + * @param len the number of bytes to use, starting at offset. + * @throws SignatureException if this signature object is not initialized + * properly. + */ + public final void update(byte[]data, int off, int len) + throws SignatureException + { + if (state != UNINITIALIZED) + engineUpdate(data, off, len); + else + throw new SignatureException(); + } + + /** + * Returns the name of the algorithm for this signature object. + * + * @return the name of the algorithm for this signature object. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Returns a string representation of this signature object, providing + * information that includes the state of the object and the name of the + * algorithm used. + * + * @return a string representation of this signature object. + */ + public String toString() + { + return (algorithm + " Signature"); + } + + /** + * Sets the specified algorithm parameter to the specified value. This method + * supplies a general-purpose mechanism through which it is possible to set + * the various parameters of this object. A parameter may be any settable + * parameter for the algorithm, such as a parameter size, or a source of + * random bits for signature generation (if appropriate), or an indication of + * whether or not to perform a specific but optional computation. A uniform + * algorithm-specific naming scheme for each parameter is desirable but left + * unspecified at this time. + * + * @param param the string identifier of the parameter. + * @param value the parameter value. + * @throws InvalidParameterException if param is an invalid parameter for this + * signature algorithm engine, the parameter is already set and cannot be set + * again, a security exception occurs, and so on. + * @see #getParameter(String) + * @deprecated Use setParameter(AlgorithmParameterSpec). + */ + public final void setParameter(String param, Object value) + throws InvalidParameterException + { + engineSetParameter(param, value); + } + + /** + * Initializes this signature engine with the specified parameter set. + * + * @param params the parameters. + * @throws InvalidAlgorithmParameterException if the given parameters are + * inappropriate for this signature engine. + * @see #getParameters() + */ + public final void setParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException + { + engineSetParameter(params); + } + + /** + *

    Returns the parameters used with this signature object.

    + * + *

    The returned parameters may be the same that were used to initialize + * this signature, or may contain a combination of default and randomly + * generated parameter values used by the underlying signature implementation + * if this signature requires algorithm parameters but was not initialized + * with any. + * + * @return the parameters used with this signature, or null if + * this signature does not use any parameters. + * @see #setParameter(AlgorithmParameterSpec) + */ + public final AlgorithmParameters getParameters() + { + return engineGetParameters(); + } + + /** + * Gets the value of the specified algorithm parameter. This method supplies + * a general-purpose mechanism through which it is possible to get the various + * parameters of this object. A parameter may be any settable parameter for + * the algorithm, such as a parameter size, or a source of random bits for + * signature generation (if appropriate), or an indication of whether or not + * to perform a specific but optional computation. A uniform + * algorithm-specific naming scheme for each parameter is desirable but left + * unspecified at this time. + * + * @param param the string name of the parameter. + * @return the object that represents the parameter value, or null if there + * is none. + * @throws InvalidParameterException if param is an invalid parameter for this + * engine, or another exception occurs while trying to get this parameter. + * @see #setParameter(String, Object) + * @deprecated + */ + public final Object getParameter(String param) + throws InvalidParameterException + { + return engineGetParameter(param); + } + + /** + * Returns a clone if the implementation is cloneable. + * + * @return a clone if the implementation is cloneable. + * @throws CloneNotSupportedException if this is called on an implementation + * that does not support {@link Cloneable}. + */ + public Object clone() throws CloneNotSupportedException + { + return super.clone(); + } +} diff --git a/libjava/classpath/java/security/SignatureException.java b/libjava/classpath/java/security/SignatureException.java new file mode 100644 index 0000000..e294c16 --- /dev/null +++ b/libjava/classpath/java/security/SignatureException.java @@ -0,0 +1,70 @@ +/* SignatureException.java -- Generic error in signature + Copyright (C) 1998, 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 java.security; + +/** + * This exception is thrown when a problem is encountered with a + * digital signature. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class SignatureException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 7509989324975124438L; + + /** + * Create an instance with no descriptive error message. + */ + public SignatureException() + { + } + + /** + * Create an instance with a descriptive error message. + * + * @param msg the message + */ + public SignatureException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/SignatureSpi.java b/libjava/classpath/java/security/SignatureSpi.java new file mode 100644 index 0000000..471a73d --- /dev/null +++ b/libjava/classpath/java/security/SignatureSpi.java @@ -0,0 +1,302 @@ +/* SignatureSpi.java --- Signature Service Provider Interface + 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 java.security; + +import java.security.spec.AlgorithmParameterSpec; + +/** + *

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

    + * + *

    All the abstract methods in this class must be implemented by each + * cryptographic service provider who wishes to supply the implementation of a + * particular signature algorithm. + * + * @author Mark Benvenuto (ivymccough@worldnet.att.net) + * @since 1.2 + * @see Signature + */ +public abstract class SignatureSpi +{ + /** Application-specified source of randomness. */ + protected SecureRandom appRandom; + + public SignatureSpi() + { + appRandom = null; + } + + /** + * Initializes this signature object with the specified public key for + * verification operations. + * + * @param publicKey the public key of the identity whose signature is going + * to be verified. + * @throws InvalidKeyException if the key is improperly encoded, parameters + * are missing, and so on. + */ + protected abstract void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException; + + /** + * Initializes this signature object with the specified private key for + * signing operations. + * + * @param privateKey the private key of the identity whose signature will be + * generated. + * @throws InvalidKeyException if the key is improperly encoded, parameters + * are missing, and so on. + */ + protected abstract void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException; + + /** + *

    Initializes this signature object with the specified private key and + * source of randomness for signing operations.

    + * + *

    This concrete method has been added to this previously-defined abstract + * class. (For backwards compatibility, it cannot be abstract.)

    + * + * @param privateKey the private key of the identity whose signature will be + * generated. + * @param random the source of randomness. + * @throws InvalidKeyException if the key is improperly encoded, parameters + * are missing, and so on. + * @since 1.2 + */ + protected void engineInitSign(PrivateKey privateKey, SecureRandom random) + throws InvalidKeyException + { + appRandom = random; + engineInitSign(privateKey); + } + + /** + * Updates the data to be signed or verified using the specified byte. + * + * @param b the byte to use for the update. + * @throws SignatureException if the engine is not initialized properly. + */ + protected abstract void engineUpdate(byte b) throws SignatureException; + + /** + * Updates the data to be signed or verified, using the specified array of + * bytes, starting at the specified offset. + * + * @param b the array of bytes. + * @param off the offset to start from in the array of bytes. + * @param len the number of bytes to use, starting at offset. + * @throws SignatureException if the engine is not initialized properly. + */ + protected abstract void engineUpdate(byte[] b, int off, int len) + throws SignatureException; + + /** + * Returns the signature bytes of all the data updated so far. The format of + * the signature depends on the underlying signature scheme. + * + * @return the signature bytes of the signing operation's result. + * @throws SignatureException if the engine is not initialized properly. + */ + protected abstract byte[] engineSign() throws SignatureException; + + /** + *

    Finishes this signature operation and stores the resulting signature + * bytes in the provided buffer outbuf, starting at offset + * . The format of the signature depends on the underlying signature + * scheme.

    + * + *

    The signature implementation is reset to its initial state (the state it + * was in after a call to one of the engineInitSign() methods) + * and can be reused to generate further signatures with the same private key. + * This method should be abstract, but we leave it concrete for binary + * compatibility. Knowledgeable providers should override this method.

    + * + * @param outbuf buffer for the signature result. + * @param offset offset into outbuf where the signature is stored. + * @param len number of bytes within outbuf allotted for the signature. Both + * this default implementation and the GNU provider do not return + * partial digests. If the value of this parameter is less than the actual + * signature length, this method will throw a {@link SignatureException}. This + * parameter is ignored if its value is greater than or equal to the actual + * signature length. + * @return the number of bytes placed into outbuf. + * @throws SignatureException if an error occurs or len is less than the + * actual signature length. + * @since 1.2 + */ + protected int engineSign(byte[] outbuf, int offset, int len) + throws SignatureException + { + byte[] tmp = engineSign(); + if (tmp.length > len) + throw new SignatureException("Invalid Length"); + + System.arraycopy(outbuf, offset, tmp, 0, tmp.length); + return tmp.length; + } + + /** + * Verifies the passed-in signature. + * + * @param sigBytes the signature bytes to be verified. + * @return true if the signature was verified, false + * if not. + * @throws SignatureException if the engine is not initialized properly, or + * the passed-in signature is improperly encoded or of the wrong type, etc. + */ + protected abstract boolean engineVerify(byte[] sigBytes) + throws SignatureException; + + /** + *

    Verifies the passed-in signature in the specified array of + * bytes, starting at the specified offset.

    + * + *

    Note: Subclasses should overwrite the default implementation.

    + * + * @param sigBytes the signature bytes to be verified. + * @param offset the offset to start from in the array of bytes. + * @param length the number of bytes to use, starting at offset. + * @return true if the signature was verified, false + * if not. + * @throws SignatureException if the engine is not initialized properly, or + * the passed-in signature is improperly encoded or of the wrong + * type, etc. + */ + protected boolean engineVerify(byte[] sigBytes, int offset, int length) + throws SignatureException + { + byte[] tmp = new byte[length]; + System.arraycopy(sigBytes, offset, tmp, 0, length); + return engineVerify(tmp); + } + + /** + * Sets the specified algorithm parameter to the specified value. This method + * supplies a general-purpose mechanism through which it is possible to set + * the various parameters of this object. A parameter may be any settable + * parameter for the algorithm, such as a parameter size, or a source of + * random bits for signature generation (if appropriate), or an indication of + * whether or not to perform a specific but optional computation. A uniform + * algorithm-specific naming scheme for each parameter is desirable but left + * unspecified at this time. + * + * @param param the string identifier of the parameter. + * @param value the parameter value. + * @throws InvalidParameterException if param is an invalid + * parameter for this signature algorithm engine, the parameter is already set + * and cannot be set again, a security exception occurs, and so on. + * @deprecated Replaced by engineSetParameter(AlgorithmParameterSpec). + */ + protected abstract void engineSetParameter(String param, Object value) + throws InvalidParameterException; + + /** + * This method is overridden by providers to initialize this signature engine + * with the specified parameter set. + * + * @param params the parameters. + * @throws UnsupportedOperationException if this method is not overridden by + * a provider. + * @throws InvalidAlgorithmParameterException if this method is overridden by + * a provider and the the given parameters are inappropriate for this + * signature engine. + */ + protected void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException + { + throw new UnsupportedOperationException(); + } + + /** + *

    This method is overridden by providers to return the parameters used + * with this signature engine, or null if this signature engine + * does not use any parameters.

    + * + *

    The returned parameters may be the same that were used to initialize + * this signature engine, or may contain a combination of default and randomly + * generated parameter values used by the underlying signature implementation + * if this signature engine requires algorithm parameters but was not + * initialized with any.

    + * + * @return the parameters used with this signature engine, or null + * if this signature engine does not use any parameters. + * @throws UnsupportedOperationException if this method is not overridden by + * a provider. + */ + protected AlgorithmParameters engineGetParameters() + { + throw new UnsupportedOperationException(); + } + + /** + * Gets the value of the specified algorithm parameter. This method supplies + * a general-purpose mechanism through which it is possible to get the various + * parameters of this object. A parameter may be any settable parameter for + * the algorithm, such as a parameter size, or a source of random bits for + * signature generation (if appropriate), or an indication of whether or not + * to perform a specific but optional computation. A uniform algorithm-specific + * naming scheme for each parameter is desirable but left unspecified at this + * time. + * + * @param param the string name of the parameter. + * @return the object that represents the parameter value, or null + * if there is none. + * @throws InvalidParameterException if param is an invalid + * parameter for this engine, or another exception occurs while trying to get + * this parameter. + * @deprecated + */ + protected abstract Object engineGetParameter(String param) + throws InvalidParameterException; + + /** + * Returns a clone if the implementation is cloneable. + * + * @return a clone if the implementation is cloneable. + * @throws CloneNotSupportedException if this is called on an implementation + * that does not support {@link Cloneable}. + * @see Cloneable + */ + public Object clone() throws CloneNotSupportedException + { + return super.clone(); + } +} diff --git a/libjava/classpath/java/security/SignedObject.java b/libjava/classpath/java/security/SignedObject.java new file mode 100644 index 0000000..d565b2e --- /dev/null +++ b/libjava/classpath/java/security/SignedObject.java @@ -0,0 +1,240 @@ +/* SignedObject.java --- Signed Object Class + 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 java.security; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + *

    SignedObject is a class for the purpose of creating authentic + * runtime objects whose integrity cannot be compromised without being detected. + *

    + * + *

    More specifically, a SignedObject contains another + * {@link Serializable} object, the (to-be-)signed object and its signature.

    + * + *

    The signed object is a "deep copy" (in serialized form) of an + * original object. Once the copy is made, further manipulation of the original + * object has no side effect on the copy.

    + * + *

    The underlying signing algorithm is designated by the {@link Signature} + * object passed to the constructor and the verify() method. A + * typical usage for signing is the following:

    + * + *
    + * Signature signingEngine = Signature.getInstance(algorithm, provider);
    + * SignedObject so = new SignedObject(myobject, signingKey, signingEngine);
    + * 
    + * + *

    A typical usage for verification is the following (having received + * SignedObject so):

    + * + *
    + * Signature verificationEngine = Signature.getInstance(algorithm, provider);
    + * if (so.verify(publickey, verificationEngine))
    + *   try
    + *     {
    + *       Object myobj = so.getObject();
    + *     }
    + *   catch (ClassNotFoundException ignored) {};
    + * 
    + * + *

    Several points are worth noting. First, there is no need to initialize the + * signing or verification engine, as it will be re-initialized inside the + * constructor and the verify() method. Secondly, for verification + * to succeed, the specified public key must be the public key corresponding to + * the private key used to generate the SignedObject.

    + * + *

    More importantly, for flexibility reasons, the constructor + * and verify() method allow for customized signature engines, + * which can implement signature algorithms that are not installed formally as + * part of a crypto provider. However, it is crucial that the programmer writing + * the verifier code be aware what {@link Signature} engine is being used, as + * its own implementation of the verify() method is invoked to + * verify a signature. In other words, a malicious {@link Signature} may choose + * to always return true on verification in an attempt to bypass a + * security check.

    + * + *

    The signature algorithm can be, among others, the NIST standard DSS, + * using DSA and SHA-1. The algorithm is specified using the same + * convention as that for signatures. The DSA algorithm using the + * SHA-1 message digest algorithm can be specified, for example, as + * "SHA/DSA" or "SHA-1/DSA" (they are equivalent). In + * the case of RSA, there are multiple choices for the message digest + * algorithm, so the signing algorithm could be specified as, for example, + * "MD2/RSA", "MD5/RSA" or "SHA-1/RSA". + * The algorithm name must be specified, as there is no default.

    + * + *

    The name of the Cryptography Package Provider is designated also by the + * {@link Signature} parameter to the constructor and the + * verify() method. If the provider is not specified, the default + * provider is used. Each installation can be configured to use a particular + * provider as default.

    + * + *

    Potential applications of SignedObject include:

    + * + *
      + *
    • It can be used internally to any Java runtime as an unforgeable + * authorization token -- one that can be passed around without the fear that + * the token can be maliciously modified without being detected.
    • + *
    • It can be used to sign and serialize data/object for storage outside the + * Java runtime (e.g., storing critical access control data on disk).
    • + *
    • Nested SignedObjects can be used to construct a logical sequence + * of signatures, resembling a chain of authorization and delegation.
    • + *
    + * + * @author Mark Benvenuto (ivymccough@worldnet.att.net) + * @since 1.2 + * @see Signature + */ +public final class SignedObject implements Serializable +{ + private static final long serialVersionUID = 720502720485447167L; + + /** @serial */ + private byte[] content; + /** @serial */ + private byte[] signature; + /** @serial */ + private String thealgorithm; + + /** + * Constructs a SignedObject from any {@link Serializable} + * object. The given object is signed with the given signing key, using the + * designated signature engine. + * + * @param object the object to be signed. + * @param signingKey the private key for signing. + * @param signingEngine the signature signing engine. + * @throws IOException if an error occurs during serialization. + * @throws InvalidKeyException if the key is invalid. + * @throws SignatureException if signing fails. + */ + public SignedObject(Serializable object, PrivateKey signingKey, + Signature signingEngine) + throws IOException, InvalidKeyException, SignatureException + { + thealgorithm = signingEngine.getAlgorithm(); + + ByteArrayOutputStream ostream = new ByteArrayOutputStream(); + ObjectOutputStream p = new ObjectOutputStream(ostream); + p.writeObject(object); + p.flush(); + p.close(); + + content = ostream.toByteArray(); + + signingEngine.initSign(signingKey); + signingEngine.update(content); + signature = signingEngine.sign(); + } + + /** + * Retrieves the encapsulated object. The encapsulated object is de-serialized + * before it is returned. + * + * @return the encapsulated object. + * @throws IOException if an error occurs during de-serialization. + * @throws ClassNotFoundException if an error occurs during de-serialization. + */ + public Object getObject() throws IOException, ClassNotFoundException + { + ByteArrayInputStream bais = new ByteArrayInputStream(content); + ObjectInput oi = new ObjectInputStream(bais); + Object obj = oi.readObject(); + oi.close(); + bais.close(); + + return obj; + } + + /** + * Retrieves the signature on the signed object, in the form of a byte array. + * + * @return a copy of the signature. + */ + public byte[] getSignature() + { + return (byte[]) signature.clone(); + + } + + /** + * Retrieves the name of the signature algorithm. + * + * @return the signature algorithm name. + */ + public String getAlgorithm() + { + return thealgorithm; + } + + /** + * Verifies that the signature in this SignedObject is the valid + * signature for the object stored inside, with the given verification key, + * using the designated verification engine. + * + * @param verificationKey the public key for verification. + * @param verificationEngine the signature verification engine. + * @return true if the signature is valid, false + * otherwise. + * @throws SignatureException if signature verification failed. + * @throws InvalidKeyException if the verification key is invalid. + */ + public boolean verify(PublicKey verificationKey, Signature verificationEngine) + throws InvalidKeyException, SignatureException + { + verificationEngine.initVerify(verificationKey); + verificationEngine.update(content); + return verificationEngine.verify(signature); + } + + /** Called to restore the state of the SignedObject from a stream. */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + content = (byte[]) content.clone(); + signature = (byte[]) signature.clone(); + } +} diff --git a/libjava/classpath/java/security/Signer.java b/libjava/classpath/java/security/Signer.java new file mode 100644 index 0000000..ae1463d --- /dev/null +++ b/libjava/classpath/java/security/Signer.java @@ -0,0 +1,164 @@ +/* Signer.java --- Signer Class + 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 java.security; + +/** + *

    This class is used to represent an {@link Identity} that can also + * digitally sign data.

    + * + *

    The management of a signer's private keys is an important and sensitive + * issue that should be handled by subclasses as appropriate to their intended + * use.

    + * + * @author Mark Benvenuto (ivymccough@worldnet.att.net) + * @deprecated This class is no longer used. Its functionality has been replaced + * by java.security.KeyStore, the java.security.cert + * package, and java.security.Principal. + */ +public abstract class Signer extends Identity +{ + private static final long serialVersionUID = -1763464102261361480L; + private PrivateKey privateKey = null; + + /** + * Creates a Signer. This constructor should only be used for + * serialization. + */ + protected Signer() + { + } + + /** + * Creates a Signer with the specified identity name. + * + * @param name the identity name. + */ + public Signer(String name) + { + super(name); + } + + /** + * Creates a Signer with the specified identity name and scope. + * + * @param name the identity name. + * @param scope the scope of the identity. + * @throws KeyManagementException if there is already an identity with the + * same name in the scope. + */ + public Signer(String name, IdentityScope scope) throws KeyManagementException + { + super(name, scope); + } + + /** + *

    Returns this signer's private key.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with "getSignerPrivateKey" as its + * argument to see if it's ok to return the private key.

    + * + * @return this signer's private key, or null if the private key + * has not yet been set. + * @throws SecurityException if a security manager exists and its + * checkSecurityAccess() method doesn't allow returning the + * private key. + * @see SecurityManager#checkSecurityAccess(String) + */ + public PrivateKey getPrivateKey() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("getSignerPrivateKey"); + + return privateKey; + } + + /** + *

    Sets the key pair (public key and private key) for this signer.

    + * + *

    First, if there is a security manager, its checkSecurityAccess() + * method is called with "setSignerKeyPair" as its + * argument to see if it's ok to set the key pair.

    + * + * @param pair an initialized key pair. + * @throws InvalidParameterException if the key pair is not properly + * initialized. + * @throws KeyException if the key pair cannot be set for any other reason. + * @throws SecurityException if a security manager exists and its + * checkSecurityAccess() method doesn't allow setting the key + * pair. + * @see SecurityManager#checkSecurityAccess(String) + */ + public final void setKeyPair(KeyPair pair) + throws InvalidParameterException, KeyException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("setSignerKeyPair"); + + try + { + if (pair.getPublic() != null) + setPublicKey(pair.getPublic()); + else + throw new InvalidParameterException(); + + } + catch (KeyManagementException kme) + { + throw new KeyException(); + } + + if (pair.getPrivate() != null) + privateKey = pair.getPrivate(); + else + throw new InvalidParameterException(); + } + + /** + * Returns a string of information about the signer. + * + * @return a string of information about the signer. + * @see SecurityManager#checkSecurityAccess(String) + */ + public String toString() + { + return (getName() + ": " + privateKey); + } +} diff --git a/libjava/classpath/java/security/UnrecoverableKeyException.java b/libjava/classpath/java/security/UnrecoverableKeyException.java new file mode 100644 index 0000000..6759c3c --- /dev/null +++ b/libjava/classpath/java/security/UnrecoverableKeyException.java @@ -0,0 +1,71 @@ +/* UnrecoverableKeyException.java -- Cannot recover a key from the key store + Copyright (C) 1998, 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 java.security; + +/** + * This exception is thrown when a key cannot be recovered from the key + * store. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.2 + * @status updated to 1.4 + */ +public class UnrecoverableKeyException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 7275063078190151277L; + + /** + * Create an instance with no descriptive error message. + */ + public UnrecoverableKeyException() + { + } + + /** + * Create an instance with a descriptive error message. + * + * @param msg the descriptive error message + */ + public UnrecoverableKeyException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/UnresolvedPermission.java b/libjava/classpath/java/security/UnresolvedPermission.java new file mode 100644 index 0000000..d3f671a --- /dev/null +++ b/libjava/classpath/java/security/UnresolvedPermission.java @@ -0,0 +1,304 @@ +/* UnresolvedPermission.java -- Placeholder for unresolved permissions + Copyright (C) 1998, 2001, 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 java.security; + +// All uses of Certificate in this file refer to the one in the listed +// package, not this one. +import java.security.cert.Certificate; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.NoSuchElementException; +import java.util.Vector; + +/** + * This class is used to hold instances of all permissions that cannot + * be resolved to available permission classes when the security + * Policy object is instantiated. This may happen when the + * necessary security class has not yet been downloaded from the network. + * + *

    Instances of this class are re-resolved when + * AccessController check is done. At that time, a scan is + * made of all existing UnresolvedPermission objects and they + * are converted to objects of the appropriate permission type if the class + * for that type is then available. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Permission + * @see Permissions + * @see PermissionCollection + * @see Policy + * @since 1.1 + * @status updated to 1.4 + */ +public final class UnresolvedPermission extends Permission +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -4821973115467008846L; + + /** + * The list of actions associated with this permission object. + * + * @serial the permission actions + */ + private final String actions; + + /** + * The list of Certificates associated with this object. + */ + private final transient Certificate[] certs; + + /** + * The name of the class this object should be resolved to. + * + * @serial the fully-qualified classname of the resolved type + */ + // Package visible for use by UnresolvedPermissionCollection. + final String type; + + /** + * The name of the permission. + * + * @serial the permission name + */ + private final String name; + + /** + * Create a new instance with all the information necessary to resolve it + * to an instance of the proper class at a future time. + * + * @param type the fully-qualified name of the class of this permission + * @param name the name of this permission + * @param actions the action list for this permission + * @param certs the list of certificates that sign this permission + */ + public UnresolvedPermission(String type, String name, String actions, + Certificate[] certs) + { + super(name); + this.name = name; + this.type = type; + this.actions = actions; + this.certs = certs; + } + + /** + * This method returns false always to indicate that this + * permission does not imply the specified permission. An + * UnresolvedPermission never grants any permissions. + * + * @param perm the Permission object to test + * @return false; until a permission is resolved, it implies nothing + */ + public boolean implies(Permission perm) + { + return false; + } + + /** + * This method tests this permission for equality against the specified + * Object. This will be true if and only if the following + * conditions are met:

      + *
    • The specified Object is an UnresolvedPermission
    • + *
    • The specified permission has the same type (i.e., desired class name) + * as this permission.
    • + *
    • The specified permission has the same name as this one.
    • + *
    • The specified permissoin has the same action list as this one.
    • + *
    • The specified permission has the same certificate list as this + * one.
    • + *
    + * + * @param obj the Object to test for equality + * @return true if the specified object is equal to this one + */ + public boolean equals(Object obj) + { + if (! (obj instanceof UnresolvedPermission)) + return (false); + UnresolvedPermission up = (UnresolvedPermission) obj; + return up.name.equals(name) && up.actions.equals(actions) + && up.type.equals(type) && Arrays.equals(up.certs, certs); + } + + /** + * Returns a hash code value for this object. Following the lead of + * Permission, this returns the hashcode of the permission name. + * + * @return A hash value + */ + public int hashCode() + { + return name.hashCode(); + } + + /** + * This method returns the list of actions associated with this + * permission. + * + * @return the action list + */ + public String getActions() + { + return actions; + } + + /** + * This method returns a String representation of this + * class. The format is: '(unresolved "ClassName "name" "actions")' + * + * @return String representation of this object + */ + public String toString() + { + return "(unresolved " + type + ' ' + name + ' ' + actions + ')'; + } + + /** + * This class returns a PermissionCollection object that can + * be used to store instances of UnresolvedPermission. + * + * @return a new PermissionCollection + */ + public PermissionCollection newPermissionCollection() + { + return new UnresolvedPermissionCollection(); + } +} // class UnresolvedPermission + +/** + * Implements the permission collection for unresolved permissions, and + * obeys serialization of JDK. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ +class UnresolvedPermissionCollection extends PermissionCollection +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -7176153071733132400L; + + // Package-private to avoid a trampoline. + /** + * Hashtable where we store permissions. + * + * @serial map of typename to a Vector of permissions (you'd think Sun + * would document this better!) + */ + final Hashtable permissions = new Hashtable(); + + /** + * Add a permission. + * + * @param perm the permission to add + * @throws IllegalArgumentException if perm is not an UnresolvedPermission + * @throws SecurityException if the collection is read-only + */ + public void add(Permission perm) + { + if (isReadOnly()) + throw new SecurityException(); + if (! (perm instanceof UnresolvedPermission)) + throw new IllegalArgumentException(); + UnresolvedPermission up = (UnresolvedPermission) perm; + Vector v = (Vector) permissions.get(up.type); + if (v == null) + { + v = new Vector(); + permissions.put(up.type, v); + } + v.add(up); + } + + /** + * Returns true if perm is implied by the collection. + * + * @param perm the permission to check + * @return false; unresolved permissions imply nothing + */ + public boolean implies(Permission perm) + { + return false; + } + + /** + * Return the elements. + * + * @return the elements + */ + public Enumeration elements() + { + return new Enumeration() + { + Enumeration main_enum = permissions.elements(); + Enumeration sub_enum; + + public boolean hasMoreElements() + { + if (sub_enum == null) + { + if (main_enum == null) + return false; + if (! main_enum.hasMoreElements()) + { + main_enum = null; + return false; + } + Vector v = (Vector) main_enum.nextElement(); + sub_enum = v.elements(); + } + if (! sub_enum.hasMoreElements()) + { + sub_enum = null; + return hasMoreElements(); + } + return true; + } + + public Object nextElement() + { + if (! hasMoreElements()) + throw new NoSuchElementException(); + return sub_enum.nextElement(); + } + }; + } +} // class UnresolvedPermissionCollection diff --git a/libjava/classpath/java/security/acl/Acl.java b/libjava/classpath/java/security/acl/Acl.java new file mode 100644 index 0000000..ff139af --- /dev/null +++ b/libjava/classpath/java/security/acl/Acl.java @@ -0,0 +1,153 @@ +/* Acl.java -- An access control list + 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 java.security.acl; + +import java.security.Principal; +import java.util.Enumeration; + +/** + * A Java access control list (ACL) is a group of individual ACL entries. + * These entries consist of a Principal and a list of + * permissions this Principal is either granted or denied. + * A given Principal can have at most one positive ACL entry + * (i.e., one that grants permissions) and one negative ACL entry (i.e., one + * that denies permissions). If a given permission is both granted and + * denied, the ACL treats it as if it were never granted or denied. If + * both a Principal and a Group to which the + * Principal belongs have an ACL entry, the permissions for + * the individual Principal take precedence over the + * permissions of the Group if there is a conflict. + *

    + * Additionally, the ACL interface extends the Owner interface + * and so an ACL has owners. Actions which modify the ACL are restricted + * to owners. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Acl extends Owner +{ + + /** + * This method returns the name of this ACL. + * + * @return The name of this ACL + */ + String getName(); + + /** + * This method sets the name of the ACL + * + * @param caller The Principal requesting the action. + * @param name The new name for this ACL. + * + * @exception NotOwnerException If the caller is not an owner of this ACL. + */ + void setName(Principal caller, String name) + throws NotOwnerException; + + /** + * This method adds the specified entry to the ACL + * + * @param caller The Principal requesting the addition + * @param entry The ACL entry to add + * + * @return true if the entry was added, false + * if there is already an entry of the same type for the + * Principal. + * + * @exception NotOwnerException If the caller is not an owner of this ACL. + */ + boolean addEntry(Principal caller, AclEntry entry) + throws NotOwnerException; + + /** + * This method delets the specified entry from the ACL + * + * @param caller The Principal requesting the deletion. + * @param entry The ACL entry to delete + * + * @return true if the entry was deleted, or false + * if this entry was not part of the ACL to begin with + * + * @exception NotOwnerException If the caller is not an owner of this ACL. + */ + boolean removeEntry(Principal caller, AclEntry entry) + throws NotOwnerException; + + /** + * This method returns a list of all the entries in the ACL as an + * Enumeration. + * + * @return An enumeration of the ACL entries + */ + Enumeration entries(); + + /** + * This method tests whether or not the specified Principal + * has the specified Permission + * + * @param user The Principal to test + * @param perm The Permission to test for + * + * @return true if the user has been granted the permission, + * false otherwise + */ + boolean checkPermission(Principal user, Permission perm); + + /** + * This method returns a list of Permission's that are granted + * to a particular Principal. This includes any permissions + * that are granted to Group's to which the Principal + * belongs unless they are overridden by a negative ACL. This permission + * list is returned as an Enumeration. + * + * @param user The Principal to retrieve permissions for. + * + * @return A list of permissions for the Principal. + */ + Enumeration getPermissions(Principal user); + + /** + * This method returns the ACL as a String + * + * @return A String representation of this ACL + */ + String toString(); +} diff --git a/libjava/classpath/java/security/acl/AclEntry.java b/libjava/classpath/java/security/acl/AclEntry.java new file mode 100644 index 0000000..7b1bcf5 --- /dev/null +++ b/libjava/classpath/java/security/acl/AclEntry.java @@ -0,0 +1,143 @@ +/* AclEntry.java -- An entry in an ACL list. + 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 java.security.acl; + +import java.security.Principal; +import java.util.Enumeration; + +/** + * This interface models an entry in an access control list (ACL). Java + * ACL's consist of a list of entries, where each consists of a + * Principal and a list of Permission's which + * have been granted to that Principal. An ACL can also + * be negative, which indicates that the list of + * Permission's is a list of permissions that are not + * granted to the Principal. A Principal can + * have at most one regular (or positive) ACL entry and one negative + * ACL entry. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface AclEntry extends Cloneable +{ + /** + * This method returns the Principal associated with this + * ACL entry. + * + * @return The Principal for this ACL entry + */ + Principal getPrincipal(); + + /** + * This method sets ths Principal associated with this + * ACL entry. This operation will only succeed if there is not already + * a Principal assigned. + * + * @param user The Principal for this ACL entry + * + * @return true if the Principal was successfully set or false if this entry already has a Principal. + */ + boolean setPrincipal(Principal user); + + /** + * This method sets this ACL entry to be a negative entry, indicating + * that it contains a list of permissions that are not granted + * to the entry's Principal. Note that there is no way to + * undo this operation. + */ + void setNegativePermissions(); + + /** + * This method tests whether or not this ACL entry is a negative entry or not. + * + * @return true if this ACL entry is negative, false otherwise + */ + boolean isNegative(); + + /** + * This method adds the specified permission to this ACL entry. + * + * @param perm The Permission to add + * + * @return true if the permission was added or false if it was already set for this entry + */ + boolean addPermission(Permission permission); + + /** + * This method deletes the specified permission to this ACL entry. + * + * @param perm The Permission to delete from this ACL entry. + * + * @return true if the permission was successfully deleted or false if the permission was not part of this ACL to begin with + */ + boolean removePermission(Permission perm); + + /** + * This method tests whether or not the specified permission is associated + * with this ACL entry. + * + * @param perm The Permission to test + * + * @return true if this permission is associated with this entry or false otherwise + */ + boolean checkPermission(Permission permission); + + /** + * This method returns a list of all Permission objects + * associated with this ACL entry as an Enumeration. + * + * @return A list of permissions for this ACL entry + */ + Enumeration permissions(); + + /** + * This method returns this object as a String. + * + * @return A String representation of this object + */ + String toString(); + + /** + * This method returns a clone of this ACL entry + * + * @return A clone of this ACL entry + */ + Object clone(); +} diff --git a/libjava/classpath/java/security/acl/AclNotFoundException.java b/libjava/classpath/java/security/acl/AclNotFoundException.java new file mode 100644 index 0000000..9a16d9c --- /dev/null +++ b/libjava/classpath/java/security/acl/AclNotFoundException.java @@ -0,0 +1,60 @@ +/* AclNotFoundException.java -- thrown when an ACL is not found + Copyright (C) 1998, 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 java.security.acl; + +/** + * This exception is thrown when a requested access control list (ACL) is + * not found. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class AclNotFoundException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5684295034092681791L; + + /** + * Initializes a new instance of this class with no descriptive message + */ + public AclNotFoundException() + { + } +} diff --git a/libjava/classpath/java/security/acl/Group.java b/libjava/classpath/java/security/acl/Group.java new file mode 100644 index 0000000..3ffdf15 --- /dev/null +++ b/libjava/classpath/java/security/acl/Group.java @@ -0,0 +1,90 @@ +/* Group.java -- Represents a group of Principals + Copyright (C) 1998, 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 java.security.acl; + +import java.security.Principal; +import java.util.Enumeration; + +/** + * This interface represents a group of Principals. Note that + * since this interface extends Principal, a Group + * can be used where ever a Principal is requested. This + * includes arguments to the methods in this interface. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Group extends Principal +{ + /** + * This method adds a new Principal to this group. + * + * @param user The new Principal to add + * + * @return true if the user was successfully added or false if the user is already a member + */ + boolean addMember(Principal user); + + /** + * This method deletes a member from the group. + * + * @param user The Principal to delete + * + * @return true if the user was successfully deleted or false if the user is not a member of the group + */ + boolean removeMember(Principal user); + + /** + * This method tests whether or not a given Principal is a + * member of this group. + * + * @param user The Principal to test for membership + * + * @return true if the user is member, false otherwise + */ + boolean isMember(Principal member); + + /** + * This method returns a list of all members of the group as an + * Enumeration. + * + * @return The list of all members of the group + */ + Enumeration members(); +} diff --git a/libjava/classpath/java/security/acl/LastOwnerException.java b/libjava/classpath/java/security/acl/LastOwnerException.java new file mode 100644 index 0000000..9527244 --- /dev/null +++ b/libjava/classpath/java/security/acl/LastOwnerException.java @@ -0,0 +1,62 @@ +/* LastOwnerException.java -- User attempted to delete last ACL owner + Copyright (C) 1998, 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 java.security.acl; + +/** + * This exception is thrown when an attempt is made to delete the last owner + * of an access control list (ACL) + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Owner#deleteOwner(java.security.Principal, java.security.Principal) + * @status updated to 1.4 + */ +public class LastOwnerException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -5141997548211140359L; + + /** + * Initialize a new instance of LastOwnerException that does + * not have a log message. + */ + public LastOwnerException() + { + } +} diff --git a/libjava/classpath/java/security/acl/NotOwnerException.java b/libjava/classpath/java/security/acl/NotOwnerException.java new file mode 100644 index 0000000..bea9476 --- /dev/null +++ b/libjava/classpath/java/security/acl/NotOwnerException.java @@ -0,0 +1,62 @@ +/* NotOwnerException.java -- Attempt to modify an unowned ACL + Copyright (C) 1998, 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 java.security.acl; + +/** + * This exception is thrown whenever an operation is attempted that requires + * the caller to be the owner of the access control list (ACL) when the caller + * is in fact not the owner of the ACL. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class NotOwnerException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -5555597911163362399L; + + /** + * Initializes a new instance of NotOwnerException that does + * not have a descriptive message. + */ + public NotOwnerException() + { + } +} diff --git a/libjava/classpath/java/security/acl/Owner.java b/libjava/classpath/java/security/acl/Owner.java new file mode 100644 index 0000000..df1605b --- /dev/null +++ b/libjava/classpath/java/security/acl/Owner.java @@ -0,0 +1,95 @@ +/* Owner.java -- ACL owner + 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 java.security.acl; + +import java.security.Principal; + +/** + * This interface provides a mechanism for maintaining a list of owners + * of an access control list (ACL). Since a Principal must + * be an owner in order to modify the owner list, a mechanism must be + * provided to specify the initial owner of the ACL. The proper way to do + * this is for the implementing class to specify the initial owner in + * the contructor for that class. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Owner +{ + /** + * This method adds an owner to the access control list (ACL). Only a + * Principal who is already an owner can perform this operation. + * + * @param caller The Principal who is requesting that an owner be added + * @param owner The Principal to add as a new owner + * + * @param true if the new owner was successfully added or false if the specified new owner is already an owner + * + * @exception NotOwnerException If the caller is not already an owner of this ACL + */ + boolean addOwner(Principal caller, Principal owner) + throws NotOwnerException; + + /** + * This method delets an owner from the access control list (ACL). Only a + * Principal who is an owner can perform this operation. An + * owner can delete itself from the list. If there is only one + * owner remaining on this list, any attempt to delete it will throw an + * exception. + * + * @param caller The Principal who is requesting that an owner be deleted + * @param owner The Principal to delete as an owner + * + * @param true if the new owner was successfully deleted or false if the specified owner is not currently an owner + * + * @exception NotOwnerException If the caller is not already an owner of this ACL + * @exception LastOwnerException If completing the operation would delete the last ACL owner + */ + boolean deleteOwner(Principal caller, Principal owner) + throws NotOwnerException, LastOwnerException; + + /** + * This method tests whether or not a given Principal is an + * owner of this access control list (ACL). + * + * @return true if the Principal is an owner, false otherwise + */ + boolean isOwner(Principal owner); +} diff --git a/libjava/classpath/java/security/acl/Permission.java b/libjava/classpath/java/security/acl/Permission.java new file mode 100644 index 0000000..e5ba291 --- /dev/null +++ b/libjava/classpath/java/security/acl/Permission.java @@ -0,0 +1,67 @@ +/* Permission.java -- Information about an ACL permission + 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 java.security.acl; + +/** + * This interface provides information about a permission that can be + * granted. Note that this is not the same as the class + * java.security.Permission. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Permission +{ + /** + * This method tests whether or not a specified Permission + * (passed as an Object) is the same as this permission. + * + * @param perm The permission to check for equality + * + * @return true if the specified permission is the same as this one, false otherwise + */ + boolean equals (Object perm); + + /** + * This method returns this Permission as a String. + * + * @return A String representing this permission. + */ + String toString(); +} diff --git a/libjava/classpath/java/security/acl/package.html b/libjava/classpath/java/security/acl/package.html new file mode 100644 index 0000000..19facf1 --- /dev/null +++ b/libjava/classpath/java/security/acl/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.security.acl + + +

    + + + diff --git a/libjava/classpath/java/security/cert/CRL.java b/libjava/classpath/java/security/cert/CRL.java new file mode 100644 index 0000000..e763663 --- /dev/null +++ b/libjava/classpath/java/security/cert/CRL.java @@ -0,0 +1,98 @@ +/* CRL.java --- Certificate Revocation List + Copyright (C) 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 java.security.cert; + +/** + Certificate Revocation List class for managing CRLs that + have different formats but the same general use. They + all serve as lists of revoked certificates and can + be queried for a given certificate. + + Specialized CRLs extend this class. + + @author Mark Benvenuto + + @since JDK 1.2 +*/ +public abstract class CRL +{ + + private String type; + + /** + Creates a new CRL for the specified type. An example + is "X.509". + + @param type the standard name for the CRL type. + */ + protected CRL(String type) + { + this.type = type; + } + + /** + Returns the CRL type. + + @return a string representing the CRL type + */ + public final String getType() + { + return type; + } + + /** + Returns a string representing the CRL. + + @return a string representing the CRL. + */ + public abstract String toString(); + + /** + Determines whether or not the specified Certificate + is revoked. + + @param cert A certificate to check if it is revoked + + @return true if the certificate is revoked, + false otherwise. + */ + public abstract boolean isRevoked(Certificate cert); + + +} diff --git a/libjava/classpath/java/security/cert/CRLException.java b/libjava/classpath/java/security/cert/CRLException.java new file mode 100644 index 0000000..f3addfe --- /dev/null +++ b/libjava/classpath/java/security/cert/CRLException.java @@ -0,0 +1,73 @@ +/* CRLException.java -- Certificate Revocation List Exception + Copyright (C) 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 java.security.cert; + +import java.security.GeneralSecurityException; + +/** + * Exception for a Certificate Revocation List. + * + * @author Mark Benvenuto + * @since 1.2 + * @status updated to 1.4 +*/ +public class CRLException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -6694728944094197147L; + + /** + * Constructs an CRLExceptionwithout a message string. + */ + public CRLException() + { + } + + /** + * Constructs an CRLException with a message string. + * + * @param msg a message to display with exception + */ + public CRLException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/cert/CRLSelector.java b/libjava/classpath/java/security/cert/CRLSelector.java new file mode 100644 index 0000000..1fa5a20 --- /dev/null +++ b/libjava/classpath/java/security/cert/CRLSelector.java @@ -0,0 +1,69 @@ +/* CRLSelector.java -- matches CRLs against criteria. + 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 java.security.cert; + +/** + * A generic interface to classes that match certificate revocation + * lists (CRLs) to some given criteria. Implementations of this + * interface are useful for finding {@link CRL} objects in a {@link + * CertStore}. + * + * @see CertStore + * @see CertSelector + * @see X509CRLSelector + */ +public interface CRLSelector extends Cloneable +{ + + /** + * Returns a clone of this instance. + * + * @return The clone. + */ + Object clone(); + + /** + * Match a given certificate revocation list to this selector's + * criteria, returning true if it matches, false otherwise. + * + * @param crl The certificate revocation list to test. + * @return The boolean result of this test. + */ + boolean match(CRL crl); +} diff --git a/libjava/classpath/java/security/cert/CertPath.java b/libjava/classpath/java/security/cert/CertPath.java new file mode 100644 index 0000000..e818763 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPath.java @@ -0,0 +1,252 @@ +/* CertPath.java -- a sequence of certificates + 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 java.security.cert; + +import java.io.ByteArrayInputStream; +import java.io.NotSerializableException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.util.Iterator; +import java.util.List; + +/** + * This class represents an immutable sequence, or path, of security + * certificates. The path type must match the type of each certificate in the + * path, or in other words, for all instances of cert in a certpath object, + * cert.getType().equals(certpath.getType()) will return true. + * + *

    Since this class is immutable, it is thread-safe. During serialization, + * the path is consolidated into a {@link CertPathRep}, which preserves the + * data regardless of the underlying implementation of the path. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class CertPath implements Serializable +{ + /** + * The serialized representation of a path. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + protected static class CertPathRep implements Serializable + { + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 3015633072427920915L; + + /** + * The certificate type. + * + * @serial the type of the certificate path + */ + private final String type; + + /** + * The encoded form of the path. + * + * @serial the encoded form + */ + private final byte[] data; + + /** + * Create the new serial representation. + * + * @param type the path type + * @param data the encoded path data + */ + protected CertPathRep(String type, byte[] data) + { + this.type = type; + this.data = data; + } + + /** + * Decode the data into an actual {@link CertPath} upon deserialization. + * + * @return the replacement object + * @throws ObjectStreamException if replacement fails + */ + protected Object readResolve() throws ObjectStreamException + { + try + { + return CertificateFactory.getInstance(type) + .generateCertPath(new ByteArrayInputStream(data)); + } + catch (CertificateException e) + { + throw (ObjectStreamException) + new NotSerializableException("java.security.cert.CertPath: " + + type).initCause(e); + } + } + } // class CertPathRep + + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 6068470306649138683L; + + /** + * The path type. + * + * @serial the type of all certificates in this path + */ + private final String type; + + /** + * Create a certificate path with the given type. Most code should use + * {@link CertificateFactory} to create CertPaths. + * + * @param type the type of the path + */ + protected CertPath(String type) + { + this.type = type; + } + + /** + * Get the (non-null) type of all certificates in the path. + * + * @return the path certificate type + */ + public String getType() + { + return type; + } + + /** + * Get an immutable iterator over the path encodings (all String names), + * starting with the default encoding. The iterator will throw an + * UnsupportedOperationException if an attempt is made to + * remove items from the list. + * + * @return the iterator of supported encodings in the path + */ + public abstract Iterator getEncodings(); + + /** + * Compares this path to another for semantic equality. To be equal, both + * must be instances of CertPath, with the same type, and identical + * certificate lists. Overriding classes must not change this behavior. + * + * @param o the object to compare to + * @return true if the two are equal + */ + public boolean equals(Object o) + { + if (! (o instanceof CertPath)) + return false; + CertPath cp = (CertPath) o; + return type.equals(cp.type) + && getCertificates().equals(cp.getCertificates()); + } + + /** + * Returns the hashcode of this certificate path. This is defined as:
    + * 31 * getType().hashCode() + getCertificates().hashCode(). + * + * @return the hashcode + */ + public int hashCode() + { + return 31 * type.hashCode() + getCertificates().hashCode(); + } + + public String toString() + { + List l = getCertificates(); + int size = l.size(); + int i = 0; + StringBuffer result = new StringBuffer(type); + result.append(" Cert Path: length = ").append(size).append(".\n[\n"); + while (--size >= 0) + result.append(l.get(i++)).append('\n'); + return result.append("\n]").toString(); + } + + /** + * Returns the encoded form of this path, via the default encoding. + * + * @return the encoded form + * @throws CertificateEncodingException if encoding fails + */ + public abstract byte[] getEncoded() throws CertificateEncodingException; + + /** + * Returns the encoded form of this path, via the specified encoding. + * + * @param encoding the encoding to use + * @return the encoded form + * @throws CertificateEncodingException if encoding fails or does not exist + */ + public abstract byte[] getEncoded(String encoding) + throws CertificateEncodingException; + + /** + * Returns the immutable, thread-safe list of certificates in this path. + * + * @return the list of certificates, non-null but possibly empty + */ + public abstract List getCertificates(); + + /** + * Serializes the path in its encoded form, to ensure reserialization with + * the appropriate factory object without worrying about list implementation. + * The result will always be an instance of {@link CertPathRep}. + * + * @return the replacement object + * @throws ObjectStreamException if the replacement creation fails + */ + protected Object writeReplace() throws ObjectStreamException + { + try + { + return new CertPathRep(type, getEncoded()); + } + catch (CertificateEncodingException e) + { + throw (ObjectStreamException) + new NotSerializableException("java.security.cert.CertPath: " + + type).initCause(e); + } + } +} // class CertPath diff --git a/libjava/classpath/java/security/cert/CertPathBuilder.java b/libjava/classpath/java/security/cert/CertPathBuilder.java new file mode 100644 index 0000000..f696520 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPathBuilder.java @@ -0,0 +1,238 @@ +/* CertPathBuilder.java -- bulids CertPath objects from Certificates. + 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 java.security.cert; + +import gnu.java.security.Engine; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +/** + * This class builds certificate paths (also called certificate chains), + * which can be used to establish trust for a particular certificate by + * building a path from a trusted certificate (a trust anchor) to the + * untrusted certificate. + * + * @see CertPath + */ +public class CertPathBuilder +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** Service name for CertPathBuilder. */ + private static final String CERT_PATH_BUILDER = "CertPathBuilder"; + + /** The underlying implementation. */ + private CertPathBuilderSpi cpbSpi; + + /** The provider of this implementation. */ + private Provider provider; + + /** The name of this implementation. */ + private String algorithm; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new CertPathBuilder. + * + * @param cpbSpi The underlying implementation. + * @param provider The provider of the implementation. + * @param algorithm This implementation's name. + */ + protected CertPathBuilder(CertPathBuilderSpi cpbSpi, Provider provider, + String algorithm) + { + this.cpbSpi = cpbSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + // Class methods. + // ------------------------------------------------------------------------ + + /** + * Get the default cert path builder type. + * + *

    This value can be set at run-time by the security property + * "certpathbuilder.type". If this property is not set, + * then the value returned is "PKIX". + * + * @return The default CertPathBuilder algorithm. + */ + public static final String getDefaultType() + { + String type = Security.getProperty("certpathbuilder.type"); + if (type == null) + type = "PKIX"; + return type; + } + + /** + * Get an instance of a named CertPathBuilder, from the first provider + * that implements it. + * + * @param algorithm The name of the CertPathBuilder to create. + * @return The new instance. + * @throws NoSuchAlgorithmException If no installed provider + * implements the named algorithm. + */ + public static CertPathBuilder getInstance(String algorithm) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(algorithm, p[i]); + } + catch (NoSuchAlgorithmException e) + { + // Ignored. + } + } + + throw new NoSuchAlgorithmException(algorithm); + } + + /** + * Get an instance of a named CertPathBuilder from the named + * provider. + * + * @param algorithm The name of the CertPathBuilder to create. + * @param provider The name of the provider from which to get the + * implementation. + * @return The new instance. + * @throws NoSuchAlgorithmException If no installed provider + * implements the named algorithm. + * @throws NoSuchProviderException If the named provider does not + * exist. + */ + public static CertPathBuilder getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + return getInstance(algorithm, p); + } + + /** + * Get an instance of a named CertPathBuilder from the specified + * provider. + * + * @param algorithm The name of the CertPathBuilder to create. + * @param provider The provider from which to get the implementation. + * @return The new instance. + * @throws NoSuchAlgorithmException If no installed provider + * implements the named algorithm. + * @throws IllegalArgumentException If provider in + * null. + */ + public static CertPathBuilder getInstance(String algorithm, Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("null provider"); + try + { + return new CertPathBuilder((CertPathBuilderSpi) + Engine.getInstance(CERT_PATH_BUILDER, algorithm, provider), + provider, algorithm); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new NoSuchAlgorithmException(algorithm); + } + catch (ClassCastException cce) + { + throw new NoSuchAlgorithmException(algorithm); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Return the name of this CertPathBuilder algorithm. + * + * @return The algorithm name. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Return the provider of this instance's implementation. + * + * @return The provider. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Builds a certificate path. The {@link CertPathParameters} parameter + * passed to this method is implementation-specific, but in general + * should contain some number of certificates and some number of + * trusted certificates (or "trust anchors"). + * + * @param params The parameters. + * @retrun The certificate path result. + * @throws CertPathBuilderException If the certificate path cannot be + * built. + * @throws InvalidAlgorithmParameterException If the implementation + * rejects the specified parameters. + */ + public final CertPathBuilderResult build(CertPathParameters params) + throws CertPathBuilderException, InvalidAlgorithmParameterException + { + return cpbSpi.engineBuild(params); + } +} diff --git a/libjava/classpath/java/security/cert/CertPathBuilderException.java b/libjava/classpath/java/security/cert/CertPathBuilderException.java new file mode 100644 index 0000000..9851510 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPathBuilderException.java @@ -0,0 +1,159 @@ +/* CertPathBuilderException.java -- wraps an exception during certificate + path building + 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 java.security.cert; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.GeneralSecurityException; + +/** + * Indicates a problem while using a CertPathBuilder, wrapping + * the lower exception. This class is not thread-safe. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see CertPathBuilder + * @since 1.4 + * @status updated to 1.4 +*/ +public class CertPathBuilderException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 5316471420178794402L; + + /** + * Create an exception without a message. The cause may be initialized. + */ + public CertPathBuilderException() + { + } + + /** + * Create an exception with a message. The cause may be initialized. + * + * @param msg a message to display with exception + */ + public CertPathBuilderException(String msg) + { + super(msg); + } + + /** + * Create an exception with a cause. The message will be + * cause == null ? null : cause.toString(). + * + * @param cause the cause + */ + public CertPathBuilderException(Throwable cause) + { + this(cause == null ? null : cause.toString(), cause); + } + + /** + * Create an exception with a cause and a message. + * + * @param msg the message + * @param cause the cause + */ + public CertPathBuilderException(String msg, Throwable cause) + { + super(msg); + initCause(cause); + } + + /** + * Get the detail message. + * + * @return the detail message + */ + public String getMessage() + { + return super.getMessage(); + } + + /** + * Get the cause, null if unknown. + * + * @return the cause + */ + public Throwable getCause() + { + return super.getCause(); + } + + /** + * Convert this to a string, including its cause. + * + * @return the string conversion + */ + public String toString() + { + return super.toString(); + } + + /** + * Print the stack trace to System.err. + */ + public void printStackTrace() + { + super.printStackTrace(); + } + + /** + * Print the stack trace to a stream. + * + * @param stream the stream + */ + public void printStackTrace(PrintStream stream) + { + super.printStackTrace(stream); + } + + /** + * Print the stack trace to a stream. + * + * @param stream the stream + */ + public void printStackTrace(PrintWriter stream) + { + super.printStackTrace(stream); + } +} diff --git a/libjava/classpath/java/security/cert/CertPathBuilderResult.java b/libjava/classpath/java/security/cert/CertPathBuilderResult.java new file mode 100644 index 0000000..737ba94 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPathBuilderResult.java @@ -0,0 +1,63 @@ +/* CertPathBuilderResult -- results from building cert paths. + 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 java.security.cert; + +/** + * A standard interface for the result of building a certificate path. + * All implementations of this class must provide a way to get the + * certificate path, but may also define additional methods for + * returning other result data generated by the certificate path + * builder. + */ +public interface CertPathBuilderResult extends Cloneable { + + /** + * Creates a copy of this builder result. + * + * @return The copy. + */ + Object clone(); + + /** + * Get the certificate path that was built. + * + * @retrn The certificate path. + */ + CertPath getCertPath(); +} diff --git a/libjava/classpath/java/security/cert/CertPathBuilderSpi.java b/libjava/classpath/java/security/cert/CertPathBuilderSpi.java new file mode 100644 index 0000000..afc7fc0 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPathBuilderSpi.java @@ -0,0 +1,74 @@ +/* CertPathBuilderSpi -- CertPathBuilder service provider interface. + 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 java.security.cert; + +/** + * The {@link CertPathBuilder} Service Provider Interface + * (SPI). + * + * @see CertPathBuilder + */ +public abstract class CertPathBuilderSpi { + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Creates a new CertPathBuilderSpi. + */ + public CertPathBuilderSpi() { + super(); + } + + // Abstract methods. + // ------------------------------------------------------------------------ + + /** + * Creates a certificate path from the specified parameters. + * + * @param params The parameters to use. + * @return The certificate path result. + * @throws CertPathBuilderException If the certificate path cannot be + * built. + * @throws java.security.InvalidAlgorithmParameterException If the + * implementation rejects the specified parameters. + */ + public abstract CertPathBuilderResult engineBuild(CertPathParameters params) + throws CertPathBuilderException, + java.security.InvalidAlgorithmParameterException; +} diff --git a/libjava/classpath/java/security/cert/CertPathParameters.java b/libjava/classpath/java/security/cert/CertPathParameters.java new file mode 100644 index 0000000..62a5cb6 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPathParameters.java @@ -0,0 +1,58 @@ +/* CertPathParameters.java -- parameters for CertPathBuilder. + 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 java.security.cert; + +/** + * Parameters for generating and validating certificate paths. This + * class does not define any methods (except a required cloneable + * interface) and is provided only to provide type safety for + * implementations. Concrete implementations implement this interface + * in accord with thier own needs. + * + * @see CertPathBuilder + * @see CertPathValidator + */ +public interface CertPathParameters extends Cloneable { + + /** + * Makes a copy of this CertPathParameters instance. + * + * @return The copy. + */ + Object clone(); +} diff --git a/libjava/classpath/java/security/cert/CertPathValidator.java b/libjava/classpath/java/security/cert/CertPathValidator.java new file mode 100644 index 0000000..5fed19e --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPathValidator.java @@ -0,0 +1,249 @@ +/* CertPathValidator -- validates certificate paths. + 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 java.security.cert; + +import gnu.java.security.Engine; + +import java.security.AccessController; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.security.Security; + +/** + * Generic interface to classes that validate certificate paths. + * + *

    Using this class is similar to all the provider-based security + * classes; the method of interest, {@link + * #validate(java.security.cert.CertPath,java.security.cert.CertPathParameters)}, + * which takes provider-specific implementations of {@link + * CertPathParameters}, and return provider-specific implementations of + * {@link CertPathValidatorResult}. + * + * @since JDK 1.4 + * @see CertPath + */ +public class CertPathValidator { + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** Service name for CertPathValidator. */ + private static final String CERT_PATH_VALIDATOR = "CertPathValidator"; + + /** The underlying implementation. */ + private final CertPathValidatorSpi validatorSpi; + + /** The provider of this implementation. */ + private final Provider provider; + + /** The algorithm's name. */ + private final String algorithm; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new CertPathValidator. + * + * @param validatorSpi The underlying implementation. + * @param provider The provider of the implementation. + * @param algorithm The algorithm name. + */ + protected CertPathValidator(CertPathValidatorSpi validatorSpi, + Provider provider, String algorithm) + { + this.validatorSpi = validatorSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + // Class methods. + // ------------------------------------------------------------------------ + + /** + * Returns the default validator type. + * + *

    This value may be set at run-time via the security property + * "certpathvalidator.type", or the value "PKIX" if this property is + * not set. + * + * @return The default validator type. + */ + public static synchronized String getDefaultType() { + String type = (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return Security.getProperty("certpathvalidator.type"); + } + } + ); + if (type == null) + type = "PKIX"; + return type; + } + + /** + * Get an instance of the given validator from the first provider that + * implements it. + * + * @param algorithm The name of the algorithm to get. + * @return The new instance. + * @throws NoSuchAlgorithmException If no installed provider + * implements the requested algorithm. + */ + public static CertPathValidator getInstance(String algorithm) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(algorithm, p[i]); + } + catch (NoSuchAlgorithmException e) + { + // Ignored. + } + } + throw new NoSuchAlgorithmException(algorithm); + } + + /** + * Get an instance of the given validator from the named provider. + * + * @param algorithm The name of the algorithm to get. + * @param provider The name of the provider from which to get the + * implementation. + * @return The new instance. + * @throws NoSuchAlgorithmException If the named provider does not + * implement the algorithm. + * @throws NoSuchProviderException If no provider named + * provider is installed. + */ + public static CertPathValidator getInstance(String algorithm, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + + return getInstance(algorithm, p); + } + + /** + * Get an instance of the given validator from the given provider. + * + * @param algorithm The name of the algorithm to get. + * @param provider The provider from which to get the implementation. + * @return The new instance. + * @throws NoSuchAlgorithmException If the provider does not implement + * the algorithm. + * @throws IllegalArgumentException If provider is null. + */ + public static CertPathValidator getInstance(String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("null provider"); + + try + { + return new CertPathValidator((CertPathValidatorSpi) + Engine.getInstance(CERT_PATH_VALIDATOR, algorithm, provider), + provider, algorithm); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new NoSuchAlgorithmException(algorithm); + } + catch (ClassCastException cce) + { + throw new NoSuchAlgorithmException(algorithm); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Return the name of this validator. + * + * @return This validator's name. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Return the provider of this implementation. + * + * @return The provider. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Attempt to validate a certificate path. + * + * @param certPath The path to validate. + * @param params The algorithm-specific parameters. + * @return The result of this validation attempt. + * @throws CertPathValidatorException If the certificate path cannot + * be validated. + * @throws InvalidAlgorithmParameterException If this implementation + * rejects the specified parameters. + */ + public final CertPathValidatorResult validate(CertPath certPath, + CertPathParameters params) + throws CertPathValidatorException, InvalidAlgorithmParameterException + { + return validatorSpi.engineValidate(certPath, params); + } +} diff --git a/libjava/classpath/java/security/cert/CertPathValidatorException.java b/libjava/classpath/java/security/cert/CertPathValidatorException.java new file mode 100644 index 0000000..f3195be --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPathValidatorException.java @@ -0,0 +1,226 @@ +/* CertPathValidatorException.java -- wraps an exception during validation + of a CertPath + 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 java.security.cert; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.GeneralSecurityException; + +/** + * Indicates a problem while validating a certification path. In addition, + * it can store the path an index in that path that caused the problem. This + * class is not thread-safe. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see CertPathValidator + * @since 1.4 + * @status updated to 1.4 +*/ +public class CertPathValidatorException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = -3083180014971893139L; + + /** + * The index of the certificate path that failed, or -1. + * + * @serial the failed index + */ + private final int index; + + /** + * The CertPath that failed. + * + * @serial the object being validated at time of failure + */ + private final CertPath certPath; + + /** + * Create an exception without a message. The cause may be initialized. The + * index is set to -1 and the failed CertPath object to null. + */ + public CertPathValidatorException() + { + this((String) null); + } + + /** + * Create an exception with a message. The cause may be initialized. The + * index is set to -1 and the failed CertPath object to null. + * + * @param msg a message to display with exception + */ + public CertPathValidatorException(String msg) + { + super(msg); + index = -1; + certPath = null; + } + + /** + * Create an exception with a cause. The message will be + * cause == null ? null : cause.toString(). The index is set + * to -1 and the failed CertPath object to null. + * + * @param cause the cause + */ + public CertPathValidatorException(Throwable cause) + { + this(cause == null ? null : cause.toString(), cause, null, -1); + } + + /** + * Create an exception with a cause and a message. The index is set to -1 + * and the failed CertPath object to null. + * + * @param msg the message + * @param cause the cause + */ + public CertPathValidatorException(String msg, Throwable cause) + { + this(msg, cause, null, -1); + } + + /** + * Create an exception with a cause, message, failed object, and index of + * failure in that CertPath. + * + * @param msg the message + * @param cause the cause + * @param certPath the path that was being validated, or null + * @param index the index of the path, or -1 + * @throws IndexOutOfBoundsException if index is < -1 or + * > certPath.getCertificates().size() + * @throws IllegalArgumentException if certPath is null but index != -1 + */ + public CertPathValidatorException(String msg, Throwable cause, + CertPath certPath, int index) + { + super(msg); + initCause(cause); + if (index < -1 || (certPath != null + && index >= certPath.getCertificates().size())) + throw new IndexOutOfBoundsException(); + if ((certPath == null) != (index == -1)) + throw new IllegalArgumentException(); + this.certPath = certPath; + this.index = index; + } + + /** + * Get the detail message. + * + * @return the detail message + */ + public String getMessage() + { + return super.getMessage(); + } + + /** + * Get the certificate path that had the failure, or null. + * + * @return the culprit path + */ + public CertPath getCertPath() + { + return certPath; + } + + /** + * Get the index that failed, or -1. + * + * @return the colprit index + */ + public int getIndex() + { + return index; + } + + /** + * Get the cause, null if unknown. + * + * @return the cause + */ + public Throwable getCause() + { + return super.getCause(); + } + + /** + * Convert this to a string, including its cause. + * + * @return the string conversion + */ + public String toString() + { + return super.toString(); + } + + /** + * Print the stack trace to System.err. + */ + public void printStackTrace() + { + super.printStackTrace(); + } + + /** + * Print the stack trace to a stream. + * + * @param stream the stream + */ + public void printStackTrace(PrintStream stream) + { + super.printStackTrace(stream); + } + + /** + * Print the stack trace to a stream. + * + * @param stream the stream + */ + public void printStackTrace(PrintWriter stream) + { + super.printStackTrace(stream); + } +} diff --git a/libjava/classpath/java/security/cert/CertPathValidatorResult.java b/libjava/classpath/java/security/cert/CertPathValidatorResult.java new file mode 100644 index 0000000..71aaf89 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPathValidatorResult.java @@ -0,0 +1,63 @@ +/* CertPathValidatorResult -- result of validating certificate paths + 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 java.security.cert; + +/** + * Interface to the result of calling {@link + * CertPathValidator#validate(java.security.cert.CertPath,java.security.cert.CertPathParameters)}. + * + *

    This interface defines no methods other than the required + * {@link java.lang.Cloneable} interface, and is intended to group and + * provide type safety for validator results. Providers that implement + * a certificate path validator must also provide an implementation of + * this interface, possibly defining additional methods. + * + * @since JDK 1.4 + * @see CertPathValidator + */ +public interface CertPathValidatorResult extends Cloneable +{ + + /** + * Returns a copy of this validator result. + * + * @return The copy. + */ + Object clone(); +} diff --git a/libjava/classpath/java/security/cert/CertPathValidatorSpi.java b/libjava/classpath/java/security/cert/CertPathValidatorSpi.java new file mode 100644 index 0000000..8d18b49 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertPathValidatorSpi.java @@ -0,0 +1,79 @@ +/* CertPathValidatorSpi -- cert path validator service provider interface + 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 java.security.cert; + +/** + * The service provider interface (SPI) for the {@link + * CertPathValidator} class. Providers implementing certificate path + * validators must subclass this class and implement its abstract + * methods. + */ +public abstract class CertPathValidatorSpi +{ + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Default constructor. + */ + public CertPathValidatorSpi() + { + super(); + } + + // Abstract methods. + // ------------------------------------------------------------------------ + + /** + * Attempt to validate a certificate path. + * + * @param certPath The path to validate. + * @param params The algorithm-specific parameters. + * @return The result of this validation attempt. + * @throws CertPathValidatorException If the certificate path cannot + * be validated. + * @throws InvalidAlgorithmParameterException If this implementation + * rejects the specified parameters. + */ + public abstract CertPathValidatorResult + engineValidate(CertPath certPath, CertPathParameters params) + throws CertPathValidatorException, + java.security.InvalidAlgorithmParameterException; +} diff --git a/libjava/classpath/java/security/cert/CertSelector.java b/libjava/classpath/java/security/cert/CertSelector.java new file mode 100644 index 0000000..aea614a --- /dev/null +++ b/libjava/classpath/java/security/cert/CertSelector.java @@ -0,0 +1,58 @@ +/* CertSelector.java -- certificate selector interface. + 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 java.security.cert; + +public interface CertSelector extends Cloneable +{ + + /** + * Returns a copy of this CertSelector. + * + * @return The copy. + */ + Object clone(); + + /** + * Match a certificate according to this selector's criteria. + * + * @param cert The certificate to match. + * @return true if the certificate matches thin criteria. + */ + boolean match(Certificate cert); +} diff --git a/libjava/classpath/java/security/cert/CertStore.java b/libjava/classpath/java/security/cert/CertStore.java new file mode 100644 index 0000000..864da86 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertStore.java @@ -0,0 +1,294 @@ +/* CertStore -- stores and retrieves certificates. + 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 java.security.cert; + +import gnu.java.security.Engine; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.security.Security; +import java.util.Collection; + +/** + * A CertStore is a read-only repository for certificates and + * certificate revocation lists. + * + * @since JDK 1.4 + */ +public class CertStore +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** Service name for CertStore. */ + private static final String CERT_STORE = "CertStore"; + + /** The underlying implementation. */ + private CertStoreSpi storeSpi; + + /** This implementation's provider. */ + private Provider provider; + + /** The name of this key store type. */ + private String type; + + /** The parameters used to initialize this instance, if any. */ + private CertStoreParameters params; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Create a new CertStore. + * + * @param storeSpi The underlying implementation. + * @param provider The provider of this implementation. + * @param type The type of CertStore this class represents. + * @param params The parameters used to initialize this instance, if any. + */ + protected CertStore(CertStoreSpi storeSpi, Provider provider, String type, + CertStoreParameters params) + { + this.storeSpi = storeSpi; + this.provider = provider; + this.type = type; + this.params = params; + } + + // Class methods. + // ------------------------------------------------------------------------ + + /** + * Returns the default certificate store type. + * + *

    This value can be set at run-time via the security property + * "certstore.type"; if not specified than the default type will be + * "LDAP". + * + * @return The default CertStore type. + */ + public static final synchronized String getDefaultType() + { + String type = null; + type = (String) java.security.AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + return Security.getProperty("certstore.type"); + } + } + ); + if (type == null) + type = "LDAP"; + return type; + } + + /** + * Get an instance of the given certificate store from the first + * installed provider. + * + * @param type The type of CertStore to create. + * @param params The parameters to initialize this cert store with. + * @return The new instance. + * @throws InvalidAlgorithmParameterException If the instance rejects + * the specified parameters. + * @throws NoSuchAlgorithmException If no installed provider + * implements the specified CertStore. + * @throws IllegalArgumentException If provider is null. + */ + public static CertStore getInstance(String type, CertStoreParameters params) + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(type, params, p[i]); + } + catch (NoSuchAlgorithmException e) + { + // Ignored. + } + } + + throw new NoSuchAlgorithmException(type); + } + + /** + * Get an instance of the given certificate store from the named + * provider. + * + * @param type The type of CertStore to create. + * @param params The parameters to initialize this cert store with. + * @param provider The name of the provider from which to get the + * implementation. + * @return The new instance. + * @throws InvalidAlgorithmParameterException If the instance rejects + * the specified parameters. + * @throws NoSuchAlgorithmException If the specified provider does not + * implement the specified CertStore. + * @throws NoSuchProviderException If no provider named + * provider is installed. + * @throws IllegalArgumentException If provider is null. + */ + public static CertStore getInstance(String type, CertStoreParameters params, + String provider) + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, + NoSuchProviderException + { + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + return getInstance(type, params, p); + } + + /** + * Get an instance of the given certificate store from the given + * provider. + * + * @param type The type of CertStore to create. + * @param params The parameters to initialize this cert store with. + * @param provider The provider from which to get the implementation. + * @return The new instance. + * @throws InvalidAlgorithmParameterException If the instance rejects + * the specified parameters. + * @throws NoSuchAlgorithmException If the specified provider does not + * implement the specified CertStore. + * @throws IllegalArgumentException If provider is null. + */ + public static CertStore getInstance(String type, CertStoreParameters params, + Provider provider) + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException + { + if (provider == null) + throw new IllegalArgumentException("null provider"); + + try + { + return new CertStore((CertStoreSpi) Engine.getInstance(CERT_STORE, + type, provider, new Object[] { params }), provider, type, params); + } + catch (ClassCastException cce) + { + throw new NoSuchAlgorithmException(type); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + Throwable cause = ite.getCause(); + if (cause instanceof InvalidAlgorithmParameterException) + throw (InvalidAlgorithmParameterException) cause; + else + throw new NoSuchAlgorithmException(type); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Return the type of certificate store this instance represents. + * + * @return The CertStore type. + */ + public final String getType() + { + return type; + } + + /** + * Return the provider of this implementation. + * + * @return The provider. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Get the parameters this instance was created with, if any. The + * parameters will be cloned before they are returned. + * + * @return The parameters, or null. + */ + public final CertStoreParameters getCertStoreParameters() + { + return params != null ? (CertStoreParameters) params.clone() : null; + } + + /** + * Get a collection of certificates from this CertStore, optionally + * filtered by the specified CertSelector. The Collection returned may + * be empty, but will never be null. + * + *

    Implementations may not allow a null argument, even if no + * filtering is desired. + * + * @param selector The certificate selector. + * @return The collection of certificates. + * @throws CertStoreException If the certificates cannot be retrieved. + */ + public final Collection getCertificates(CertSelector selector) + throws CertStoreException + { + return storeSpi.engineGetCertificates(selector); + } + + /** + * Get a collection of certificate revocation lists from this CertStore, + * optionally filtered by the specified CRLSelector. The Collection + * returned may be empty, but will never be null. + * + *

    Implementations may not allow a null argument, even if no + * filtering is desired. + * + * @param selector The certificate selector. + * @return The collection of certificate revocation lists. + * @throws CertStoreException If the CRLs cannot be retrieved. + */ + public final Collection getCRLs(CRLSelector selector) + throws CertStoreException + { + return storeSpi.engineGetCRLs(selector); + } +} diff --git a/libjava/classpath/java/security/cert/CertStoreException.java b/libjava/classpath/java/security/cert/CertStoreException.java new file mode 100644 index 0000000..a4d8b7a --- /dev/null +++ b/libjava/classpath/java/security/cert/CertStoreException.java @@ -0,0 +1,159 @@ +/* CertStoreException.java -- wraps an exception during certificate storage + 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 java.security.cert; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.GeneralSecurityException; + +/** + * Indicates a problem while retrieving certificates and CRLs from + * CertStore, wrapping the lower exception. This class is not + * thread-safe. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see CertStore + * @since 1.4 + * @status updated to 1.4 +*/ +public class CertStoreException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 2395296107471573245L; + + /** + * Create an exception without a message. The cause may be initialized. + */ + public CertStoreException() + { + } + + /** + * Create an exception with a message. The cause may be initialized. + * + * @param msg a message to display with exception + */ + public CertStoreException(String msg) + { + super(msg); + } + + /** + * Create an exception with a cause. The message will be + * cause == null ? null : cause.toString(). + * + * @param cause the cause + */ + public CertStoreException(Throwable cause) + { + this(cause == null ? null : cause.toString(), cause); + } + + /** + * Create an exception with a cause and a message. + * + * @param msg the message + * @param cause the cause + */ + public CertStoreException(String msg, Throwable cause) + { + super(msg); + initCause(cause); + } + + /** + * Get the detail message. + * + * @return the detail message + */ + public String getMessage() + { + return super.getMessage(); + } + + /** + * Get the cause, null if unknown. + * + * @return the cause + */ + public Throwable getCause() + { + return super.getCause(); + } + + /** + * Convert this to a string, including its cause. + * + * @return the string conversion + */ + public String toString() + { + return super.toString(); + } + + /** + * Print the stack trace to System.err. + */ + public void printStackTrace() + { + super.printStackTrace(); + } + + /** + * Print the stack trace to a stream. + * + * @param stream the stream + */ + public void printStackTrace(PrintStream stream) + { + super.printStackTrace(stream); + } + + /** + * Print the stack trace to a stream. + * + * @param stream the stream + */ + public void printStackTrace(PrintWriter stream) + { + super.printStackTrace(stream); + } +} diff --git a/libjava/classpath/java/security/cert/CertStoreParameters.java b/libjava/classpath/java/security/cert/CertStoreParameters.java new file mode 100644 index 0000000..aab22f0 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertStoreParameters.java @@ -0,0 +1,60 @@ +/* CertStoreParameters -- interface to CertStore parameters. + 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 java.security.cert; + +/** + * Parameters used when creating instances of {@link CertStore}. This + * class does not define any methods (except a required cloneable + * interface) and is provided only to provide type safety for + * implementations. Concrete implementations implement this interface + * in accord with thier own needs. + * + * @see LDAPCertStoreParameters + * @see CollectionCertStoreParameters + */ +public interface CertStoreParameters extends Cloneable +{ + + /** + * Create a copy of these parameters. + * + * @return The copy. + */ + Object clone(); +} diff --git a/libjava/classpath/java/security/cert/CertStoreSpi.java b/libjava/classpath/java/security/cert/CertStoreSpi.java new file mode 100644 index 0000000..eca0e86 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertStoreSpi.java @@ -0,0 +1,102 @@ +/* CertStoreSpi -- certificate store service provider interface. + 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 java.security.cert; + +import java.util.Collection; + +/** + * The service provider interface (SPI) for the {@link + * CertStore} class. + * + *

    Providers wishing to implement a CertStore must subclass this + * class, implementing all the abstract methods. Providers may also + * implement the {@link CertStoreParameters} interface, if they require + * parameters. + * + * @since JDK 1.4 + * @see CertStore + * @see CollectionCertStoreParameters + * @see LDAPCertStoreParameters + */ +public abstract class CertStoreSpi +{ + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Creates a new CertStoreSpi. + * + * @param params The parameters to initialize this instance with, or + * null if no parameters are required. + * @throws InvalidAlgorithmParameterException If the specified + * parameters are inappropriate for this class. + */ + public CertStoreSpi(CertStoreParameters params) + throws java.security.InvalidAlgorithmParameterException + { + super(); + } + + // Abstract methods. + // ------------------------------------------------------------------------ + + /** + * Get the certificates from this store, filtering them through the + * specified CertSelector. + * + * @param selector The CertSelector to filter certificates. + * @return A (non-null) collection of certificates. + * @throws CertStoreException If the certificates cannot be retrieved. + */ + public abstract Collection engineGetCertificates(CertSelector selector) + throws CertStoreException; + + /** + * Get the certificate revocation list from this store, filtering them + * through the specified CRLSelector. + * + * @param selector The CRLSelector to filter certificate revocation + * lists. + * @return A (non-null) collection of certificate revocation list. + * @throws CertStoreException If the CRLs cannot be retrieved. + */ + public abstract Collection engineGetCRLs(CRLSelector selector) + throws CertStoreException; +} diff --git a/libjava/classpath/java/security/cert/Certificate.java b/libjava/classpath/java/security/cert/Certificate.java new file mode 100644 index 0000000..f8456f9 --- /dev/null +++ b/libjava/classpath/java/security/cert/Certificate.java @@ -0,0 +1,306 @@ +/* Certificate.java --- Certificate class + Copyright (C) 1999, 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 java.security.cert; + +import java.io.ByteArrayInputStream; +import java.io.InvalidObjectException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.SignatureException; + +/** + * The Certificate class is an abstract class used to manage + * identity certificates. An identity certificate is a + * combination of a principal and a public key which is + * certified by another principal. This is the puprose of + * Certificate Authorities (CA). + * + *

    This class is used to manage different types of certificates + * but have important common puposes. Different types of + * certificates like X.509 and OpenPGP share general certificate + * functions (like encoding and verifying) and information like + * public keys. + * + *

    X.509, OpenPGP, and SDSI can be implemented by subclassing this + * class even though they differ in storage methods and information + * stored. + * + * @see CertificateFactory + * @see X509Certificate + * @since JDK 1.2 + * @author Mark Benvenuto + * @author Casey Marshall + */ +public abstract class Certificate implements Serializable +{ + private static final long serialVersionUID = -6751606818319535583L; + + private String type; + + /** + Constructs a new certificate of the specified type. An example + is "X.509". + + @param type a valid standard name for a certificate. + */ + protected Certificate(String type) + { + this.type = type; + } + + /** + Returns the Certificate type. + + @return a string representing the Certificate type + */ + public final String getType() + { + return type; + } + + /** + Compares this Certificate to other. It checks if the + object if instanceOf Certificate and then checks if + the encoded form matches. + + @param other An Object to test for equality + + @return true if equal, false otherwise + */ + public boolean equals(Object other) + { + if( other instanceof Certificate ) { + try { + Certificate x = (Certificate) other; + if( getEncoded().length != x.getEncoded().length ) + return false; + + byte[] b1 = getEncoded(); + byte[] b2 = x.getEncoded(); + + for( int i = 0; i < b1.length; i++ ) + if( b1[i] != b2[i] ) + return false; + + } catch( CertificateEncodingException cee ) { + return false; + } + return true; + } + return false; + } + + /** + Returns a hash code for this Certificate in its encoded + form. + + @return A hash code of this class + */ + public int hashCode() + { + return super.hashCode(); + } + + /** + Gets the DER ASN.1 encoded format for this Certificate. + It assumes each certificate has only one encoding format. + Ex: X.509 is encoded as ASN.1 DER + + @return byte array containg encoded form + + @throws CertificateEncodingException if an error occurs + */ + public abstract byte[] getEncoded() throws CertificateEncodingException; + + /** + Verifies that this Certificate was properly signed with the + PublicKey that corresponds to its private key. + + @param key PublicKey to verify with + + @throws CertificateException encoding error + @throws NoSuchAlgorithmException unsupported algorithm + @throws InvalidKeyException incorrect key + @throws NoSuchProviderException no provider + @throws SignatureException signature error + */ + public abstract void verify(PublicKey key) + throws CertificateException, + NoSuchAlgorithmException, + InvalidKeyException, + NoSuchProviderException, + SignatureException; + + /** + Verifies that this Certificate was properly signed with the + PublicKey that corresponds to its private key and uses + the signature engine provided by the provider. + + @param key PublicKey to verify with + @param sigProvider Provider to use for signature algorithm + + @throws CertificateException encoding error + @throws NoSuchAlgorithmException unsupported algorithm + @throws InvalidKeyException incorrect key + @throws NoSuchProviderException incorrect provider + @throws SignatureException signature error + */ + public abstract void verify(PublicKey key, + String sigProvider) + throws CertificateException, + NoSuchAlgorithmException, + InvalidKeyException, + NoSuchProviderException, + SignatureException; + + /** + Returns a string representing the Certificate. + + @return a string representing the Certificate. + */ + public abstract String toString(); + + + /** + Returns the public key stored in the Certificate. + + @return The public key + */ + public abstract PublicKey getPublicKey(); + + // Protected methods. + // ------------------------------------------------------------------------ + + /** + * Returns a replacement for this certificate to be serialized. This + * method returns the equivalent to the following for this class: + * + *

    + *
    new CertificateRep(getType(), getEncoded());
    + *
    + * + *

    This thusly replaces the certificate with its name and its + * encoded form, which can be deserialized later with the {@link + * CertificateFactory} implementation for this certificate's type. + * + * @return The replacement object to be serialized. + * @throws ObjectStreamException If the replacement could not be + * created. + */ + protected Object writeReplace() throws ObjectStreamException + { + try + { + return new CertificateRep(getType(), getEncoded()); + } + catch (CertificateEncodingException cee) + { + throw new InvalidObjectException(cee.toString()); + } + } + + // Inner class. + // ------------------------------------------------------------------------ + + /** + Certificate.CertificateRep is an inner class used to provide an alternate + storage mechanism for serialized Certificates. + */ + protected static class CertificateRep implements java.io.Serializable + { + + /** From JDK1.4. */ + private static final long serialVersionUID = -8563758940495660020L; + + /** The certificate type, e.g. "X.509". */ + private String type; + + /** The encoded certificate data. */ + private byte[] data; + + /** + * Create an alternative representation of this certificate. The + * (type, data) pair is typically the certificate's + * type as returned by {@link Certificate#getType()} (i.e. the + * canonical name of the certificate type) and the encoded form as + * returned by {@link Certificate#getEncoded()}. + * + *

    For example, X.509 certificates would create an instance of + * this class with the parameters "X.509" and the ASN.1 + * representation of the certificate, encoded as DER bytes. + * + * @param type The certificate type. + * @param data The encoded certificate data. + */ + protected CertificateRep(String type, byte[] data) + { + this.type = type; + this.data = data; + } + + /** + * Deserialize this certificate replacement into the appropriate + * certificate object. That is, this method attempts to create a + * {@link CertificateFactory} for this certificate's type, then + * attempts to parse the encoded data with that factory, returning + * the resulting certificate. + * + * @return The deserialized certificate. + * @throws ObjectStreamException If there is no appropriate + * certificate factory for the given type, or if the encoded form + * cannot be parsed. + */ + protected Object readResolve() throws ObjectStreamException + { + try + { + CertificateFactory fact = CertificateFactory.getInstance(type); + return fact.generateCertificate(new ByteArrayInputStream(data)); + } + catch (Exception e) + { + throw new InvalidObjectException(e.toString()); + } + } + } +} diff --git a/libjava/classpath/java/security/cert/CertificateEncodingException.java b/libjava/classpath/java/security/cert/CertificateEncodingException.java new file mode 100644 index 0000000..0bb0c26 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertificateEncodingException.java @@ -0,0 +1,71 @@ +/* CertificateEncodingException.java -- Certificate Encoding Exception + Copyright (C) 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 java.security.cert; + +/** + * Exception for a Certificate Encoding. + * + * @author Mark Benvenuto + * @since 1.2 + * @status updated to 1.4 + */ +public class CertificateEncodingException extends CertificateException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 6219492851589449162L; + + /** + * Constructs an exception without a message string. + */ + public CertificateEncodingException() + { + } + + /** + * Constructs an exception with a message string. + * + * @param msg A message to display with exception + */ + public CertificateEncodingException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/cert/CertificateException.java b/libjava/classpath/java/security/cert/CertificateException.java new file mode 100644 index 0000000..3e075dd --- /dev/null +++ b/libjava/classpath/java/security/cert/CertificateException.java @@ -0,0 +1,74 @@ +/* CertificateException.java -- Certificate Exception + Copyright (C) 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 java.security.cert; + +import java.security.GeneralSecurityException; + +/** + * Exception for a Certificate. + * + * @author Mark Benvenuto + * @see Certificate + * @since 1.2 + * @status updated to 1.4 + */ +public class CertificateException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 3192535253797119798L; + + /** + * Constructs an exception without a message string. + */ + public CertificateException() + { + } + + /** + * Constructs an exception with a message string. + * + * @param msg a message to display with exception + */ + public CertificateException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/cert/CertificateExpiredException.java b/libjava/classpath/java/security/cert/CertificateExpiredException.java new file mode 100644 index 0000000..5b37142 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertificateExpiredException.java @@ -0,0 +1,71 @@ +/* CertificateExpiredException.java --- Certificate Expired Exception + Copyright (C) 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 java.security.cert; + +/** + * Exception for a Certificate Expiring. + * + * @author Mark Benvenuto + * @since 1.2 + * @status updated to 1.4 + */ +public class CertificateExpiredException extends CertificateException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 9071001339691533771L; + + /** + * Constructs an exception without a message string. + */ + public CertificateExpiredException() + { + } + + /** + * Constructs an exception with a message string. + * + * @param msg a message to display with exception + */ + public CertificateExpiredException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/cert/CertificateFactory.java b/libjava/classpath/java/security/cert/CertificateFactory.java new file mode 100644 index 0000000..aedeff5 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertificateFactory.java @@ -0,0 +1,358 @@ +/* CertificateFactory.java -- Certificate Factory Class + Copyright (C) 1999, 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 java.security.cert; + +import gnu.java.security.Engine; + +import java.io.InputStream; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * This class implements the CertificateFactory class interface used to + * generate certificates, certificate revocation lists (CRLs), and certificate + * paths objects from their encoded forms. + * + * @author Mark Benvenuto + * @author Casey Marshall + * @since JDK 1.2 + * @status Fully compatible with JDK 1.4. + */ +public class CertificateFactory +{ + + /** The service name for certificate factories. */ + private static final String CERTIFICATE_FACTORY = "CertificateFactory"; + + private CertificateFactorySpi certFacSpi; + private Provider provider; + private String type; + + /** + * Creates an instance of CertificateFactory. + * + * @param certFacSpi The underlying CertificateFactory engine. + * @param provider The provider of this implementation. + * @param type The type of Certificate this factory creates. + */ + protected CertificateFactory(CertificateFactorySpi certFacSpi, + Provider provider, String type) + { + this.certFacSpi = certFacSpi; + this.provider = provider; + this.type = type; + } + + // Class methods. + // ------------------------------------------------------------------------ + + /** + * Gets an instance of the CertificateFactory class representing + * the specified certificate factory. If the type is not + * found then, it throws CertificateException. + * + * @param type The type of certificate factory to create. + * @return a CertificateFactory repesenting the desired type + * @throws CertificateException If the type of certificate is not + * implemented by any installed provider. + */ + public static final CertificateFactory getInstance(String type) + throws CertificateException + { + Provider[] p = Security.getProviders(); + + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(type, p[i]); + } + catch (CertificateException e) + { + // Ignored. + } + } + + throw new CertificateException(type); + } + + /** + * Gets an instance of the CertificateFactory class representing + * the specified certificate factory from the specified provider. + * If the type is not found then, it throws {@link CertificateException}. + * If the provider is not found, then it throws + * {@link java.security.NoSuchProviderException}. + * + * @param type The type of certificate factory to create. + * @param provider The name of the provider from which to get the + * implementation. + * @return A CertificateFactory for the desired type. + * @throws CertificateException If the type of certificate is not + * implemented by the named provider. + * @throws NoSuchProviderException If the named provider is not installed. + */ + public static final CertificateFactory getInstance(String type, + String provider) + throws CertificateException, NoSuchProviderException + { + Provider p = Security.getProvider(provider); + if( p == null) + throw new NoSuchProviderException(provider); + + return getInstance(type, p); + } + + /** + * Get a certificate factory for the given certificate type from the + * given provider. + * + * @param type The type of certificate factory to create. + * @param provider The provider from which to get the implementation. + * @return A CertificateFactory for the desired type. + * @throws CertificateException If the type of certificate is not + * implemented by the provider. + * @throws IllegalArgumentException If the provider is null. + */ + public static final CertificateFactory getInstance(String type, + Provider provider) + throws CertificateException + { + if (provider == null) + throw new IllegalArgumentException("null provider"); + + try + { + return new CertificateFactory((CertificateFactorySpi) + Engine.getInstance(CERTIFICATE_FACTORY, type, provider), + provider, type); + } + catch (ClassCastException cce) + { + throw new CertificateException(type); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + throw new CertificateException(type); + } + catch (NoSuchAlgorithmException nsae) + { + throw new CertificateException(nsae.getMessage()); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Gets the provider of this implementation. + * + * @return The provider of this implementation. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Returns the type of the certificate this factory creates. + * + * @return A string with the type of certificate + */ + public final String getType() + { + return type; + } + + /** + * Generates a Certificate from the encoded data read + * from an InputStream. + * + *

    The input stream must contain only one certificate. + * + *

    If there exists a specialized certificate class for the + * certificate format handled by the certificate factory + * then the return Ceritificate should be a typecast of it. + * Ex: A X.509 CertificateFactory should return X509Certificate. + * + *

    For X.509 certificates, the certificate in inStream must be + * DER encoded and supplied in binary or printable (Base64) + * encoding. If the certificate is in Base64 encoding, it must be + * bounded by -----BEGINCERTIFICATE-----, and + * -----END CERTIFICATE-----. + * + * @param inStream An input stream containing the certificate data. + * @return A certificate initialized from the decoded InputStream data. + * @throws CertificateException If an error occurs decoding the + * certificate. + */ + public final Certificate generateCertificate(InputStream inStream) + throws CertificateException + { + return certFacSpi.engineGenerateCertificate(inStream); + } + + /** + * Returns a collection of certificates that were read from the + * input stream. It may be empty, have only one, or have + * multiple certificates. + * + * For a X.509 certificate factory, the stream may contain a + * single DER encoded certificate or a PKCS#7 certificate + * chain. This is a PKCS#7 SignedData object with the + * most significant field being certificates. If no + * CRLs are present, then an empty collection is returned. + * + * @param inStream An input stream containing the certificate data. + * @return A collection of certificates initialized from the decoded + * InputStream data. + * @throws CertificateException If an error occurs decoding the + * certificates. + */ + public final Collection generateCertificates(InputStream inStream) + throws CertificateException + { + return certFacSpi.engineGenerateCertificates(inStream); + } + + /** + * Generates a CRL based on the encoded data read + * from the InputStream. + * + *

    The input stream must contain only one CRL. + * + *

    If there exists a specialized CRL class for the + * CRL format handled by the certificate factory + * then the return CRL should be a typecast of it. + * Ex: A X.509 CertificateFactory should return X509CRL. + * + * @param inStream An input stream containing the CRL data. + * @return A CRL initialized from the decoded InputStream data. + * @throws CRLException If an error occurs decoding the CRL. + */ + public final CRL generateCRL(InputStream inStream) + throws CRLException + { + return certFacSpi.engineGenerateCRL(inStream); + } + + /** + *

    Generates CRLs based on the encoded data read + * from the InputStream. + * + *

    For a X.509 certificate factory, the stream may contain a + * single DER encoded CRL or a PKCS#7 CRL set. This is a + * PKCS#7 SignedData object with the most significant + * field being crls. If no CRLs are present, then an + * empty collection is returned. + * + * @param inStream an input stream containing the CRLs. + * @return a collection of CRLs initialized from the decoded + * InputStream data. + * @throws CRLException If an error occurs decoding the CRLs. + */ + public final Collection generateCRLs(InputStream inStream) + throws CRLException + { + return certFacSpi.engineGenerateCRLs( inStream ); + } + + /** + * Generate a {@link CertPath} and initialize it with data parsed from + * the input stream. The default encoding of this factory is used. + * + * @param inStream The InputStream containing the CertPath data. + * @return A CertPath initialized from the input stream data. + * @throws CertificateException If an error occurs decoding the + * CertPath. + */ + public final CertPath generateCertPath(InputStream inStream) + throws CertificateException + { + return certFacSpi.engineGenerateCertPath(inStream); + } + + /** + * Generate a {@link CertPath} and initialize it with data parsed from + * the input stream, using the specified encoding. + * + * @param inStream The InputStream containing the CertPath data. + * @param encoding The encoding of the InputStream data. + * @return A CertPath initialized from the input stream data. + * @throws CertificateException If an error occurs decoding the + * CertPath. + */ + public final CertPath generateCertPath(InputStream inStream, String encoding) + throws CertificateException + { + return certFacSpi.engineGenerateCertPath(inStream, encoding); + } + + /** + * Generate a {@link CertPath} and initialize it with the certificates + * in the {@link java.util.List} argument. + * + * @param certificates The list of certificates with which to create + * the CertPath. + * @return A CertPath initialized from the certificates. + * @throws CertificateException If an error occurs generating the + * CertPath. + */ + public final CertPath generateCertPath(List certificates) + throws CertificateException + { + return certFacSpi.engineGenerateCertPath(certificates); + } + + /** + * Returns an Iterator of CertPath encodings supported by this + * factory, with the default encoding first. The returned Iterator + * cannot be modified. + * + * @return The Iterator of supported encodings. + */ + public final Iterator getCertPathEncodings() + { + return certFacSpi.engineGetCertPathEncodings(); + } +} // class CertificateFactory diff --git a/libjava/classpath/java/security/cert/CertificateFactorySpi.java b/libjava/classpath/java/security/cert/CertificateFactorySpi.java new file mode 100644 index 0000000..beea964 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertificateFactorySpi.java @@ -0,0 +1,225 @@ +/* CertificateFactorySpi.java --- Certificate Factory Class + 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 java.security.cert; + +import java.io.InputStream; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + CertificateFactorySpi is the abstract class Service Provider + Interface (SPI) for the CertificateFactory class. A provider + must implement all the abstract methods if they wish to + supply a certificate factory for a particular certificate + type. Ex: X.509 + + Certificate factories are used to generate certificates and + certificate revocation lists (CRL) from their encoding. + + @since JDK 1.2 + + @author Mark Benvenuto + */ +public abstract class CertificateFactorySpi +{ + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Constructs a new CertificateFactorySpi + */ + public CertificateFactorySpi() + {} + + // Abstract methods. + // ------------------------------------------------------------------------ + + /** + Generates a Certificate based on the encoded data read + from the InputStream. + + The input stream must contain only one certificate. + + If there exists a specialized certificate class for the + certificate format handled by the certificate factory + then the return Ceritificate should be a typecast of it. + Ex: A X.509 CertificateFactory should return X509Certificate. + + For X.509 certificates, the certificate in inStream must be + DER encoded and supplied in binary or printable (Base64) + encoding. If the certificate is in Base64 encoding, it must be + bounded by -----BEGIN CERTIFICATE-----, and + -----END CERTIFICATE-----. + + @param inStream an input stream containing the certificate data + + @return a certificate initialized with InputStream data. + + @throws CertificateException Certificate parsing error + */ + public abstract Certificate engineGenerateCertificate(InputStream inStream) + throws CertificateException; + + /** + Returns a collection of certificates that were read from the + input stream. It may be empty, have only one, or have + multiple certificates. + + For a X.509 certificate factory, the stream may contain a + single DER encoded certificate or a PKCS#7 certificate + chain. This is a PKCS#7 SignedData object with the + most significant field being certificates. If no + CRLs are present, then an empty collection is returned. + + @param inStream an input stream containing the certificates + + @return a collection of certificates initialized with + the InputStream data. + + @throws CertificateException Certificate parsing error + */ + public abstract Collection engineGenerateCertificates(InputStream inStream) + throws CertificateException; + + /** + Generates a CRL based on the encoded data read + from the InputStream. + + The input stream must contain only one CRL. + + If there exists a specialized CRL class for the + CRL format handled by the certificate factory + then the return CRL should be a typecast of it. + Ex: A X.509 CertificateFactory should return X509CRL. + + @param inStream an input stream containing the CRL data + + @return a CRL initialized with InputStream data. + + @throws CRLException CRL parsing error + */ + public abstract CRL engineGenerateCRL(InputStream inStream) + throws CRLException; + + /** + Generates CRLs based on the encoded data read + from the InputStream. + + For a X.509 certificate factory, the stream may contain a + single DER encoded CRL or a PKCS#7 CRL set. This is a + PKCS#7 SignedData object with the most significant + field being crls. If no CRLs are present, then an + empty collection is returned. + + @param inStream an input stream containing the CRLs + + @return a collection of CRLs initialized with + the InputStream data. + + @throws CRLException CRL parsing error + */ + public abstract Collection engineGenerateCRLs(InputStream inStream) + throws CRLException; + + // 1.4 instance methods. + // ------------------------------------------------------------------------ + + /** + * Generate a {@link CertPath} and initialize it with data parsed from + * the input stream. The default encoding of this factory is used. + * + * @param inStream The InputStream containing the CertPath data. + * @return A CertPath initialized from the input stream data. + * @throws CertificateException If an error occurs decoding the + * CertPath. + */ + public CertPath engineGenerateCertPath(InputStream inStream) + throws CertificateException + { + throw new UnsupportedOperationException("not implemented"); + } + + /** + * Generate a {@link CertPath} and initialize it with data parsed from + * the input stream, using the specified encoding. + * + * @param inStream The InputStream containing the CertPath data. + * @param encoding The encoding of the InputStream data. + * @return A CertPath initialized from the input stream data. + * @throws CertificateException If an error occurs decoding the + * CertPath. + */ + public CertPath engineGenerateCertPath(InputStream inStream, String encoding) + throws CertificateException + { + throw new UnsupportedOperationException("not implemented"); + } + + /** + * Generate a {@link CertPath} and initialize it with the certificates + * in the {@link java.util.List} argument. + * + * @param certificates The list of certificates with which to create + * the CertPath. + * @return A CertPath initialized from the certificates. + * @throws CertificateException If an error occurs generating the + * CertPath. + */ + public CertPath engineGenerateCertPath(List certificates) + throws CertificateException + { + throw new UnsupportedOperationException("not implemented"); + } + + /** + * Returns an Iterator of CertPath encodings supported by this + * factory, with the default encoding first. The returned Iterator + * cannot be modified. + * + * @return The Iterator of supported encodings. + */ + public Iterator engineGetCertPathEncodings() + { + throw new UnsupportedOperationException("not implemented"); + } +} + diff --git a/libjava/classpath/java/security/cert/CertificateNotYetValidException.java b/libjava/classpath/java/security/cert/CertificateNotYetValidException.java new file mode 100644 index 0000000..dfb4b48 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertificateNotYetValidException.java @@ -0,0 +1,71 @@ +/* CertificateNotYetValidException.java -- Certificate Not Yet Valid Exception + Copyright (C) 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 java.security.cert; + +/** + * Exception for a Certificate that is not yet valid. + * + * @author Mark Benvenuto + * @since 1.2 + * @status updated to 1.4 +*/ +public class CertificateNotYetValidException extends CertificateException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 4355919900041064702L; + + /** + * Constructs an exception without a message string. + */ + public CertificateNotYetValidException() + { + } + + /** + * Constructs an exception with a message string. + * + * @param msg A message to display with exception + */ + public CertificateNotYetValidException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/cert/CertificateParsingException.java b/libjava/classpath/java/security/cert/CertificateParsingException.java new file mode 100644 index 0000000..61faa44 --- /dev/null +++ b/libjava/classpath/java/security/cert/CertificateParsingException.java @@ -0,0 +1,71 @@ +/* CertificateParsingException.java -- Certificate Parsing Exception + Copyright (C) 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 java.security.cert; + +/** + * Exception for parsing a DER-encoded Certificate. + * + * @author Mark Benvenuto + * @since 1.2 + * @status updated to 1.4 +*/ +public class CertificateParsingException extends CertificateException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -7989222416793322029L; + + /** + * Constructs an exception without a message string. + */ + public CertificateParsingException() + { + } + + /** + * Constructs an exception with a message string. + * + * @param msg a message to display with exception + */ + public CertificateParsingException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/cert/CollectionCertStoreParameters.java b/libjava/classpath/java/security/cert/CollectionCertStoreParameters.java new file mode 100644 index 0000000..bac1e3b --- /dev/null +++ b/libjava/classpath/java/security/cert/CollectionCertStoreParameters.java @@ -0,0 +1,121 @@ +/* CollectionCertStoreParameters -- collection-based cert store parameters + 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 java.security.cert; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +/** + * An implementation of {@link CertStoreParameters} with a simple, + * in-memory {@link Collection} of certificates and certificate + * revocation list. + * + *

    Note that this class is not thread-safe, and its underlying + * collection may be changed at any time. + * + * @see CertStore + */ +public class CollectionCertStoreParameters implements CertStoreParameters +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** The underlying collection. */ + private final Collection collection; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Creates a new CollectionCertStoreParameters with an empty, + * immutable collection. + */ + public CollectionCertStoreParameters() + { + this(Collections.EMPTY_LIST); + } + + /** + * Create a new CollectionCertStoreParameters with the specified + * collection. The argument is not copied, and subsequent changes to + * the collection will change this class's collection. + * + * @param collection The collection. + * @throws NullPointerException If collection is null. + */ + public CollectionCertStoreParameters(Collection collection) + { + if (collection == null) + throw new NullPointerException(); + this.collection = collection; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public Object clone() + { + return new CollectionCertStoreParameters(new ArrayList(collection)); + } + + /** + * Return the underlying collection. The collection is not copied + * before being returned, so callers may update the collection that is + * returned. + * + * @return The collection. + */ + public Collection getCollection() + { + return collection; + } + + /** + * Return a string representation of these parameters. + * + * @return The string representation of these parameters. + */ + public String toString() + { + return "CollectionCertStoreParameters: [ collection: " + + collection + " ]"; + } +} diff --git a/libjava/classpath/java/security/cert/LDAPCertStoreParameters.java b/libjava/classpath/java/security/cert/LDAPCertStoreParameters.java new file mode 100644 index 0000000..4414e65 --- /dev/null +++ b/libjava/classpath/java/security/cert/LDAPCertStoreParameters.java @@ -0,0 +1,140 @@ +/* LDAPCertStoreParameters.java -- LDAP CertStore parameters. + 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 java.security.cert; + +/** + * Parameters for CertStores that are retrieved via the lightweight + * directory access protocol (LDAP). + * + * @see CertStore + */ +public class LDAPCertStoreParameters implements CertStoreParameters +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** The default LDAP port. */ + private static final int LDAP_PORT = 389; + + /** The server name. */ + private final String serverName; + + /** The LDAP port. */ + private final int port; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new LDAPCertStoreParameters object, with a servername of + * "localhost" and a port of 389. + */ + public LDAPCertStoreParameters() + { + this("localhost", LDAP_PORT); + } + + /** + * Create a new LDAPCertStoreParameters object, with a specified + * server name and a port of 389. + * + * @param serverName The LDAP server name. + * @throws NullPointerException If serverName is null. + */ + public LDAPCertStoreParameters(String serverName) + { + this(serverName, LDAP_PORT); + } + + /** + * Create a new LDAPCertStoreParameters object, with a specified + * server name and port. + * + * @param serverName The LDAP server name. + * @param port The LDAP port. + * @throws NullPointerException If serverName is null. + */ + public LDAPCertStoreParameters(String serverName, int port) + { + if (serverName == null) + throw new NullPointerException(); + this.serverName = serverName; + this.port = port; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public Object clone() + { + return new LDAPCertStoreParameters(serverName, port); + } + + /** + * Return the server name. + * + * @return The server name. + */ + public String getServerName() + { + return serverName; + } + + /** + * Return the port. + * + * @return the port. + */ + public int getPort() + { + return port; + } + + /** + * Return a string representation of these parameters. + * + * @return The string representation of these parameters. + */ + public String toString() + { + return "LDAPCertStoreParameters: [ serverName: " + serverName + + "; port: " + port + " ]"; + } +} diff --git a/libjava/classpath/java/security/cert/PKIXBuilderParameters.java b/libjava/classpath/java/security/cert/PKIXBuilderParameters.java new file mode 100644 index 0000000..38b3df5 --- /dev/null +++ b/libjava/classpath/java/security/cert/PKIXBuilderParameters.java @@ -0,0 +1,145 @@ +/* PKIXBuilderParameters.java -- parameters for PKIX cert path builders + 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 java.security.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; + +import java.util.Set; + +/** + * Parameters for building certificate paths using the PKIX algorithm. + * + * @see CertPathBuilder + */ +public class PKIXBuilderParameters extends PKIXParameters +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The maximum path length. */ + private int maxPathLength; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new PKIXBuilderParameters object, populating the trusted + * certificates set with all X.509 certificates found in the given key + * store. All certificates found in the key store are assumed to be + * trusted by this constructor. + * + * @param keystore The key store. + * @param targetConstraints The target certificate constraints. + * @throws KeyStoreException If the certificates cannot be retrieved + * from the key store. + * @throws InvalidAlgorithmParameterException If there are no + * certificates in the key store. + * @throws NullPointerException If keystore is null. + */ + public PKIXBuilderParameters(KeyStore keystore, + CertSelector targetConstraints) + throws KeyStoreException, InvalidAlgorithmParameterException + { + super(keystore); + setTargetCertConstraints(targetConstraints); + maxPathLength = 5; + } + + /** + * Create a new PKIXBuilderParameters object, populating the trusted + * certificates set with the elements of the given set, each of which + * must be a {@link TrustAnchor}. + * + * @param trustAnchors The set of trust anchors. + * @param targetConstraints The target certificate constraints. + * @throws InvalidAlgorithmParameterException If there are no + * certificates in the set. + * @throws NullPointerException If trustAnchors is null. + * @throws ClassCastException If every element in trustAnchors + * is not a {@link TrustAnchor}. + */ + public PKIXBuilderParameters(Set trustAnchors, CertSelector targetConstraints) + throws InvalidAlgorithmParameterException + { + super(trustAnchors); + setTargetCertConstraints(targetConstraints); + maxPathLength = 5; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the maximum length of certificate paths to build. + * + *

    If this value is 0 it is taken to mean that the certificate path + * should contain only one certificate. A value of -1 means that the + * certificate path length is unconstrained. The default value is 5. + * + * @return The maximum path length. + */ + public int getMaxPathLength() + { + return maxPathLength; + } + + /** + * Sets the maximum length of certificate paths to build. + * + * @param maxPathLength The new path length. + * @throws IllegalArgumentException If maxPathLength is less + * than -1. + */ + public void setMaxPathLength(int maxPathLength) + { + if (maxPathLength < -1) + throw new IllegalArgumentException(); + this.maxPathLength = maxPathLength; + } + + public String toString() + { + StringBuffer buf = new StringBuffer(super.toString()); + buf.insert(buf.length() - 2, "; Max Path Length=" + maxPathLength); + return buf.toString(); + } +} diff --git a/libjava/classpath/java/security/cert/PKIXCertPathBuilderResult.java b/libjava/classpath/java/security/cert/PKIXCertPathBuilderResult.java new file mode 100644 index 0000000..5091dd412 --- /dev/null +++ b/libjava/classpath/java/security/cert/PKIXCertPathBuilderResult.java @@ -0,0 +1,102 @@ +/* PKIXCertPathBuilderResult.java -- PKIX cert path bulider result + 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 java.security.cert; + +/** + * The result of calling the {@link + * CertPathBuilder#build(java.security.cert.CertPathParameters)} method + * of PKIX {@link CertPathBuilder}s. + * + * @see CertPathBuilder + * @see CertPathBuilderResult + */ +public class PKIXCertPathBuilderResult extends PKIXCertPathValidatorResult + implements CertPathBuilderResult +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The certificate path. */ + private CertPath certPath; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new PKIXCertPathBuilderResult. + * + * @param certPath The certificate path. + * @param trustAnchor The trust anchor. + * @param policyTree The root node of the policy tree. + * @param subjectPublicKey The public key. + * @throws NullPointerException If certPath, trustAnchor or + * subjectPublicKey is null. + */ + public PKIXCertPathBuilderResult(CertPath certPath, + TrustAnchor trustAnchor, + PolicyNode policyTree, + java.security.PublicKey subjectPublicKey) + { + super(trustAnchor, policyTree, subjectPublicKey); + if (certPath == null) + throw new NullPointerException(); + this.certPath = certPath; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the certificate path that was built. + * + * @return The certificate path that was built. + */ + public CertPath getCertPath() + { + return certPath; + } + + public String toString() + { + StringBuffer buf = new StringBuffer(super.toString()); + buf.insert(buf.length() - 2, "; CertPath=" + certPath); + return buf.toString(); + } +} diff --git a/libjava/classpath/java/security/cert/PKIXCertPathChecker.java b/libjava/classpath/java/security/cert/PKIXCertPathChecker.java new file mode 100644 index 0000000..7a33576 --- /dev/null +++ b/libjava/classpath/java/security/cert/PKIXCertPathChecker.java @@ -0,0 +1,133 @@ +/* PKIXCertPathChecker.java -- checks X.509 certificate paths. + 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 java.security.cert; + +import java.util.Collection; +import java.util.Set; + +/** + * A validator for X.509 certificates when approving certificate chains. + * + *

    Concrete subclasses can be passed to the {@link + * PKIXParameters#setCertPathCheckers(java.util.List)} and {@link + * PKIXParameters#addCertPathChecker(java.security.cert.PKIXCertPathChecker} + * methods, which are then used to set up PKIX certificate chain + * builders or validators. These classes then call the {@link + * #check(java.security.cert.Certificate,java.util.Collection)} method + * of this class, performing whatever checks on the certificate, + * throwing an exception if any check fails. + * + *

    Subclasses of this must be able to perform their checks in the + * backward direction -- from the most-trusted certificate to the target + * -- and may optionally support forward checking -- from the target to + * the most-trusted certificate. + * + * @see PKIXParameters + */ +public abstract class PKIXCertPathChecker implements Cloneable +{ + + // Constructor. + // ------------------------------------------------------------------------ + + /** Default constructor. */ + protected PKIXCertPathChecker() + { + super(); + } + + // Cloneable interface. + // ------------------------------------------------------------------------ + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException cnse) + { + throw new InternalError(cnse.getMessage()); + } + } + + // Abstract methods. + // ------------------------------------------------------------------------ + + /** + * Initialize this PKIXCertPathChecker. If subclasses support forward + * checking, a value of true can be passed to this method, and + * certificates can be validated from the target certificate to the + * most-trusted certifcate. + * + * @param forward The direction of this PKIXCertPathChecker. + * @throws CertPathValidatorException If forward is true and + * this class does not support forward checking. + */ + public abstract void init(boolean forward) throws CertPathValidatorException; + + /** + * Returns whether or not this class supports forward checking. + * + * @return Whether or not this class supports forward checking. + */ + public abstract boolean isForwardCheckingSupported(); + + /** + * Returns an immutable set of X.509 extension object identifiers (OIDs) + * supported by this PKIXCertPathChecker. + * + * @return An immutable set of Strings of the supported X.509 OIDs, or + * null if no extensions are supported. + */ + public abstract Set getSupportedExtensions(); + + /** + * Checks a certificate, removing any critical extensions that are + * resolved in this check. + * + * @param cert The certificate to check. + * @param unresolvedCritExts The (mutable) collection of as-of-yet + * unresolved critical extensions, as OID strings. + * @throws CertPathValidatorException If this certificate fails this + * check. + */ + public abstract void check(Certificate cert, Collection unresolvedCritExts) + throws CertPathValidatorException; +} diff --git a/libjava/classpath/java/security/cert/PKIXCertPathValidatorResult.java b/libjava/classpath/java/security/cert/PKIXCertPathValidatorResult.java new file mode 100644 index 0000000..5a1660c --- /dev/null +++ b/libjava/classpath/java/security/cert/PKIXCertPathValidatorResult.java @@ -0,0 +1,142 @@ +/* PKIXCertPathValidatorResult.java -- PKIX cert path builder result + 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 java.security.cert; + +import java.security.PublicKey; + +/** + * Results returned by the {@link + * CertPathValidator#validate(java.security.cert.CertPath,java.security.cert.CertPathParameters)} + * method for PKIX {@link CertPathValidator}s. + * + * @see CertPathValidator + */ +public class PKIXCertPathValidatorResult implements CertPathValidatorResult +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The trust anchor. */ + private final TrustAnchor trustAnchor; + + /** The root node of the policy tree. */ + private final PolicyNode policyTree; + + /** The subject's public key. */ + private final PublicKey subjectPublicKey; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new PKIXCertPathValidatorResult. + * + * @param trustAnchor The trust anchor. + * @param policyTree The root node of the policy tree. + * @param subjectPublicKey The public key. + * @throws NullPointerException If either trustAnchor or + * subjectPublicKey is null. + */ + public PKIXCertPathValidatorResult(TrustAnchor trustAnchor, + PolicyNode policyTree, + PublicKey subjectPublicKey) + { + if (trustAnchor == null || subjectPublicKey == null) + throw new NullPointerException(); + this.trustAnchor = trustAnchor; + this.policyTree = policyTree; + this.subjectPublicKey = subjectPublicKey; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the trust anchor. + * + * @return The trust anchor. + */ + public TrustAnchor getTrustAnchor() + { + return trustAnchor; + } + + /** + * Returns the root node of the policy tree. + * + * @return The root node of the policy tree. + */ + public PolicyNode getPolicyTree() + { + return policyTree; + } + + /** + * Returns the subject public key. + * + * @return The subject public key. + */ + public PublicKey getPublicKey() + { + return subjectPublicKey; + } + + /** + * Returns a copy of this object. + * + * @return The copy. + */ + public Object clone() + { + return new PKIXCertPathValidatorResult(trustAnchor, policyTree, + subjectPublicKey); + } + + /** + * Returns a printable string representation of this result. + * + * @return A printable string representation of this result. + */ + public String toString() + { + return "[ Trust Anchor=" + trustAnchor + "; Policy Tree=" + + policyTree + "; Subject Public Key=" + subjectPublicKey + " ]"; + } +} diff --git a/libjava/classpath/java/security/cert/PKIXParameters.java b/libjava/classpath/java/security/cert/PKIXParameters.java new file mode 100644 index 0000000..4a98711 --- /dev/null +++ b/libjava/classpath/java/security/cert/PKIXParameters.java @@ -0,0 +1,546 @@ +/* PKIXParameters.java -- parameters for the PKIX cert path algorithm + 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 java.security.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; + +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * Parameters for verifying certificate paths using the PKIX + * (Public-Key Infrastructure (X.509)) algorithm. + * + * @see CertPathBulider + */ +public class PKIXParameters implements CertPathParameters +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The trusted certificates. */ + private final Set trustAnchors; + + /** The set of initial policy identifiers. */ + private final Set initPolicies; + + /** The list of certificate stores. */ + private final List certStores; + + /** The list of path checkers. */ + private final List pathCheckers; + + /** The revocation enabled flag. */ + private boolean revocationEnabled; + + /** The explicit policy required flag. */ + private boolean exPolicyRequired; + + /** The policy mapping inhibited flag. */ + private boolean policyMappingInhibited; + + /** The any policy inhibited flag. */ + private boolean anyPolicyInhibited; + + /** The policy qualifiers rejected flag. */ + private boolean policyQualRejected; + + /** The target validation date. */ + private Date date; + + /** The signature algorithm provider. */ + private String sigProvider; + + /** The target constraints. */ + private CertSelector targetConstraints; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new PKIXParameters object, populating the trusted + * certificates set with all certificates found in the given key + * store. All certificates found in the key store are assumed to be + * trusted by this constructor. + * + * @param keystore The key store. + * @throws KeyStoreException If the certificates cannot be retrieved + * from the key store. + * @throws InvalidAlgorithmParameterException If there are no + * certificates in the key store. + * @throws NullPointerException If keystore is null. + */ + public PKIXParameters(KeyStore keystore) + throws KeyStoreException, InvalidAlgorithmParameterException + { + this(); + for (Enumeration e = keystore.aliases(); e.hasMoreElements(); ) + { + String alias = (String) e.nextElement(); + if (!keystore.isCertificateEntry(alias)) + continue; + Certificate cert = keystore.getCertificate(alias); + if (cert instanceof X509Certificate) + trustAnchors.add(new TrustAnchor((X509Certificate) cert, null)); + } + if (trustAnchors.isEmpty()) + throw new InvalidAlgorithmParameterException("no certs in the key store"); + } + + /** + * Create a new PKIXParameters object, populating the trusted + * certificates set with the elements of the given set, each of which + * must be a {@link TrustAnchor}. + * + * @param trustAnchors The set of trust anchors. + * @throws InvalidAlgorithmParameterException If there are no + * certificates in the set. + * @throws NullPointerException If trustAnchors is null. + * @throws ClassCastException If every element in trustAnchors + * is not a {@link TrustAnchor}. + */ + public PKIXParameters(Set trustAnchors) + throws InvalidAlgorithmParameterException + { + this(); + setTrustAnchors(trustAnchors); + } + + /** + * Default constructor. + */ + private PKIXParameters() + { + trustAnchors = new HashSet(); + initPolicies = new HashSet(); + certStores = new LinkedList(); + pathCheckers = new LinkedList(); + revocationEnabled = true; + exPolicyRequired = false; + policyMappingInhibited = false; + anyPolicyInhibited = false; + policyQualRejected = true; + } + + /** + * Copying constructor for cloning. + * + * @param that The instance being cloned. + */ + private PKIXParameters(PKIXParameters that) + { + this(); + this.trustAnchors.addAll(that.trustAnchors); + this.initPolicies.addAll(that.initPolicies); + this.certStores.addAll(that.certStores); + this.pathCheckers.addAll(that.pathCheckers); + this.revocationEnabled = that.revocationEnabled; + this.exPolicyRequired = that.exPolicyRequired; + this.policyMappingInhibited = that.policyMappingInhibited; + this.anyPolicyInhibited = that.anyPolicyInhibited; + this.policyQualRejected = that.policyQualRejected; + this.date = that.date; + this.sigProvider = that.sigProvider; + this.targetConstraints = that.targetConstraints != null + ? (CertSelector) that.targetConstraints.clone() : null; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns an immutable set of trust anchors. The set returned will + * never be null and will never be empty. + * + * @return A (never null, never empty) immutable set of trust anchors. + */ + public Set getTrustAnchors() + { + return Collections.unmodifiableSet(trustAnchors); + } + + /** + * Sets the trust anchors of this class, replacing the current trust + * anchors with those in the given set. The supplied set is copied to + * prevent modification. + * + * @param trustAnchors The new set of trust anchors. + * @throws InvalidAlgorithmParameterException If there are no + * certificates in the set. + * @throws NullPointerException If trustAnchors is null. + * @throws ClassCastException If every element in trustAnchors + * is not a {@link TrustAnchor}. + */ + public void setTrustAnchors(Set trustAnchors) + throws InvalidAlgorithmParameterException + { + if (trustAnchors.isEmpty()) + throw new InvalidAlgorithmParameterException("no trust anchors"); + this.trustAnchors.clear(); + for (Iterator i = trustAnchors.iterator(); i.hasNext(); ) + { + this.trustAnchors.add((TrustAnchor) i.next()); + } + } + + /** + * Returns the set of initial policy identifiers (as OID strings). If + * any policy is accepted, this method returns the empty set. + * + * @return An immutable set of initial policy OID strings, or the + * empty set if any policy is acceptable. + */ + public Set getInitialPolicies() + { + return Collections.unmodifiableSet(initPolicies); + } + + /** + * Sets the initial policy identifiers (as OID strings). If the + * argument is null or the empty set, then any policy identifier will + * be accepted. + * + * @param initPolicies The new set of policy strings, or null. + * @throws ClassCastException If any element in initPolicies is + * not a string. + */ + public void setInitialPolicies(Set initPolicies) + { + this.initPolicies.clear(); + if (initPolicies == null) + return; + for (Iterator i = initPolicies.iterator(); i.hasNext(); ) + { + this.initPolicies.add((String) i.next()); + } + } + + /** + * Add a {@link CertStore} to the list of cert stores. + * + * @param store The CertStore to add. + */ + public void addCertStore(CertStore store) + { + if (store != null) + certStores.add(store); + } + + /** + * Returns an immutable list of cert stores. This method never returns + * null. + * + * @return The list of cert stores. + */ + public List getCertStores() + { + return Collections.unmodifiableList(certStores); + } + + /** + * Set the cert stores. If the argument is null the list of cert + * stores will be empty. + * + * @param certStores The cert stores. + */ + public void setCertStores(List certStores) + { + this.certStores.clear(); + if (certStores == null) + return; + for (Iterator i = certStores.iterator(); i.hasNext(); ) + { + this.certStores.add((CertStore) i.next()); + } + } + + /** + * Returns the value of the revocation enabled flag. The default + * value for this flag is true. + * + * @return The revocation enabled flag. + */ + public boolean isRevocationEnabled() + { + return revocationEnabled; + } + + /** + * Sets the value of the revocation enabled flag. + * + * @param value The new value. + */ + public void setRevocationEnabled(boolean value) + { + revocationEnabled = value; + } + + /** + * Returns the value of the explicit policy required flag. The + * default value of this flag is false. + * + * @return The explicit policy required flag. + */ + public boolean isExplicitPolicyRequired() + { + return exPolicyRequired; + } + + /** + * Sets the value of the explicit policy required flag. + * + * @param value The new value. + */ + public void setExplicitPolicyRequired(boolean value) + { + exPolicyRequired = value; + } + + /** + * Returns the value of the policy mapping inhibited flag. The + * default value of this flag is false. + * + * @return The policy mapping inhibited flag. + */ + public boolean isPolicyMappingInhibited() + { + return policyMappingInhibited; + } + + /** + * Sets the value of the policy mapping inhibited flag. + * + * @param value The new value. + */ + public void setPolicyMappingInhibited(boolean value) + { + policyMappingInhibited = value; + } + + /** + * Returns the value of the any policy inhibited flag. The + * default value of this flag is false. + * + * @return The any policy inhibited flag. + */ + public boolean isAnyPolicyInhibited() + { + return anyPolicyInhibited; + } + + /** + * Sets the value of the any policy inhibited flag. + * + * @param value The new value. + */ + public void setAnyPolicyInhibited(boolean value) + { + anyPolicyInhibited = value; + } + + /** + * Returns the value of the policy qualifiers enabled flag. The + * default value of this flag is true. + * + * @return The policy qualifiers enabled flag. + */ + public boolean getPolicyQualifiersRejected() + { + return policyQualRejected; + } + + /** + * Sets the value of the policy qualifiers enabled flag. + * + * @param value The new value. + */ + public void setPolicyQualifiersRejected(boolean value) + { + policyQualRejected = value; + } + + /** + * Returns the date for which the certificate path should be + * validated, or null if the current time should be used. The date + * object is copied to prevent subsequent modification. + * + * @return The date, or null if not set. + */ + public Date getDate() + { + return date != null ? (Date) date.clone() : null; + } + + /** + * Sets the date for which the certificate path should be validated, + * or null if the current time should be used. + * + * @param date The new date, or null. + */ + public void setDate(Date date) + { + if (date != null) + this.date = (Date) date.clone(); + else + this.date = null; + } + + /** + * Add a certificate path checker. + * + * @param checker The certificate path checker to add. + */ + public void addCertPathChecker(PKIXCertPathChecker checker) + { + if (checker != null) + pathCheckers.add(checker); + } + + /** + * Returns an immutable list of all certificate path checkers. + * + * @return An immutable list of all certificate path checkers. + */ + public List getCertPathCheckers() + { + return Collections.unmodifiableList(pathCheckers); + } + + /** + * Sets the certificate path checkers. If the argument is null, the + * list of checkers will merely be cleared. + * + * @param pathCheckers The new list of certificate path checkers. + * @throws ClassCastException If any element of pathCheckers is + * not a {@link PKIXCertPathChecker}. + */ + public void setCertPathCheckers(List pathCheckers) + { + this.pathCheckers.clear(); + if (pathCheckers == null) + return; + for (Iterator i = pathCheckers.iterator(); i.hasNext(); ) + { + this.pathCheckers.add((PKIXCertPathChecker) i.next()); + } + } + + /** + * Returns the signature algorithm provider, or null if not set. + * + * @return The signature algorithm provider, or null if not set. + */ + public String getSigProvider() + { + return sigProvider; + } + + /** + * Sets the signature algorithm provider, or null if there is no + * preferred provider. + * + * @param sigProvider The signature provider name. + */ + public void setSigProvider(String sigProvider) + { + this.sigProvider = sigProvider; + } + + /** + * Returns the constraints placed on the target certificate, or null + * if there are none. The target constraints are copied to prevent + * subsequent modification. + * + * @return The target constraints, or null. + */ + public CertSelector getTargetCertConstraints() + { + return targetConstraints != null + ? (CertSelector) targetConstraints.clone() : null; + } + + /** + * Sets the constraints placed on the target certificate. + * + * @param targetConstraints The target constraints. + */ + public void setTargetCertConstraints(CertSelector targetConstraints) + { + this.targetConstraints = targetConstraints != null + ? (CertSelector) targetConstraints.clone() : null; + } + + /** + * Returns a copy of these parameters. + * + * @return The copy. + */ + public Object clone() + { + return new PKIXParameters(this); + } + + /** + * Returns a printable representation of these parameters. + * + * @return A printable representation of these parameters. + */ + public String toString() { + return "[ Trust Anchors: " + trustAnchors + "; Initial Policy OIDs=" + + (initPolicies != null ? initPolicies.toString() : "any") + + "; Validity Date=" + date + "; Signature Provider=" + + sigProvider + "; Default Revocation Enabled=" + revocationEnabled + + "; Explicit Policy Required=" + exPolicyRequired + + "; Policy Mapping Inhibited=" + policyMappingInhibited + + "; Any Policy Inhibited=" + anyPolicyInhibited + + "; Policy Qualifiers Rejected=" + policyQualRejected + + "; Target Cert Contstraints=" + targetConstraints + + "; Certification Path Checkers=" + pathCheckers + + "; CertStores=" + certStores + " ]"; + } +} diff --git a/libjava/classpath/java/security/cert/PolicyNode.java b/libjava/classpath/java/security/cert/PolicyNode.java new file mode 100644 index 0000000..58d411c --- /dev/null +++ b/libjava/classpath/java/security/cert/PolicyNode.java @@ -0,0 +1,102 @@ +/* PolicyNode.java -- a single node in a policy tree + 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 java.security.cert; + +public interface PolicyNode +{ + + /** + * Get the iterator of the child nodes of this node. The returned + * iterator is (naturally) unmodifiable. + * + * @return An iterator over the child nodes. + */ + java.util.Iterator getChildren(); + + /** + * Get the depth of this node within the tree, starting at 0 for the + * root node. + * + * @return The depth of this node. + */ + int getDepth(); + + /** + * Returns a set of policies (string OIDs) that will satisfy this + * node's policy. The root node should always return the singleton set + * with the element "any-policy". + * + * @return The set of expected policies. + */ + java.util.Set getExpectedPolicies(); + + /** + * Returns the parent node of this node, or null if this is the root + * node. + * + * @return The parent node, or null. + */ + PolicyNode getParent(); + + /** + * Returns a set of {@link PolicyQualifierInfo} objects that qualify + * the valid policy of this node. The root node should always return + * the empty set. + * + * @return The set of {@link PolicyQualifierInfo} objects. + */ + java.util.Set getPolicyQualifiers(); + + /** + * Get the policy OID this node represents. The root node should return + * the special value "any-policy". + * + * @return The policy of this node. + */ + String getValidPolicy(); + + /** + * Return the criticality flag of this policy node. Nodes who return + * true for this method should be considered critical. The root node + * is never critical. + * + * @return The criticality flag. + */ + boolean isCritical(); +} diff --git a/libjava/classpath/java/security/cert/PolicyQualifierInfo.java b/libjava/classpath/java/security/cert/PolicyQualifierInfo.java new file mode 100644 index 0000000..7dcf231 --- /dev/null +++ b/libjava/classpath/java/security/cert/PolicyQualifierInfo.java @@ -0,0 +1,168 @@ +/* PolicyQualifierInfo.java -- policy qualifier info object. + 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 java.security.cert; + +import gnu.java.io.ASN1ParsingException; +import gnu.java.security.OID; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** + * The PolicyQualifierInfo X.509 certificate extension. + * PolicyQualifierInfo objects are represented by the ASN.1 structure: + * + *

    + * PolicyQualifierInfo ::= SEQUENCE {
    + *    policyQualifierId   PolicyQualifierId,
    + *    qualifier           ANY DEFINED BY policyQualifierId
    + * }
    + *
    + * PolicyQualifierId ::= OBJECT IDENTIFIER
    + * 
    + * + * @since JDK 1.4 + */ +public final class PolicyQualifierInfo +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The policyQualifierId field. */ + private OID oid; + + /** The DER encoded form of this object. */ + private byte[] encoded; + + /** The DER encoded form of the qualifier field. */ + private DERValue qualifier; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Create a new PolicyQualifierInfo object from the DER encoded form + * passed in the byte array. The argument is copied. + * + *

    The ASN.1 form of PolicyQualifierInfo is: +

    +PolicyQualifierInfo ::= SEQUENCE {
    +   policyQualifierId     PolicyQualifierId,
    +   qualifier             ANY DEFINED BY policyQualifierId
    +}
    +
    +PolicyQualifierId ::= OBJECT IDENTIFIER
    +
    + * + * @param encoded The DER encoded form. + * @throws IOException If the structure cannot be parsed from the + * encoded bytes. + */ + public PolicyQualifierInfo(byte[] encoded) throws IOException + { + if (encoded == null) + throw new IOException("null bytes"); + this.encoded = (byte[]) encoded.clone(); + DERReader in = new DERReader(new ByteArrayInputStream(this.encoded)); + DERValue qualInfo = in.read(); + if (!qualInfo.isConstructed()) + throw new ASN1ParsingException("malformed PolicyQualifierInfo"); + DERValue val = in.read(); + if (!(val.getValue() instanceof OID)) + throw new ASN1ParsingException("value read not an OBJECT IDENTIFIER"); + oid = (OID) val.getValue(); + if (val.getEncodedLength() < val.getLength()) + qualifier = in.read(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the policyQualifierId field of this structure, + * as a dotted-decimal representation of the object identifier. + * + * @return This structure's OID field. + */ + public String getPolicyQualifierId() + { + return oid.toString(); + } + + /** + * Returns the DER encoded form of this object; the contents of the + * returned byte array are equivalent to those that were passed to the + * constructor. The byte array is cloned every time this method is + * called. + * + * @return The encoded form. + */ + public byte[] getEncoded() + { + return (byte[]) encoded.clone(); + } + + /** + * Get the qualifier field of this object, as a DER + * encoded byte array. The byte array returned is cloned every time + * this method is called. + * + * @return The encoded qualifier. + */ + public byte[] getPolicyQualifier() + { + if (qualifier == null) + return new byte[0]; + return qualifier.getEncoded(); + } + + /** + * Returns a printable string representation of this object. + * + * @return The string representation. + */ + public String toString() + { + return "PolicyQualifierInfo { policyQualifierId ::= " + oid + + ", qualifier ::= " + qualifier + " }"; + } +} diff --git a/libjava/classpath/java/security/cert/TrustAnchor.java b/libjava/classpath/java/security/cert/TrustAnchor.java new file mode 100644 index 0000000..2110ed5 --- /dev/null +++ b/libjava/classpath/java/security/cert/TrustAnchor.java @@ -0,0 +1,185 @@ +/* TrustAnchor.java -- an ultimately-trusted certificate. + 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 java.security.cert; + +import gnu.java.security.x509.X500DistinguishedName; + +import java.security.PublicKey; + +/** + * An ultimately-trusted certificate to serve as the root of a + * certificate chain. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class TrustAnchor +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The certificate authority's distinguished name. */ + private final X500DistinguishedName caName; + + /** The certficate authority's public key. */ + private final PublicKey caKey; + + /** The certficate authority's certificate. */ + private final X509Certificate trustedCert; + + /** The encoded name constraints bytes. */ + private final byte[] nameConstraints; + + // Constnuctors. + // ------------------------------------------------------------------------ + + /** + * Create a new trust anchor from a certificate and (optional) name + * constraints. + * + *

    If the nameConstraints argument in non-null, it will be + * copied to prevent modification. + * + * @param trustedCert The trusted certificate. + * @param nameConstraints The encoded nameConstraints. + */ + public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) + { + if (trustedCert == null) + throw new NullPointerException(); + this.trustedCert = trustedCert; + caName = null; + caKey = null; + if (nameConstraints != null) + this.nameConstraints = (byte[]) nameConstraints.clone(); + else + this.nameConstraints = null; + } + + /** + * Create a new trust anchor from a certificate authority's + * distinguished name, public key, and (optional) name constraints. + * + *

    If the nameConstraints argument in non-null, it will be + * copied to prevent modification. + * + * @params caName The CA's distinguished name. + * @params caKey The CA's public key. + * @params nameConstraints The encoded nameConstraints. + */ + public TrustAnchor(String caName, PublicKey caKey, byte[] nameConstraints) + { + if (caName == null || caKey == null) + throw new NullPointerException(); + if (caName.length() == 0) + throw new IllegalArgumentException(); + trustedCert = null; + this.caName = new X500DistinguishedName(caName); + this.caKey = caKey; + if (nameConstraints != null) + this.nameConstraints = (byte[]) nameConstraints.clone(); + else + this.nameConstraints = null; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Return the trusted certificate, or null if none was specified. + * + * @return The trusted certificate. + */ + public final X509Certificate getTrustedCert() + { + return trustedCert; + } + + /** + * Return the certificate authority's distinguished name, or null if + * none was specified. + * + * @return The CA's distinguished name. + */ + public final String getCAName() + { + if (caName != null) + return caName.toString(); + return null; + } + + /** + * Return the certificate authority's public key, or null if none was + * specified. + * + * @return The CA's public key. + */ + public final PublicKey getCAPublicKey() + { + return caKey; + } + + /** + * Return the encoded name constraints, or null if none was specified. + * + *

    The name constraints byte array is copied when this method is + * called to prevent modification. + * + * @return The encoded name constraints. + */ + public final byte[] getNameConstraints() + { + if (nameConstraints == null) + return null; + return (byte[]) nameConstraints.clone(); + } + + /** + * Return a printable representation of this trust anchor. + * + * @return The printable representation. + */ + public String toString() + { + if (trustedCert == null) + return "[ Trusted CA Public Key=" + caKey + ", Trusted CA Issuer Name=" + + caName.toString() + " ]"; + return "[ Trusted CA Certificate=" + trustedCert + " ]"; + } +} diff --git a/libjava/classpath/java/security/cert/X509CRL.java b/libjava/classpath/java/security/cert/X509CRL.java new file mode 100644 index 0000000..5657b3e --- /dev/null +++ b/libjava/classpath/java/security/cert/X509CRL.java @@ -0,0 +1,397 @@ +/* X509CRL.java --- X.509 Certificate Revocation List + 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 java.security.cert; + +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.SignatureException; +import java.util.Date; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + The X509CRL class is the abstract class used to manage + X.509 Certificate Revocation Lists. The CRL is a list of + time stamped entries which indicate which lists have been + revoked. The list is signed by a Certificate Authority (CA) + and made publically available in a repository. + + Each revoked certificate in the CRL is identified by its + certificate serial number. When a piece of code uses a + certificate, the certificates validity is checked by + validating its signature and determing that it is not + only a recently acquired CRL. The recently aquired CRL + is depends on the local policy in affect. The CA issues + a new CRL periodically and entries are removed as the + certificate expiration date is reached + + + A description of the X.509 v2 CRL follows below from rfc2459. + + "The X.509 v2 CRL syntax is as follows. For signature calculation, + the data that is to be signed is ASN.1 DER encoded. ASN.1 DER + encoding is a tag, length, value encoding system for each element. + + CertificateList ::= SEQUENCE { + tbsCertList TBSCertList, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING } + + TBSCertList ::= SEQUENCE { + version Version OPTIONAL, + -- if present, shall be v2 + signature AlgorithmIdentifier, + issuer Name, + thisUpdate Time, + nextUpdate Time OPTIONAL, + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, shall be v2 + } OPTIONAL, + crlExtensions [0] EXPLICIT Extensions OPTIONAL + -- if present, shall be v2 + }" + + @author Mark Benvenuto + + @since JDK 1.2 +*/ +public abstract class X509CRL extends CRL implements X509Extension +{ + + /** + Constructs a new X509CRL. + */ + protected X509CRL() + { + super("X.509"); + } + + /** + Compares this X509CRL to other. It checks if the + object if instanceOf X509CRL and then checks if + the encoded form matches. + + @param other An Object to test for equality + + @return true if equal, false otherwise + */ + public boolean equals(Object other) + { + if( other instanceof X509CRL ) { + try { + X509CRL x = (X509CRL) other; + if( getEncoded().length != x.getEncoded().length ) + return false; + + byte[] b1 = getEncoded(); + byte[] b2 = x.getEncoded(); + + for( int i = 0; i < b1.length; i++ ) + if( b1[i] != b2[i] ) + return false; + + } catch( CRLException crle ) { + return false; + } + return true; + } + return false; + } + + /** + Returns a hash code for this X509CRL in its encoded + form. + + @return A hash code of this class + */ + public int hashCode() + { + return super.hashCode(); + } + + /** + Gets the DER ASN.1 encoded format for this X.509 CRL. + + @return byte array containg encoded form + + @throws CRLException if an error occurs + */ + public abstract byte[] getEncoded() throws CRLException; + + /** + Verifies that this CRL was properly signed with the + PublicKey that corresponds to its private key. + + @param key PublicKey to verify with + + @throws CRLException encoding error + @throws NoSuchAlgorithmException unsupported algorithm + @throws InvalidKeyException incorrect key + @throws NoSuchProviderException no provider + @throws SignatureException signature error + */ + public abstract void verify(PublicKey key) + throws CRLException, + NoSuchAlgorithmException, + InvalidKeyException, + NoSuchProviderException, + SignatureException; + + /** + Verifies that this CRL was properly signed with the + PublicKey that corresponds to its private key and uses + the signature engine provided by the provider. + + @param key PublicKey to verify with + @param sigProvider Provider to use for signature algorithm + + @throws CRLException encoding error + @throws NoSuchAlgorithmException unsupported algorithm + @throws InvalidKeyException incorrect key + @throws NoSuchProviderException incorrect provider + @throws SignatureException signature error + */ + public abstract void verify(PublicKey key, + String sigProvider) + throws CRLException, + NoSuchAlgorithmException, + InvalidKeyException, + NoSuchProviderException, + SignatureException; + + /** + Gets the version of this CRL. + + The ASN.1 encoding is: + + version Version OPTIONAL, + -- if present, shall be v2 + + Version ::= INTEGER { v1(0), v2(1), v3(2) } + + Consult rfc2459 for more information. + + @return the version number, Ex: 1 or 2 + */ + public abstract int getVersion(); + + /** + Returns the issuer (issuer distinguished name) of the CRL. + The issuer is the entity who signed and issued the + Certificate Revocation List. + + The ASN.1 DER encoding is: + + issuer Name, + + Name ::= CHOICE { + RDNSequence } + + RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + + RelativeDistinguishedName ::= + SET OF AttributeTypeAndValue + + AttributeTypeAndValue ::= SEQUENCE { + type AttributeType, + value AttributeValue } + + AttributeType ::= OBJECT IDENTIFIER + + AttributeValue ::= ANY DEFINED BY AttributeType + + DirectoryString ::= CHOICE { + teletexString TeletexString (SIZE (1..MAX)), + printableString PrintableString (SIZE (1..MAX)), + universalString UniversalString (SIZE (1..MAX)), + utf8String UTF8String (SIZE (1.. MAX)), + bmpString BMPString (SIZE (1..MAX)) } + + Consult rfc2459 for more information. + + @return the issuer in the Principal class + */ + public abstract Principal getIssuerDN(); + + /** + Returns the thisUpdate date of the CRL. + + The ASN.1 DER encoding is: + + thisUpdate Time, + + Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime } + + Consult rfc2459 for more information. + + @return the thisUpdate date + */ + public abstract Date getThisUpdate(); + + /* + Gets the nextUpdate field + + The ASN.1 DER encoding is: + + nextUpdate Time OPTIONAL, + + Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime } + + Consult rfc2459 for more information. + + @return the nextUpdate date + */ + public abstract Date getNextUpdate(); + + /** + Gets the requeste dX509Entry for the specified + certificate serial number. + + @return a X509CRLEntry representing the X.509 CRL entry + */ + public abstract X509CRLEntry getRevokedCertificate(BigInteger serialNumber); + + /** + Returns a Set of revoked certificates. + + @return a set of revoked certificates. + */ + public abstract Set getRevokedCertificates(); + + /** + Returns the DER ASN.1 encoded tbsCertList which is + the basic information of the list and associated certificates + in the encoded state. See top for more information. + + The ASN.1 DER encoding is: + + tbsCertList TBSCertList, + + Consult rfc2459 for more information. + + @return byte array representing tbsCertList + */ + public abstract byte[] getTBSCertList() throws CRLException; + + + /** + Returns the signature for the CRL. + + The ASN.1 DER encoding is: + + signatureValue BIT STRING + + Consult rfc2459 for more information. + */ + public abstract byte[] getSignature(); + + /** + Returns the signature algorithm used to sign the CRL. + An examples is "SHA-1/DSA". + + The ASN.1 DER encoding is: + + signatureAlgorithm AlgorithmIdentifier, + + AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL } + + Consult rfc2459 for more information. + + The algorithm name is determined from the OID. + + @return a string with the signature algorithm name + */ + public abstract String getSigAlgName(); + + /** + Returns the OID for the signature algorithm used. + Example "1.2.840.10040.4.3" is return for SHA-1 with DSA.\ + + The ASN.1 DER encoding for the example is: + + id-dsa-with-sha1 ID ::= { + iso(1) member-body(2) us(840) x9-57 (10040) + x9cm(4) 3 } + + Consult rfc2459 for more information. + + @return a string containing the OID. + */ + public abstract String getSigAlgOID(); + + /** + Returns the AlgorithmParameters in the encoded form + for the signature algorithm used. + + If access to the parameters is need, create an + instance of AlgorithmParameters. + + @return byte array containing algorithm parameters, null + if no parameters are present in CRL + */ + public abstract byte[] getSigAlgParams(); + + // 1.4 instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the X.500 distinguished name of this CRL's issuer. + * + * @return The issuer's X.500 distinguished name. + * @since JDK 1.4 + */ + public X500Principal getIssuerX500Principal() + { + throw new UnsupportedOperationException(); + } +} diff --git a/libjava/classpath/java/security/cert/X509CRLEntry.java b/libjava/classpath/java/security/cert/X509CRLEntry.java new file mode 100644 index 0000000..4c9cada --- /dev/null +++ b/libjava/classpath/java/security/cert/X509CRLEntry.java @@ -0,0 +1,169 @@ +/* X509CRLEntry.java --- X.509 Certificate Revocation List Entry + Copyright (C) 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 java.security.cert; + +import java.math.BigInteger; +import java.util.Date; + +/** + Abstract class for entries in the CRL (Certificate Revocation + List). The ASN.1 definition for revokedCertificates is + + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, shall be v2 + } OPTIONAL, + + CertificateSerialNumber ::= INTEGER + + Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime } + + Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + + Extension ::= SEQUENCE { + extnID OBJECT IDENTIFIER, + critical BOOLEAN DEFAULT FALSE, + extnValue OCTET STRING } + + For more information consult rfc2459. + + @author Mark Benvenuto + + @since JDK 1.2 +*/ +public abstract class X509CRLEntry implements X509Extension +{ + + /** + Creates a new X509CRLEntry + */ + public X509CRLEntry() + {} + + /** + Compares this X509CRLEntry to other. It checks if the + object if instanceOf X509CRLEntry and then checks if + the encoded form( the inner SEQUENCE) matches. + + @param other An Object to test for equality + + @return true if equal, false otherwise + */ + public boolean equals(Object other) + { + if( other instanceof X509CRLEntry ) { + try { + X509CRLEntry xe = (X509CRLEntry) other; + if( getEncoded().length != xe.getEncoded().length ) + return false; + + byte[] b1 = getEncoded(); + byte[] b2 = xe.getEncoded(); + + for( int i = 0; i < b1.length; i++ ) + if( b1[i] != b2[i] ) + return false; + + } catch( CRLException crle ) { + return false; + } + return true; + } + return false; + } + + /** + Returns a hash code for this X509CRLEntry in its encoded + form. + + @return A hash code of this class + */ + public int hashCode() + { + return super.hashCode(); + } + + /** + Gets the DER ASN.1 encoded format for this CRL Entry, + the inner SEQUENCE. + + @return byte array containg encoded form + + @throws CRLException if an error occurs + */ + public abstract byte[] getEncoded() throws CRLException; + + /** + Gets the serial number for userCertificate in + this X509CRLEntry. + + @return the serial number for this X509CRLEntry. + */ + public abstract BigInteger getSerialNumber(); + + + /** + Gets the revocation date in revocationDate for + this X509CRLEntry. + + @return the revocation date for this X509CRLEntry. + */ + public abstract Date getRevocationDate(); + + + /** + Checks if this X509CRLEntry has extensions. + + @return true if it has extensions, false otherwise + */ + public abstract boolean hasExtensions(); + + + /** + Returns a string that represents this X509CRLEntry. + + @return a string representing this X509CRLEntry. + */ + public abstract String toString(); + +} diff --git a/libjava/classpath/java/security/cert/X509CRLSelector.java b/libjava/classpath/java/security/cert/X509CRLSelector.java new file mode 100644 index 0000000..3c79fba --- /dev/null +++ b/libjava/classpath/java/security/cert/X509CRLSelector.java @@ -0,0 +1,440 @@ +/* X509CRLSelector.java -- selects X.509 CRLs by criteria. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.security.cert; + +import gnu.classpath.SystemProperties; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.security.auth.x500.X500Principal; + +/** + * A class for matching X.509 certificate revocation lists by criteria. + * + *

    Use of this class requires extensive knowledge of the Internet + * Engineering Task Force's Public Key Infrastructure (X.509). The primary + * document describing this standard is RFC 3280: Internet X.509 + * Public Key Infrastructure Certificate and Certificate Revocation List + * (CRL) Profile. + * + *

    Note that this class is not thread-safe. If multiple threads will + * use or modify this class then they need to synchronize on the object. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class X509CRLSelector implements CRLSelector, Cloneable +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final String CRL_NUMBER_ID = "2.5.29.20"; + + private List issuerNames; + private BigInteger maxCrlNumber; + private BigInteger minCrlNumber; + private Date date; + private X509Certificate cert; + + // Constructor. + // ------------------------------------------------------------------------- + + /** + * Creates a new CRL selector with no criteria enabled; i.e., every CRL + * will be matched. + */ + public X509CRLSelector() + { + } + + // Instance methods. + // ------------------------------------------------------------------------- + + /** + * Add an issuer name to the set of issuer names criteria, as the DER + * encoded form. + * + * @param name The name to add, as DER bytes. + * @throws IOException If the argument is not a valid DER-encoding. + */ + public void addIssuerName(byte[] name) throws IOException + { + X500Principal p = null; + try + { + p = new X500Principal(name); + } + catch (IllegalArgumentException iae) + { + IOException ioe = new IOException("malformed name"); + ioe.initCause(iae); + throw ioe; + } + if (issuerNames == null) + issuerNames = new LinkedList(); + issuerNames.add(p); + } + + /** + * Add an issuer name to the set of issuer names criteria, as a + * String representation. + * + * @param name The name to add. + * @throws IOException If the argument is not a valid name. + */ + public void addIssuerName(String name) throws IOException + { + X500Principal p = null; + try + { + p = new X500Principal(name); + } + catch (IllegalArgumentException iae) + { + IOException ioe = new IOException("malformed name: " + name); + ioe.initCause(iae); + throw ioe; + } + if (issuerNames == null) + issuerNames = new LinkedList(); + issuerNames.add(p); + } + + /** + * Sets the issuer names criterion. Pass null to clear this + * value. CRLs matched by this selector must have an issuer name in this + * set. + * + * @param names The issuer names. + * @throws IOException If any of the elements in the collection is not + * a valid name. + */ + public void setIssuerNames(Collection names) throws IOException + { + if (names == null) + { + issuerNames = null; + return; + } + List l = new ArrayList(names.size()); + for (Iterator it = names.iterator(); it.hasNext(); ) + { + Object o = it.next(); + if (o instanceof X500Principal) + l.add(o); + else if (o instanceof String) + { + try + { + l.add(new X500Principal((String) o)); + } + catch (IllegalArgumentException iae) + { + IOException ioe = new IOException("malformed name: " + o); + ioe.initCause(iae); + throw ioe; + } + } + else if (o instanceof byte[]) + { + try + { + l.add(new X500Principal((byte[]) o)); + } + catch (IllegalArgumentException iae) + { + IOException ioe = new IOException("malformed name"); + ioe.initCause(iae); + throw ioe; + } + } + else if (o instanceof InputStream) + { + try + { + l.add(new X500Principal((InputStream) o)); + } + catch (IllegalArgumentException iae) + { + IOException ioe = new IOException("malformed name"); + ioe.initCause(iae); + throw ioe; + } + } + else + throw new IOException("not a valid name: " + + (o != null ? o.getClass().getName() : "null")); + + } + issuerNames = l; + } + + /** + * Returns the set of issuer names that are matched by this selector, + * or null if this criteria is not set. The returned + * collection is not modifiable. + * + * @return The set of issuer names. + */ + public Collection getIssuerNames() + { + if (issuerNames != null) + return Collections.unmodifiableList(issuerNames); + else + return null; + } + + /** + * Returns the maximum value of the CRLNumber extension present in + * CRLs matched by this selector, or null if this + * criteria is not set. + * + * @return The maximum CRL number. + */ + public BigInteger getMaxCRL() + { + return maxCrlNumber; + } + + /** + * Returns the minimum value of the CRLNumber extension present in + * CRLs matched by this selector, or null if this + * criteria is not set. + * + * @return The minimum CRL number. + */ + public BigInteger getMinCRL() + { + return minCrlNumber; + } + + /** + * Sets the maximum value of the CRLNumber extension present in CRLs + * matched by this selector. Specify null to clear this + * criterion. + * + * @param maxCrlNumber The maximum CRL number. + */ + public void setMaxCRLNumber(BigInteger maxCrlNumber) + { + this.maxCrlNumber = maxCrlNumber; + } + + /** + * Sets the minimum value of the CRLNumber extension present in CRLs + * matched by this selector. Specify null to clear this + * criterion. + * + * @param minCrlNumber The minimum CRL number. + */ + public void setMinCRLNumber(BigInteger minCrlNumber) + { + this.minCrlNumber = minCrlNumber; + } + + /** + * Returns the date when this CRL must be valid; that is, the date + * must be after the thisUpdate date, but before the nextUpdate date. + * Returns null if this criterion is not set. + * + * @return The date. + */ + public Date getDateAndTime() + { + return date != null ? (Date) date.clone() : null; + } + + /** + * Sets the date at which this CRL must be valid. Specify + * null to clear this criterion. + * + * @param date The date. + */ + public void setDateAndTime(Date date) + { + this.date = date != null ? (Date) date.clone() : null; + } + + /** + * Returns the certificate being checked, or null if this + * value is not set. + * + * @return The certificate. + */ + public X509Certificate getCertificateChecking() + { + return cert; + } + + /** + * Sets the certificate being checked. This is not a criterion, but + * info used by certificate store implementations to aid in searching. + * + * @param cert The certificate. + */ + public void setCertificateChecking(X509Certificate cert) + { + this.cert = cert; + } + + /** + * Returns a string representation of this selector. The string will + * only describe the enabled criteria, so if none are enabled this will + * return a string that contains little else besides the class name. + * + * @return The string. + */ + public String toString() + { + StringBuffer str = new StringBuffer(X509CRLSelector.class.getName()); + String nl = SystemProperties.getProperty("line.separator"); + String eol = ";" + nl; + + str.append(" {").append(nl); + if (issuerNames != null) + str.append(" issuer names = ").append(issuerNames).append(eol); + if (maxCrlNumber != null) + str.append(" max CRL = ").append(maxCrlNumber).append(eol); + if (minCrlNumber != null) + str.append(" min CRL = ").append(minCrlNumber).append(eol); + if (date != null) + str.append(" date = ").append(date).append(eol); + if (cert != null) + str.append(" certificate = ").append(cert).append(eol); + str.append("}").append(nl); + return str.toString(); + } + + /** + * Checks a CRL against the criteria of this selector, returning + * true if the given CRL matches all the criteria. + * + * @param _crl The CRL being checked. + * @return True if the CRL matches, false otherwise. + */ + public boolean match(CRL _crl) + { + if (!(_crl instanceof X509CRL)) + return false; + X509CRL crl = (X509CRL) _crl; + if (issuerNames != null) + { + if (!issuerNames.contains(crl.getIssuerX500Principal())) + return false; + } + BigInteger crlNumber = null; + if (maxCrlNumber != null) + { + byte[] b = crl.getExtensionValue(CRL_NUMBER_ID); + if (b == null) + return false; + try + { + DERValue val = DERReader.read(b); + if (!(val.getValue() instanceof BigInteger)) + return false; + crlNumber = (BigInteger) val.getValue(); + } + catch (IOException ioe) + { + return false; + } + if (maxCrlNumber.compareTo(crlNumber) < 0) + return false; + } + if (minCrlNumber != null) + { + if (crlNumber == null) + { + byte[] b = crl.getExtensionValue(CRL_NUMBER_ID); + if (b == null) + return false; + try + { + DERValue val = DERReader.read(b); + if (!(val.getValue() instanceof BigInteger)) + return false; + crlNumber = (BigInteger) val.getValue(); + } + catch (IOException ioe) + { + return false; + } + } + if (minCrlNumber.compareTo(crlNumber) > 0) + return false; + } + if (date != null) + { + if (date.compareTo(crl.getThisUpdate()) < 0 || + date.compareTo(crl.getNextUpdate()) > 0) + return false; + } + return true; + } + + /** + * Returns a copy of this object. + * + * @return The copy. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException shouldNotHappen) + { + throw new Error(shouldNotHappen); + } + } +} diff --git a/libjava/classpath/java/security/cert/X509CertSelector.java b/libjava/classpath/java/security/cert/X509CertSelector.java new file mode 100644 index 0000000..4149a37 --- /dev/null +++ b/libjava/classpath/java/security/cert/X509CertSelector.java @@ -0,0 +1,1106 @@ +/* X509CertSelector.java -- selects X.509 certificates by criteria. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.security.cert; + +import gnu.classpath.SystemProperties; +import gnu.java.security.OID; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PublicKey; +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.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * A concrete implementation of {@link CertSelector} for X.509 certificates, + * which allows a number of criteria to be set when accepting certificates, + * from validity dates, to issuer and subject distinguished names, to some + * of the various X.509 extensions. + * + *

    Use of this class requires extensive knowledge of the Internet + * Engineering Task Force's Public Key Infrastructure (X.509). The primary + * document describing this standard is RFC 3280: Internet X.509 + * Public Key Infrastructure Certificate and Certificate Revocation List + * (CRL) Profile. + * + *

    Note that this class is not thread-safe. If multiple threads will + * use or modify this class then they need to synchronize on the object. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class X509CertSelector implements CertSelector, Cloneable +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final String AUTH_KEY_ID = "2.5.29.35"; + private static final String SUBJECT_KEY_ID = "2.5.29.14"; + private static final String NAME_CONSTRAINTS_ID = "2.5.29.30"; + + private int basicConstraints; + private X509Certificate cert; + private BigInteger serialNo; + private X500Principal issuer; + private X500Principal subject; + private byte[] subjectKeyId; + private byte[] authKeyId; + private boolean[] keyUsage; + private Date certValid; + private OID sigId; + private PublicKey subjectKey; + private X509EncodedKeySpec subjectKeySpec; + private Set keyPurposeSet; + private List altNames; + private boolean matchAllNames; + private byte[] nameConstraints; + private Set policy; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Creates a new X.509 certificate selector. The new selector will be + * empty, and will accept any certificate (provided that it is an + * {@link X509Certificate}). + */ + public X509CertSelector() + { + basicConstraints = -1; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the certificate criterion, or null if this value + * was not set. + * + * @return The certificate. + */ + public X509Certificate getCertificate() + { + return cert; + } + + /** + * Sets the certificate criterion. If set, only certificates that are + * equal to the certificate passed here will be accepted. + * + * @param cert The certificate. + */ + public void setCertificate(X509Certificate cert) + { + this.cert = cert; + } + + /** + * Returns the serial number criterion, or null if this + * value was not set. + * + * @return The serial number. + */ + public BigInteger getSerialNumber() + { + return serialNo; + } + + /** + * Sets the serial number of the desired certificate. Only certificates that + * contain this serial number are accepted. + * + * @param serialNo The serial number. + */ + public void setSerialNumber(BigInteger serialNo) + { + this.serialNo = serialNo; + } + + /** + * Returns the issuer criterion as a string, or null if this + * value was not set. + * + * @return The issuer. + */ + public String getIssuerAsString() + { + if (issuer != null) + return issuer.getName(); + else + return null; + } + + /** + * Returns the issuer criterion as a sequence of DER bytes, or + * null if this value was not set. + * + * @return The issuer. + */ + public byte[] getIssuerAsBytes() throws IOException + { + if (issuer != null) + return issuer.getEncoded(); + else + return null; + } + + /** + * Sets the issuer, specified as a string representation of the issuer's + * distinguished name. Only certificates issued by this issuer will + * be accepted. + * + * @param name The string representation of the issuer's distinguished name. + * @throws IOException If the given name is incorrectly formatted. + */ + public void setIssuer(String name) throws IOException + { + if (name != null) + { + try + { + issuer = new X500Principal(name); + } + catch (IllegalArgumentException iae) + { + throw new IOException(iae.getMessage()); + } + } + else + issuer = null; + } + + /** + * Sets the issuer, specified as the DER encoding of the issuer's + * distinguished name. Only certificates issued by this issuer will + * be accepted. + * + * @param name The DER encoding of the issuer's distinguished name. + * @throws IOException If the given name is incorrectly formatted. + */ + public void setIssuer(byte[] name) throws IOException + { + if (name != null) + { + try + { + issuer = new X500Principal(name); + } + catch (IllegalArgumentException iae) + { + throw new IOException(iae.getMessage()); + } + } + else + issuer = null; + } + + /** + * Returns the subject criterion as a string, of null if + * this value was not set. + * + * @return The subject. + */ + public String getSubjectAsString() + { + if (subject != null) + return subject.getName(); + else + return null; + } + + /** + * Returns the subject criterion as a sequence of DER bytes, or + * null if this value is not set. + * + * @return The subject. + */ + public byte[] getSubjectAsBytes() throws IOException + { + if (subject != null) + return subject.getEncoded(); + else + return null; + } + + /** + * Sets the subject, specified as a string representation of the + * subject's distinguished name. Only certificates with the given + * subject will be accepted. + * + * @param name The string representation of the subject's distinguished name. + * @throws IOException If the given name is incorrectly formatted. + */ + public void setSubject(String name) throws IOException + { + if (name != null) + { + try + { + subject = new X500Principal(name); + } + catch (IllegalArgumentException iae) + { + throw new IOException(iae.getMessage()); + } + } + else + subject = null; + } + + /** + * Sets the subject, specified as the DER encoding of the subject's + * distinguished name. Only certificates with the given subject will + * be accepted. + * + * @param name The DER encoding of the subject's distinguished name. + * @throws IOException If the given name is incorrectly formatted. + */ + public void setSubject(byte[] name) throws IOException + { + if (name != null) + { + try + { + subject = new X500Principal(name); + } + catch (IllegalArgumentException iae) + { + throw new IOException(iae.getMessage()); + } + } + else + subject = null; + } + + /** + * Returns the subject key identifier criterion, or null if + * this value was not set. Note that the byte array is cloned to prevent + * modification. + * + * @return The subject key identifier. + */ + public byte[] getSubjectKeyIdentifier() + { + if (subjectKeyId != null) + return (byte[]) subjectKeyId.clone(); + else + return null; + } + + /** + * Sets the subject key identifier criterion, or null to clear + * this criterion. Note that the byte array is cloned to prevent modification. + * + * @param subjectKeyId The subject key identifier. + */ + public void setSubjectKeyIdentifier(byte[] subjectKeyId) + { + this.subjectKeyId = subjectKeyId != null ? (byte[]) subjectKeyId.clone() : + null; + } + + /** + * Returns the authority key identifier criterion, or null if + * this value was not set. Note that the byte array is cloned to prevent + * modification. + * + * @return The authority key identifier. + */ + public byte[] getAuthorityKeyIdentifier() + { + if (authKeyId != null) + return (byte[]) authKeyId.clone(); + else + return null; + } + + /** + * Sets the authority key identifier criterion, or null to clear + * this criterion. Note that the byte array is cloned to prevent modification. + * + * @param subjectKeyId The subject key identifier. + */ + public void setAuthorityKeyIdentifier(byte[] authKeyId) + { + this.authKeyId = authKeyId != null ? (byte[]) authKeyId.clone() : null; + } + + /** + * Returns the date at which certificates must be valid, or null + * if this criterion was not set. + * + * @return The target certificate valitity date. + */ + public Date getCertificateValid() + { + if (certValid != null) + return (Date) certValid.clone(); + else + return null; + } + + /** + * Sets the date at which certificates must be valid. Specify + * null to clear this criterion. + * + * @param certValid The certificate validity date. + */ + public void setCertificateValid(Date certValid) + { + this.certValid = certValid != null ? (Date) certValid.clone() : null; + } + + /** + * This method, and its related X.509 certificate extension — the + * private key usage period — is not supported under the Internet + * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this + * method is not supported either. + * + *

    Do not use this method. It is not deprecated, as it is not deprecated + * in the Java standard, but it is basically a no-operation and simply + * returns null. + * + * @return Null. + */ + public Date getPrivateKeyValid() + { + return null; + } + + /** + * This method, and its related X.509 certificate extension — the + * private key usage period — is not supported under the Internet + * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this + * method is not supported either. + * + *

    Do not use this method. It is not deprecated, as it is not deprecated + * in the Java standard, but it is basically a no-operation. + * + * @param UNUSED Is silently ignored. + */ + public void setPrivateKeyValid(Date UNUSED) + { + } + + /** + * Returns the public key algorithm ID that matching certificates must have, + * or null if this criterion was not set. + * + * @return The public key algorithm ID. + */ + public String getSubjectPublicKeyAlgID() + { + return String.valueOf(sigId); + } + + /** + * Sets the public key algorithm ID that matching certificates must have. + * Specify null to clear this criterion. + * + * @param sigId The public key ID. + * @throws IOException If the specified ID is not a valid object identifier. + */ + public void setSubjectPublicKeyAlgID(String sigId) throws IOException + { + if (sigId != null) + { + try + { + OID oid = new OID(sigId); + int[] comp = oid.getIDs(); + if (!checkOid(comp)) + throw new IOException("malformed OID: " + sigId); + this.sigId = oid; + } + catch (IllegalArgumentException iae) + { + IOException ioe = new IOException("malformed OID: " + sigId); + ioe.initCause(iae); + throw ioe; + } + } + else + this.sigId = null; + } + + /** + * Returns the subject public key criterion, or null if this + * value is not set. + * + * @return The subject public key. + */ + public PublicKey getSubjectPublicKey() + { + return subjectKey; + } + + /** + * Sets the subject public key criterion as an opaque representation. + * Specify null to clear this criterion. + * + * @param key The public key. + */ + public void setSubjectPublicKey(PublicKey key) + { + this.subjectKey = key; + if (key == null) + { + subjectKeySpec = null; + return; + } + try + { + KeyFactory enc = KeyFactory.getInstance("X.509"); + subjectKeySpec = (X509EncodedKeySpec) + enc.getKeySpec(key, X509EncodedKeySpec.class); + } + catch (Exception x) + { + subjectKey = null; + subjectKeySpec = null; + } + } + + /** + * Sets the subject public key criterion as a DER-encoded key. Specify + * null to clear this value. + * + * @param key The DER-encoded key bytes. + * @throws IOException If the argument is not a valid DER-encoded key. + */ + public void setSubjectPublicKey(byte[] key) throws IOException + { + if (key == null) + { + subjectKey = null; + subjectKeySpec = null; + return; + } + try + { + subjectKeySpec = new X509EncodedKeySpec(key); + KeyFactory enc = KeyFactory.getInstance("X.509"); + subjectKey = enc.generatePublic(subjectKeySpec); + } + catch (Exception x) + { + subjectKey = null; + subjectKeySpec = null; + IOException ioe = new IOException(x.getMessage()); + ioe.initCause(x); + throw ioe; + } + } + + /** + * Returns the public key usage criterion, or null if this + * value is not set. Note that the array is cloned to prevent modification. + * + * @return The public key usage. + */ + public boolean[] getKeyUsage() + { + if (keyUsage != null) + return (boolean[]) keyUsage.clone(); + else + return null; + } + + /** + * Sets the public key usage criterion. Specify null to clear + * this value. + * + * @param keyUsage The public key usage. + */ + public void setKeyUsage(boolean[] keyUsage) + { + this.keyUsage = keyUsage != null ? (boolean[]) keyUsage.clone() : null; + } + + /** + * Returns the set of extended key purpose IDs, as an unmodifiable set + * of OID strings. Returns null if this criterion is not + * set. + * + * @return The set of key purpose OIDs (strings). + */ + public Set getExtendedKeyUsage() + { + if (keyPurposeSet != null) + return Collections.unmodifiableSet(keyPurposeSet); + else + return null; + } + + /** + * Sets the extended key usage criterion, as a set of OID strings. Specify + * null to clear this value. + * + * @param keyPurposeSet The set of key purpose OIDs. + * @throws IOException If any element of the set is not a valid OID string. + */ + public void setExtendedKeyUsage(Set keyPurposeSet) throws IOException + { + if (keyPurposeSet == null) + { + this.keyPurposeSet = null; + return; + } + Set s = new HashSet(); + for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); ) + { + Object o = it.next(); + if (!(o instanceof String)) + throw new IOException("not a string: " + o); + try + { + OID oid = new OID((String) o); + int[] comp = oid.getIDs(); + if (!checkOid(comp)) + throw new IOException("malformed OID: " + o); + } + catch (IllegalArgumentException iae) + { + IOException ioe = new IOException("malformed OID: " + o); + ioe.initCause(iae); + throw ioe; + } + } + this.keyPurposeSet = s; + } + + /** + * Returns whether or not all specified alternative names must match. + * If false, a certificate is considered a match if one of the + * specified alternative names matches. + * + * @return true if all names must match. + */ + public boolean getMatchAllSubjectAltNames() + { + return matchAllNames; + } + + /** + * Sets whether or not all subject alternative names must be matched. + * If false, then a certificate will be considered a match if one + * alternative name matches. + * + * @param matchAllNames Whether or not all alternative names must be + * matched. + */ + public void setMatchAllSubjectAltNames(boolean matchAllNames) + { + this.matchAllNames = matchAllNames; + } + + /** + * Sets the subject alternative names critertion. Each element of the + * argument must be a {@link java.util.List} that contains exactly two + * elements: the first an {@link Integer}, representing the type of + * name, and the second either a {@link String} or a byte array, + * representing the name itself. + * + * @param altNames The alternative names. + * @throws IOException If any element of the argument is invalid. + */ + public void setSubjectAlternativeNames(Collection altNames) + throws IOException + { + if (altNames == null) + { + this.altNames = null; + return; + } + List l = new ArrayList(altNames.size()); + for (Iterator it = altNames.iterator(); it.hasNext(); ) + { + Object o = it.next(); + if (!(o instanceof List) || ((List) o).size() != 2 || + !(((List) o).get(0) instanceof Integer) || + !(((List) o).get(1) instanceof String) || + !(((List) o).get(1) instanceof byte[])) + throw new IOException("illegal alternative name: " + o); + Integer i = (Integer) ((List) o).get(0); + if (i.intValue() < 0 || i.intValue() > 8) + throw new IOException("illegal alternative name: " + o + + ", bad id: " + i); + l.add(new ArrayList((List) o)); + } + this.altNames = l; + } + + /** + * Add a name to the subject alternative names criterion. + * + * @param id The type of name this is. Must be in the range [0,8]. + * @param name The name. + * @throws IOException If the id is out of range, or if the name + * is null. + */ + public void addSubjectAlternativeName(int id, String name) + throws IOException + { + if (id < 0 || id > 8 || name == null) + throw new IOException("illegal alternative name"); + if (altNames == null) + altNames = new LinkedList(); + ArrayList l = new ArrayList(2); + l.add(new Integer(id)); + l.add(name); + altNames.add(l); + } + + /** + * Add a name, as DER-encoded bytes, to the subject alternative names + * criterion. + * + * @param id The type of name this is. + */ + public void addSubjectAlternativeName(int id, byte[] name) + throws IOException + { + if (id < 0 || id > 8 || name == null) + throw new IOException("illegal alternative name"); + if (altNames == null) + altNames = new LinkedList(); + ArrayList l = new ArrayList(2); + l.add(new Integer(id)); + l.add(name); + altNames.add(l); + } + + /** + * Returns the name constraints criterion, or null if this + * value is not set. Note that the byte array is cloned to prevent + * modification. + * + * @return The name constraints. + */ + public byte[] getNameConstraints() + { + if (nameConstraints != null) + return (byte[]) nameConstraints.clone(); + else + return null; + } + + /** + * Sets the name constraints criterion; specify null to + * clear this criterion. Note that if non-null, the argument will be + * cloned to prevent modification. + * + * @param nameConstraints The new name constraints. + * @throws IOException If the argument is not a valid DER-encoded + * name constraints. + */ + public void setNameConstraints(byte[] nameConstraints) + throws IOException + { + // FIXME check if the argument is valid. + this.nameConstraints = nameConstraints != null + ? (byte[]) nameConstraints.clone() : null; + } + + /** + * Returns the basic constraints criterion, or -1 if this value is not set. + * + * @return The basic constraints. + */ + public int getBasicConstraints() + { + return basicConstraints; + } + + /** + * Sets the basic constraints criterion. Specify -1 to clear this parameter. + * + * @param basicConstraints The new basic constraints value. + */ + public void setBasicConstraints(int basicConstraints) + { + if (basicConstraints < -1) + basicConstraints = -1; + this.basicConstraints = basicConstraints; + } + + // The last two criteria not yet implemented are certificate policies + // and path-to-names. Both of these are somewhat advanced extensions + // (you could probably count the applications that actually use them + // on one hand), and they both have no support in the X509Certificate + // class. + // + // Not having support in X509Certificate is not always a problem; for + // example, we can compare DER-encoded values as byte arrays for some + // extensions. We can't, however, compare them if they are specified + // in a set (as policies are). We need to parse the actual value in the + // certificate, and check it against the specified set. + + // FIXME +// public void setPolicy(Set policy) throws IOException +// { +// if (policy != null) +// { +// for (Iterator it = policy.iterator(); it.hasNext(); ) +// try +// { +// OID oid = new OID((String) it.next()); +// int[] i = oid.getIDs(); +// if (!checkOid(i)) +// throw new IOException("invalid OID"); +// } +// catch (Exception x) +// { +// throw new IOException("invalid OID"); +// } +// } +// this.policy = policy != null ? new HashSet(policy) : null; +// } + + // FIXME +// public void setPathToNames(Collection names) throws IOException +// { +// if (names == null) +// { +// this.names = null; +// return; +// } +// for (Iterator it = names.iterator(); it.hasNext(); ) +// { +// try +// { +// List l = (List) it.next(); +// if (l.get(1) instanceof String) +// addPathToName(((Integer)l.get(0)).intValue(), (String)l.get(1)); +// else +// addPathToName(((Integer)l.get(0)).intValue(), (byte[])l.get(1)); +// } +// catch (Exception x) +// { +// this.names = null; +// throw new IOException("invalid names"); +// } +// } +// } + + // FIXME +// public void addPathToName(int id, String name) throws IOException +// { +// } + + // FIXME +// public void addPathToName(int id, byte[] name) throws IOException +// { +// } + + // FIXME +// public Collection getSubjectAlternativeNames() +// { +// return null; +// } + + // FIXME +// public Set getPolicy() +// { +// return null; +// } + + // FIXME +// public Collection getPathToNames() +// { +// return null; +// } + + /** + * Match a certificate. This method will check the given certificate + * against all the enabled criteria of this selector, and will return + * true if the given certificate matches. + * + * @param certificate The certificate to check. + * @return true if the certificate matches all criteria. + */ + public boolean match(Certificate certificate) + { + if (!(certificate instanceof X509Certificate)) + return false; + X509Certificate cert = (X509Certificate) certificate; + if (this.cert != null) + { + try + { + byte[] e1 = this.cert.getEncoded(); + byte[] e2 = cert.getEncoded(); + if (!Arrays.equals(e1, e2)) + return false; + } + catch (CertificateEncodingException cee) + { + return false; + } + } + if (serialNo != null) + { + if (!serialNo.equals(cert.getSerialNumber())) + return false; + } + if (certValid != null) + { + try + { + cert.checkValidity(certValid); + } + catch (CertificateException ce) + { + return false; + } + } + if (issuer != null) + { + if (!issuer.equals(cert.getIssuerX500Principal())) + return false; + } + if (subject != null) + { + if (!subject.equals(cert.getSubjectX500Principal())) + return false; + } + if (sigId != null) + { + if (!sigId.equals(cert.getSigAlgOID())) + return false; + } + if (subjectKeyId != null) + { + byte[] b = cert.getExtensionValue(SUBJECT_KEY_ID); + if (!Arrays.equals(b, subjectKeyId)) + return false; + } + if (authKeyId != null) + { + byte[] b = cert.getExtensionValue(AUTH_KEY_ID); + if (!Arrays.equals(b, authKeyId)) + return false; + } + if (keyUsage != null) + { + boolean[] b = cert.getKeyUsage(); + if (!Arrays.equals(b, keyUsage)) + return false; + } + if (basicConstraints >= 0) + { + if (cert.getBasicConstraints() != basicConstraints) + return false; + } + if (keyPurposeSet != null) + { + List kp = null; + try + { + kp = cert.getExtendedKeyUsage(); + } + catch (CertificateParsingException cpe) + { + return false; + } + if (kp == null) + return false; + for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); ) + { + if (!kp.contains(it.next())) + return false; + } + } + if (altNames != null) + { + Collection an = null; + try + { + an = cert.getSubjectAlternativeNames(); + } + catch (CertificateParsingException cpe) + { + return false; + } + if (an == null) + return false; + int match = 0; + for (Iterator it = altNames.iterator(); it.hasNext(); ) + { + List l = (List) it.next(); + Integer id = (Integer) l.get(0); + String s = null; + byte[] b = null; + if (l.get(1) instanceof String) + s = (String) l.get(1); + else if (l.get(1) instanceof byte[]) + b = (byte[]) l.get(1); + else + return false; + for (Iterator it2 = an.iterator(); it2.hasNext(); ) + { + Object o = it2.next(); + if (!(o instanceof List)) + continue; + List l2 = (List) o; + if (l2.size() != 2) + continue; + if (!id.equals(l2.get(0))) + continue; + if (s != null && (l2.get(1) instanceof String) && + s.equals(l2.get(1))) + match++; + else if (b != null && (l2.get(1) instanceof byte[]) && + Arrays.equals(b, (byte[]) l2.get(1))) + match++; + } + if (match == 0 || (matchAllNames && match != altNames.size())) + return false; + } + } + if (nameConstraints != null) + { + byte[] nc = cert.getExtensionValue(NAME_CONSTRAINTS_ID); + if (!Arrays.equals(nameConstraints, nc)) + return false; + } + + // FIXME check policies. + // FIXME check path-to-names. + + return true; + } + + public String toString() + { + StringBuffer str = new StringBuffer(X509CertSelector.class.getName()); + String nl = SystemProperties.getProperty("line.separator"); + String eol = ";" + nl; + str.append(" {").append(nl); + if (cert != null) + str.append(" certificate = ").append(cert).append(eol); + if (basicConstraints >= 0) + str.append(" basic constraints = ").append(basicConstraints).append(eol); + if (serialNo != null) + str.append(" serial number = ").append(serialNo).append(eol); + if (certValid != null) + str.append(" valid date = ").append(certValid).append(eol); + if (issuer != null) + str.append(" issuer = ").append(issuer).append(eol); + if (subject != null) + str.append(" subject = ").append(subject).append(eol); + if (sigId != null) + str.append(" signature OID = ").append(sigId).append(eol); + if (subjectKey != null) + str.append(" subject public key = ").append(subjectKey).append(eol); + if (subjectKeyId != null) + { + str.append(" subject key ID = "); + for (int i = 0; i < subjectKeyId.length; i++) + { + str.append(Character.forDigit((subjectKeyId[i] & 0xF0) >>> 8, 16)); + str.append(Character.forDigit((subjectKeyId[i] & 0x0F), 16)); + if (i < subjectKeyId.length - 1) + str.append(':'); + } + str.append(eol); + } + if (authKeyId != null) + { + str.append(" authority key ID = "); + for (int i = 0; i < authKeyId.length; i++) + { + str.append(Character.forDigit((authKeyId[i] & 0xF0) >>> 8, 16)); + str.append(Character.forDigit((authKeyId[i] & 0x0F), 16)); + if (i < authKeyId.length - 1) + str.append(':'); + } + str.append(eol); + } + if (keyUsage != null) + { + str.append(" key usage = "); + for (int i = 0; i < keyUsage.length; i++) + str.append(keyUsage[i] ? '1' : '0'); + str.append(eol); + } + if (keyPurposeSet != null) + str.append(" key purpose = ").append(keyPurposeSet).append(eol); + if (altNames != null) + str.append(" alternative names = ").append(altNames).append(eol); + if (nameConstraints != null) + str.append(" name constraints = ").append(eol); + str.append("}").append(nl); + return str.toString(); + } + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException shouldNotHappen) + { + throw new Error(shouldNotHappen); + } + } + + // Own methods. + // ------------------------------------------------------------------------- + + private static boolean checkOid(int[] oid) + { + return (oid != null && oid.length > 2 && + (oid[0] >= 0 && oid[0] <= 2) && (oid[1] >= 0 && oid[1] <= 39)); + } +} diff --git a/libjava/classpath/java/security/cert/X509Certificate.java b/libjava/classpath/java/security/cert/X509Certificate.java new file mode 100644 index 0000000..f6c6fcf --- /dev/null +++ b/libjava/classpath/java/security/cert/X509Certificate.java @@ -0,0 +1,588 @@ +/* X509Certificate.java --- X.509 Certificate class + 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 java.security.cert; + +import java.math.BigInteger; +import java.security.Principal; +import java.util.Date; + +/** + * X509Certificate is the abstract class for X.509 certificates. + * This provides a stanard class interface for accessing all + * the attributes of X.509 certificates. + * + *

    In June 1996, the basic X.509 v3 format was finished by + * ISO/IEC and ANSI X.9. The ASN.1 DER format is below: + * + *

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

    These certificates are widely used in various Internet + * protocols to support authentication. It is used in + * Privacy Enhanced Mail (PEM), Transport Layer Security (TLS), + * Secure Sockets Layer (SSL), code signing for trusted software + * distribution, and Secure Electronic Transactions (SET). + * + *

    The certificates are managed and vouched for by + * Certificate Authorities (CAs). CAs are companies or + * groups that create certificates by placing the data in the + * X.509 certificate format and signing it with their private + * key. CAs serve as trusted third parties by certifying that + * the person or group specified in the certificate is who + * they say they are. + * + *

    The ASN.1 defintion for tbsCertificate is + * + *

    + * TBSCertificate  ::=  SEQUENCE  {
    + *   version         [0]  EXPLICIT Version DEFAULT v1,
    + *   serialNumber         CertificateSerialNumber,
    + *   signature            AlgorithmIdentifier,
    + *   issuer               Name,
    + *   validity             Validity,
    + *   subject              Name,
    + *   subjectPublicKeyInfo SubjectPublicKeyInfo,
    + *   issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
    + *                        -- If present, version shall be v2 or v3
    + *   subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
    + *                        -- If present, version shall be v2 or v3
    + *   extensions      [3]  EXPLICIT Extensions OPTIONAL
    + *                        -- If present, version shall be v3
    + * }
    + *
    + * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
    + *
    + * CertificateSerialNumber  ::=  INTEGER
    + *
    + * Validity ::= SEQUENCE {
    + *   notBefore      Time,
    + *   notAfter       Time }
    + *
    + * Time ::= CHOICE {
    + *   utcTime        UTCTime,
    + *   generalTime    GeneralizedTime }
    + *
    + * UniqueIdentifier  ::=  BIT STRING
    + *
    + * SubjectPublicKeyInfo  ::=  SEQUENCE  {
    + *   algorithm            AlgorithmIdentifier,
    + *   subjectPublicKey     BIT STRING  }
    + *
    + * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
    + *
    + * Extension  ::=  SEQUENCE  {
    + *   extnID      OBJECT IDENTIFIER,
    + *   critical    BOOLEAN DEFAULT FALSE,
    + *   extnValue   OCTET STRING  }
    + * 
    + * + * Certificates are created with the CertificateFactory. + * + *

    References: + * + *

      + *
    1. Olivier Dubuisson, Philippe Fouquart (Translator) ASN.1 - + * Communication between heterogeneous systems, (C) September 2000, + * Morgan Kaufmann Publishers, ISBN 0-12-6333361-0. Available on-line at + * http://www.oss.com/asn1/dubuisson.html
    2. + *
    3. R. Housley et al, RFC + * 3280: Internet X.509 Public Key Infrastructure Certificate and CRL + * Profile.
    4. + *
    + * + * @since JDK 1.2 + * @author Mark Benvenuto + * @author Casey Marshall (rsdio@metastatic.org) + */ +public abstract class X509Certificate + extends java.security.cert.Certificate // XXX workaround for gcj bug #17845 + implements X509Extension +{ + private static final long serialVersionUID = -2491127588187038216L; + + /** + * Constructs a new certificate of the specified type. + */ + protected X509Certificate() + { + super( "X.509" ); + } + + /** + Checks the validity of the X.509 certificate. It is valid + if the current date and time are within the period specified + by the certificate. + + The ASN.1 DER encoding is: + + validity Validity, + + Validity ::= SEQUENCE { + notBefore Time, + notAfter Time } + + Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime } + + Consult rfc2459 for more information. + + @throws CertificateExpiredException if the certificate expired + @throws CertificateNotYetValidException if the certificate is + not yet valid + */ + public abstract void checkValidity() + throws CertificateExpiredException, + CertificateNotYetValidException; + + /** + Checks the validity of the X.509 certificate for the + specified time and date. It is valid if the specified + date and time are within the period specified by + the certificate. + + @throws CertificateExpiredException if the certificate expired + based on the date + @throws CertificateNotYetValidException if the certificate is + not yet valid based on the date + */ + public abstract void checkValidity(Date date) + throws CertificateExpiredException, + CertificateNotYetValidException; + + /** + Returns the version of this certificate. + + The ASN.1 DER encoding is: + + version [0] EXPLICIT Version DEFAULT v1, + + Version ::= INTEGER { v1(0), v2(1), v3(2) } + + Consult rfc2459 for more information. + + @return version number of certificate + */ + public abstract int getVersion(); + + /** + Gets the serial number for serial Number in + this Certifcate. It must be a unique number + unique other serial numbers from the granting CA. + + The ASN.1 DER encoding is: + + serialNumber CertificateSerialNumber, + + CertificateSerialNumber ::= INTEGER + + Consult rfc2459 for more information. + + @return the serial number for this X509CRLEntry. + */ + public abstract BigInteger getSerialNumber(); + + /** + Returns the issuer (issuer distinguished name) of the + Certificate. The issuer is the entity who signed + and issued the Certificate. + + The ASN.1 DER encoding is: + + issuer Name, + + Name ::= CHOICE { + RDNSequence } + + RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + + RelativeDistinguishedName ::= + SET OF AttributeTypeAndValue + + AttributeTypeAndValue ::= SEQUENCE { + type AttributeType, + value AttributeValue } + + AttributeType ::= OBJECT IDENTIFIER + + AttributeValue ::= ANY DEFINED BY AttributeType + + DirectoryString ::= CHOICE { + teletexString TeletexString (SIZE (1..MAX)), + printableString PrintableString (SIZE (1..MAX)), + universalString UniversalString (SIZE (1..MAX)), + utf8String UTF8String (SIZE (1.. MAX)), + bmpString BMPString (SIZE (1..MAX)) } + + Consult rfc2459 for more information. + + @return the issuer in the Principal class + */ + public abstract Principal getIssuerDN(); + + /** + Returns the subject (subject distinguished name) of the + Certificate. The subject is the entity who the Certificate + identifies. + + The ASN.1 DER encoding is: + + subject Name, + + Consult rfc2459 for more information. + + @return the issuer in the Principal class + */ + public abstract Principal getSubjectDN(); + + /** + Returns the date that this certificate is not to be used + before, notBefore. + + The ASN.1 DER encoding is: + + validity Validity, + + Validity ::= SEQUENCE { + notBefore Time, + notAfter Time } + + Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime } + + Consult rfc2459 for more information. + + @return the date notBefore + */ + public abstract Date getNotBefore(); + + /** + Returns the date that this certificate is not to be used + after, notAfter. + + @return the date notAfter + */ + public abstract Date getNotAfter(); + + + /** + Returns the tbsCertificate from the certificate. + + @return the DER encoded tbsCertificate + + @throws CertificateEncodingException if encoding error occurred + */ + public abstract byte[] getTBSCertificate() throws CertificateEncodingException; + + /** + Returns the signature in its raw DER encoded format. + + The ASN.1 DER encoding is: + + signatureValue BIT STRING + + Consult rfc2459 for more information. + + @return byte array representing signature + */ + public abstract byte[] getSignature(); + + /** + Returns the signature algorithm used to sign the CRL. + An examples is "SHA-1/DSA". + + The ASN.1 DER encoding is: + + signatureAlgorithm AlgorithmIdentifier, + + AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL } + + Consult rfc2459 for more information. + + The algorithm name is determined from the OID. + + @return a string with the signature algorithm name + */ + public abstract String getSigAlgName(); + + + /** + Returns the OID for the signature algorithm used. + Example "1.2.840.10040.4.3" is return for SHA-1 with DSA.\ + + The ASN.1 DER encoding for the example is: + + id-dsa-with-sha1 ID ::= { + iso(1) member-body(2) us(840) x9-57 (10040) + x9cm(4) 3 } + + Consult rfc2459 for more information. + + @return a string containing the OID. + */ + public abstract String getSigAlgOID(); + + + /** + Returns the AlgorithmParameters in the encoded form + for the signature algorithm used. + + If access to the parameters is need, create an + instance of AlgorithmParameters. + + @return byte array containing algorithm parameters, null + if no parameters are present in certificate + */ + public abstract byte[] getSigAlgParams(); + + + /** + Returns the issuer unique ID for this certificate. + + The ASN.1 DER encoding is: + + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + -- If present, version shall be v2 or v3 + + UniqueIdentifier ::= BIT STRING + + Consult rfc2459 for more information. + + @return bit representation of issuerUniqueID + */ + public abstract boolean[] getIssuerUniqueID(); + + /** + Returns the subject unique ID for this certificate. + + The ASN.1 DER encoding is: + + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + -- If present, version shall be v2 or v3 + + UniqueIdentifier ::= BIT STRING + + Consult rfc2459 for more information. + + @return bit representation of subjectUniqueID + */ + public abstract boolean[] getSubjectUniqueID(); + + /** + Returns a boolean array representing the KeyUsage + extension for the certificate. The KeyUsage (OID = 2.5.29.15) + defines the purpose of the key in the certificate. + + The ASN.1 DER encoding is: + + id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } + + KeyUsage ::= BIT STRING { + digitalSignature (0), + nonRepudiation (1), + keyEncipherment (2), + dataEncipherment (3), + keyAgreement (4), + keyCertSign (5), + cRLSign (6), + encipherOnly (7), + decipherOnly (8) } + + Consult rfc2459 for more information. + + @return bit representation of KeyUsage + */ + public abstract boolean[] getKeyUsage(); + + /** + Returns the certificate constraints path length from the + critical BasicConstraints extension, (OID = 2.5.29.19). + + The basic constraints extensions is used to determine if + the subject of the certificate is a Certificate Authority (CA) + and how deep the certification path may exist. The + pathLenConstraint only takes affect if cA + is set to true. "A value of zero indicates that only an + end-entity certificate may follow in the path." (rfc2459) + + The ASN.1 DER encoding is: + + id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } + + BasicConstraints ::= SEQUENCE { + cA BOOLEAN DEFAULT FALSE, + pathLenConstraint INTEGER (0..MAX) OPTIONAL } + + Consult rfc2459 for more information. + + @return the length of the path constraint if BasicConstraints + is present and cA is TRUE. Otherwise returns -1. + */ + public abstract int getBasicConstraints(); + + // 1.4 instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the ExtendedKeyUsage extension of this + * certificate, or null if there is no extension present. The returned + * value is a {@link java.util.List} strings representing the object + * identifiers of the extended key usages. This extension has the OID + * 2.5.29.37. + * + *

    The ASN.1 definition for this extension is: + * + *

     
    +   * ExtendedKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
    +   *
    +   * KeyPurposeId ::= OBJECT IDENTIFIER
    +   * 
    + * + * @return The list of extension OIDs, or null if there are none + * present in this certificate. + * @throws CertificateParsingException If this extension cannot be + * parsed from its encoded form. + */ + public java.util.List getExtendedKeyUsage() + throws CertificateParsingException + { + throw new UnsupportedOperationException(); + } + + /** + * Returns the alternative names for this certificate's subject (the + * owner), or null if there are none. + * + *

    This is an X.509 extension with OID 2.5.29.17 and is defined by + * the ASN.1 construction: + * + *

    +   * SubjectAltNames ::= GeneralNames
    +   *
    +   * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
    +   *
    +   * 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
    +   * }
    +   * 
    + * + *

    The returned collection contains one or more two-element Lists, + * with the first object being an Integer representing the choice + * above (with value 0 through 8) and the second being an (a) String + * if the GeneralName is a rfc822Name, dNSName, + * uniformResourceIdentifier, iPAddress, or registeredID, or (b) a + * byte array of the DER encoded form for any others. + * + * @return The collection of alternative names, or null if there are + * none. + * @throws CertificateParsingException If the encoded extension cannot + * be parsed. + * @since JDK 1.4 + */ + public java.util.Collection getSubjectAlternativeNames() + throws CertificateParsingException + { + throw new UnsupportedOperationException(); + } + + /** + * Returns the alternative names for this certificate's issuer, or + * null if there are none. + * + *

    This is an X.509 extension with OID 2.5.29.18, and is defined by + * the ASN.1 construction: + * + *

    +   * IssuerAltNames ::= GeneralNames
    +   * 
    + * + *

    The GeneralNames construct and the form of the + * returned collection are the same as with {@link + * #getSubjectAlternativeNames()}. + * + * @return The collection of alternative names, or null if there are + * none. + * @throws CertificateParsingException If the encoded extension cannot + * be parsed. + * @since JDK 1.4 + */ + public java.util.Collection getIssuerAlternativeNames() + throws CertificateParsingException + { + throw new UnsupportedOperationException(); + } + + /** + * Returns the X.500 distinguished name of this certificate's subject. + * + * @return The subject's X.500 distinguished name. + * @since JDK 1.4 + */ + public javax.security.auth.x500.X500Principal getSubjectX500Principal() + { + throw new UnsupportedOperationException(); + } + + /** + * Returns the X.500 distinguished name of this certificate's issuer. + * + * @return The issuer's X.500 distinguished name. + * @since JDK 1.4 + */ + public javax.security.auth.x500.X500Principal getIssuerX500Principal() + { + throw new UnsupportedOperationException(); + } +} diff --git a/libjava/classpath/java/security/cert/X509Extension.java b/libjava/classpath/java/security/cert/X509Extension.java new file mode 100644 index 0000000..d2cb80a --- /dev/null +++ b/libjava/classpath/java/security/cert/X509Extension.java @@ -0,0 +1,113 @@ +/* X509Extension.java --- X.509 Extension + Copyright (C) 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 java.security.cert; +import java.util.Set; + +/** + Public interface for the X.509 Extension. + + This is used for X.509 v3 Certificates and CRL v2 (Certificate + Revocation Lists) for managing attributes assoicated with + Certificates, for managing the hierarchy of certificates, + and for managing the distribution of CRL. This extension + format is used to define private extensions. + + Each extensions for a certificate or CRL must be marked + either critical or non-critical. If the certificate/CRL + system encounters a critical extension not recognized then + it must reject the certificate. A non-critical extension + may be just ignored if not recognized. + + + The ASN.1 definition for this class is: + + Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + + Extension ::= SEQUENCE { + extnId OBJECT IDENTIFIER, + critical BOOLEAN DEFAULT FALSE, + extnValue OCTET STRING + -- contains a DER encoding of a value + -- of the type registered for use with + -- the extnId object identifier value + } + + @author Mark Benvenuto + + @since JDK 1.2 +*/ +public interface X509Extension +{ + + /** + Returns true if the certificate contains a critical extension + that is not supported. + + @return true if has unsupported extension, false otherwise + */ + boolean hasUnsupportedCriticalExtension(); + + /** + Returns a set of the CRITICAL extension OIDs from the + certificate/CRL that the object implementing this interface + manages. + + @return A Set containing the OIDs. If there are no CRITICAL + extensions or extensions at all this returns null. + */ + Set getCriticalExtensionOIDs(); + + /** + Returns a set of the NON-CRITICAL extension OIDs from the + certificate/CRL that the object implementing this interface + manages. + + @return A Set containing the OIDs. If there are no NON-CRITICAL + extensions or extensions at all this returns null. + */ + Set getNonCriticalExtensionOIDs(); + + /** + Returns the DER encoded OCTET string for the specified + extension value identified by a OID. The OID is a string + of number separated by periods. Ex: 12.23.45.67 + */ + byte[] getExtensionValue(String oid); + +} diff --git a/libjava/classpath/java/security/cert/package.html b/libjava/classpath/java/security/cert/package.html new file mode 100644 index 0000000..14b12d1 --- /dev/null +++ b/libjava/classpath/java/security/cert/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.security.cert + + +

    + + + diff --git a/libjava/classpath/java/security/interfaces/DSAKey.java b/libjava/classpath/java/security/interfaces/DSAKey.java new file mode 100644 index 0000000..c6e819e --- /dev/null +++ b/libjava/classpath/java/security/interfaces/DSAKey.java @@ -0,0 +1,56 @@ +/* DSAKey.java -- Interface for Digital Signature Algorithm key + 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 java.security.interfaces; + +/** + * This interface is implemented by a class to return the parameters + * of a Digital Signature Algorithm (DSA) public or private key. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface DSAKey +{ + /** + * This method returns non-secret parameters of the DSA key + * + * @return The DSA parameters + */ + DSAParams getParams(); +} diff --git a/libjava/classpath/java/security/interfaces/DSAKeyPairGenerator.java b/libjava/classpath/java/security/interfaces/DSAKeyPairGenerator.java new file mode 100644 index 0000000..e657c54 --- /dev/null +++ b/libjava/classpath/java/security/interfaces/DSAKeyPairGenerator.java @@ -0,0 +1,85 @@ +/* DSAKeyPairGenerator.java -- Initialize a DSA key generator + 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 java.security.interfaces; + +import java.security.InvalidParameterException; +import java.security.SecureRandom; + +/** + * This interface contains methods for intializing a Digital Signature + * Algorithm key generation engine. The initialize methods may be called + * any number of times. If no explicity initialization call is made, then + * the engine defaults to generating 1024-bit keys using pre-calculated + * base, prime, and subprime values. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface DSAKeyPairGenerator +{ + /** + * Initializes the key generator with the specified DSA parameters and + * random bit source + * + * @param params The DSA parameters to use + * @param random The random bit source to use + * + * @exception InvalidParameterException If the parameters passed are not valid + */ + void initialize (DSAParams params, SecureRandom random) + throws InvalidParameterException; + + /** + * Initializes the key generator to a give modulus. If the genParams + * value is true then new base, prime, and subprime values + * will be generated for the given modulus. If not, the pre-calculated + * values will be used. If no pre-calculated values exist for the specified + * modulus, an exception will be thrown. It is guaranteed that there will + * always be pre-calculated values for all modulus values between 512 and + * 1024 bits inclusives. + * + * @param modlen The modulus length + * @param genParams true to generate new DSA parameters, false otherwise + * @param random The random bit source to use + * + * @exception InvalidParameterException If a parameter is invalid + */ + void initialize (int modlen, boolean genParams, SecureRandom random) + throws InvalidParameterException; +} diff --git a/libjava/classpath/java/security/interfaces/DSAParams.java b/libjava/classpath/java/security/interfaces/DSAParams.java new file mode 100644 index 0000000..42baeeb --- /dev/null +++ b/libjava/classpath/java/security/interfaces/DSAParams.java @@ -0,0 +1,72 @@ +/* DSAParams.java -- Digital Signature Algorithm parameter access + 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 java.security.interfaces; + +import java.math.BigInteger; + +/** + * This interface allows the Digital Signature Algorithm (DSA) parameters + * to be queried. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface DSAParams +{ + /** + * Returns the base, or 'g' value + * + * @return The DSA base value + */ + BigInteger getG(); + + /** + * Returns the prime, or 'p' value + * + * @return The DSA prime value + */ + BigInteger getP(); + + /** + * Returns the subprime, or 'q' value + * + * @return The DSA subprime value + */ + BigInteger getQ(); +} diff --git a/libjava/classpath/java/security/interfaces/DSAPrivateKey.java b/libjava/classpath/java/security/interfaces/DSAPrivateKey.java new file mode 100644 index 0000000..d79b34b --- /dev/null +++ b/libjava/classpath/java/security/interfaces/DSAPrivateKey.java @@ -0,0 +1,61 @@ +/* DSAPublicKey.java -- A Digital Signature Algorithm private key + Copyright (C) 1998, 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 java.security.interfaces; + +import java.math.BigInteger; +import java.security.PrivateKey; + +/** + * This interface models a Digital Signature Algorithm (DSA) private key + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface DSAPrivateKey extends DSAKey, PrivateKey +{ + /** + * The version identifier used for serialization. + */ + long serialVersionUID = 7776497482533790279L; + + /** + * This method returns the value of the DSA private key + */ + BigInteger getX(); +} diff --git a/libjava/classpath/java/security/interfaces/DSAPublicKey.java b/libjava/classpath/java/security/interfaces/DSAPublicKey.java new file mode 100644 index 0000000..d73e189 --- /dev/null +++ b/libjava/classpath/java/security/interfaces/DSAPublicKey.java @@ -0,0 +1,61 @@ +/* DSAPublicKey.java -- A Digital Signature Algorithm public key + Copyright (C) 1998, 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 java.security.interfaces; + +import java.math.BigInteger; +import java.security.PublicKey; + +/** + * This interface models a Digital Signature Algorithm (DSA) public key + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface DSAPublicKey extends DSAKey, PublicKey +{ + /** + * The version identifier used for serialization. + */ + long serialVersionUID = 1234526332779022332L; + + /** + * This method returns the value of the DSA public key + */ + BigInteger getY(); +} diff --git a/libjava/classpath/java/security/interfaces/RSAKey.java b/libjava/classpath/java/security/interfaces/RSAKey.java new file mode 100644 index 0000000..485fa81 --- /dev/null +++ b/libjava/classpath/java/security/interfaces/RSAKey.java @@ -0,0 +1,57 @@ +/* RSAKey.java --- A generic RSA Key interface + Copyright (C) 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 java.security.interfaces; + +import java.math.BigInteger; + +/** + A generic RSA Key interface for public and private keys + + @since JDK 1.3 + + @author Mark Benvenuto + */ +public interface RSAKey +{ + /** + Generates a modulus. + + @returns a modulus + */ + BigInteger getModulus(); +} diff --git a/libjava/classpath/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java b/libjava/classpath/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java new file mode 100644 index 0000000..d80b962 --- /dev/null +++ b/libjava/classpath/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java @@ -0,0 +1,111 @@ +/* RSAMultiPrimePrivateCrtKey.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 java.security.interfaces; + +import java.math.BigInteger; +import java.security.spec.RSAOtherPrimeInfo; + +/** + * The interface to an RSA multi-prime private key, as defined in the PKCS#1 + * v2.1, using the Chinese Remainder Theorem (CRT) information values. + * + * @since 1.4 + * @see java.security.spec.RSAPrivateKeySpec + * @see java.security.spec.RSAMultiPrimePrivateCrtKeySpec + * @see RSAPrivateKey + * @see RSAPrivateCrtKey + */ +public interface RSAMultiPrimePrivateCrtKey extends RSAPrivateKey +{ + // Constants + // -------------------------------------------------------------------------- + long serialVersionUID = 618058533534628008L; + + // Methods + // -------------------------------------------------------------------------- + + /** + * Returns the public exponent. + * + * @return the public exponent. + */ + BigInteger getPublicExponent(); + + /** + * Returns the primeP. + * + * @return the primeP. + */ + BigInteger getPrimeP(); + + /** + * Returns the primeQ. + * + * @return the primeQ. + */ + BigInteger getPrimeQ(); + + /** + * Returns the primeExponentP. + * + * @return the primeExponentP. + */ + BigInteger getPrimeExponentP(); + + /** + * Returns the primeExponentQ. + * + * @return the primeExponentQ. + */ + BigInteger getPrimeExponentQ(); + + /** + * Returns the crtCoefficient. + * + * @return the crtCoefficient. + */ + BigInteger getCrtCoefficient(); + + /** + * Returns the otherPrimeInfo or null if there are only two + * prime factors (p and q). + * + * @return the otherPrimeInfo. + */ + RSAOtherPrimeInfo[] getOtherPrimeInfo(); +} diff --git a/libjava/classpath/java/security/interfaces/RSAPrivateCrtKey.java b/libjava/classpath/java/security/interfaces/RSAPrivateCrtKey.java new file mode 100644 index 0000000..96a1496 --- /dev/null +++ b/libjava/classpath/java/security/interfaces/RSAPrivateCrtKey.java @@ -0,0 +1,95 @@ +/* RSAPrivateCrtKey.java -- An RSA private key in CRT format + 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 java.security.interfaces; + +import java.math.BigInteger; + +/** + * This interface provides access to information about an RSA private + * key in Chinese Remainder Theorem (CRT) format. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface RSAPrivateCrtKey extends RSAPrivateKey +{ + long serialVersionUID = -5682214253527700368L; + + /** + * Returns the public exponent for this key + * + * @return The public exponent for this key + */ + BigInteger getPublicExponent(); + + /** + * Returns the primeP value + * + * @return The primeP value + */ + BigInteger getPrimeP(); + + /** + * Returns the primeQ value + * + * @return The primeQ value + */ + BigInteger getPrimeQ(); + + /** + * Returns the primeExponentP + * + * @return The primeExponentP + */ + BigInteger getPrimeExponentP(); + + /** + * Returns the primeExponentQ + * + * @return The primeExponentQ + */ + BigInteger getPrimeExponentQ(); + + /** + * Returns the CRT coefficient + * + * @return The CRT coefficient + */ + BigInteger getCrtCoefficient(); +} diff --git a/libjava/classpath/java/security/interfaces/RSAPrivateKey.java b/libjava/classpath/java/security/interfaces/RSAPrivateKey.java new file mode 100644 index 0000000..5149876 --- /dev/null +++ b/libjava/classpath/java/security/interfaces/RSAPrivateKey.java @@ -0,0 +1,60 @@ +/* RSAPrivateKey.java -- An RSA private key + Copyright (C) 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 java.security.interfaces; + +import java.math.BigInteger; +import java.security.PrivateKey; + +/** + * This interface provides access to information about an RSA private key. + * + * @version 0.1 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface RSAPrivateKey extends PrivateKey, RSAKey +{ + long serialVersionUID = 5187144804936595022L; + + /** + * Returns the private exponent value for this key + * + * @return The private exponent value for this key + */ + BigInteger getPrivateExponent(); +} diff --git a/libjava/classpath/java/security/interfaces/RSAPublicKey.java b/libjava/classpath/java/security/interfaces/RSAPublicKey.java new file mode 100644 index 0000000..5fb569d --- /dev/null +++ b/libjava/classpath/java/security/interfaces/RSAPublicKey.java @@ -0,0 +1,60 @@ +/* RSAPublicKey.java -- An RSA public key + Copyright (C) 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 java.security.interfaces; + +import java.math.BigInteger; +import java.security.PublicKey; + +/** + * This interface provides access to information about an RSA public key. + * + * @version 0.1 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface RSAPublicKey extends PublicKey, RSAKey +{ + long serialVersionUID = -8727434096241101194L; + + /** + * Returns the public exponent value for this key + * + * @return The public exponent value for this key + */ + BigInteger getPublicExponent(); +} diff --git a/libjava/classpath/java/security/interfaces/package.html b/libjava/classpath/java/security/interfaces/package.html new file mode 100644 index 0000000..aab0d63 --- /dev/null +++ b/libjava/classpath/java/security/interfaces/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.security.interfaces + + +

    + + + diff --git a/libjava/classpath/java/security/package.html b/libjava/classpath/java/security/package.html new file mode 100644 index 0000000..328b704 --- /dev/null +++ b/libjava/classpath/java/security/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.security + + +

    + + + diff --git a/libjava/classpath/java/security/spec/AlgorithmParameterSpec.java b/libjava/classpath/java/security/spec/AlgorithmParameterSpec.java new file mode 100644 index 0000000..25506f5 --- /dev/null +++ b/libjava/classpath/java/security/spec/AlgorithmParameterSpec.java @@ -0,0 +1,52 @@ +/* AlgorithmParameterSpec.java --- Algorithm Parameter Spec Interface + Copyright (C) 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 java.security.spec; + +/** + A transparent interface for Algorithm Parameter Specifications. + It contains no member functions. It is used to group + algorithm parameter classes. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public interface AlgorithmParameterSpec +{ +} diff --git a/libjava/classpath/java/security/spec/DSAParameterSpec.java b/libjava/classpath/java/security/spec/DSAParameterSpec.java new file mode 100644 index 0000000..7e26329 --- /dev/null +++ b/libjava/classpath/java/security/spec/DSAParameterSpec.java @@ -0,0 +1,101 @@ +/* DSAParameterSpec.java --- DSA Parameter Specificaton class + 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 java.security.spec; + +import java.math.BigInteger; +import java.security.interfaces.DSAParams; + +/** + * DSA Parameter class Specification. Used to maintain the DSA + * Parameters. + * + * @since 1.2 + * + * @author Mark Benvenuto +*/ +public class DSAParameterSpec implements AlgorithmParameterSpec, DSAParams +{ + private BigInteger p = null; + private BigInteger q = null; + private BigInteger g = null; + + /** + * Constructs a new DSAParameterSpec with the specified p, q, and g. + * + * @param p the prime + * @param q the sub-prime + * @param g the base + */ + public DSAParameterSpec(BigInteger p, BigInteger q, BigInteger g) + { + this.p = p; + this.q = q; + this.g = g; + } + + /** + * Returns p for the DSA algorithm. + * + * @return Returns the requested BigInteger + */ + public BigInteger getP() + { + return this.p; + } + + /** + * Returns p for the DSA algorithm. + * + * @return Returns the requested BigInteger + */ + public BigInteger getQ() + { + return this.q; + } + + /** + * Returns g for the DSA algorithm. + * + * @return Returns the requested BigInteger + */ + public BigInteger getG() + { + return this.g; + } +} \ No newline at end of file diff --git a/libjava/classpath/java/security/spec/DSAPrivateKeySpec.java b/libjava/classpath/java/security/spec/DSAPrivateKeySpec.java new file mode 100644 index 0000000..7415fa1 --- /dev/null +++ b/libjava/classpath/java/security/spec/DSAPrivateKeySpec.java @@ -0,0 +1,113 @@ +/* DSAPrivateKeySpec.java --- DSA Private Key Specificaton class + 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 java.security.spec; +import java.math.BigInteger; + +/** + DSA Private Key class Specification. Used to maintain the DSA + Private Keys. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public class DSAPrivateKeySpec implements KeySpec +{ + private BigInteger x = null; + private BigInteger p = null; + private BigInteger q = null; + private BigInteger g = null; + + /** + Constructs a new DSAPrivateKeySpec with the specified x, p, q, and g. + + @param x the private key + @param p the prime + @param q the sub-prime + @param g the base + */ + public DSAPrivateKeySpec(BigInteger x, BigInteger p, BigInteger q, BigInteger g) + { + this.x = x; + this.p = p; + this.q = q; + this.g = g; + } + + /** + Returns private key x for the DSA algorithm. + + @return Returns the requested BigInteger + */ + public BigInteger getX() + { + return this.x; + } + + /** + Returns p for the DSA algorithm. + + @return Returns the requested BigInteger + */ + public BigInteger getP() + { + return this.p; + } + + /** + Returns p for the DSA algorithm. + + @return Returns the requested BigInteger + */ + public BigInteger getQ() + { + return this.q; + } + + /** + Returns g for the DSA algorithm. + + @return Returns the requested BigInteger + */ + public BigInteger getG() + { + return this.g; + } + +} diff --git a/libjava/classpath/java/security/spec/DSAPublicKeySpec.java b/libjava/classpath/java/security/spec/DSAPublicKeySpec.java new file mode 100644 index 0000000..ac1310c --- /dev/null +++ b/libjava/classpath/java/security/spec/DSAPublicKeySpec.java @@ -0,0 +1,113 @@ +/* DSAPublicKeySpec.java --- DSA Public Key Specificaton class + 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 java.security.spec; +import java.math.BigInteger; + +/** + DSA Public Key class Specification. Used to maintain the DSA + Public Keys. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public class DSAPublicKeySpec implements KeySpec +{ + private BigInteger y = null; + private BigInteger p = null; + private BigInteger q = null; + private BigInteger g = null; + + /** + Constructs a new DSAPublicKeySpec with the specified y, p, q, and g. + + @param y the public key + @param p the prime + @param q the sub-prime + @param g the base + */ + public DSAPublicKeySpec(BigInteger y, BigInteger p, BigInteger q, BigInteger g) + { + this.y = y; + this.p = p; + this.q = q; + this.g = g; + } + + /** + Returns public key y for the DSA algorithm. + + @return Returns the requested BigInteger + */ + public BigInteger getY() + { + return this.y; + } + + /** + Returns p for the DSA algorithm. + + @return Returns the requested BigInteger + */ + public BigInteger getP() + { + return this.p; + } + + /** + Returns p for the DSA algorithm. + + @return Returns the requested BigInteger + */ + public BigInteger getQ() + { + return this.q; + } + + /** + Returns g for the DSA algorithm. + + @return Returns the requested BigInteger + */ + public BigInteger getG() + { + return this.g; + } + +} diff --git a/libjava/classpath/java/security/spec/EncodedKeySpec.java b/libjava/classpath/java/security/spec/EncodedKeySpec.java new file mode 100644 index 0000000..c5baf55 --- /dev/null +++ b/libjava/classpath/java/security/spec/EncodedKeySpec.java @@ -0,0 +1,85 @@ +/* EncodedKeySpec.java --- Encoded Key Specificaton class + Copyright (C) 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 java.security.spec; + +/** + Encoded Key Specification class which is used to store + byte encoded keys. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public abstract class EncodedKeySpec implements KeySpec +{ + + private byte[] encodedKey; + + /** + Constructs a new EncodedKeySpec with the specified encoded key. + + @param encodedKey A key to store + */ + public EncodedKeySpec(byte[] encodedKey) + { + this.encodedKey = encodedKey; + } + + /** + Gets the encoded key in byte format. + + @returns the encoded key + */ + public byte[] getEncoded() + { + return this.encodedKey; + } + + /** + Returns the name of the key format used. + + This name is the format such as "PKCS#8" or "X.509" which + if it matches a Key class name of the same type can be + transformed using the apporiate KeyFactory. + + @return a string representing the name + */ + public abstract String getFormat(); + +} diff --git a/libjava/classpath/java/security/spec/InvalidKeySpecException.java b/libjava/classpath/java/security/spec/InvalidKeySpecException.java new file mode 100644 index 0000000..c2ec6b0 --- /dev/null +++ b/libjava/classpath/java/security/spec/InvalidKeySpecException.java @@ -0,0 +1,74 @@ +/* InvalidKeySpecException.java -- invalid KeySpec Exception + Copyright (C) 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 java.security.spec; + +import java.security.GeneralSecurityException; + +/** + * Exception for an invalid key specification. + * + * @author Mark Benvenuto + * @see KeySpec + * @since 1.2 + * @status updated to 1.4 + */ +public class InvalidKeySpecException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 3546139293998810778L; + + /** + * Constructs an InvalidKeySpecException without a message string. + */ + public InvalidKeySpecException() + { + } + + /** + * Constructs an InvalidKeySpecException with a message string. + * + * @param msg a message to display with exception + */ + public InvalidKeySpecException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/spec/InvalidParameterSpecException.java b/libjava/classpath/java/security/spec/InvalidParameterSpecException.java new file mode 100644 index 0000000..481e11e --- /dev/null +++ b/libjava/classpath/java/security/spec/InvalidParameterSpecException.java @@ -0,0 +1,76 @@ +/* InvalidParameterSpecException.java --- invalid ParameterSpec Exception + Copyright (C) 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 java.security.spec; + +import java.security.GeneralSecurityException; + +/** + * Exception for an invalid algorithm specification. + * + * @author Mark Benvenuto + * @see AlogorithmParameters + * @see AlogorithmParameterSpec + * @see DSAParameterSpec + * @since 1.2 + * @status updated to 1.4 +*/ +public class InvalidParameterSpecException extends GeneralSecurityException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -970468769593399342L; + + /** + * Constructs an InvalidParameterSpecException without a message string. + */ + public InvalidParameterSpecException() + { + } + + /** + * Constructs an InvalidParameterSpecException with a message string. + * + * @param msg a message to display with exception + */ + public InvalidParameterSpecException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/security/spec/KeySpec.java b/libjava/classpath/java/security/spec/KeySpec.java new file mode 100644 index 0000000..93f1a6d --- /dev/null +++ b/libjava/classpath/java/security/spec/KeySpec.java @@ -0,0 +1,52 @@ +/* KeySpec.java --- Key Specification interface + Copyright (C) 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 java.security.spec; + +/** + A transparent interface for Key Specifications. + It contains no member functions. It is used to group + key classes. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public interface KeySpec +{ +} diff --git a/libjava/classpath/java/security/spec/PKCS8EncodedKeySpec.java b/libjava/classpath/java/security/spec/PKCS8EncodedKeySpec.java new file mode 100644 index 0000000..4a4f1ec --- /dev/null +++ b/libjava/classpath/java/security/spec/PKCS8EncodedKeySpec.java @@ -0,0 +1,81 @@ +/* PKCS8EncodedKeySpec.java --- PKCS8 Encoded Key Specificaton class + Copyright (C) 1999, 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 java.security.spec; + +/** + PKCS8 Encoded Key Specification class which is used to store + "PKCS#8" byte encoded keys. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public class PKCS8EncodedKeySpec extends EncodedKeySpec +{ + /** + Constructs a new PKCS8EncodedKeySpec with the specified encoded key. + + @param encodedKey A key to store, assumed to be "PKCS#8" + */ + public PKCS8EncodedKeySpec(byte[] encodedKey) + { + super( encodedKey ); + } + + /** + Gets the encoded key in byte format. + + @returns the encoded key +*/ + public byte[] getEncoded() + { + return super.getEncoded(); + } + + /** + Returns the name of the key format used which is "PKCS#8" + + @return a string representing the name +*/ + public final String getFormat() + { + return "PKCS#8"; + } + +} diff --git a/libjava/classpath/java/security/spec/PSSParameterSpec.java b/libjava/classpath/java/security/spec/PSSParameterSpec.java new file mode 100644 index 0000000..7a14a24 --- /dev/null +++ b/libjava/classpath/java/security/spec/PSSParameterSpec.java @@ -0,0 +1,90 @@ +/* PSSParameterSpec.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 java.security.spec; + +/** + * This class specifies a parameter spec for RSA PSS encoding scheme, as + * defined in the PKCS#1 v2.1. + * + * @since 1.4 + * @see AlgorithmParameterSpec + * @see java.security.Signature + */ +public class PSSParameterSpec implements AlgorithmParameterSpec +{ + // Constants and fields + // -------------------------------------------------------------------------- + + private int saltLen; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** + * Creates a new PSSParameterSpec given the salt length as + * defined in PKCS#1. + * + * @param saltLen the length of salt in bits to be used in PKCS#1 PSS encoding. + * @throws IllegalArgumentException if saltLen is less than + * 0. + */ + public PSSParameterSpec(int saltLen) + { + super(); + + if (saltLen < 0) + throw new IllegalArgumentException(); + this.saltLen = saltLen; + } + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + /** + * Returns the salt length in bits. + * + * @return the salt length. + */ + public int getSaltLength() + { + return this.saltLen; + } +} diff --git a/libjava/classpath/java/security/spec/RSAKeyGenParameterSpec.java b/libjava/classpath/java/security/spec/RSAKeyGenParameterSpec.java new file mode 100644 index 0000000..0df8dec --- /dev/null +++ b/libjava/classpath/java/security/spec/RSAKeyGenParameterSpec.java @@ -0,0 +1,97 @@ +/* RSAKeyGenParameterSpec.java --- RSA Key Generator Parameter Spec Class + Copyright (C) 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 java.security.spec; +import java.math.BigInteger; + +/** + This class generates a set of RSA Key parameters used in the generation + of RSA keys. + + @since JDK 1.3 + + @author Mark Benvenuto +*/ +public class RSAKeyGenParameterSpec implements AlgorithmParameterSpec +{ + private int keysize; + private BigInteger publicExponent; + + /** + Public Exponent F0 = 3 + */ + public static final BigInteger F0 = new BigInteger("3"); + + /** + Public Exponent F4 = 3 + */ + public static final BigInteger F4 = new BigInteger("65537"); + + /** + Create a new RSAKeyGenParameterSpec to store the RSA key's keysize + and public exponent + + @param keysize Modulus size of key in bits + @param publicExponent - the exponent + */ + public RSAKeyGenParameterSpec(int keysize, BigInteger publicExponent) + { + this.keysize = keysize; + this.publicExponent = publicExponent; + } + + /** + Return the size of the key. + + @return the size of the key. + */ + public int getKeysize() + { + return keysize; + } + + /** + Return the public exponent. + + @return the public exponent. + */ + public BigInteger getPublicExponent() + { + return publicExponent; + } +} diff --git a/libjava/classpath/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java b/libjava/classpath/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java new file mode 100644 index 0000000..519a029 --- /dev/null +++ b/libjava/classpath/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java @@ -0,0 +1,217 @@ +/* PSSParameterSpec.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 java.security.spec; + +import java.math.BigInteger; + +/** + * This class specifies an RSA multi-prime private key, as defined in the + * PKCS#1 v2.1, using the Chinese Remainder Theorem (CRT) information + * values for efficiency. + * + * @since 1.4 + * @see java.security.Key + * @see java.security.KeyFactory + * @see KeySpec + * @see PKCS8EncodedKeySpec + * @see RSAPrivateKeySpec + * @see RSAPublicKeySpec + * @see RSAOtherPrimeInfo + */ +public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec +{ + // Constants and fields + // -------------------------------------------------------------------------- + + private BigInteger publicExponent; + private BigInteger primeP; + private BigInteger primeQ; + private BigInteger primeExponentP; + private BigInteger primeExponentQ; + private BigInteger crtCoefficient; + private RSAOtherPrimeInfo[] otherPrimeInfo; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** + *

    Creates a new RSAMultiPrimePrivateCrtKeySpec given the + * modulus, publicExponent, privateExponent, primeP, primeQ, primeExponentP, + * primeExponentQ, crtCoefficient, and otherPrimeInfo as defined in PKCS#1 + * v2.1.

    + * + *

    Note that otherPrimeInfo is cloned when constructing this + * object.

    + * + * @param modulus the modulus n. + * @param publicExponent the public exponent e. + * @param privateExponent the private exponent d. + * @param primeP the prime factor p of n. + * @param primeQ the prime factor q of n. + * @param primeExponentP this is d mod (p-1). + * @param primeExponentQ this is d mod (q-1). + * @param crtCoefficient the Chinese Remainder Theorem coefficient q-1 mod p. + * @param otherPrimeInfo triplets of the rest of primes, null + * can be specified if there are only two prime factors (p and q). + * @throws NullPointerException if any of the parameters, i.e. modulus, + * publicExponent, privateExponent, primeP, primeQ, primeExponentP, + * primeExponentQ, crtCoefficient, is null. + * @throws IllegalArgumentException if an empty, i.e. 0-length, + * otherPrimeInfo is specified. + */ + public RSAMultiPrimePrivateCrtKeySpec(BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger primeP, + BigInteger primeQ, + BigInteger primeExponentP, + BigInteger primeExponentQ, + BigInteger crtCoefficient, + RSAOtherPrimeInfo[] otherPrimeInfo) + { + super(modulus, privateExponent); + + if (modulus == null) + throw new NullPointerException("modulus"); + if (publicExponent == null) + throw new NullPointerException("publicExponent"); + if (privateExponent == null) + throw new NullPointerException("privateExponent"); + if (primeP == null) + throw new NullPointerException("primeP"); + if (primeQ == null) + throw new NullPointerException("primeQ"); + if (primeExponentP == null) + throw new NullPointerException("primeExponentP"); + if (primeExponentQ == null) + throw new NullPointerException("primeExponentQ"); + if (crtCoefficient == null) + throw new NullPointerException("crtCoefficient"); + if (otherPrimeInfo != null) + if (otherPrimeInfo.length == 0) + throw new IllegalArgumentException(); + else + this.otherPrimeInfo = (RSAOtherPrimeInfo[]) otherPrimeInfo.clone(); + + this.publicExponent = publicExponent; + this.primeP = primeP; + this.primeQ = primeQ; + this.primeExponentP = primeExponentP; + this.primeExponentQ = primeExponentQ; + this.crtCoefficient = crtCoefficient; + } + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + /** + * Returns the public exponent. + * + * @return the public exponent. + */ + public BigInteger getPublicExponent() + { + return this.publicExponent; + } + + /** + * Returns the primeP. + * + * @return the primeP. + */ + public BigInteger getPrimeP() + { + return this.primeP; + } + + /** + * Returns the primeQ. + * + * @return the primeQ. + */ + public BigInteger getPrimeQ() + { + return this.primeQ; + } + + /** + * Returns the primeExponentP. + * + * @return the primeExponentP. + */ + public BigInteger getPrimeExponentP() + { + return this.primeExponentP; + } + + /** + * Returns the primeExponentQ. + * + * @return the primeExponentQ. + */ + public BigInteger getPrimeExponentQ() + { + return this.primeExponentQ; + } + + /** + * Returns the crtCoefficient. + * + * @return the crtCoefficient. + */ + public BigInteger getCrtCoefficient() + { + return this.crtCoefficient; + } + + /** + * Returns a copy of the otherPrimeInfo or null if there are + * only two prime factors (p and q). + * + * @return the otherPrimeInfo. + */ + public RSAOtherPrimeInfo[] getOtherPrimeInfo() + { + return this.otherPrimeInfo == null + ? null + : (RSAOtherPrimeInfo[]) this.otherPrimeInfo.clone(); + } +} diff --git a/libjava/classpath/java/security/spec/RSAOtherPrimeInfo.java b/libjava/classpath/java/security/spec/RSAOtherPrimeInfo.java new file mode 100644 index 0000000..654bcb5 --- /dev/null +++ b/libjava/classpath/java/security/spec/RSAOtherPrimeInfo.java @@ -0,0 +1,133 @@ +/* RSAOtherPrimeInfo.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 java.security.spec; + +import java.math.BigInteger; + +/** + * This class represents the triplet (prime, exponent, and coefficient) inside + * RSA's OtherPrimeInfo structure, as defined in the PKCS#1 v2.1. The ASN.1 + * syntax of RSA's OtherPrimeInfo is as follows: + * + *
    + *  OtherPrimeInfo ::= SEQUENCE {
    + *    prime INTEGER,
    + *    exponent INTEGER,
    + *    coefficient INTEGER
    + *  }
    + * 
    + * + * @since 1.4 + * @see RSAPrivateCrtKeySpec + * @see java.security.interfaces.RSAMultiPrimePrivateCrtKey + */ +public class RSAOtherPrimeInfo +{ + // Constants and fields + // -------------------------------------------------------------------------- + + private BigInteger prime; + private BigInteger primeExponent; + private BigInteger crtCoefficient; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** + * Creates a new RSAOtherPrimeInfo given the prime, + * primeExponent, and crtCoefficient as defined in PKCS#1. + * + * @param prime the prime factor of n. + * @param primeExponent the exponent. + * @param crtCoefficient the Chinese Remainder Theorem coefficient. + * @throws NullPointerException if any of the parameters, i.e. prime, + * primeExponent, crtCoefficient, is null. + */ + public RSAOtherPrimeInfo(BigInteger prime, BigInteger primeExponent, + BigInteger crtCoefficient) + { + super(); + + if (prime == null) + throw new NullPointerException("prime"); + if (primeExponent == null) + throw new NullPointerException("primeExponent"); + if (crtCoefficient == null) + throw new NullPointerException("crtCoefficient"); + + this.prime = prime; + this.primeExponent = primeExponent; + this.crtCoefficient = crtCoefficient; + } + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + /** + * Returns the prime. + * + * @return the prime. + */ + public final BigInteger getPrime() + { + return this.prime; + } + + /** + * Returns the prime's exponent. + * + * @return the primeExponent. + */ + public final BigInteger getExponent() + { + return this.primeExponent; + } + + /** + * Returns the prime's crtCoefficient. + * + * @return the crtCoefficient. + */ + public final BigInteger getCrtCoefficient() + { + return this.crtCoefficient; + } +} diff --git a/libjava/classpath/java/security/spec/RSAPrivateCrtKeySpec.java b/libjava/classpath/java/security/spec/RSAPrivateCrtKeySpec.java new file mode 100644 index 0000000..a904c30 --- /dev/null +++ b/libjava/classpath/java/security/spec/RSAPrivateCrtKeySpec.java @@ -0,0 +1,151 @@ +/* RSAPrivateCrtKeySpec.java --- RSA Private Certificate Key Specificaton class + Copyright (C) 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 java.security.spec; +import java.math.BigInteger; + +/** + RSA Private Certificate Key class Specification. Used to + maintain the RSA Private Certificate Keys with the + Chinese Remainder Theorem(CRT) as specified by PKCS#1. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public class RSAPrivateCrtKeySpec extends RSAPrivateKeySpec +{ + private BigInteger publicExponent; + private BigInteger primeP; + private BigInteger primeQ; + private BigInteger primeExponentP; + private BigInteger primeExponentQ; + private BigInteger crtCoefficient; + + /** + Constructs a new RSAPrivateKeySpec with the specified + variables. + + @param modulus the RSA modulus + @param publicExponent the public key exponent + @param privateExponent the private key exponent + @param primeP the prime P + @param primeQ the prime Q + @param primeExponentP the prime exponent P + @param primeExponentQ the prime exponent P + @param crtCoefficient the CRT coefficient + */ + public RSAPrivateCrtKeySpec(BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger primeP, + BigInteger primeQ, + BigInteger primeExponentP, + BigInteger primeExponentQ, + BigInteger crtCoefficient) + { + super( modulus, privateExponent); + this.publicExponent = publicExponent; + this.primeP = primeP; + this.primeQ = primeQ; + this.primeExponentP = primeExponentP; + this.primeExponentQ = primeExponentQ; + this.crtCoefficient = crtCoefficient; + } + + /** + Gets the RSA public exponent. + + @return the RSA public exponent + */ + public BigInteger getPublicExponent() + { + return this.publicExponent; + } + + /** + Gets the RSA prime P. + + @return the RSA prime P + */ + public BigInteger getPrimeP() + { + return this.primeP; + } + + /** + Gets the RSA prime Q. + + @return the RSA prime Q + */ + public BigInteger getPrimeQ() + { + return this.primeQ; + } + + /** + Gets the RSA prime exponent P. + + @return the RSA prime exponent P + */ + public BigInteger getPrimeExponentP() + { + return this.primeExponentP; + } + + /** + Gets the RSA prime exponent P. + + @return the RSA prime exponent Q + */ + public BigInteger getPrimeExponentQ() + { + return this.primeExponentQ; + } + + /** + Gets the RSA CRT coefficient. + + @return the RSA CRT coefficient + */ + public BigInteger getCrtCoefficient() + { + return this.crtCoefficient; + } + +} diff --git a/libjava/classpath/java/security/spec/RSAPrivateKeySpec.java b/libjava/classpath/java/security/spec/RSAPrivateKeySpec.java new file mode 100644 index 0000000..d29f261 --- /dev/null +++ b/libjava/classpath/java/security/spec/RSAPrivateKeySpec.java @@ -0,0 +1,88 @@ +/* RSAPrivateKeySpec.java --- RSA Private Key Specificaton class + Copyright (C) 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 java.security.spec; +import java.math.BigInteger; + +/** + RSA Private Key class Specification. Used to maintain the RSA + Private Keys. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public class RSAPrivateKeySpec implements KeySpec +{ + private BigInteger modulus; + private BigInteger privateExponent; + + /** + Constructs a new RSAPrivateKeySpec with the specified + modulus and privateExponent. + + @param modulus the RSA modulus + @param privateExponent the private key exponent + */ + public RSAPrivateKeySpec(BigInteger modulus, BigInteger privateExponent) + { + this.modulus = modulus; + this.privateExponent = privateExponent; + } + + /** + Gets the RSA modulus. + + @return the RSA modulus + */ + public BigInteger getModulus() + { + return this.modulus; + } + + /** + Gets the RSA private exponent. + + @return the RSA private exponent + */ + public BigInteger getPrivateExponent() + { + return this.privateExponent; + } + +} diff --git a/libjava/classpath/java/security/spec/RSAPublicKeySpec.java b/libjava/classpath/java/security/spec/RSAPublicKeySpec.java new file mode 100644 index 0000000..21283aa --- /dev/null +++ b/libjava/classpath/java/security/spec/RSAPublicKeySpec.java @@ -0,0 +1,88 @@ +/* RSAPublicKeySpec.java --- RSA Public Key Specificaton class + Copyright (C) 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 java.security.spec; +import java.math.BigInteger; + +/** + RSA Public Key class Specification. Used to maintain the RSA + Public Keys. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public class RSAPublicKeySpec implements KeySpec +{ + private BigInteger modulus; + private BigInteger publicExponent; + + /** + Constructs a new RSAPublicKeySpec with the specified + modulus and publicExponent. + + @param modulus the RSA modulus + @param publicExponent the public key exponent + */ + public RSAPublicKeySpec(BigInteger modulus, BigInteger publicExponent) + { + this.modulus = modulus; + this.publicExponent = publicExponent; + } + + /** + Gets the RSA modulus. + + @return the RSA modulus + */ + public BigInteger getModulus() + { + return this.modulus; + } + + /** + Gets the RSA public exponent. + + @return the RSA public exponent + */ + public BigInteger getPublicExponent() + { + return this.publicExponent; + } + +} diff --git a/libjava/classpath/java/security/spec/X509EncodedKeySpec.java b/libjava/classpath/java/security/spec/X509EncodedKeySpec.java new file mode 100644 index 0000000..de35960 --- /dev/null +++ b/libjava/classpath/java/security/spec/X509EncodedKeySpec.java @@ -0,0 +1,82 @@ +/* X509EncodedKeySpec.java --- X.509 Encoded Key Specificaton class + Copyright (C) 1999, 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 java.security.spec; + +/** + X.509 Encoded Key Specification class which is used to store + "X.509" byte encoded keys. + + @since JDK 1.2 + + @author Mark Benvenuto +*/ +public class X509EncodedKeySpec extends EncodedKeySpec +{ + + /** + Constructs a new X509EncodedKeySpec with the specified encoded key. + + @param encodedKey A key to store, assumed to be "X.509" + */ + public X509EncodedKeySpec(byte[] encodedKey) + { + super( encodedKey ); + } + + /** + Gets the encoded key in byte format. + + @returns the encoded key + */ + public byte[] getEncoded() + { + return super.getEncoded(); + } + + /** + Returns the name of the key format used which is "X.509" + + @return a string representing the name + */ + public final String getFormat() + { + return "X.509"; + } + +} diff --git a/libjava/classpath/java/security/spec/package.html b/libjava/classpath/java/security/spec/package.html new file mode 100644 index 0000000..8e81889 --- /dev/null +++ b/libjava/classpath/java/security/spec/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.security.spec + + +

    + + + diff --git a/libjava/classpath/java/sql/Array.java b/libjava/classpath/java/sql/Array.java new file mode 100644 index 0000000..5162875 --- /dev/null +++ b/libjava/classpath/java/sql/Array.java @@ -0,0 +1,185 @@ +/* Array.java -- Interface for accessing SQL array object + Copyright (C) 1999, 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 java.sql; + +import java.util.Map; + +/** + * This interface provides methods for accessing SQL array types. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Array +{ + /** + * Returns the name of the SQL type of the elements in this + * array. This name is database specific. + * + * @param The name of the SQL type of the elements in this array. + * @exception SQLException If an error occurs. + */ + String getBaseTypeName() throws SQLException; + + /** + * Returns the JDBC type identifier of the elements in this + * array. This will be one of the values defined in the + * Types class. + * + * @return The JDBC type of the elements in this array. + * @exception SQLException If an error occurs. + * @see Types + */ + int getBaseType() throws SQLException; + + /** + * Returns the contents of this array. This object returned + * will be an array of Java objects of the appropriate types. + * + * @return The contents of the array as an array of Java objects. + * @exception SQLException If an error occurs. + */ + Object getArray() throws SQLException; + + /** + * Returns the contents of this array. The specified + * Map will be used to override selected mappings + * between SQL types and Java classes. + * + * @param map A mapping of SQL types to Java classes. + * @return The contents of the array as an array of Java objects. + * @exception SQLException If an error occurs. + */ + Object getArray(Map map) throws SQLException; + + /** + * Returns a portion of this array starting at index + * into the array and continuing for count + * elements. Fewer than the requested number of elements will be + * returned if the array does not contain the requested number of elements. + * The object returned will be an array of Java objects of + * the appropriate types. + * + * @param offset The offset into this array to start returning elements from. + * @param count The requested number of elements to return. + * @return The requested portion of the array. + * @exception SQLException If an error occurs. + */ + Object getArray(long index, int count) throws SQLException; + + /** + * This method returns a portion of this array starting at index + * into the array and continuing for count + * elements. Fewer than the requested number of elements will be + * returned if the array does not contain the requested number of elements. + * The object returned will be an array of Java objects. The specified + * Map will be used for overriding selected SQL type to + * Java class mappings. + * + * @param offset The offset into this array to start returning elements from. + * @param count The requested number of elements to return. + * @param map A mapping of SQL types to Java classes. + * @return The requested portion of the array. + * @exception SQLException If an error occurs. + */ + Object getArray(long index, int count, Map map) throws SQLException; + + /** + * Returns the elements in the array as a ResultSet. + * Each row of the result set will have two columns. The first will be + * the index into the array of that row's contents. The second will be + * the actual value of that array element. + * + * @return The elements of this array as a ResultSet. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + ResultSet getResultSet() throws SQLException; + + /** + * This method returns the elements in the array as a ResultSet. + * Each row of the result set will have two columns. The first will be + * the index into the array of that row's contents. The second will be + * the actual value of that array element. The specified Map + * will be used to override selected default mappings of SQL types to + * Java classes. + * + * @param map A mapping of SQL types to Java classes. + * @return The elements of this array as a ResultSet. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + ResultSet getResultSet(Map map) throws SQLException; + + /** + * This method returns a portion of the array as a ResultSet. + * The returned portion will start at index into the + * array and up to count elements will be returned. + *

    + * Each row of the result set will have two columns. The first will be + * the index into the array of that row's contents. The second will be + * the actual value of that array element. + * + * @param offset The index into the array to start returning elements from. + * @param length The requested number of elements to return. + * @return The requested elements of this array as a ResultSet. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + ResultSet getResultSet(long index, int count) throws SQLException; + + /** + * This method returns a portion of the array as a ResultSet. + * The returned portion will start at index into the + * array and up to count elements will be returned. + * + *

    Each row of the result set will have two columns. The first will be + * the index into the array of that row's contents. The second will be + * the actual value of that array element. The specified Map + * will be used to override selected default mappings of SQL types to + * Java classes.

    + * + * @param offset The index into the array to start returning elements from. + * @param length The requested number of elements to return. + * @param map A mapping of SQL types to Java classes. + * @return The requested elements of this array as a ResultSet. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + ResultSet getResultSet(long index, int count, Map map) + throws SQLException; +} diff --git a/libjava/classpath/java/sql/BatchUpdateException.java b/libjava/classpath/java/sql/BatchUpdateException.java new file mode 100644 index 0000000..c2e1865 --- /dev/null +++ b/libjava/classpath/java/sql/BatchUpdateException.java @@ -0,0 +1,141 @@ +/* BatchUpdateException.java -- Exception for batch oriented SQL errors + Copyright (C) 1999, 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 java.sql; + +/** + * This class extends SQLException to count the successful + * updates in each statement in a batch that was successfully updated prior + * to the error. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class BatchUpdateException extends SQLException +{ + static final long serialVersionUID = 5977529877145521757L; + + /** + * This is the array of update counts for the commands which completed + * successfully prior to the error. + */ + private int[] updateCounts; + + /** + * This method initializes a new instance of BatchUpdateException + * with the specified descriptive error message, SQL state, and update count + * information. The vendor specific error code will be initialized to 0. + * + * @param message The descriptive error message. + * @param SQLState The SQL state information for this error. + * @param vendorCode + * @param updateCounts The update count information for this error. + */ + public BatchUpdateException(String message, String SQLState, int vendorCode, + int[] updateCounts) + { + super(message, SQLState, vendorCode); + this.updateCounts = updateCounts; + } + + /** + * This method initializes a new instance of BatchUpdateException + * with the specified descriptive error message, SQL state, and update count + * information. The vendor specific error code will be initialized to 0. + * + * @param message The descriptive error message. + * @param SQLState The SQL state information for this error. + * @param updateCounts The update count information for this error. + */ + public BatchUpdateException(String message, String SQLState, + int[] updateCounts) + { + super(message, SQLState); + this.updateCounts = updateCounts; + } + + /** + * This method initializes a new instance of BatchUpdateException + * with the specified descriptive error message and update count information. + * The SQL state will be initialized to null and the vendor + * specific error code will be initialized to 0. + * + * @param message The descriptive error message. + * @param updateCounts The update count information for this error. + */ + public BatchUpdateException(String message, int[] updateCounts) + { + super(message); + this.updateCounts = updateCounts; + } + + /** + * Initializes a new instance of BatchUpdateException + * with the specified update count information and no descriptive error + * message. This SQL state will be initialized to null and + * the vendor specific error code will be initialized to 0. + * + * @param updateCounts The update count array. + */ + public BatchUpdateException(int[] updateCounts) + { + this.updateCounts = updateCounts; + } + + /** + * Initializes a new instance of BatchUpdateException + * with no descriptive error message. The SQL state and update count will + * be initialized to null and the vendor specific error code will + * initialized to 0. + */ + public BatchUpdateException() + { + super(); + } + + /** + * This method returns the update count information for this error. If + * not null this is an array of int's that are + * the update accounts for each command that was successfully executed. + * The array elements are in the order that the commands were executed. + * + * @return The update count information, which may be null. + */ + public int[] getUpdateCounts() + { + return updateCounts; + } +} diff --git a/libjava/classpath/java/sql/Blob.java b/libjava/classpath/java/sql/Blob.java new file mode 100644 index 0000000..616839d --- /dev/null +++ b/libjava/classpath/java/sql/Blob.java @@ -0,0 +1,131 @@ +/* Blob.java -- Access a SQL Binary Large OBject. + Copyright (C) 1999, 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 java.sql; + +import java.io.InputStream; +import java.io.OutputStream; + +/** + * This interface specified methods for accessing a SQL BLOB (Binary + * Large OBject) type. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.2 + */ +public interface Blob +{ + /** + * This method returns the number of bytes in the BLOB. + * + * @return The number of bytes in the BLOB. + * @exception SQLException If an error occurs. + */ + long length() throws SQLException; + + /** + * This method returns up to the requested bytes of this BLOB as a + * byte array. + * + * @param pos The index into the BLOB to start returning bytes from. + * @param length The requested number of bytes to return. + * @return The requested bytes from the BLOB. + * @exception SQLException If an error occurs. + */ + byte[] getBytes(long pos, int length) throws SQLException; + + /** + * This method returns a stream that will read the bytes of the BLOB. + * + * @return A stream that will read the bytes of the BLOB. + * @exception SQLException If an error occurs. + */ + InputStream getBinaryStream() throws SQLException; + + /** + * This method returns the index into the BLOB at which the first instance + * of the specified bytes occur. The searching starts at the specified + * index into the BLOB. + * + * @param pattern The byte pattern to search for. + * @param offset The index into the BLOB to starting searching for the pattern. + * @return The offset at which the pattern is first found, or -1 if the + * pattern is not found. + * @exception SQLException If an error occurs. + */ + long position(byte[] pattern, long start) throws SQLException; + + /** + * This method returns the index into the BLOB at which the first instance + * of the specified pattern occurs. The searching starts at the specified + * index into this BLOB. The bytes in the specified Blob are + * used as the search pattern. + * + * @param pattern The Blob containing the byte pattern to + * search for. + * @param offset The index into the BLOB to starting searching for the pattern. + * @return The offset at which the pattern is first found, or -1 if the + * pattern is not found. + * @exception SQLException If an error occurs. + */ + long position(Blob pattern, long start) throws SQLException; + + /** + * @exception SQLException If an error occurs. + * @since 1.4 + */ + int setBytes(long pos, byte[] bytes) throws SQLException; + + /** + * @exception SQLException If an error occurs. + * @since 1.4 + */ + int setBytes(long pos, byte[] bytes, int offset, int len) + throws SQLException; + + /** + * @exception SQLException If an error occurs. + * @since 1.4 + */ + OutputStream setBinaryStream(long pos) throws SQLException; + + /** + * @exception SQLException If an error occurs. + * @since 1.4 + */ + void truncate(long len) throws SQLException; +} diff --git a/libjava/classpath/java/sql/CallableStatement.java b/libjava/classpath/java/sql/CallableStatement.java new file mode 100644 index 0000000..4522941 --- /dev/null +++ b/libjava/classpath/java/sql/CallableStatement.java @@ -0,0 +1,651 @@ +/* CallableStatement.java -- A statement for calling stored procedures. + Copyright (C) 1999, 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 java.sql; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.util.Calendar; +import java.util.Map; + +/** + * This interface provides a mechanism for calling stored procedures. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface CallableStatement extends PreparedStatement +{ + /** + * This method registers the specified parameter as an output parameter + * of the specified SQL type. + * + * @param index The index of the parameter to register as output. + * @param type The SQL type value from Types. + * @exception SQLException If an error occurs. + */ + void registerOutParameter(int parameterIndex, int sqlType) + throws SQLException; + + /** + * This method registers the specified parameter as an output parameter + * of the specified SQL type and scale. + * + * @param index The index of the parameter to register as output. + * @param type The SQL type value from Types. + * @param scale The scale of the value that will be returned. + * @exception SQLException If an error occurs. + */ + void registerOutParameter(int parameterIndex, int sqlType, int scale) + throws SQLException; + + /** + * This method tests whether the value of the last parameter that was fetched + * was actually a SQL NULL value. + * + * @return true if the last parameter fetched was a NULL, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean wasNull() throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * String. + * + * @param index The index of the parameter to return. + * @return The parameter value as a String. + * @exception SQLException If an error occurs. + */ + String getString(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * boolean. + * + * @param index The index of the parameter to return. + * @return The parameter value as a boolean. + * @exception SQLException If an error occurs. + */ + boolean getBoolean(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * byte. + * + * @param index The index of the parameter to return. + * @return The parameter value as a byte. + * @exception SQLException If an error occurs. + */ + byte getByte(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * short. + * + * @param index The index of the parameter to return. + * @return The parameter value as a short. + * @exception SQLException If an error occurs. + */ + short getShort(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * int. + * + * @param index The index of the parameter to return. + * @return The parameter value as a int. + * @exception SQLException If an error occurs. + */ + int getInt(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * long. + * + * @param index The index of the parameter to return. + * @return The parameter value as a long. + * @exception SQLException If an error occurs. + */ + long getLong(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * float. + * + * @param index The index of the parameter to return. + * @return The parameter value as a float. + * @exception SQLException If an error occurs. + */ + float getFloat(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * double. + * + * @param index The index of the parameter to return. + * @return The parameter value as a double. + * @exception SQLException If an error occurs. + */ + double getDouble(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * BigDecimal. + * + * @param parameterIndex The index of the parameter to return. + * @param scale The number of digits to the right of the decimal to return. + * @return The parameter value as a BigDecimal. + * @exception SQLException If an error occurs. + * @deprecated Use getBigDecimal(int parameterIndex) + * or getBigDecimal(String parameterName) instead. + */ + BigDecimal getBigDecimal(int parameterIndex, int scale) + throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * byte array. + * + * @param parameterIndex The index of the parameter to return. + * @return The parameter value as a byte array + * @exception SQLException If an error occurs. + */ + byte[] getBytes(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * java.sql.Date. + * + * @param index The index of the parameter to return. + * @return The parameter value as a java.sql.Date. + * @exception SQLException If an error occurs. + */ + Date getDate(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * java.sql.Time. + * + * @param index The index of the parameter to return. + * @return The parameter value as a java.sql.Time. + * @exception SQLException If an error occurs. + */ + Time getTime(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * java.sql.Timestamp. + * + * @param index The index of the parameter to return. + * @return The parameter value as a java.sql.Timestamp. + * @exception SQLException If an error occurs. + */ + Timestamp getTimestamp(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * Object. + * + * @param parameterIndex The index of the parameter to return. + * @return The parameter value as an Object. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Object getObject(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * BigDecimal. + * + * @param parameterIndex The index of the parameter to return. + * @return The parameter value as a BigDecimal. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + BigDecimal getBigDecimal(int parameterIndex) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * Object. + * + * @param index The index of the parameter to return. + * @param map The mapping to use for conversion from SQL to Java types. + * @return The parameter value as an Object. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Object getObject(int index, Map map) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * Ref. + * + * @param index The index of the parameter to return. + * @return The parameter value as a Ref. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Ref getRef(int index) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * Blob. + * + * @param index The index of the parameter to return. + * @return The parameter value as a Blob. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Blob getBlob(int index) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * Clob. + * + * @param index The index of the parameter to return. + * @return The parameter value as a Clob. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Clob getClob(int index) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * Array. + * + * @param parameterIndex The index of the parameter to return. + * @return The parameter value as a Array. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Array getArray(int index) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * java.sql.Date. + * + * @param parameterIndex The index of the parameter to return. + * @param cal The Calendar to use for timezone and locale. + * @return The parameter value as a java.sql.Date. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Date getDate(int parameterIndex, Calendar cal) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * java.sql.Time. + * + * @param parameterIndex The index of the parameter to return. + * @param cal The Calendar to use for timezone and locale. + * @return The parameter value as a java.sql.Time. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Time getTime(int parameterIndex, Calendar cal) throws SQLException; + + /** + * This method returns the value of the specified parameter as a Java + * java.sql.Timestamp. + * + * @param index The index of the parameter to return. + * @return The parameter value as a java.sql.Timestamp. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Timestamp getTimestamp(int parameterIndex, Calendar cal) + throws SQLException; + + /** + * This method registers the specified parameter as an output parameter + * of the specified SQL type. + * + * @param index The index of the parameter to register as output. + * @param type The SQL type value from Types. + * @param name The user defined data type name. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + void registerOutParameter(int paramIndex, int sqlType, + String typeName) + throws SQLException; + + /** + * This method registers the specified parameter as an output parameter + * of the specified SQL type. + * + * @param parameterName The name of the parameter to register as output. + * @param sqlType The SQL type value from Types. + * @exception SQLException If an error occurs. + * @since 1.4 + */ + void registerOutParameter(String parameterName, int sqlType) + throws SQLException; + + /** + * This method registers the specified parameter as an output parameter + * of the specified SQL type. This version of registerOutParameter is used + * for NUMERIC or DECIMAL types. + * + * @param parameterName The name of the parameter to register as output. + * @param sqlType The SQL type value from Types. + * @param scale Number of digits to the right of the decimal point. + * @exception SQLException If an error occurs. + * @since 1.4 + */ + void registerOutParameter(String parameterName, int sqlType, + int scale) + throws SQLException; + + + /** + * This method registers the specified parameter as an output parameter + * of the specified SQL type. This version of registerOutParameter is used + * for user-named or REF types. If the type of the output parameter does + * not have such a type, the typeName argument is ignored. + * + * @param parameterName The name of the parameter to register as output. + * @param sqlType The SQL type value from Types. + * @param typeName The SQL structured type name. + * @exception SQLException If an error occurs. + * @since 1.4 + */ + void registerOutParameter(String parameterName, int sqlType, + String typeName) + throws SQLException; + + /** + * @since 1.4 + */ + URL getURL(int parameterIndex) throws SQLException; + + /** + * @since 1.4 + */ + void setURL(String parameterName, URL val) throws SQLException; + + /** + * @since 1.4 + */ + void setNull(String parameterName, int sqlType) throws SQLException; + + /** + * @since 1.4 + */ + void setBoolean(String parameterName, boolean x) throws SQLException; + + /** + * @since 1.4 + */ + void setByte(String parameterName, byte x) throws SQLException; + + /** + * @since 1.4 + */ + void setShort(String parameterName, short x) throws SQLException; + + /** + * @since 1.4 + */ + void setInt(String parameterName, int x) throws SQLException; + + /** + * @since 1.4 + */ + void setLong(String parameterName, long x) throws SQLException; + + /** + * @since 1.4 + */ + void setFloat(String parameterName, float x) throws SQLException; + + /** + * @since 1.4 + */ + void setDouble(String parameterName, double x) throws SQLException; + + /** + * @since 1.4 + */ + void setBigDecimal(String parameterName, BigDecimal x) + throws SQLException; + + /** + * @since 1.4 + */ + void setString(String parameterName, String x) throws SQLException; + + /** + * @since 1.4 + */ + void setBytes(String parameterName, byte[] x) throws SQLException; + + /** + * @since 1.4 + */ + void setDate(String parameterName, Date x) throws SQLException; + + /** + * @since 1.4 + */ + void setTime(String parameterName, Time x) throws SQLException; + + /** + * @since 1.4 + */ + void setTimestamp(String parameterName, Timestamp x) + throws SQLException; + + /** + * @since 1.4 + */ + void setAsciiStream(String parameterName, InputStream x, int length) + throws SQLException; + + /** + * @since 1.4 + */ + void setBinaryStream(String parameterName, InputStream x, int length) + throws SQLException; + + /** + * @since 1.4 + */ + void setObject(String parameterName, Object x, int targetSqlType, + int scale) + throws SQLException; + + /** + * @since 1.4 + */ + void setObject(String parameterName, Object x, int targetSqlType) + throws SQLException; + + /** + * @since 1.4 + */ + void setObject(String parameterName, Object x) throws SQLException; + + /** + * @since 1.4 + */ + void setCharacterStream(String parameterName, Reader reader, + int length) + throws SQLException; + + /** + * @since 1.4 + */ + void setDate(String parameterName, Date x, Calendar cal) + throws SQLException; + + /** + * @since 1.4 + */ + void setTime(String parameterName, Time x, Calendar cal) + throws SQLException; + + /** + * @since 1.4 + */ + void setTimestamp(String parameterName, Timestamp x, Calendar cal) + throws SQLException; + + /** + * @since 1.4 + */ + void setNull(String parameterName, int sqlType, String typeName) + throws SQLException; + + /** + * @since 1.4 + */ + String getString(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + boolean getBoolean(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + byte getByte(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + short getShort(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + int getInt(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + long getLong(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + float getFloat(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + double getDouble(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + byte[] getBytes(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + Date getDate(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + Time getTime(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + Timestamp getTimestamp(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + Object getObject(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + BigDecimal getBigDecimal(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + Object getObject(String parameterName, Map map) throws SQLException; + + /** + * @since 1.4 + */ + Ref getRef(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + Blob getBlob(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + Clob getClob(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + Array getArray(String parameterName) throws SQLException; + + /** + * @since 1.4 + */ + Date getDate(String parameterName, Calendar cal) throws SQLException; + + /** + * @since 1.4 + */ + Time getTime(String parameterName, Calendar cal) throws SQLException; + + /** + * @since 1.4 + */ + Timestamp getTimestamp(String parameterName, Calendar cal) + throws SQLException; + + /** + * @since 1.4 + */ + URL getURL(String parameterName) throws SQLException; +} diff --git a/libjava/classpath/java/sql/Clob.java b/libjava/classpath/java/sql/Clob.java new file mode 100644 index 0000000..8789da5 --- /dev/null +++ b/libjava/classpath/java/sql/Clob.java @@ -0,0 +1,152 @@ +/* Clob.java -- Access Character Large OBjects + Copyright (C) 1999, 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 java.sql; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +/** + * This interface contains methods for accessing a SQL CLOB (Character + * Large OBject) type. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Clob +{ + /** + * This method returns the number of characters in the CLOB. + * + * @return The number of characters in the CLOB. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + long length() throws SQLException; + + /** + * This method returns the specified portion of the CLOB as a + * String. + * + * @param offset The index into the CLOB (index values start at 1) to + * start returning characters from. + * @param length The requested number of characters to return. + * @return The requested CLOB section, as a String. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + String getSubString(long pos, int length) throws SQLException; + + /** + * This method returns a character stream that reads the contents of the + * CLOB. + * + * @return A character stream to read the CLOB's contents. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + Reader getCharacterStream() throws SQLException; + + /** + * This method returns a byte stream that reads the contents of the + * CLOB as a series of ASCII bytes. + * + * @return A stream to read the CLOB's contents. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + InputStream getAsciiStream() throws SQLException; + + /** + * This method returns the index into the CLOB of the first occurrence of + * the specified character pattern (supplied by the caller as a + * String). The search begins at the specified index. + * + * @param searchstr The character pattern to search for, passed as a + * String. + * @param start. The index into the CLOB to start search (indexes start + * at 1). + * @return The index at which the pattern was found (indexes start at 1), + * or -1 if the pattern was not found. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + long position(String searchstr, long start) throws SQLException; + + /** + * This method returns the index into the CLOB of the first occurrence of + * the specified character pattern (supplied by the caller as a + * Clob). The search begins at the specified index. + * + * @param searchstr The character pattern to search for, passed as a + * Clob. + * @param start. The index into the CLOB to start search (indexes start + * at 1). + * @return The index at which the pattern was found (indexes start at 1), + * or -1 if the pattern was not found. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + long position(Clob searchstr, long start) throws SQLException; + + /** + * @since 1.4 + */ + int setString(long pos, String str) throws SQLException; + + /** + * @since 1.4 + */ + int setString(long pos, String str, int offset, int len) + throws SQLException; + + /** + * @since 1.4 + */ + OutputStream setAsciiStream(long pos) throws SQLException; + + /** + * @since 1.4 + */ + Writer setCharacterStream(long pos) throws SQLException; + + /** + * @since 1.4 + */ + void truncate(long len) throws SQLException; +} diff --git a/libjava/classpath/java/sql/Connection.java b/libjava/classpath/java/sql/Connection.java new file mode 100644 index 0000000..48ec12d --- /dev/null +++ b/libjava/classpath/java/sql/Connection.java @@ -0,0 +1,420 @@ +/* Connection.java -- Manage a database connection. + Copyright (C) 1999, 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 java.sql; + +import java.util.Map; + +/** + * This interface provides methods for managing a connection to a database. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Connection +{ + /** + * This transaction isolation level indicates that transactions are not + * supported. + */ + int TRANSACTION_NONE = 0; + + /** + * This transaction isolation level indicates that one transaction can + * read modifications by other transactions before the other transactions + * have committed their changes. This could result in invalid reads. + */ + int TRANSACTION_READ_UNCOMMITTED = 1; + + /** + * This transaction isolation leve indicates that only committed data from + * other transactions will be read. If a transaction reads a row, then + * another transaction commits a change to that row, the first transaction + * would retrieve the changed row on subsequent reads of the same row. + */ + int TRANSACTION_READ_COMMITTED = 2; + + /** + * This transaction isolation level indicates that only committed data from + * other transactions will be read. It also ensures that data read from + * a row will not be different on a subsequent read even if another + * transaction commits a change. + */ + int TRANSACTION_REPEATABLE_READ = 4; + + /** + * This transaction isolation level indicates that only committed data from + * other transactions will be read. It also ensures that data read from + * a row will not be different on a subsequent read even if another + * transaction commits a change. Additionally, rows modified by other + * transactions will not affect the result set returned during subsequent + * executions of the same WHERE clause in this transaction. + */ + int TRANSACTION_SERIALIZABLE = 8; + + /** + * This method creates a new SQL statement. The default result set type + * and concurrency will be used. + * + * @return A new Statement object. + * @exception SQLException If an error occurs. + * @see Statement + */ + Statement createStatement() throws SQLException; + + /** + * This method creates a new PreparedStatement for the specified + * SQL string. This method is designed for use with parameterized + * statements. The default result set type and concurrency will be used. + * + * @param The SQL statement to use in creating this + * PreparedStatement. + * @return A new PreparedStatement. + * @exception SQLException If an error occurs. + * @see PreparedStatement + */ + PreparedStatement prepareStatement(String sql) throws SQLException; + + /** + * This method creates a new CallableStatement for the + * specified SQL string. Thie method is designed to be used with + * stored procedures. The default result set type and concurrency + * will be used. + * + * @param The SQL statement to use in creating this + * CallableStatement. + * @return A new CallableStatement. + * @exception SQLException If an error occurs. + * @see CallableStatement + */ + CallableStatement prepareCall(String sql) throws SQLException; + + /** + * This method converts the specified generic SQL statement into the + * native grammer of the database this object is connected to. + * + * @param The JDBC generic SQL statement. + * @return The native SQL statement. + * @exception SQLException If an error occurs. + */ + String nativeSQL(String sql) throws SQLException; + + /** + * This method turns auto commit mode on or off. In auto commit mode, + * every SQL statement is committed its own transaction. Otherwise a + * transaction must be explicitly committed or rolled back. + * + * @param autoCommit true to enable auto commit mode, + * false to disable it. + * @exception SQLException If an error occurs. + * @see commit + * @see rollback + */ + void setAutoCommit(boolean autoCommit) throws SQLException; + + /** + * This method tests whether or not auto commit mode is currently enabled. + * In auto commit mode, every SQL statement is committed its own transaction. + * Otherwise a transaction must be explicitly committed or rolled back. + * + * @return true if auto commit mode is enabled, + * false otherwise. + * + * @exception SQLException If an error occurs. + * + * @see commit + * @see rollback + */ + boolean getAutoCommit() throws SQLException; + + /** + * This method commits any SQL statements executed on this connection since + * the last commit or rollback. + * + * @exception SQLException If an error occurs. + */ + void commit() throws SQLException; + + /** + * This method rolls back any SQL statements executed on this connection + * since the last commit or rollback. + * + * @exception SQLException If an error occurs. + */ + void rollback() throws SQLException; + + /** + * This method immediately closes this database connection. + * + * @exception SQLException If an error occurs. + */ + void close() throws SQLException; + + /** + * This method tests whether or not this connection has been closed. + * + * @return true if the connection is closed, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean isClosed() throws SQLException; + + /** + * This method returns the meta data for this database connection. + * + * @return The meta data for this database. + * @exception SQLException If an error occurs. + * @see DatabaseMetaData + */ + DatabaseMetaData getMetaData() throws SQLException; + + /** + * This method turns read only mode on or off. It may not be called while + * a transaction is in progress. + * + * @param readOnly true if this connection is read only, + * false otherwise. + * @exception SQLException If an error occurs. + */ + void setReadOnly(boolean readOnly) throws SQLException; + + /** + * This method tests whether or not this connection is in read only mode. + * + * @return true if the connection is read only false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean isReadOnly() throws SQLException; + + /** + * This method sets the name of the catalog in use by this connection. + * Note that this method does nothing if catalogs are not supported by + * this database. + * + * @param catalog The name of the catalog to use for this connection. + * @exception SQLException If an error occurs. + */ + void setCatalog(String catalog) throws SQLException; + + /** + * This method returns the name of the catalog in use by this connection, + * if any. + * + * @return The name of the catalog, or null if one does not + * exist or catalogs are not supported by this database. + * @exception SQLException If an error occurs. + */ + String getCatalog() throws SQLException; + + /** + * This method sets the current transaction isolation mode. This must + * be one of the constants defined in this interface. + * + * @param level The transaction isolation level. + * @exception SQLException If an error occurs. + */ + void setTransactionIsolation(int level) throws SQLException; + + /** + * This method returns the current transaction isolation mode. This will + * be one of the constants defined in this interface. + * + * @return The transaction isolation level. + * @exception SQLException If an error occurs. + */ + int getTransactionIsolation() throws SQLException; + + /** + * This method returns the first warning that occurred on this connection, + * if any. If there were any subsequence warnings, they will be chained + * to the first one. + * + * @return The first SQLWarning that occurred, or + * null if there have been no warnings. + * @exception SQLException If an error occurs. + */ + SQLWarning getWarnings() throws SQLException; + + /** + * This method clears all warnings that have occurred on this connection. + * + * @exception SQLException If an error occurs. + */ + void clearWarnings() throws SQLException; + + /** + * This method creates a new SQL statement with the specified type and + * concurrency. Valid values for these parameters are specified in the + * ResultSet class. + * + * @param resultSetType The type of result set to use for this statement. + * @param resultSetConcurrency. The type of concurrency to be used in + * the result set for this statement. + * @return A new Statement object. + * @exception SQLException If an error occurs. + * @see Statement + * @see ResultSet + */ + Statement createStatement(int resultSetType, int resultSetConcurrency) + throws SQLException; + + /** + * This method creates a new PreparedStatement for the specified + * SQL string. This method is designed for use with parameterized + * statements. The specified result set type and concurrency will be used. + * Valid values for these parameters are specified in the + * ResultSet class. + * + * @param The SQL statement to use in creating this + * PreparedStatement. + * @param resultSetType The type of result set to use for this statement. + * @param resultSetConcurrency. The type of concurrency to be used in + * the result set for this statement. + * @return A new PreparedStatement. + * @exception SQLException If an error occurs. + * @see PreparedStatement + * @see ResultSet + */ + PreparedStatement prepareStatement(String sql, int resultSetType, + int resultSetConcurrency) throws SQLException; + + /** + * This method creates a new CallableStatement for the + * specified SQL string. Thie method is designed to be used with + * stored procedures. The specified result set type and concurrency + * will be used. Valid values for these parameters are specified in the + * ResultSet class. + * + * @param The SQL statement to use in creating this + * PreparedStatement. + * @param resultSetType The type of result set to use for this statement. + * @param resultSetConcurrency. The type of concurrency to be used in + * the result set for this statement. + * @return A new CallableStatement. + * @exception SQLException If an error occurs. + * @see CallableStatement + * @see ResultSet + */ + CallableStatement prepareCall(String sql, int resultSetType, int + resultSetConcurrency) throws SQLException; + + /** + * This method returns the mapping of SQL types to Java classes + * currently in use by this connection. This mapping will have no + * entries unless they have been manually added. + * + * @return The SQL type to Java class mapping. + * @exception SQLException If an error occurs. + */ + Map getTypeMap() throws SQLException; + + /** + * This method sets the mapping table for SQL types to Java classes. + * Any entries in this map override the defaults. + * + * @param map The new SQL mapping table. + * @exception SQLException If an error occurs. + */ + void setTypeMap(Map map) throws SQLException; + + /** + * @since 1.4 + */ + void setHoldability(int holdability) throws SQLException; + + /** + * @since 1.4 + */ + int getHoldability() throws SQLException; + + /** + * @since 1.4 + */ + Savepoint setSavepoint() throws SQLException; + + /** + * @since 1.4 + */ + Savepoint setSavepoint(String name) throws SQLException; + + /** + * @since 1.4 + */ + void rollback(Savepoint savepoint) throws SQLException; + + /** + * @since 1.4 + */ + void releaseSavepoint(Savepoint savepoint) throws SQLException; + + /** + * @since 1.4 + */ + Statement createStatement(int resultSetType, int + resultSetConcurrency, int resultSetHoldability) throws SQLException; + + /** + * @since 1.4 + */ + PreparedStatement prepareStatement(String sql, int resultSetType, int + resultSetConcurrency, int resultSetHoldability) throws SQLException; + + /** + * @since 1.4 + */ + CallableStatement prepareCall(String sql, int resultSetType, int + resultSetConcurrency, int resultSetHoldability) throws SQLException; + + /** + * @since 1.4 + */ + PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) + throws SQLException; + + /** + * @since 1.4 + */ + PreparedStatement prepareStatement(String sql, int[] columnIndexes) + throws SQLException; + + /** + * @since 1.4 + */ + PreparedStatement prepareStatement(String sql, String[] columnNames) + throws SQLException; +} diff --git a/libjava/classpath/java/sql/DataTruncation.java b/libjava/classpath/java/sql/DataTruncation.java new file mode 100644 index 0000000..ec522c0 --- /dev/null +++ b/libjava/classpath/java/sql/DataTruncation.java @@ -0,0 +1,157 @@ +/* DataTruncation.java -- Warning when data has been truncated. + Copyright (C) 1999, 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 java.sql; + +/** + * This exception is thrown when a piece of data is unexpectedly + * truncated in JDBC. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class DataTruncation extends SQLWarning +{ + static final long serialVersionUID = 6464298989504059473L; + + /** + * The original size of the data. + */ + private int dataSize; + + /** + * The index of the parameter or column whose value was truncated. + */ + private int index; + + /** + * Indicates whether or not a parameter value was truncated. + */ + private boolean parameter; + + /** + * Indicates whether or not a data column value was truncated. + */ + private boolean read; + + /** + * This is the size of the data after truncation. + */ + private int transferSize; + + /** + * This method initializes a new instance of DataTruncation + * with the specified values. The descriptive error message for this + * exception will be "Data truncation", the SQL state will be "01004" + * and the vendor specific error code will be set to 0. + * + * @param index The index of the parameter or column that was truncated. + * @param parameter true if a parameter was truncated, + * false otherwise. + * @param read true if a data column was truncated, + * false otherwise. + * @param dataSize The original size of the data. + * @param transferSize The size of the data after truncation. + */ + public DataTruncation(int index, boolean parameter, boolean read, int + dataSize, int transferSize) + { + super("Data truncation", "01004"); + + this.index = index; + this.parameter = parameter; + this.read = read; + this.dataSize = dataSize; + this.transferSize = transferSize; + } + + /** + * This method returns the index of the column or parameter that was + * truncated. + * + * @return The index of the column or parameter that was truncated. + */ + public int getIndex() + { + return index; + } + + /** + * This method determines whether or not it was a parameter that was + * truncated. + * + * @return true if a parameter was truncated, false + * otherwise. + */ + public boolean getParameter() + { + return parameter; + } + + /** + * This method determines whether or not it was a column that was + * truncated. + * + * @return true if a column was truncated, false + * otherwise. + */ + public boolean getRead() + { + return read; + } + + /** + * This method returns the original size of the parameter or column that + * was truncated. + * + * @return The original size of the parameter or column that was truncated. + */ + public int getDataSize() + { + return dataSize; + } + + /** + * This method returns the size of the parameter or column after it was + * truncated. + * + * @return The size of the parameter or column after it was truncated. + */ + public int getTransferSize() + { + return transferSize; + } +} diff --git a/libjava/classpath/java/sql/DatabaseMetaData.java b/libjava/classpath/java/sql/DatabaseMetaData.java new file mode 100644 index 0000000..d34c4e2 --- /dev/null +++ b/libjava/classpath/java/sql/DatabaseMetaData.java @@ -0,0 +1,2214 @@ +/* DatabaseMetaData.java -- Information about the database itself. + Copyright (C) 1999, 2000, 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 java.sql; + +public interface DatabaseMetaData +{ + /** + * It is unknown whether or not the procedure returns a result. + */ + int procedureResultUnknown = 0; + + /** + * The procedure does not return a result. + */ + int procedureNoResult = 1; + + /** + * The procedure returns a result. + */ + int procedureReturnsResult = 2; + + /** + * The column type is unknown. + */ + int procedureColumnUnknown = 0; + + /** + * The column type is input. + */ + int procedureColumnIn = 1; + + /** + * The column type is input/output. + */ + int procedureColumnInOut = 2; + + /** + * The column type is output + */ + int procedureColumnOut = 4; + + /** + * The column is used for return values. + */ + int procedureColumnReturn = 5; + + /** + * The column is used for storing results + */ + int procedureColumnResult = 3; + + /** + * NULL values are not allowed. + */ + int procedureNoNulls = 0; + + /** + * NULL values are allowed. + */ + int procedureNullable = 1; + + /** + * It is unknown whether or not NULL values are allowed. + */ + int procedureNullableUnknown = 2; + + /** + * The column does not allow NULL + */ + int columnNoNulls = 0; + + /** + * The column does allow NULL + */ + int columnNullable = 1; + + /** + * It is unknown whether or not the column allows NULL + */ + int columnNullableUnknown = 2; + + /** + * The best row's scope is only guaranteed to be valid so long as the + * row is actually being used. + */ + int bestRowTemporary = 0; + + /** + * The best row identifier is valid to the end of the transaction. + */ + int bestRowTransaction = 1; + + /** + * The best row identifier is valid to the end of the session. + */ + int bestRowSession = 2; + + /** + * The best row may or may not be a pseudo-column. + */ + int bestRowUnknown = 0; + + /** + * The best row identifier is not a pseudo-column. + */ + int bestRowNotPseudo = 1; + + /** + * The best row identifier is a pseudo-column. + */ + int bestRowPseudo = 2; + + /** + * It is unknown whether or not the version column is a pseudo-column. + */ + int versionColumnUnknown = 0; + + /** + * The version column is not a pseudo-column + */ + int versionColumnNotPseudo = 1; + + /** + * The version column is a pseudo-column + */ + int versionColumnPseudo = 2; + + /** + * Foreign key changes are cascaded in updates or deletes. + */ + int importedKeyCascade = 0; + + /** + * Column may not be updated or deleted in use as a foreign key. + */ + int importedKeyRestrict = 1; + + /** + * When primary key is updated or deleted, the foreign key is set to NULL. + */ + int importedKeySetNull = 2; + + /** + * If the primary key is a foreign key, it cannot be udpated or deleted. + */ + int importedKeyNoAction = 3; + + /** + * If the primary key is updated or deleted, the foreign key is set to + * a default value. + */ + int importedKeySetDefault = 4; + + /** + * Wish I knew what this meant. + */ + int importedKeyInitiallyDeferred = 5; + + /** + * Wish I knew what this meant. + */ + int importedKeyInitiallyImmediate = 6; + + /** + * Wish I knew what this meant. + */ + int importedKeyNotDeferrable = 7; + + /** + * A NULL value is not allowed for this data type. + */ + int typeNoNulls = 0; + + /** + * A NULL value is allowed for this data type. + */ + int typeNullable = 1; + + /** + * It is unknown whether or not NULL values are allowed for this data type. + */ + int typeNullableUnknown = 2; + + /** + * Where clauses are not supported for this type. + */ + int typePredNone = 0; + + /** + * Only "WHERE..LIKE" style WHERE clauses are allowed on this data type. + */ + int typePredChar = 1; + + /** + * All WHERE clauses except "WHERE..LIKE" style are allowed on this data type. + */ + int typePredBasic = 2; + + /** + * Any type of WHERE clause is allowed for this data type. + */ + int typeSearchable = 3; + + /** + * This column contains table statistics. + */ + short tableIndexStatistic = 0; + + /** + * This table index is clustered. + */ + short tableIndexClustered = 1; + + /** + * This table index is hashed. + */ + short tableIndexHashed = 2; + + /** + * This table index is of another type. + */ + short tableIndexOther = 3; + + short attributeNoNulls = 0; + + short attributeNullable = 1; + + short attributeNullableUnknown = 2; + + int sqlStateXOpen = 1; + + int sqlStateSQL99 = 2; + + /** + * This method tests whether or not all the procedures returned by + * the getProcedures method can be called by this user. + * + * @return true if all the procedures can be called, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean allProceduresAreCallable() throws SQLException; + + /** + * This method tests whether or not all the table returned by the + * getTables method can be selected by this user. + * + * @return true if all the procedures can be called, + * false otherwise. + * + * @exception SQLException If an error occurs. + */ + boolean allTablesAreSelectable() throws SQLException; + + /** + * This method returns the URL for this database. + * + * @return The URL string for this database, or null if it + * is not known. + * @exception SQLException If an error occurs. + */ + String getURL() throws SQLException; + + /** + * This method returns the database username for this connection. + * + * @return The database username. + * @exception SQLException If an error occurs. + */ + String getUserName() throws SQLException; + + /** + * This method tests whether or not the database is in read only mode. + * + * @return true if the database is in read only mode, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isReadOnly() throws SQLException; + + /** + * This method tests whether or not NULL's sort as high values. + * + * @return true if NULL's sort as high values, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean nullsAreSortedHigh() throws SQLException; + + /** + * This method tests whether or not NULL's sort as low values. + * + * @return true if NULL's sort as low values, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean nullsAreSortedLow() throws SQLException; + + /** + * This method tests whether or not NULL's sort as high values. + * + * @return true if NULL's sort as high values, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean nullsAreSortedAtStart() throws SQLException; + + /** + * This method test whether or not NULL's are sorted to the end + * of the list regardless of ascending or descending sort order. + * + * @return true if NULL's always sort to the end, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean nullsAreSortedAtEnd() throws SQLException; + + /** + * This method returns the name of the database product. + * + * @return The database product. + * @exception SQLException If an error occurs. + */ + String getDatabaseProductName() throws SQLException; + + /** + * This method returns the version of the database product. + * + * @return The version of the database product. + * @exception SQLException If an error occurs. + */ + String getDatabaseProductVersion() throws SQLException; + + /** + * This method returns the name of the JDBC driver. + * + * @return The name of the JDBC driver. + * @exception SQLException If an error occurs. + */ + String getDriverName() throws SQLException; + + /** + * This method returns the version of the JDBC driver. + * + * @return The version of the JDBC driver. + * @exception SQLException If an error occurs. + */ + String getDriverVersion() throws SQLException; + + /** + * This method returns the major version number of the JDBC driver. + * + * @return The major version number of the JDBC driver. + */ + int getDriverMajorVersion(); + + /** + * This method returns the minor version number of the JDBC driver. + * + * @return The minor version number of the JDBC driver. + */ + int getDriverMinorVersion(); + + /** + * This method tests whether or not the database uses local files to + * store tables. + * + * @return true if the database uses local files, + * false otherwise. + * + * @exception SQLException If an error occurs. + */ + boolean usesLocalFiles() throws SQLException; + + /** + * This method tests whether or not the database uses a separate file for + * each table. + * + * @return true if the database uses a separate file for each + * table false otherwise. + * + * @exception SQLException If an error occurs. + */ + boolean usesLocalFilePerTable() throws SQLException; + + /** + * This method tests whether or not the database supports identifiers + * with mixed case. + * + * @return true if the database supports mixed case identifiers, + * false otherwise. + * + * @exception SQLException If an error occurs. + */ + boolean supportsMixedCaseIdentifiers() throws SQLException; + + /** + * This method tests whether or not the database treats mixed case + * identifiers as all upper case. + * + * @return true if the database treats all identifiers as + * upper case, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean storesUpperCaseIdentifiers() throws SQLException; + + /** + * This method tests whether or not the database treats mixed case + * identifiers as all lower case. + * + * @return true if the database treats all identifiers as + * lower case, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean storesLowerCaseIdentifiers() throws SQLException; + + /** + * This method tests whether or not the database stores mixed case + * identifers even if it treats them as case insensitive. + * + * @return true if the database stores mixed case identifiers, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean storesMixedCaseIdentifiers() throws SQLException; + + /** + * This method tests whether or not the database supports quoted identifiers + * with mixed case. + * + * @return true if the database supports mixed case quoted + * identifiers, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsMixedCaseQuotedIdentifiers() throws SQLException; + + /** + * This method tests whether or not the database treats mixed case + * quoted identifiers as all upper case. + * + * @return true if the database treats all quoted identifiers + * as upper case, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean storesUpperCaseQuotedIdentifiers() throws SQLException; + + /** + * This method tests whether or not the database treats mixed case + * quoted identifiers as all lower case. + * + * @return true if the database treats all quoted identifiers + * as lower case, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean storesLowerCaseQuotedIdentifiers() throws SQLException; + + /** + * This method tests whether or not the database stores mixed case + * quoted identifers even if it treats them as case insensitive. + * + * @return true if the database stores mixed case quoted + * identifiers, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean storesMixedCaseQuotedIdentifiers() throws SQLException; + + /** + * This metohd returns the quote string for SQL identifiers. + * + * @return The quote string for SQL identifers, or a space if quoting + * is not supported. + * @exception SQLException If an error occurs. + */ + String getIdentifierQuoteString() throws SQLException; + + /** + * This method returns a comma separated list of all the SQL keywords in + * the database that are not in SQL92. + * + * @return The list of SQL keywords not in SQL92. + * @exception SQLException If an error occurs. + */ + String getSQLKeywords() throws SQLException; + + /** + * This method returns a comma separated list of math functions. + * + * @return The list of math functions. + * @exception SQLException If an error occurs. + */ + String getNumericFunctions() throws SQLException; + + /** + * This method returns a comma separated list of string functions. + * + * @return The list of string functions. + * @exception SQLException If an error occurs. + */ + String getStringFunctions() throws SQLException; + + /** + * This method returns a comma separated list of of system functions. + * + * @return A comma separated list of system functions. + * @exception SQLException If an error occurs. + */ + String getSystemFunctions() throws SQLException; + + /** + * This method returns comma separated list of time/date functions. + * + * @return The list of time/date functions. + * @exception SQLException If an error occurs. + */ + String getTimeDateFunctions() throws SQLException; + + /** + * This method returns the string used to escape wildcards in search strings. + * + * @return The string used to escape wildcards in search strings. + * @exception SQLException If an error occurs. + */ + String getSearchStringEscape() throws SQLException; + + /** + * This methods returns non-standard characters that can appear in + * unquoted identifiers. + * + * @return Non-standard characters that can appear in unquoted identifiers. + * @exception SQLException If an error occurs. + */ + String getExtraNameCharacters() throws SQLException; + + /** + * This method tests whether or not the database supports + * "ALTER TABLE ADD COLUMN" + * + * @return true if column add supported, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsAlterTableWithAddColumn() throws SQLException; + + /** + * This method tests whether or not the database supports + * "ALTER TABLE DROP COLUMN" + * + * @return true if column drop supported, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsAlterTableWithDropColumn() throws SQLException; + + /** + * This method tests whether or not column aliasing is supported. + * + * @return true if column aliasing is supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsColumnAliasing() throws SQLException; + + /** + * This method tests whether the concatenation of a NULL and non-NULL + * value results in a NULL. This will always be true in fully JDBC compliant + * drivers. + * + * @return true if concatenating NULL and a non-NULL value + * returns a NULL, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean nullPlusNonNullIsNull() throws SQLException; + + /** + * Tests whether or not CONVERT is supported. + * + * @return true if CONVERT is supported, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsConvert() throws SQLException; + + /** + * This method tests whether or not CONVERT can be performed between the + * specified types. The types are contants from Types. + * + * @param fromType The SQL type to convert from. + * @param toType The SQL type to convert to. + * @return true if the conversion can be performed, + * false otherwise. + * @see Types + */ + boolean supportsConvert(int fromType, int toType) throws + SQLException; + + /** + * This method tests whether or not table correlation names are + * supported. This will be always be true in a fully JDBC + * compliant driver. + * + * @return true if table correlation names are supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsTableCorrelationNames() throws SQLException; + + /** + * This method tests whether correlation names must be different from the + * name of the table. + * + * @return true if the correlation name must be different from + * the table name, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsDifferentTableCorrelationNames() throws SQLException; + + /** + * This method tests whether or not expressions are allowed in an + * ORDER BY lists. + * + * @return true if expressions are allowed in ORDER BY + * lists, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsExpressionsInOrderBy() throws SQLException; + + /** + * This method tests whether or ORDER BY on a non-selected column is + * allowed. + * + * @return true if a non-selected column can be used in an + * ORDER BY, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsOrderByUnrelated() throws SQLException; + + /** + * This method tests whether or not GROUP BY is supported. + * + * @return true if GROUP BY is supported, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsGroupBy() throws SQLException; + + /** + * This method tests whether GROUP BY on a non-selected column is + * allowed. + * + * @return true if a non-selected column can be used in a + * GROUP BY, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsGroupByUnrelated() throws SQLException; + + /** + * This method tests whether or not a GROUP BY can add columns not in the + * select if it includes all the columns in the select. + * + * @return true if GROUP BY an add columns provided it includes + * all columns in the select, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsGroupByBeyondSelect() throws SQLException; + + /** + * This method tests whether or not the escape character is supported in + * LIKE expressions. A fully JDBC compliant driver will always return + * true. + * + * @return true if escapes are supported in LIKE expressions, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsLikeEscapeClause() throws SQLException; + + /** + * This method tests whether multiple result sets for a single statement are + * supported. + * + * @return true if multiple result sets are supported for a + * single statement, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsMultipleResultSets() throws SQLException; + + /** + * This method test whether or not multiple transactions may be open + * at once, as long as they are on different connections. + * + * @return true if multiple transactions on different + * connections are supported, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsMultipleTransactions() throws SQLException; + + /** + * This method tests whether or not columns can be defined as NOT NULL. A + * fully JDBC compliant driver always returns true. + * + * @return true if NOT NULL columns are supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsNonNullableColumns() throws SQLException; + + /** + * This method tests whether or not the minimum grammer for ODBC is supported. + * A fully JDBC compliant driver will always return true. + * + * @return true if the ODBC minimum grammar is supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsMinimumSQLGrammar() throws SQLException; + + /** + * This method tests whether or not the core grammer for ODBC is supported. + * + * @return true if the ODBC core grammar is supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsCoreSQLGrammar() throws SQLException; + + /** + * This method tests whether or not the extended grammer for ODBC is supported. + * + * @return true if the ODBC extended grammar is supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsExtendedSQLGrammar() throws SQLException; + + /** + * This method tests whether or not the ANSI92 entry level SQL + * grammar is supported. A fully JDBC compliant drivers must return + * true. + * + * @return true if the ANSI92 entry level SQL grammar is + * supported, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsANSI92EntryLevelSQL() throws SQLException; + + /** + * This method tests whether or not the ANSI92 intermediate SQL + * grammar is supported. + * + * @return true if the ANSI92 intermediate SQL grammar is + * supported, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsANSI92IntermediateSQL() throws SQLException; + + /** + * This method tests whether or not the ANSI92 full SQL + * grammar is supported. + * + * @return true if the ANSI92 full SQL grammar is + * supported, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsANSI92FullSQL() throws SQLException; + + /** + * This method tests whether or not the SQL integrity enhancement + * facility is supported. + * + * @return true if the integrity enhancement facility is + * supported, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsIntegrityEnhancementFacility() throws SQLException; + + /** + * This method tests whether or not the database supports outer joins. + * + * @return true if outer joins are supported, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsOuterJoins() throws SQLException; + + /** + * This method tests whether or not the database supports full outer joins. + * + * @return true if full outer joins are supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsFullOuterJoins() throws SQLException; + + /** + * This method tests whether or not the database supports limited outer joins. + * + * @return true if limited outer joins are supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsLimitedOuterJoins() throws SQLException; + + /** + * This method returns the vendor's term for "schema". + * + * @return The vendor's term for schema. + * @exception SQLException if an error occurs. + */ + String getSchemaTerm() throws SQLException; + + /** + * This method returns the vendor's term for "procedure". + * + * @return The vendor's term for procedure. + * @exception SQLException if an error occurs. + */ + String getProcedureTerm() throws SQLException; + + /** + * This method returns the vendor's term for "catalog". + * + * @return The vendor's term for catalog. + * @exception SQLException if an error occurs. + */ + String getCatalogTerm() throws SQLException; + + /** + * This method tests whether a catalog name appears at the beginning of + * a fully qualified table name. + * + * @return true if the catalog name appears at the beginning, + * false if it appears at the end. + * @exception SQLException If an error occurs. + */ + boolean isCatalogAtStart() throws SQLException; + + /** + * This method returns the separator between the catalog name and the + * table name. + * + * @return The separator between the catalog name and the table name. + * @exception SQLException If an error occurs. + */ + String getCatalogSeparator() throws SQLException; + + /** + * This method tests whether a catalog name can appear in a data + * manipulation statement. + * + * @return true if a catalog name can appear in a data + * manipulation statement, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSchemasInDataManipulation() throws SQLException; + + /** + * This method tests whether a catalog name can appear in a procedure + * call + * + * @return true if a catalog name can appear in a procedure + * call, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSchemasInProcedureCalls() throws SQLException; + + /** + * This method tests whether a catalog name can appear in a table definition. + * + * @return true if a catalog name can appear in a table + * definition, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSchemasInTableDefinitions() throws SQLException; + + /** + * This method tests whether a catalog name can appear in an index definition. + * + * @return true if a catalog name can appear in an index + * definition, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSchemasInIndexDefinitions() throws SQLException; + + /** + * This method tests whether a catalog name can appear in privilege definitions. + * + * @return true if a catalog name can appear in privilege + * definition, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSchemasInPrivilegeDefinitions() throws SQLException; + + /** + * This method tests whether a catalog name can appear in a data + * manipulation statement. + * + * @return true if a catalog name can appear in a data + * manipulation statement, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsCatalogsInDataManipulation() throws SQLException; + + /** + * This method tests whether a catalog name can appear in a procedure + * call + * + * @return true if a catalog name can appear in a procedure + * call, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsCatalogsInProcedureCalls() throws SQLException; + + /** + * This method tests whether a catalog name can appear in a table definition. + * + * @return true if a catalog name can appear in a table + * definition, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsCatalogsInTableDefinitions() throws SQLException; + + /** + * This method tests whether a catalog name can appear in an index definition. + * + * @return true if a catalog name can appear in an index + * definition, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsCatalogsInIndexDefinitions() throws SQLException; + + /** + * This method tests whether a catalog name can appear in privilege definitions. + * + * @return true if a catalog name can appear in privilege + * definition, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException; + + /** + * This method tests whether or not that database supports positioned + * deletes. + * + * @return true if positioned deletes are supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsPositionedDelete() throws SQLException; + + /** + * This method tests whether or not that database supports positioned + * updates. + * + * @return true if positioned updates are supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsPositionedUpdate() throws SQLException; + + /** + * This method tests whether or not SELECT FOR UPDATE is supported by the + * database. + * + * @return true if SELECT FOR UPDATE is supported + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSelectForUpdate() throws SQLException; + + /** + * This method tests whether or not stored procedures are supported on + * this database. + * + * @return true if stored procedures are supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsStoredProcedures() throws SQLException; + + /** + * This method tests whether or not subqueries are allowed in comparisons. + * A fully JDBC compliant driver will always return true. + * + * @return true if subqueries are allowed in comparisons, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSubqueriesInComparisons() throws SQLException; + + /** + * This method tests whether or not subqueries are allowed in exists + * expressions. A fully JDBC compliant driver will always return + * true. + * + * @return true if subqueries are allowed in exists + * expressions, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSubqueriesInExists() throws SQLException; + + /** + * This method tests whether subqueries are allowed in IN statements. + * A fully JDBC compliant driver will always return true. + * + * @return true if the driver supports subqueries in IN + * statements, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSubqueriesInIns() throws SQLException; + + /** + * This method tests whether or not subqueries are allowed in quantified + * expressions. A fully JDBC compliant driver will always return + * true. + * + * @return true if subqueries are allowed in quantified + * expressions, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsSubqueriesInQuantifieds() throws SQLException; + + /** + * This method test whether or not correlated subqueries are allowed. A + * fully JDBC compliant driver will always return true. + * + * @return true if correlated subqueries are allowed, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsCorrelatedSubqueries() throws SQLException; + + /** + * This method tests whether or not the UNION statement is supported. + * + * @return true if UNION is supported, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsUnion() throws SQLException; + + /** + * This method tests whether or not the UNION ALL statement is supported. + * + * @return true if UNION ALL is supported, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsUnionAll() throws SQLException; + + /** + * This method tests whether or not the database supports cursors + * remaining open across commits. + * + * @return true if cursors can remain open across commits, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsOpenCursorsAcrossCommit() throws SQLException; + + /** + * This method tests whether or not the database supports cursors + * remaining open across rollbacks. + * + * @return true if cursors can remain open across rollbacks, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsOpenCursorsAcrossRollback() throws SQLException; + + /** + * This method tests whether or not the database supports statements + * remaining open across commits. + * + * @return true if statements can remain open across commits, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsOpenStatementsAcrossCommit() throws SQLException; + + /** + * This method tests whether or not the database supports statements + * remaining open across rollbacks. + * + * @return true if statements can remain open across rollbacks, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsOpenStatementsAcrossRollback() throws SQLException; + + /** + * This method returns the number of hex characters allowed in an inline + * binary literal. + * + * @return The number of hex characters allowed in a binary literal, 0 meaning + * either an unknown or unlimited number. + * @exception SQLException If an error occurs. + */ + int getMaxBinaryLiteralLength() throws SQLException; + + /** + * This method returns the maximum length of a character literal. + * + * @return The maximum length of a character literal. + * @exception SQLException If an error occurs. + */ + int getMaxCharLiteralLength() throws SQLException; + + /** + * This method returns the maximum length of a column name. + * + * @return The maximum length of a column name. + * @exception SQLException If an error occurs. + */ + int getMaxColumnNameLength() throws SQLException; + + /** + * This method returns the maximum number of columns in a GROUP BY statement. + * + * @return The maximum number of columns in a GROUP BY statement. + * @exception SQLException If an error occurs. + */ + int getMaxColumnsInGroupBy() throws SQLException; + + /** + * This method returns the maximum number of columns in an index. + * + * @return The maximum number of columns in an index. + * @exception SQLException If an error occurs. + */ + int getMaxColumnsInIndex() throws SQLException; + + /** + * This method returns the maximum number of columns in an ORDER BY statement. + * + * @return The maximum number of columns in an ORDER BY statement. + * @exception SQLException If an error occurs. + */ + int getMaxColumnsInOrderBy() throws SQLException; + + /** + * This method returns the maximum number of columns in a SELECT statement. + * + * @return The maximum number of columns in a SELECT statement. + * @exception SQLException If an error occurs. + */ + int getMaxColumnsInSelect() throws SQLException; + + /** + * This method returns the maximum number of columns in a table. + * + * @return The maximum number of columns in a table. + * @exception SQLException If an error occurs. + */ + int getMaxColumnsInTable() throws SQLException; + + /** + * This method returns the maximum number of connections this client + * can have to the database. + * + * @return The maximum number of database connections. + * @SQLException If an error occurs. + */ + int getMaxConnections() throws SQLException; + + /** + * This method returns the maximum length of a cursor name. + * + * @return The maximum length of a cursor name. + * @exception SQLException If an error occurs. + */ + int getMaxCursorNameLength() throws SQLException; + + /** + * This method returns the maximum length of an index. + * + * @return The maximum length of an index. + * @exception SQLException If an error occurs. + */ + int getMaxIndexLength() throws SQLException; + + /** + * This method returns the maximum length of a schema name. + * + * @return The maximum length of a schema name. + * @exception SQLException If an error occurs. + */ + int getMaxSchemaNameLength() throws SQLException; + + /** + * This method returns the maximum length of a procedure name. + * + * @return The maximum length of a procedure name. + * @exception SQLException If an error occurs. + */ + int getMaxProcedureNameLength() throws SQLException; + + /** + * This method returns the maximum length of a catalog name. + * + * @return The maximum length of a catalog name. + * @exception SQLException If an error occurs. + */ + int getMaxCatalogNameLength() throws SQLException; + + /** + * This method returns the maximum size of a row in bytes. + * + * @return The maximum size of a row. + * @exception SQLException If an error occurs. + */ + int getMaxRowSize() throws SQLException; + + /** + * This method tests whether or not the maximum row size includes BLOB's + * + * @return true if the maximum row size includes BLOB's, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean doesMaxRowSizeIncludeBlobs() throws SQLException; + + /** + * This method includes the maximum length of a SQL statement. + * + * @return The maximum length of a SQL statement. + * @exception SQLException If an error occurs. + */ + int getMaxStatementLength() throws SQLException; + + /** + * This method returns the maximum number of statements that can be + * active at any time. + * + * @return The maximum number of statements that can be active at any time. + * @exception SQLException If an error occurs. + */ + int getMaxStatements() throws SQLException; + + /** + * This method returns the maximum length of a table name. + * + * @return The maximum length of a table name. + * @exception SQLException If an error occurs. + */ + int getMaxTableNameLength() throws SQLException; + + /** + * This method returns the maximum number of tables that may be referenced + * in a SELECT statement. + * + * @return The maximum number of tables allowed in a SELECT statement. + * @exception SQLException If an error occurs. + */ + int getMaxTablesInSelect() throws SQLException; + + /** + * This method returns the maximum length of a user name. + * + * @return The maximum length of a user name. + * @exception SQLException If an error occurs. + */ + int getMaxUserNameLength() throws SQLException; + + /** + * This method returns the default transaction isolation level of the + * database. + * + * @return The default transaction isolation level of the database. + * @exception SQLException If an error occurs. + * @see Connection + */ + int getDefaultTransactionIsolation() throws SQLException; + + /** + * This method tests whether or not the database supports transactions. + * + * @return true if the database supports transactions, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsTransactions() throws SQLException; + + /** + * This method tests whether or not the database supports the specified + * transaction isolation level. + * + * @param level The transaction isolation level. + * + * @return true if the specified transaction isolation level + * is supported, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsTransactionIsolationLevel(int level) throws + SQLException; + + /** + * This method tests whether or not DDL and DML statements allowed within + * the same transaction. + * + * @return true if DDL and DML statements are allowed in the + * same transaction, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsDataDefinitionAndDataManipulationTransactions() + throws SQLException; + + /** + * This method tests whether or not only DML statement are allowed + * inside a transaction. + * + * @return true if only DML statements are allowed in + * transactions, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsDataManipulationTransactionsOnly() throws + SQLException; + + /** + * This method tests whether or not a DDL statement will cause the + * current transaction to be automatically committed. + * + * @return true if DDL causes an immediate transaction commit, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean dataDefinitionCausesTransactionCommit() throws SQLException; + + /** + * This method tests whether or not DDL statements are ignored in + * transactions. + * + * @return true if DDL statements are ignored in transactions, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean dataDefinitionIgnoredInTransactions() throws SQLException; + + /** + * This method returns a list of all the stored procedures matching the + * specified pattern in the given schema and catalog. This is returned + * a ResultSet with the following columns: + *

    + *

      + *
    1. PROCEDURE_CAT - The catalog the procedure is in, which may be + * null.
    2. + *
    3. PROCEDURE_SCHEM - The schema the procedures is in, which may be + * null.
    4. + *
    5. PROCEDURE_NAME - The name of the procedure.
    6. + *
    7. Unused
    8. + *
    9. Unused
    10. + *
    11. Unused
    12. + *
    13. REMARKS - A description of the procedure
    14. + *
    15. PROCEDURE_TYPE - Indicates the return type of the procedure, which + * is one of the contstants defined in this class + * (procedureResultUnknown, procedureNoResult, or + * procedureReturnsResult).
    16. + *
    + * + * @param catalog The name of the catalog to return stored procedured from, + * or "" to return procedures from all catalogs. + * @param schemaPattern A schema pattern for the schemas to return stored + * procedures from, or "" to return procedures from all schemas. + * @param namePattern The pattern of procedures names to return. + * @returns A ResultSet with all the requested procedures. + * @exception SQLException If an error occurs. + */ + ResultSet getProcedures(String catalog, String schemaPattern, String + procedureNamePattern) throws SQLException; + + /** + * This method returns a list of the parameter and result columns for + * the requested stored procedures. This is returned in the form of a + * ResultSet with the following columns: + *

    + *

      + *
    1. PROCEDURE_CAT - The catalog the procedure is in, which may be + * null.
    2. + *
    3. PROCEDURE_SCHEM - The schema the procedures is in, which may be + * null.
    4. + *
    5. PROCEDURE_NAME - The name of the procedure.
    6. + *
    7. COLUMN_NAME - The name of the column
    8. + *
    9. COLUMN_TYPE - The type of the column, which will be one of the + * contants defined in this class (procedureColumnUnknown, + * procedureColumnIn, procedureColumnInOut, + * procedureColumnOut, procedureColumnReturn, + * or procedureColumnResult).
    10. + *
    11. DATA_TYPE - The SQL type of the column. This is one of the constants + * defined in Types.
    12. + *
    13. TYPE_NAME - The string name of the data type for this column.
    14. + *
    15. PRECISION - The precision of the column.
    16. + *
    17. LENGTH - The length of the column in bytes
    18. + *
    19. SCALE - The scale of the column.
    20. + *
    21. RADIX - The radix of the column.
    22. + *
    23. NULLABLE - Whether or not the column is NULLABLE. This is one of + * the constants defined in this class (procedureNoNulls, + * procedureNullable, or procedureNullableUnknown)
    24. + *
    25. REMARKS - A description of the column.
    26. + *
    + * + * @param catalog The name of the catalog to return stored procedured from, + * or "" to return procedures from all catalogs. + * @param schemaPattern A schema pattern for the schemas to return stored + * procedures from, or "" to return procedures from all schemas. + * @param namePattern The pattern of procedures names to return. + * @param columnPattern The pattern of column names to return. + * @returns A ResultSet with all the requested procedures. + * @exception SQLException If an error occurs. + */ + ResultSet getProcedureColumns(String catalog, String schemaPattern, + String procedureNamePattern, String columnNamePattern) throws + SQLException; + + /** + * This method returns a list of the requested table as a + * ResultSet with the following columns: + * + *
      + *
    1. TABLE_CAT - The catalog the table is in, which may be null.
    2. + *
    3. TABLE_SCHEM - The schema the table is in, which may be null.
    4. + *
    5. TABLE_NAME - The name of the table.
    6. + *
    7. TABLE_TYPE - A string describing the table type. This will be one + * of the values returned by the getTableTypes() method.
    8. + *
    9. REMARKS - Comments about the table.
    10. + *
    + * + * @param catalog The name of the catalog to return tables from, + * or "" to return tables from all catalogs. + * @param schemaPattern A schema pattern for the schemas to return tables + * from, or "" to return tables from all schemas. + * @param namePattern The pattern of table names to return. + * @param types The list of table types to include; null returns all types. + * @returns A ResultSet with all the requested tables. + * @exception SQLException If an error occurs. + */ + ResultSet getTables(String catalog, String schemaPattern, String + tableNamePattern, String[] types) throws SQLException; + + /** + * This method returns the list of database schemas as a + * ResultSet, with one column - TABLE_SCHEM - that is the + * name of the schema. + * + * @return A ResultSet with all the requested schemas. + * @exception SQLException If an error occurs. + */ + ResultSet getSchemas() throws SQLException; + + /** + * This method returns the list of database catalogs as a + * ResultSet with one column - TABLE_CAT - that is the + * name of the catalog. + * + * @return A ResultSet with all the requested catalogs. + * @exception SQLException If an error occurs. + */ + ResultSet getCatalogs() throws SQLException; + + /** + * This method returns the list of database table types as a + * ResultSet with one column - TABLE_TYPE - that is the + * name of the table type. + * + * @return A ResultSet with all the requested table types. + * @exception SQLException If an error occurs. + */ + ResultSet getTableTypes() throws SQLException; + + /** + * This method returns a list of the tables columns for + * the requested tables. This is returned in the form of a + * ResultSet with the following columns: + *

    + *

      + *
    1. TABLE_CAT - The catalog the table is in, which may be + * null.
    2. + *
    3. TABLE_SCHEM - The schema the tables is in, which may be + * null.
    4. + *
    5. TABLE_NAME - The name of the table.
    6. + *
    7. COLUMN_NAME - The name of the column
    8. + *
    9. DATA_TYPE - The SQL type of the column. This is one of the constants + * defined in Types.
    10. + *
    11. TYPE_NAME - The string name of the data type for this column.
    12. + *
    13. COLUMN_SIZE - The size of the column.
    14. + *
    15. Unused
    16. + *
    17. NUM_PREC_RADIX - The radix of the column.
    18. + *
    19. NULLABLE - Whether or not the column is NULLABLE. This is one of + * the constants defined in this class (tableNoNulls, + * tableNullable, or tableNullableUnknown)
    20. + *
    21. REMARKS - A description of the column.
    22. + *
    23. COLUMN_DEF - The default value for the column, may be null.
    24. + *
    25. SQL_DATA_TYPE - Unused
    26. + *
    27. SQL_DATETIME_SUB - Unused
    28. + *
    29. CHAR_OCTET_LENGTH - For character columns, the maximum number of bytes + * in the column.
    30. + *
    31. ORDINAL_POSITION - The index of the column in the table.
    32. + *
    33. IS_NULLABLE - "NO" means no, "YES" means maybe, and an empty string + * means unknown.
    34. + *
    + * + * @param catalog The name of the catalog to return table from, + * or "" to return tables from all catalogs. + * @param schemaPattern A schema pattern for the schemas to return + * tables from, or "" to return tables from all schemas. + * @param namePattern The pattern of tables names to return. + * @param columnPattern The pattern of column names to return. + * @returns A ResultSet with all the requested tables. + * @exception SQLException If an error occurs. + */ + ResultSet getColumns(String catalog, String schemaPattern, String + tableNamePattern, String columnNamePattern) throws SQLException; + + /** + * This method returns the access rights that have been granted to the + * requested columns. This information is returned as a ResultSet + * with the following columns: + * + *
      + *
    1. TABLE_CAT - The catalog the table is in, which may be + * null.
    2. + *
    3. TABLE_SCHEM - The schema the tables is in, which may be + * null.
    4. + *
    5. TABLE_NAME - The name of the table.
    6. + *
    7. COLUMN_NAME - The name of the column.
    8. + *
    9. GRANTOR - The entity that granted the access.
    10. + *
    11. GRANTEE - The entity granted the access.
    12. + *
    13. PRIVILEGE - The name of the privilege granted.
    14. + *
    15. IS_GRANTABLE - "YES" if the grantee can grant the privilege to + * others, "NO" if not, and null if unknown.
    16. + *
    + * + * @param catalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs. + * @param schema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema. + * @param table The table name to return information for. + * @param columnPattern A pattern of column names to return information for. + * @return A ResultSet with all the requested privileges. + * @exception SQLException If an error occurs. + */ + ResultSet getColumnPrivileges(String catalog, String schema, String + table, String columnNamePattern) throws SQLException; + + /** + * This method returns the access rights that have been granted to the + * requested tables. This information is returned as a ResultSet + * with the following columns: + * + *
      + *
    1. TABLE_CAT - The catalog the table is in, which may be + * null.
    2. + *
    3. TABLE_SCHEM - The schema the tables is in, which may be + * null.
    4. + *
    5. TABLE_NAME - The name of the table.
    6. + *
    7. GRANTOR - The entity that granted the access.
    8. + *
    9. GRANTEE - The entity granted the access.
    10. + *
    11. PRIVILEGE - The name of the privilege granted.
    12. + *
    13. IS_GRANTABLE - "YES" if the grantee can grant the privilege to + * others, "NO" if not, and null if unknown.
    14. + *
    + * + * @param catalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs. + * @param schema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema. + * @param tablePattern The table name pattern of tables to return + * information for. + * @return A ResultSet with all the requested privileges. + * @exception SQLException If an error occurs. + */ + ResultSet getTablePrivileges(String catalog, String schemaPattern, + String tableNamePattern) throws SQLException; + + /** + * This method returns the best set of columns for uniquely identifying + * a row. It returns this information as a ResultSet with + * the following columns: + * + *
      + *
    1. SCOPE - The scope of the results returned. This is one of the + * constants defined in this class (bestRowTemporary, + * bestRowTransaction, or bestRowSession).
    2. + *
    3. COLUMN_NAME - The name of the column.
    4. + *
    5. DATA_TYPE - The SQL type of the column. This is one of the constants + * defined in Types.
    6. + *
    7. TYPE_NAME - The string name of the data type for this column.
    8. + *
    9. COLUMN_SIZE - The precision of the columns
    10. + *
    11. BUFFER_LENGTH - Unused
    12. + *
    13. DECIMAL_DIGITS - The scale of the column.
    14. + *
    15. PSEUDO_COLUMN - Whether or not the best row identifier is a + * pseudo_column. This is one of the constants defined in this class + * (bestRowUnknown, bestRowNotPseudo, or + * bestRowPseudo).
    16. + *
    + * + * @param catalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs. + * @param schema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema. + * @param table The table name to return information for. + * @param columnPattern A pattern of column names to return information for. + * @param scope One of the best row id scope constants from this class. + * @param nullable true to include columns that are nullable, + * false otherwise. + * @return A ResultSet with the best row identifier. + * @exception SQLException If an error occurs. + */ + ResultSet getBestRowIdentifier(String catalog, String schema, + String table, int scope, boolean nullable) throws SQLException; + + /** + * This method returns the set of columns that are automatically updated + * when the row is update. It returns this information as a + * ResultSet with the following columns: + * + *
      + *
    1. SCOPE - Unused
    2. + *
    3. COLUMN_NAME - The name of the column.
    4. + *
    5. DATA_TYPE - The SQL type of the column. This is one of the constants + * defined in Types.
    6. + *
    7. TYPE_NAME - The string name of the data type for this column.
    8. + *
    9. COLUMN_SIZE - The precision of the columns
    10. + *
    11. BUFFER_LENGTH - Unused
    12. + *
    13. DECIMAL_DIGITS - The scale of the column.
    14. + *
    15. PSEUDO_COLUMN - Whether or not the best row identifier is a + * pseudo_column. This is one of the constants defined in this class + * (versionRowUnknown, versionRowNotPseudo, or + * versionRowPseudo).
    16. + *
    + * + * @param catalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs. + * @param schema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema. + * @param table The table name to return information for. + * @param columnPattern A pattern of column names to return information for. + * @return A ResultSet with the version columns. + * @exception SQLException If an error occurs. + */ + ResultSet getVersionColumns(String catalog, String schema, + String table) throws SQLException; + + /** + * This method returns a list of a table's primary key columns. These + * are returned as a ResultSet with the following columns. + * + *
      + *
    1. TABLE_CAT - The catalog of the table, which may be null.
    2. + *
    3. TABLE_SCHEM - The schema of the table, which may be null.
    4. + *
    5. TABLE_NAME - The name of the table.
    6. + *
    7. COLUMN_NAME - The name of the column.
    8. + *
    9. KEY_SEQ - The sequence number of the column within the primary key.
    10. + *
    11. PK_NAME - The name of the primary key, which may be null.
    12. + *
    + * + * @param catalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs. + * @param schema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema. + * @param table The table name to return information for. + * @param columnPattern A pattern of column names to return information for. + * @return A ResultSet with the primary key columns. + * @exception SQLException If an error occurs. + */ + ResultSet getPrimaryKeys(String catalog, String schema, String table) + throws SQLException; + + /** + * This method returns a list of the table's foreign keys. These are + * returned as a ResultSet with the following columns: + * + *
      + *
    1. PKTABLE_CAT - The catalog of the table the key was imported from.
    2. + *
    3. PKTABLE_SCHEM - The schema of the table the key was imported from.
    4. + *
    5. PKTABLE_NAME - The name of the table the key was imported from.
    6. + *
    7. PKCOLUMN_NAME - The name of the column that was imported.
    8. + *
    9. FKTABLE_CAT - The foreign key catalog name.
    10. + *
    11. FKTABLE_SCHEM - The foreign key schema name.
    12. + *
    13. FKTABLE_NAME - The foreign key table name.
    14. + *
    15. FKCOLUMN_NAME - The foreign key column name.
    16. + *
    17. KEY_SEQ - The sequence number of the column within the foreign key.
    18. + *
    19. UPDATE_RULE - How the foreign key behaves when the primary key is + * updated. This is one of the constants defined in this class + * (importedNoAction, importedKeyCascade, + * importedKeySetNull, importedKeySetDefault, or + * importedKeyRestrict).
    20. + *
    21. DELETE_RULE - How the foreign key behaves when the primary key is + * deleted. This is one of the constants defined in this class + * (importedNoAction, importedKeyCascade, + * importedKeySetNull, or importedKeySetDefault)
    22. + *
    23. FK_NAME - The name of the foreign key.
    24. + *
    25. PK_NAME - The name of the primary key.
    26. + *
    27. DEFERRABILITY - The deferrability value. This is one of the + * constants defined in this table (importedKeyInitiallyDeferred, + * importedKeyInitiallyImmediate, or + * importedKeyNotDeferrable).
    28. + *
    + * + * @param catalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs. + * @param schema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema. + * @param table The table name to return information for. + * + * @return A ResultSet with the foreign key columns. + * + * @exception SQLException If an error occurs. + */ + ResultSet getImportedKeys(String catalog, String schema, + String table) throws SQLException; + + /** + * This method returns a list of the table's which use this table's + * primary key as a foreign key. The information is + * returned as a ResultSet with the following columns: + * + *
      + *
    1. PKTABLE_CAT - The catalog of the table the key was imported from.
    2. + *
    3. PKTABLE_SCHEM - The schema of the table the key was imported from.
    4. + *
    5. PKTABLE_NAME - The name of the table the key was imported from.
    6. + *
    7. PKCOLUMN_NAME - The name of the column that was imported.
    8. + *
    9. FKTABLE_CAT - The foreign key catalog name.
    10. + *
    11. FKTABLE_SCHEM - The foreign key schema name.
    12. + *
    13. FKTABLE_NAME - The foreign key table name.
    14. + *
    15. FKCOLUMN_NAME - The foreign key column name.
    16. + *
    17. KEY_SEQ - The sequence number of the column within the foreign key.
    18. + *
    19. UPDATE_RULE - How the foreign key behaves when the primary key is + * updated. This is one of the constants defined in this class + * (importedNoAction, importedKeyCascade, + * importedKeySetNull, importedKeySetDefault, or + * importedKeyRestrict).
    20. + *
    21. DELETE_RULE - How the foreign key behaves when the primary key is + * deleted. This is one of the constants defined in this class + * (importedNoAction, importedKeyCascade, + * importedKeySetNull, or importedKeySetDefault)
    22. + *
    23. FK_NAME - The name of the foreign key.
    24. + *
    25. PK_NAME - The name of the primary key.
    26. + *
    27. DEFERRABILITY - The deferrability value. This is one of the + * constants defined in this table (importedKeyInitiallyDeferred, + * importedKeyInitiallyImmediate, or + * importedKeyNotDeferrable).
    28. + *
    + * + * @param catalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs. + * @param schema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema. + * @param table The table name to return information for. + * @return A ResultSet with the requested information + * @exception SQLException If an error occurs. + */ + ResultSet getExportedKeys(String catalog, String schema, + String table) throws SQLException; + + /** + * This method returns a description of how one table imports another + * table's primary key as a foreign key. The information is + * returned as a ResultSet with the following columns: + * + *
      + *
    1. PKTABLE_CAT - The catalog of the table the key was imported from.
    2. + *
    3. PKTABLE_SCHEM - The schema of the table the key was imported from.
    4. + *
    5. PKTABLE_NAME - The name of the table the key was imported from.
    6. + *
    7. PKCOLUMN_NAME - The name of the column that was imported.
    8. + *
    9. FKTABLE_CAT - The foreign key catalog name.
    10. + *
    11. FKTABLE_SCHEM - The foreign key schema name.
    12. + *
    13. FKTABLE_NAME - The foreign key table name.
    14. + *
    15. FKCOLUMN_NAME - The foreign key column name.
    16. + *
    17. KEY_SEQ - The sequence number of the column within the foreign key.
    18. + *
    19. UPDATE_RULE - How the foreign key behaves when the primary key is + * updated. This is one of the constants defined in this class + * (importedNoAction, importedKeyCascade, + * importedKeySetNull, importedKeySetDefault, or + * importedKeyRestrict).
    20. + *
    21. DELETE_RULE - How the foreign key behaves when the primary key is + * deleted. This is one of the constants defined in this class + * (importedNoAction, importedKeyCascade, + * importedKeySetNull, or importedKeySetDefault)
    22. + *
    23. FK_NAME - The name of the foreign key.
    24. + *
    25. PK_NAME - The name of the primary key.
    26. + *
    27. DEFERRABILITY - The deferrability value. This is one of the + * constants defined in this table (importedKeyInitiallyDeferred, + * importedKeyInitiallyImmediate, or + * importedKeyNotDeferrable).
    28. + *
    + * + * @param primCatalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs, on the exporting side. + * @param primSchema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema, on the exporting side. + * @param primTable The table name to return information for, on the exporting + * side. + * @param forCatalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs, on the importing side. + * @param forSchema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema on the importing side. + * @param forTable The table name to return information for on the importing + * side. + * @return A ResultSet with the requested information + * @exception SQLException If an error occurs. + */ + ResultSet getCrossReference(String primaryCatalog, String + primarySchema, String primaryTable, String foreignCatalog, String + foreignSchema, String foreignTable) throws SQLException; + + /** + * This method returns a list of the SQL types supported by this + * database. The information is returned as a ResultSet + * with the following columns: + * + *
      + *
    1. TYPE_NAME - The name of the data type.
    2. + *
    3. DATA_TYPE - A data type constant from Types for this + * type.
    4. + *
    5. PRECISION - The maximum precision of this type.
    6. + *
    7. LITERAL_PREFIX - Prefix value used to quote a literal, which may be + * null.
    8. + *
    9. LITERAL_SUFFIX - Suffix value used to quote a literal, which may be + * null.
    10. + *
    11. CREATE_PARAMS - The parameters used to create the type, which may be + * null.
    12. + *
    13. NULLABLE - Whether or not this type supports NULL values. This will + * be one of the constants defined in this interface + * (typeNoNulls, typeNullable, or + * typeNullableUnknown).
    14. + *
    15. CASE_SENSITIVE - Whether or not the value is case sensitive.
    16. + *
    17. SEARCHABLE - Whether or not "LIKE" expressions are supported in + * WHERE clauses for this type. This will be one of the constants defined + * in this interface (typePredNone, typePredChar, + * typePredBasic, or typeSearchable).
    18. + *
    19. UNSIGNED_ATTRIBUTE - Is the value of this type unsigned.
    20. + *
    21. FIXED_PREC_SCALE - Whether or not this type can be used for money.
    22. + *
    23. AUTO_INCREMENT - Whether or not this type supports auto-incrementing.
    24. + *
    25. LOCAL_TYPE_NAME - A localized name for this data type.
    26. + *
    27. MINIMUM_SCALE - The minimum scale supported by this type.
    28. + *
    29. MAXIMUM_SCALE - The maximum scale supported by this type.
    30. + *
    31. SQL_DATA_TYPE - Unused.
    32. + *
    33. SQL_DATETIME_SUB - Unused.
    34. + *
    35. NUM_PREC_RADIX - The radix of this data type.
    36. + *
    + * + * @return A ResultSet with the list of available data types. + * @exception SQLException If an error occurs. + */ + ResultSet getTypeInfo() throws SQLException; + + /** + * This method returns information about a tables indices and statistics. + * It is returned as a ResultSet with the following columns: + * + *
      + *
    1. TABLE_CAT - The catalog of the table, which may be null.
    2. + *
    3. TABLE_SCHEM - The schema of the table, which may be null.
    4. + *
    5. TABLE_NAME - The name of the table.
    6. + *
    7. NON_UNIQUE - Are index values non-unique?
    8. + *
    9. INDEX_QUALIFIER The index catalog, which may be null
    10. + *
    11. INDEX_NAME - The name of the index.
    12. + *
    13. TYPE - The type of index, which will be one of the constants defined + * in this interface (tableIndexStatistic, + * tableIndexClustered, tableIndexHashed, or + * tableIndexOther).
    14. + *
    15. ORDINAL_POSITION - The sequence number of this column in the index. + * This will be 0 when the index type is tableIndexStatistic.
    16. + *
    17. COLUMN_NAME - The name of this column in the index.
    18. + *
    19. ASC_OR_DESC - "A" for an ascending sort sequence, "D" for a + * descending sort sequence or null if a sort sequence is not + * supported.
    20. + *
    21. CARDINALITY - The number of unique rows in the index, or the number + * of rows in the table if the index type is tableIndexStatistic.
    22. + *
    23. PAGES - The number of pages used for the index, or the number of pages + * in the table if the index type is tableIndexStatistic.
    24. + *
    25. FILTER_CONDITION - The filter condition for this index, which may be + * null.
    26. + *
    + * + * @param catalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or + * null to return information from all catalogs. + * @param schema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema. + * @param table The table name to return information for. + * @param unique true to return only unique indexes, + * false otherwise. + * @param approx true if data values can be approximations, + * false otherwise. + * @return A ResultSet with the requested index information + * @exception SQLException If an error occurs. + */ + ResultSet getIndexInfo(String catalog, String schema, String table, + boolean unique, boolean approximate) throws SQLException; + + /** + * This method tests whether or not the datbase supports the specified + * result type. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * + * @return true if the result set type is supported, + * false otherwise. + * + * @exception SQLException If an error occurs. + * + * @see ResultSet + */ + boolean supportsResultSetType(int type) throws SQLException; + + /** + * This method tests whether the specified result set type and result set + * concurrency type are supported by the database. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @param concur The desired concurrency type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type is supported, + * false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean supportsResultSetConcurrency(int type, int concurrency) + throws SQLException; + + /** + * This method tests whether or not the specified result set type sees its + * own updates. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type sees its own updates, + * false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean ownUpdatesAreVisible(int type) throws SQLException; + + /** + * This method tests whether or not the specified result set type sees its + * own deletes. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type sees its own deletes, + * false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean ownDeletesAreVisible(int type) throws SQLException; + + /** + * This method tests whether or not the specified result set type sees its + * own inserts. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type sees its own inserts, + * false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean ownInsertsAreVisible(int type) throws SQLException; + + /** + * This method tests whether or not the specified result set type sees + * updates committed by others. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type sees other updates, + * false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean othersUpdatesAreVisible(int type) throws SQLException; + + /** + * This method tests whether or not the specified result set type sees + * deletes committed by others. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type sees other deletes, + * false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean othersDeletesAreVisible(int type) throws SQLException; + + /** + * This method tests whether or not the specified result set type sees + * inserts committed by others. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type sees other inserts, + * false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean othersInsertsAreVisible(int type) throws SQLException; + + /** + * This method tests whether or not the specified result set type can detect + * a visible update by calling the rowUpdated method. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type can detect visible updates + * using rowUpdated, false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean updatesAreDetected(int type) throws SQLException; + + /** + * This method tests whether or not the specified result set type can detect + * a visible delete by calling the rowUpdated method. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type can detect visible deletes + * using rowUpdated, false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean deletesAreDetected(int type) throws SQLException; + + /** + * This method tests whether or not the specified result set type can detect + * a visible insert by calling the rowUpdated method. + * + * @param type The desired result type, which is one of the constants + * defined in ResultSet. + * @return true if the result set type can detect visible inserts + * using rowUpdated, false otherwise. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + boolean insertsAreDetected(int type) throws SQLException; + + /** + * This method tests whether or not the database supports batch updates. + * + * @return true if batch updates are supported, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean supportsBatchUpdates() throws SQLException; + + /** + * This method returns the list of user defined data types in use. These + * are returned as a ResultSet with the following columns: + * + *
      + *
    1. TYPE_CAT - The catalog name, which may be null.
    2. + *
    3. TYPE_SCEHM - The schema name, which may be null.
    4. + *
    5. TYPE_NAME - The user defined data type name.
    6. + *
    7. CLASS_NAME - The Java class name this type maps to.
    8. + *
    9. DATA_TYPE - A type identifier from Types for this type. + * This will be one of JAVA_OBJECT, STRUCT, or + * DISTINCT.
    10. + *
    11. REMARKS - Comments about this data type.
    12. + *
    + * + * @param catalog The catalog to retrieve information from, or the empty string + * to return entities not associated with a catalog, or null + * to return information from all catalogs. + * @param schema The schema to retrieve information from, or the empty string + * to return entities not associated with a schema. + * @param typePattern The type name pattern to match. + * @param types The type identifier patterns (from Types) to + * match. + * @return A ResultSet with the requested type information + * @exception SQLException If an error occurs. + */ + ResultSet getUDTs(String catalog, String schemaPattern, String + typeNamePattern, int[] types) throws SQLException; + + /** + * This method returns the Connection object that was used + * to generate the metadata in this object. + * + * @return The connection for this object. + * @exception SQLException If an error occurs. + */ + Connection getConnection() throws SQLException; + + /** + * @since 1.4 + */ + boolean supportsSavepoints() throws SQLException; + + /** + * @since 1.4 + */ + boolean supportsNamedParameters() throws SQLException; + + /** + * @since 1.4 + */ + boolean supportsMultipleOpenResults() throws SQLException; + + /** + * @since 1.4 + */ + boolean supportsGetGeneratedKeys() throws SQLException; + + /** + * @since 1.4 + */ + ResultSet getSuperTypes(String catalog, String schemaPattern, + String typeNamePattern) throws SQLException; + + /** + * @since 1.4 + */ + ResultSet getSuperTables(String catalog, String schemaPattern, + String tableNamePattern) throws SQLException; + + /** + * @since 1.4 + */ + ResultSet getAttributes(String catalog, String schemaPattern, String + typeNamePattern, String attributeNamePattern) throws SQLException; + + /** + * @since 1.4 + */ + boolean supportsResultSetHoldability(int holdability) + throws SQLException; + + /** + * @since 1.4 + */ + int getResultSetHoldability() throws SQLException; + + /** + * @since 1.4 + */ + int getDatabaseMajorVersion() throws SQLException; + + /** + * @since 1.4 + */ + int getDatabaseMinorVersion() throws SQLException; + + /** + * @since 1.4 + */ + int getJDBCMajorVersion() throws SQLException; + + /** + * @since 1.4 + */ + int getJDBCMinorVersion() throws SQLException; + + /** + * @since 1.4 + */ + int getSQLStateType() throws SQLException; + + /** + * @since 1.4 + */ + boolean locatorsUpdateCopy() throws SQLException; + + /** + * @since 1.4 + */ + boolean supportsStatementPooling() throws SQLException; +} diff --git a/libjava/classpath/java/sql/Date.java b/libjava/classpath/java/sql/Date.java new file mode 100644 index 0000000..48a274f --- /dev/null +++ b/libjava/classpath/java/sql/Date.java @@ -0,0 +1,188 @@ +/* Date.java -- Wrapper around java.util.Date + Copyright (C) 1999, 2000, 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 java.sql; + +import java.text.ParseException; +import java.text.SimpleDateFormat; + +/** + * This class is a wrapper around java.util.Date to allow the JDBC + * driver to identify the value as a SQL Date. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Date extends java.util.Date +{ + static final long serialVersionUID = 1511598038487230103L; + + /** + * Used for parsing and formatting this date. + */ + private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + + /** + * This method initializes a new instance of this class with the + * specified year, month, and day. + * + * @param year The year of this date minue 1900. + * @param month The month of this date (0-11). + * @param day The day of this date (1-31). + * + * @deprecated + */ + public Date(int year, int month, int day) + { + super(year, month, day); + } + + /** + * This method initializes a new instance of this class with the + * specified time value representing the number of seconds since + * Jan 1, 1970 at 12:00 midnight GMT. + * + * @param time The time value to intialize this date to. + */ + public Date(long date) + { + super(date); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public int getHours() throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public int getMinutes() throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public int getSeconds() throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public void setHours(int newValue) throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public void setMinutes(int newValue) throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public void setSeconds(int newValue) throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method returns a new instance of this class by parsing a + * date in JDBC format into a Java date. + * + * @param str The string to parse. + * @return The resulting java.sql.Date value. + * + * @deprecated + */ + public static Date valueOf (String str) + { + try + { + java.util.Date d = (java.util.Date) sdf.parseObject(str); + + if (d == null) + throw new IllegalArgumentException(str); + else + return new Date(d.getTime()); + } + catch (ParseException e) + { + throw new IllegalArgumentException(str); + } + } + + /** + * This method returns this date in JDBC format. + * + * @return This date as a string. + * + * @deprecated + */ + public String toString() + { + return sdf.format(this); + } +} diff --git a/libjava/classpath/java/sql/Driver.java b/libjava/classpath/java/sql/Driver.java new file mode 100644 index 0000000..10f83ef --- /dev/null +++ b/libjava/classpath/java/sql/Driver.java @@ -0,0 +1,123 @@ +/* Driver.java -- A JDBC driver + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.sql; + +import java.util.Properties; + +/** + * This interface specifies a mechanism for accessing a JDBC database + * driver. When the class implementing this method is loaded, it should + * register an instance of itself with the DriverManager in + * a static initializer. + *

    + * Because the DriverManager might attempt to use several + * drivers to find one that can connect to the requested database, + * this driver should not cause large numbers of classes and code to + * be loaded. If another driver is the one that ends up performing the + * request, any loading done by this driver would be wasted. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Driver +{ + /** + * This method connects to the specified database using the connection + * properties supplied. If the driver does not understand the database + * URL, it should return null instead of throwing an + * exception since the DriverManager will probe a driver + * in this manner. + * + * @param url The URL string for this connection. + * @param properties The list of database connection properties. + * @return A Connection object for the newly established + * connection, or null if the URL is not understood. + * @exception SQLException If an error occurs. + */ + Connection connect(String url, Properties info) throws SQLException; + + /** + * This method tests whether or not the driver believes it can connect to + * the specified database. The driver should only test whether it + * understands and accepts the URL. It should not necessarily attempt to + * probe the database for a connection. + * + * @param The database URL string. + * @return true if the drivers can connect to the database, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean acceptsURL(String url) throws SQLException; + + /** + * This method returns an array of possible properties that could be + * used to connect to the specified database. + * + * @param url The URL string of the database to connect to. + * @param properties The list of properties the caller is planning to use + * to connect to the database. + * @return A list of possible additional properties for a connection to this + * database. This list may be empty. + * @exception SQLException If an error occurs. + */ + DriverPropertyInfo[] getPropertyInfo(String url, Properties properties) + throws SQLException; + + /** + * This method returns the major version number of the driver. + * + * @return The major version number of the driver. + */ + int getMajorVersion(); + + /** + * This method returns the minor version number of the driver. + * + * @return The minor version number of the driver. + */ + int getMinorVersion(); + + /** + * This method tests whether or not the driver is JDBC compliant. This + * method should only return true if the driver has been + * certified as JDBC compliant. + * + * @return true if the driver has been certified JDBC compliant, + * false otherwise. + */ + boolean jdbcCompliant(); +} diff --git a/libjava/classpath/java/sql/DriverManager.java b/libjava/classpath/java/sql/DriverManager.java new file mode 100644 index 0000000..9e252ab --- /dev/null +++ b/libjava/classpath/java/sql/DriverManager.java @@ -0,0 +1,346 @@ +/* DriverManager.java -- Manage JDBC drivers + Copyright (C) 1999, 2000, 2001, 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 java.sql; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.Enumeration; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * This class manages the JDBC drivers in the system. It maintains a + * registry of drivers and locates the appropriate driver to handle a + * JDBC database URL. + *

    + * On startup, DriverManager loads all the managers specified + * by the system property jdbc.drivers. The value of this + * property should be a colon separated list of fully qualified driver + * class names. Additional drivers can be loaded at any time by + * simply loading the driver class with class.forName(String). + * The driver should automatically register itself in a static + * initializer. + *

    + * The methods in this class are all static. This class + * cannot be instantiated. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class DriverManager +{ + /** + * This is the log stream for JDBC drivers. + */ + private static PrintStream log_stream; + + /** + * This is the log writer for JDBC drivers. + */ + private static PrintWriter log_writer; + + /** + * This is the login timeout used by JDBC drivers. + */ + private static int login_timeout; + + /** + * This is the list of JDBC drivers that are loaded. + */ + private static Vector drivers; + // Hmm, seems like we might want to do a Hashtable and lookup by something, + // but what would it be? + + // Load all drivers on startup + static + { + drivers = new Vector(); + + String driver_string = System.getProperty("jdbc.drivers"); + if (driver_string != null) + { + StringTokenizer st = new StringTokenizer(driver_string); + while (st.hasMoreTokens()) + { + String driver_classname = st.nextToken(); + + try + { + Class.forName(driver_classname); // The driver registers itself + } + catch (Exception e) + { + // Ignore not founds + } + } + } + + } + + /** Can't be instantiated. */ + private DriverManager() + { + } + + /** + * This method returns the log writer being used by all JDBC drivers. + * This method should be used in place of the deprecated + * getLogStream method. + * + * @return The log writer in use by JDBC drivers. + */ + public static PrintWriter getLogWriter() + { + return log_writer; + } + + /** + * This method sets the log writer being used by JDBC drivers. This is a + * system-wide parameter that affects all drivers. Note that since there + * is no way to retrieve a PrintStream from a + * PrintWriter, this method cannot set the log stream in + * use by JDBC. Thus any older drivers may not see this setting. + * + * @param out The new log writer for JDBC. + */ + public static void setLogWriter(PrintWriter out) + { + DriverManager.log_writer = out; + } + +/** + * This method attempts to return a connection to the specified + * JDBC URL string using the specified connection properties. + * + * @param url The JDBC URL string to connect to. + * @param properties The connection properties. + * + * @return A Connection to that URL. + * + * @exception SQLException If an error occurs. + */ + public static Connection getConnection(String url, Properties properties) + throws SQLException + { + Driver d = getDriver(url); + if (d == null) + throw new SQLException("Driver not found for URL: " + url); + + return d.connect(url, properties); + } + + + /** + * This method attempts to return a connection to the specified + * JDBC URL string using the specified username and password. + * + * @param url The JDBC URL string to connect to. + * @param user The username to connect with. + * @param password The password to connect with. + * @return A Connection to that URL. + * @exception SQLException If an error occurs. + */ + public static Connection getConnection(String url, String user, + String password) throws SQLException + { + Properties p = new Properties(); + + if (user != null) + p.setProperty("user", user); + if (password != null) + p.setProperty("password", password); + + return getConnection(url, p); + } + + /** + * This method attempts to return a connection to the specified + * JDBC URL string. + * + * @param url The JDBC URL string to connect to. + * + * @return A Connection to that URL. + * + * @exception SQLException If an error occurs. + */ + public static Connection getConnection(String url) throws SQLException + { + return getConnection(url, new Properties()); + } + + /** + * This method returns a driver that can connect to the specified + * JDBC URL string. This will be selected from among drivers loaded + * at initialization time and those drivers manually loaded by the + * same class loader as the caller. + * + * @param url The JDBC URL string to find a driver for. + * + * @return A Driver that can connect to the specified + * URL. + * + * @exception SQLException If an error occurs, or no suitable driver can be found. + */ + public static Driver getDriver(String url) throws SQLException + { + // FIXME: Limit driver search to the appropriate subset of loaded drivers. + Enumeration e = drivers.elements(); + while(e.hasMoreElements()) + { + Driver d = (Driver)e.nextElement(); + if (d.acceptsURL(url)) + return d; + } + + throw new SQLException("No driver found for " + url); + } + + /** + * This method registers a new driver with the manager. This is normally + * called by the driver itself in a static initializer. + * + * @param driver The new Driver to add. + * + * @exception SQLException If an error occurs. + */ + public static void registerDriver(Driver driver) throws SQLException + { + if (! drivers.contains(driver)) + drivers.addElement(driver); + } + +/** + * This method de-registers a driver from the manager. + * + * @param driver The Driver to unregister. + * + * @exception SQLException If an error occurs. + */ + public static void deregisterDriver(Driver driver) throws SQLException + { + if (drivers.contains(driver)) + drivers.removeElement(driver); + } + + /** + * This method returns a list of all the currently registered JDBC drivers + * that were loaded by the current ClassLoader. + * + * @return An Enumeration of all currently loaded JDBC drivers. + */ + public static Enumeration getDrivers() + { + Vector v = new Vector(); + Enumeration e = drivers.elements(); + + // Is this right? + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + + while(e.hasMoreElements()) + { + Object obj = e.nextElement(); + + ClassLoader loader = obj.getClass().getClassLoader(); + + if (loader == null) + loader = ClassLoader.getSystemClassLoader(); + if (! loader.equals(cl)) + continue; + + v.addElement(obj); + } + + return v.elements(); + } + + /** + * This method set the login timeout used by JDBC drivers. This is a + * system-wide parameter that applies to all drivers. + * + * @param login_timeout The new login timeout value. + */ + public static void setLoginTimeout(int seconds) + { + DriverManager.login_timeout = login_timeout; + } + + /** + * This method returns the login timeout in use by JDBC drivers systemwide. + * + * @return The login timeout. + */ + public static int getLoginTimeout() + { + return login_timeout; + } + + /** + * This method sets the log stream in use by JDBC. + * + * @param log_stream The log stream in use by JDBC. + * + * @deprecated Use setLogWriter instead. + */ + public static void setLogStream(PrintStream out) + { + DriverManager.log_stream = log_stream; + } + + /** + * This method returns the log stream in use by JDBC. + * + * @return The log stream in use by JDBC. + * + * @deprecated Use getLogWriter() instead. + */ + public static PrintStream getLogStream() + { + return log_stream; + } + + /** + * This method prints the specified line to the log stream. + * + * @param str The string to write to the log stream. + */ + public static void println(String message) + { + if (log_stream != null) // Watch for user not using logging + log_stream.println(message); + } +} diff --git a/libjava/classpath/java/sql/DriverPropertyInfo.java b/libjava/classpath/java/sql/DriverPropertyInfo.java new file mode 100644 index 0000000..34e40fa --- /dev/null +++ b/libjava/classpath/java/sql/DriverPropertyInfo.java @@ -0,0 +1,88 @@ +/* DriverPropertyInfo.java -- Property information about drivers. + Copyright (C) 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 java.sql; + +/** + * This class holds a driver property that can be used for querying or + * setting driver configuration parameters. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class DriverPropertyInfo +{ + /** + * The name of the property. + */ + public String name; + + /** + * A description of the property, possibly null. + */ + public String description; + + /** + * A flag indicating whether or not a value for this property is required + * in order to connect to the database. + */ + public boolean required; + + /** + * This is the value of the property. + */ + public String value; + + /** + * If values are restricted to certain choices, this is the list of valid + * ones. Otherwise it is null. + */ + public String[] choices; + + /** + * This method initializes a new instance of DriverPropertyInfo + * with the specified name and value. All other fields are defaulted. + * + * @param name The name of the property. + * @param value The value to assign to the property. + */ + public DriverPropertyInfo(String name, String value) + { + this.name = name; + this.value = value; + } +} diff --git a/libjava/classpath/java/sql/ParameterMetaData.java b/libjava/classpath/java/sql/ParameterMetaData.java new file mode 100644 index 0000000..b3a75fd --- /dev/null +++ b/libjava/classpath/java/sql/ParameterMetaData.java @@ -0,0 +1,103 @@ +/* ParameterMetaData.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 java.sql; + +/** + * @since 1.4 + */ +public interface ParameterMetaData +{ + int parameterNoNulls = 0; + + int parameterNullable = 1; + + int parameterNullableUnknown = 2; + + int parameterModeUnknown = 0; + + int parameterModeIn = 1; + + int parameterModeInOut = 2; + + int parameterModeOut = 4; + + /** + * @since 1.4 + */ + int getParameterCount() throws SQLException; + + /** + * @since 1.4 + */ + int isNullable(int param) throws SQLException; + + /** + * @since 1.4 + */ + boolean isSigned(int param) throws SQLException; + + /** + * @since 1.4 + */ + int getPrecision(int param) throws SQLException; + + /** + * @since 1.4 + */ + int getScale(int param) throws SQLException; + + /** + * @since 1.4 + */ + int getParameterType(int param) throws SQLException; + + /** + * @since 1.4 + */ + String getParameterTypeName(int param) throws SQLException; + + /** + * @since 1.4 + */ + String getParameterClassName(int param) throws SQLException; + + /** + * @since 1.4 + */ + int getParameterMode(int param) throws SQLException; +} diff --git a/libjava/classpath/java/sql/PreparedStatement.java b/libjava/classpath/java/sql/PreparedStatement.java new file mode 100644 index 0000000..3aedbc5 --- /dev/null +++ b/libjava/classpath/java/sql/PreparedStatement.java @@ -0,0 +1,438 @@ +/* PreparedStatement.java -- Interface for pre-compiled statements. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.sql; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.util.Calendar; + +/** + * This interface provides a mechanism for executing pre-compiled + * statements. This provides greater efficiency when calling the same + * statement multiple times. Parameters are allowed in a statement, + * providings for maximum reusability. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface PreparedStatement extends Statement +{ + /** + * This method executes a prepared SQL query and returns its ResultSet. + * + * @return The ResultSet of the SQL statement. + * @exception SQLException If an error occurs. + */ + ResultSet executeQuery() throws SQLException; + + /** + * This method executes an SQL INSERT, UPDATE or DELETE statement. SQL + * statements that return nothing such as SQL DDL statements can be executed. + * + * @return The result is either the row count for INSERT, UPDATE or DELETE + * statements; or 0 for SQL statements that return nothing. + * @exception SQLException If an error occurs. + */ + int executeUpdate() throws SQLException; + + /** + * This method populates the specified parameter with a SQL NULL value + * for the specified type. + * + * @param index The index of the parameter to set. + * @param type The SQL type identifier of the parameter from Types + * + * @exception SQLException If an error occurs. + */ + void setNull(int parameterIndex, int sqlType) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * boolean value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setBoolean(int parameterIndex, boolean x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * byte value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setByte(int parameterIndex, byte x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * short value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setShort(int parameterIndex, short x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * int value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setInt(int parameterIndex, int x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * long value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setLong(int parameterIndex, long x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * float value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setFloat(int parameterIndex, float x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * double value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setDouble(int parameterIndex, double x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * java.math.BigDecimal value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setBigDecimal(int parameterIndex, BigDecimal x) throws + SQLException; + + /** + * This method sets the specified parameter from the given Java + * String value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setString(int parameterIndex, String x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * byte array value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setBytes(int parameterIndex, byte[] x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * java.sql.Date value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setDate(int parameterIndex, Date x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * java.sql.Time value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setTime(int parameterIndex, Time x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * java.sql.Timestamp value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setTimestamp(int parameterIndex, Timestamp x) + throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * ASCII InputStream value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @param length The number of bytes in the stream. + * @exception SQLException If an error occurs. + */ + void setAsciiStream(int parameterIndex, InputStream x, int length) + throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * Unicode UTF-8 InputStream value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @param length The number of bytes in the stream. + * @exception SQLException If an error occurs. + * @deprecated + */ + void setUnicodeStream(int parameterIndex, InputStream x, int length) + throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * binary InputStream value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @param length The number of bytes in the stream. + * @exception SQLException If an error occurs. + */ + void setBinaryStream(int parameterIndex, InputStream x, int length) + throws SQLException; + + /** + * This method clears all of the input parameter that have been + * set on this statement. + * + * @exception SQLException If an error occurs. + */ + void clearParameters() throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * Object value. The specified SQL object type will be used. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @param type The SQL type to use for the parameter, from Types + * @param scale The scale of the value, for numeric values only. + * @exception SQLException If an error occurs. + * @see Types + */ + void setObject(int parameterIndex, Object x, int targetSqlType, + int scale) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * Object value. The specified SQL object type will be used. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @param type The SQL type to use for the parameter, from Types + * @exception SQLException If an error occurs. + * @see Types + */ + void setObject(int parameterIndex, Object x, int targetSqlType) + throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * Object value. The default object type to SQL type mapping + * will be used. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setObject(int parameterIndex, Object x) throws SQLException; + + /** + * This method executes a prepared SQL query. + * Some prepared statements return multiple results; the execute method + * handles these complex statements as well as the simpler form of + * statements handled by executeQuery and executeUpdate. + * + * @return The result of the SQL statement. + * @exception SQLException If an error occurs. + */ + boolean execute() throws SQLException; + + /** + * This method adds a set of parameters to the batch for JDBC 2.0. + * @exception SQLException If an error occurs. + */ + void addBatch() throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * character Reader value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @param length The number of bytes in the stream. + * @exception SQLException If an error occurs. + */ + void setCharacterStream(int parameterIndex, Reader reader, + int length) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * Ref value. The default object type to SQL type mapping + * will be used. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setRef(int i, Ref x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * Blob value. The default object type to SQL type mapping + * will be used. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setBlob(int i, Blob x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * Clob value. The default object type to SQL type mapping + * will be used. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setClob(int i, Clob x) throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * Array value. The default object type to SQL type mapping + * will be used. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @exception SQLException If an error occurs. + */ + void setArray(int i, Array x) throws SQLException; + + /** + * This method returns meta data for the result set from this statement. + * + * @return Meta data for the result set from this statement. + * @exception SQLException If an error occurs. + */ + ResultSetMetaData getMetaData() throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * java.sql.Date value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @param calendar The Calendar to use for timezone and locale. + * @exception SQLException If an error occurs. + */ + void setDate(int parameterIndex, Date x, Calendar cal) + throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * java.sql.Time value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @param calendar The Calendar to use for timezone and locale. + * @exception SQLException If an error occurs. + */ + void setTime(int parameterIndex, Time x, Calendar cal) + throws SQLException; + + /** + * This method sets the specified parameter from the given Java + * java.sql.Timestamp value. + * + * @param index The index of the parameter value to set. + * @param value The value of the parameter. + * @param calendar The Calendar to use for timezone and locale. + * @exception SQLException If an error occurs. + */ + void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) + throws SQLException; + + /** + * This method populates the specified parameter with a SQL NULL value + * for the specified type. + * + * @param index The index of the parameter to set. + * @param type The SQL type identifier of the parameter from Types + * @param name The name of the data type, for user defined types. + * @exception SQLException If an error occurs. + */ + void setNull(int paramIndex, int sqlType, String typeName) + throws SQLException; + + /** + * @since 1.4 + */ + void setURL(int parameterIndex, URL x) throws SQLException; + + /** + * @since 1.4 + */ + ParameterMetaData getParameterMetaData() throws SQLException; +} diff --git a/libjava/classpath/java/sql/Ref.java b/libjava/classpath/java/sql/Ref.java new file mode 100644 index 0000000..4ebd5e6 --- /dev/null +++ b/libjava/classpath/java/sql/Ref.java @@ -0,0 +1,75 @@ +/* Ref.java -- Reference to a SQL structured type. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.sql; + +import java.util.Map; + +/** + * This interface provides a mechanism for obtaining information about + * a SQL structured type + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.2 + */ +public interface Ref +{ + /** + * This method returns the fully qualified name of the SQL structured + * type of the referenced item. + * + * @return The fully qualified name of the SQL structured type. + * @exception SQLException If an error occurs. + * @since 1.2 + */ + String getBaseTypeName() throws SQLException; + + /** + * @since 1.4 + */ + Object getObject(Map map) throws SQLException; + + /** + * @since 1.4 + */ + Object getObject() throws SQLException; + + /** + * @since 1.4 + */ + void setObject(Object value) throws SQLException; +} diff --git a/libjava/classpath/java/sql/ResultSet.java b/libjava/classpath/java/sql/ResultSet.java new file mode 100644 index 0000000..97f2897 --- /dev/null +++ b/libjava/classpath/java/sql/ResultSet.java @@ -0,0 +1,1530 @@ +/* ResultSet.java -- A SQL statement result set. + Copyright (C) 1999, 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 java.sql; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.util.Calendar; +import java.util.Map; + +/** + * This interface provides access to the data set returned by a SQL + * statement. An instance of this interface is returned by the various + * execution methods in the Statement. + * + *

    This class models a cursor, which can be stepped through one row at a + * time. Methods are provided for accessing columns by column name or by + * index.

    + * + *

    Note that a result set is invalidated if the statement that returned + * it is closed.

    + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface ResultSet +{ + /** + * The rows will be processed in order from first to last. + */ + int FETCH_FORWARD = 1000; + + /** + * The rows will be processed in order from last to first. + */ + int FETCH_REVERSE = 1001; + + /** + * The rows will be processed in an unknown order + */ + int FETCH_UNKNOWN = 1002; + + /** + * This type of result set may only step forward through the rows returned. + */ + int TYPE_FORWARD_ONLY = 1003; + + /** + * This type of result set is scrollable and is not sensitive to changes + * made by other statements. + */ + int TYPE_SCROLL_INSENSITIVE = 1004; + + /** + * This type of result set is scrollable and is also sensitive to changes + * made by other statements. + */ + int TYPE_SCROLL_SENSITIVE = 1005; + + /** + * The concurrency mode of for the result set may not be modified. + */ + int CONCUR_READ_ONLY = 1007; + + /** + * The concurrency mode of for the result set may be modified. + */ + int CONCUR_UPDATABLE = 1008; + + int HOLD_CURSORS_OVER_COMMIT = 1; + + int CLOSE_CURSORS_AT_COMMIT = 2; + + /** + * This method advances to the next row in the result set. Any streams + * open on the current row are closed automatically. + * + * @return true if the next row exists, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean next() throws SQLException; + + /** + * This method closes the result set and frees any associated resources. + * + * @exception SQLException If an error occurs. + */ + void close() throws SQLException; + + /** + * This method tests whether the value of the last column that was fetched + * was actually a SQL NULL value. + * + * @return true if the last column fetched was a NULL, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean wasNull() throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * String. + * + * @param index The index of the column to return. + * @return The column value as a String. + * @exception SQLException If an error occurs. + */ + String getString(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * boolean. + * + * @param index The index of the column to return. + * @return The column value as a boolean. + * @exception SQLException If an error occurs. + */ + boolean getBoolean(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * byte. + * + * @param index The index of the column to return. + * @return The column value as a byte. + * @exception SQLException If an error occurs. + */ + byte getByte(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * short. + * + * @param index The index of the column to return. + * @return The column value as a short. + * @exception SQLException If an error occurs. + */ + short getShort(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * int. + * + * @param index The index of the column to return. + * @return The column value as a int. + * @exception SQLException If an error occurs. + */ + int getInt(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * long. + * + * @param index The index of the column to return. + * @return The column value as a long. + * @exception SQLException If an error occurs. + */ + long getLong(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * float. + * + * @param index The index of the column to return. + * @return The column value as a float. + * @exception SQLException If an error occurs. + */ + float getFloat(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * double. + * + * @param index The index of the column to return. + * @return The column value as a double. + * @exception SQLException If an error occurs. + */ + double getDouble(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * BigDecimal. + * + * @param index The index of the column to return. + * @param scale The number of digits to the right of the decimal to return. + * @return The column value as a BigDecimal. + * @exception SQLException If an error occurs. + * @deprecated + */ + BigDecimal getBigDecimal(int columnIndex, int scale) + throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * byte array. + * + * @param index The index of the column to return. + * @return The column value as a byte array + * @exception SQLException If an error occurs. + */ + byte[] getBytes(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * java.sql.Date. + * + * @param index The index of the column to return. + * @return The column value as a java.sql.Date. + * @exception SQLException If an error occurs. + */ + Date getDate(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * java.sql.Time. + * + * @param index The index of the column to return. + * @return The column value as a java.sql.Time. + * @exception SQLException If an error occurs. + */ + Time getTime(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * java.sql.Timestamp. + * + * @param index The index of the column to return. + * @return The column value as a java.sql.Timestamp. + * @exception SQLException If an error occurs. + */ + Timestamp getTimestamp(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as an ASCII + * stream. Note that all the data from this stream must be read before + * fetching the value of any other column. Please also be aware that + * calling next() or close() on this result set + * will close this stream as well. + * + * @param index The index of the column to return. + * @return The column value as an ASCII InputStream. + * @exception SQLException If an error occurs. + */ + InputStream getAsciiStream(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Unicode UTF-8 + * stream. Note that all the data from this stream must be read before + * fetching the value of any other column. Please also be aware that + * calling next() or close() on this result set + * will close this stream as well. + * + * @param index The index of the column to return. + * @return The column value as a Unicode UTF-8 InputStream. + * @exception SQLException If an error occurs. + * @deprecated Use getCharacterStream instead. + */ + InputStream getUnicodeStream(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a raw byte + * stream. Note that all the data from this stream must be read before + * fetching the value of any other column. Please also be aware that + * calling next() or close() on this result set + * will close this stream as well. + * + * @param index The index of the column to return. + * @return The column value as a raw byte InputStream. + * @exception SQLException If an error occurs. + */ + InputStream getBinaryStream(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * String. + * + * @param column The name of the column to return. + * @return The column value as a String. + * @exception SQLException If an error occurs. + */ + String getString(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * boolean. + * + * @param column The name of the column to return. + * @return The column value as a boolean. + * @exception SQLException If an error occurs. + */ + boolean getBoolean(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * byte. + * + * @param column The name of the column to return. + * @return The column value as a byte. + * @exception SQLException If an error occurs. + */ + byte getByte(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * short. + * + * @param column The name of the column to return. + * @return The column value as a short. + * @exception SQLException If an error occurs. + */ + short getShort(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * int. + * + * @param column The name of the column to return. + * @return The column value as a int. + * @exception SQLException If an error occurs. + */ + int getInt(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * long. + * + * @param column The name of the column to return. + * @return The column value as a long. + * @exception SQLException If an error occurs. + */ + long getLong(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * float. + * + * @param column The name of the column to return. + * @return The column value as a float. + * @exception SQLException If an error occurs. + */ + float getFloat(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * double. + * + * @param column The name of the column to return. + * @return The column value as a double. + * @exception SQLException If an error occurs. + */ + double getDouble(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * BigDecimal. + * + * @param index The index of the column to return. + * @return The column value as a BigDecimal. + * @exception SQLException If an error occurs. + * @deprecated + */ + BigDecimal getBigDecimal(String columnName, int scale) + throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * byte array. + * + * @param column The name of the column to return. + * @return The column value as a byte array + * @exception SQLException If an error occurs. + */ + byte[] getBytes(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * java.sql.Date. + * + * @param column The name of the column to return. + * @return The column value as a java.sql.Date. + * @exception SQLException If an error occurs. + */ + Date getDate(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * java.sql.Time. + * + * @param column The name of the column to return. + * @return The column value as a java.sql.Time. + * @exception SQLException If an error occurs. + */ + Time getTime(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * java.sql.Timestamp. + * + * @param column The name of the column to return. + * @return The column value as a java.sql.Timestamp. + * @exception SQLException If an error occurs. + */ + Timestamp getTimestamp(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as an ASCII + * stream. Note that all the data from this stream must be read before + * fetching the value of any other column. Please also be aware that + * calling next() or close() on this result set + * will close this stream as well. + * + * @param column The name of the column to return. + * @return The column value as an ASCII InputStream. + * @exception SQLException If an error occurs. + */ + InputStream getAsciiStream(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Unicode UTF-8 + * stream. Note that all the data from this stream must be read before + * fetching the value of any other column. Please also be aware that + * calling next() or close() on this result set + * will close this stream as well. + * + * @param column The name of the column to return. + * @return The column value as a Unicode UTF-8 InputStream. + * @exception SQLException If an error occurs. + * @deprecated Use getCharacterStream instead. + */ + InputStream getUnicodeStream(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a raw byte + * stream. Note that all the data from this stream must be read before + * fetching the value of any other column. Please also be aware that + * calling next() or close() on this result set + * will close this stream as well. + * + * @param column The name of the column to return. + * @return The column value as a raw byte InputStream. + * @exception SQLException If an error occurs. + */ + InputStream getBinaryStream(String columnName) throws SQLException; + + /** + * This method returns the first SQL warning associated with this result + * set. Any additional warnings will be chained to this one. + * + * @return The first SQLWarning for this result set, or null if + * there are no warnings. + * @exception SQLException If an error occurs. + */ + SQLWarning getWarnings() throws SQLException; + + /** + * This method clears all warnings associated with this result set. + * + * @exception SQLException If an error occurs. + */ + void clearWarnings() throws SQLException; + + /** + * This method returns the name of the database cursor used by this + * result set. + * + * @return The name of the database cursor used by this result set. + * @exception SQLException If an error occurs. + */ + String getCursorName() throws SQLException; + + /** + * This method returns data about the columns returned as part of the + * result set as a ResultSetMetaData instance. + * + * @return The ResultSetMetaData instance for this result set. + * @exception SQLException If an error occurs. + */ + ResultSetMetaData getMetaData() throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * Object. + * + * @param index The index of the column to return. + * @return The column value as an Object. + * @exception SQLException If an error occurs. + */ + Object getObject(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * Object. + * + * @param column The name of the column to return. + * @return The column value as an Object. + * @exception SQLException If an error occurs. + */ + Object getObject(String columnName) throws SQLException; + + /** + * This method returns the column index of the specified named column. + * + * @param column The name of the column. + * @return The index of the column. + * @exception SQLException If an error occurs. + */ + int findColumn(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a character + * stream. Note that all the data from this stream must be read before + * fetching the value of any other column. Please also be aware that + * calling next() or close() on this result set + * will close this stream as well. + * + * @param index The index of the column to return. + * @return The column value as an character Reader. + * @exception SQLException If an error occurs. + */ + Reader getCharacterStream(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a character + * stream. Note that all the data from this stream must be read before + * fetching the value of any other column. Please also be aware that + * calling next() or close() on this result set + * will close this stream as well. + * + * @param column The name of the column to return. + * @return The column value as an character Reader. + * @exception SQLException If an error occurs. + */ + Reader getCharacterStream(String columnName) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * BigDecimal. + * + * @param index The index of the column to return. + * @return The column value as a BigDecimal. + * @exception SQLException If an error occurs. + */ + BigDecimal getBigDecimal(int columnIndex) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * BigDecimal. + * + * @param column The name of the column to return. + * @return The column value as a BigDecimal. + * @exception SQLException If an error occurs. + */ + BigDecimal getBigDecimal(String columnName) throws SQLException; + + /** + * This method tests whether or not the cursor is before the first row + * in the result set. + * + * @return true if the cursor is positioned before the first + * row, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isBeforeFirst() throws SQLException; + + /** + * This method tests whether or not the cursor is after the last row + * in the result set. + * + * @return true if the cursor is positioned after the last + * row, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isAfterLast() throws SQLException; + + /** + * This method tests whether or not the cursor is positioned on the first + * row in the result set. + * + * @return true if the cursor is positioned on the first + * row, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isFirst() throws SQLException; + + /** + * This method tests whether or not the cursor is on the last row + * in the result set. + * + * @return true if the cursor is positioned on the last + * row, false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isLast() throws SQLException; + + /** + * This method repositions the cursor to before the first row in the + * result set. + * + * @exception SQLException If an error occurs. + */ + void beforeFirst() throws SQLException; + + /** + * This method repositions the cursor to after the last row in the result + * set. + * + * @exception SQLException If an error occurs. + */ + void afterLast() throws SQLException; + + /** + * This method repositions the cursor on the first row in the + * result set. + * + * @return true if the cursor is on a valid row; + * false if there are no rows in the result set. + * @exception SQLException If an error occurs. + */ + boolean first() throws SQLException; + + /** + * This method repositions the cursor on the last row in the result + * set. + * + * @return true if the cursor is on a valid row; + * false if there are no rows in the result set. + * @exception SQLException If an error occurs. + */ + boolean last() throws SQLException; + + /** + * This method returns the current row number in the cursor. Numbering + * begins at index 1. + * + * @return The current row number, or 0 if there is not current row. + * @exception SQLException If an error occurs. + */ + int getRow() throws SQLException; + + /** + * This method positions the result set to the specified absolute row. + * Positive numbers are row offsets from the beginning of the result + * set (numbering starts from row 1) and negative numbers are row offsets + * from the end of the result set (numbering starts from -1). + * + * @param row The row to position the result set to. + * + * @return true if the current position was changed, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean absolute(int row) throws SQLException; + + /** + * This method moves the result set position relative to the current row. + * The offset can be positive or negative. + * + * @param row The relative row position to move to. + * @return true if the current position was changed, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean relative(int rows) throws SQLException; + + /** + * This method moves the current position to the previous row in the + * result set. + * + * @return true if the previous row exists, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean previous() throws SQLException; + + /** + * This method provides a hint to the driver about which direction the + * result set will be processed in. + * + * @param direction The direction in which rows will be processed. (Values?) + * @exception SQLException If an error occurs. + */ + void setFetchDirection(int direction) throws SQLException; + + /** + * This method returns the current fetch direction for this result set. + * + * @return The fetch direction for this result set. + * @exception SQLException If an error occurs. + */ + int getFetchDirection() throws SQLException; + + /** + * This method provides a hint to the driver about how many rows at a + * time it should fetch from the database. + * + * @param rows The number of rows the driver should fetch per call. + * @exception SQLException If an error occurs. + */ + void setFetchSize(int rows) throws SQLException; + + /** + * This method returns the current number of rows that will be fetched + * from the database at a time. + * + * @return The current fetch size for this result set. + * @exception SQLException If an error occurs. + */ + int getFetchSize() throws SQLException; + + /** + * This method returns the result set type of this result set. This will + * be one of the TYPE_* constants defined in this interface. + * + * @return The result set type. + * @exception SQLException If an error occurs. + */ + int getType() throws SQLException; + + /** + * This method returns the concurrency type of this result set. This will + * be one of the CONCUR_* constants defined in this interface. + * + * @return The result set concurrency type. + * @exception SQLException If an error occurs. + */ + int getConcurrency() throws SQLException; + + /** + * This method tests whether or not the current row in the result set + * has been updated. Updates must be visible in order of this method to + * detect the update. + * + * @return true if the row has been updated, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean rowUpdated() throws SQLException; + + /** + * This method tests whether or not the current row in the result set + * has been inserted. Inserts must be visible in order of this method to + * detect the insert. + * + * @return true if the row has been inserted, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean rowInserted() throws SQLException; + + /** + * This method tests whether or not the current row in the result set + * has been deleted. Deletes must be visible in order of this method to + * detect the deletion. + * + * @return true if the row has been deleted, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean rowDeleted() throws SQLException; + + /** + * This method updates the specified column to have a NULL value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @return index The index of the column to update. + * @exception SQLException If an error occurs. + */ + void updateNull(int columnIndex) throws SQLException; + + /** + * This method updates the specified column to have a boolean value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateBoolean(int columnIndex, boolean x) throws SQLException; + + /** + * This method updates the specified column to have a byte value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateByte(int columnIndex, byte x) throws SQLException; + + /** + * This method updates the specified column to have a short value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateShort(int columnIndex, short x) throws SQLException; + + /** + * This method updates the specified column to have an int value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateInt(int columnIndex, int x) throws SQLException; + + /** + * This method updates the specified column to have a long value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateLong(int columnIndex, long x) throws SQLException; + + /** + * This method updates the specified column to have a float value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateFloat(int columnIndex, float x) throws SQLException; + + /** + * This method updates the specified column to have a double value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateDouble(int columnIndex, double x) throws SQLException; + + /** + * This method updates the specified column to have a BigDecimal value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateBigDecimal(int columnIndex, BigDecimal x) + throws SQLException; + + /** + * This method updates the specified column to have a String value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateString(int columnIndex, String x) throws SQLException; + + /** + * This method updates the specified column to have a byte array value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateBytes(int columnIndex, byte[] x) throws SQLException; + + /** + * This method updates the specified column to have a java.sql.Date value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateDate(int columnIndex, Date x) throws SQLException; + + /** + * This method updates the specified column to have a java.sql.Time value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateTime(int columnIndex, Time x) throws SQLException; + + /** + * This method updates the specified column to have a java.sql.Timestamp value. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateTimestamp(int columnIndex, Timestamp x) + throws SQLException; + + /** + * This method updates the specified column from an ASCII text stream. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @param length The length of the stream. + * @exception SQLException If an error occurs. + */ + void updateAsciiStream(int columnIndex, InputStream x, int length) + throws SQLException; + + /** + * This method updates the specified column from a binary stream. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @param length The length of the stream. + * @exception SQLException If an error occurs. + */ + void updateBinaryStream(int columnIndex, InputStream x, int length) + throws SQLException; + + /** + * This method updates the specified column from a character stream. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @param length The length of the stream. + * @exception SQLException If an error occurs. + */ + void updateCharacterStream(int columnIndex, Reader x, int length) + throws SQLException; + + /** + * This method updates the specified column to have an Object value. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * + * @exception SQLException If an error occurs. + */ + void updateObject(int columnIndex, Object x, int scale) + throws SQLException; + + /** + * This method updates the specified column to have an Object value. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param index The index of the column to update. + * @param value The new value of the column. + * @param scale The scale of the object in question, which is used only + * for numeric type objects. + * @exception SQLException If an error occurs. + */ + void updateObject(int columnIndex, Object x) throws SQLException; + + /** + * This method updates the specified column to have a NULL value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @return name The name of the column to update. + * @exception SQLException If an error occurs. + */ + void updateNull(String columnName) throws SQLException; + + /** + * This method updates the specified column to have a boolean value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateBoolean(String columnName, boolean x) throws SQLException; + + /** + * This method updates the specified column to have a byte value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateByte(String columnName, byte x) throws SQLException; + + /** + * This method updates the specified column to have a short value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateShort(String columnName, short x) throws SQLException; + + /** + * This method updates the specified column to have an int value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateInt(String columnName, int x) throws SQLException; + + /** + * This method updates the specified column to have a long value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateLong(String columnName, long x) throws SQLException; + + /** + * This method updates the specified column to have a float value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateFloat(String columnName, float x) throws SQLException; + + /** + * This method updates the specified column to have a double value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateDouble(String columnName, double x) throws SQLException; + + /** + * This method updates the specified column to have a BigDecimal value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateBigDecimal(String columnName, BigDecimal x) + throws SQLException; + + /** + * This method updates the specified column to have a String value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateString(String columnName, String x) throws SQLException; + + /** + * This method updates the specified column to have a byte array value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateBytes(String columnName, byte[] x) throws SQLException; + + /** + * This method updates the specified column to have a java.sql.Date value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateDate(String columnName, Date x) throws SQLException; + + /** + * This method updates the specified column to have a java.sql.Time value. This + * does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateTime(String columnName, Time x) throws SQLException; + + /** + * This method updates the specified column to have a java.sql.Timestamp value. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateTimestamp(String columnName, Timestamp x) + throws SQLException; + + /** + * This method updates the specified column from an ASCII text stream. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @param length The length of the stream. + * @exception SQLException If an error occurs. + */ + void updateAsciiStream(String columnName, InputStream x, int length) + throws SQLException; + + /** + * This method updates the specified column from a binary stream. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @param length The length of the stream. + * @exception SQLException If an error occurs. + */ + void updateBinaryStream(String columnName, InputStream x, int length) + throws SQLException; + + /** + * This method updates the specified column from a character stream. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @param length The length of the stream. + * + * @exception SQLException If an error occurs. + */ + void updateCharacterStream(String columnName, Reader reader, + int length) throws SQLException; + + /** + * This method updates the specified column to have an Object value. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @exception SQLException If an error occurs. + */ + void updateObject(String columnName, Object x, int scale) + throws SQLException; + + /** + * This method updates the specified column to have an Object value. + * This does not update the actual database. updateRow must be + * called in order to do that. + * + * @param name The name of the column to update. + * @param value The new value of the column. + * @param scale The scale of the object in question, which is used only + * for numeric type objects. + * @exception SQLException If an error occurs. + */ + void updateObject(String columnName, Object x) throws SQLException; + + /** + * This method inserts the current row into the database. The result set + * must be positioned on the insert row in order to call this method + * successfully. + * + * @exception SQLException If an error occurs. + */ + void insertRow() throws SQLException; + + /** + * This method updates the current row in the database. + * + * @exception SQLException If an error occurs. + */ + void updateRow() throws SQLException; + + /** + * This method deletes the current row in the database. + * + * @exception SQLException If an error occurs. + */ + void deleteRow() throws SQLException; + + /** + * This method refreshes the contents of the current row from the database. + * + * @exception SQLException If an error occurs. + */ + void refreshRow() throws SQLException; + + /** + * This method cancels any changes that have been made to a row. If + * the rowUpdate method has been called, then the changes + * cannot be undone. + * + * @exception SQLException If an error occurs. + */ + void cancelRowUpdates() throws SQLException; + + /** + * This method positions the result set to the "insert row", which allows + * a new row to be inserted into the database from the result set. + * + * @exception SQLException If an error occurs. + */ + void moveToInsertRow() throws SQLException; + + /** + * This method moves the result set position from the insert row back to + * the current row that was selected prior to moving to the insert row. + * + * @exception SQLException If an error occurs. + */ + void moveToCurrentRow() throws SQLException; + + /** + * This method returns a the Statement that was used to + * produce this result set. + * + * @return The Statement used to produce this result set. + * + * @exception SQLException If an error occurs. + */ + Statement getStatement() throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * Object using the specified SQL type to Java type map. + * + * @param index The index of the column to return. + * @param map The SQL type to Java type map to use. + * @return The value of the column as an Object. + * @exception SQLException If an error occurs. + */ + Object getObject(int i, Map map) throws SQLException; + + /** + * This method returns a Ref for the specified column which + * represents the structured type for the column. + * + * @param index The index of the column to return. + * @return A Ref object for the column + * @exception SQLException If an error occurs. + */ + Ref getRef(int i) throws SQLException; + + /** + * This method returns the specified column value as a BLOB. + * + * @param index The index of the column value to return. + * @return The value of the column as a BLOB. + * @exception SQLException If an error occurs. + */ + Blob getBlob(int i) throws SQLException; + + /** + * This method returns the specified column value as a CLOB. + * + * @param index The index of the column value to return. + * @return The value of the column as a CLOB. + * @exception SQLException If an error occurs. + */ + Clob getClob(int i) throws SQLException; + + /** + * This method returns the specified column value as an Array. + * + * @param index The index of the column value to return. + * @return The value of the column as an Array. + * @exception SQLException If an error occurs. + */ + Array getArray(int i) throws SQLException; + + /** + * This method returns the value of the specified column as a Java + * Object using the specified SQL type to Java type map. + * + * @param name The name of the column to return. + * @param map The SQL type to Java type map to use. + * @return The value of the column as an Object. + * @exception SQLException If an error occurs. + */ + Object getObject(String colName, Map map) throws SQLException; + + /** + * This method returns a Ref for the specified column which + * represents the structured type for the column. + * + * @param index The index of the column to return. + * @return A Ref object for the column + * @exception SQLException If an error occurs. + */ + Ref getRef(String colName) throws SQLException; + + /** + * This method returns the specified column value as a BLOB. + * + * @param name The name of the column value to return. + * @return The value of the column as a BLOB. + * @exception SQLException If an error occurs. + */ + Blob getBlob(String colName) throws SQLException; + + /** + * This method returns the specified column value as a CLOB. + * + * @param name The name of the column value to return. + * @return The value of the column as a CLOB. + * @exception SQLException If an error occurs. + */ + Clob getClob(String colName) throws SQLException; + + /** + * This method returns the specified column value as an Array. + * + * @param name The name of the column value to return. + * @return The value of the column as an Array. + * @exception SQLException If an error occurs. + */ + Array getArray(String colName) throws SQLException; + + /** + * This method returns the specified column value as a + * java.sql.Date. The specified Calendar is used + * to generate a value for the date if the database does not support + * timezones. + * + * @param index The index of the column value to return. + * @param cal The Calendar to use for calculating timezones. + * @return The value of the column as a java.sql.Date. + * @exception SQLException If an error occurs. + */ + Date getDate(int columnIndex, Calendar cal) throws SQLException; + + /** + * This method returns the specified column value as a + * java.sql.Date. The specified Calendar is used + * to generate a value for the date if the database does not support + * timezones. + * + * @param name The name of the column value to return. + * @param cal The Calendar to use for calculating timezones. + * @return The value of the column as a java.sql.Date. + * @exception SQLException If an error occurs. + */ + Date getDate(String columnName, Calendar cal) throws SQLException; + + /** + * This method returns the specified column value as a + * java.sql.Time. The specified Calendar is used + * to generate a value for the time if the database does not support + * timezones. + * + * @param index The index of the column value to return. + * @param cal The Calendar to use for calculating timezones. + * @return The value of the column as a java.sql.Time. + * @exception SQLException If an error occurs. + */ + Time getTime(int columnIndex, Calendar cal) throws SQLException; + + /** + * This method returns the specified column value as a + * java.sql.Time. The specified Calendar is used + * to generate a value for the time if the database does not support + * timezones. + * + * @param name The name of the column value to return. + * @param cal The Calendar to use for calculating timezones. + * @return The value of the column as a java.sql.Time. + * @exception SQLException If an error occurs. + */ + Time getTime(String columnName, Calendar cal) throws SQLException; + + /** + * This method returns the specified column value as a + * java.sql.Timestamp. The specified Calendar is used + * to generate a value for the timestamp if the database does not support + * timezones. + * + * @param index The index of the column value to return. + * @param cal The Calendar to use for calculating timezones. + * @return The value of the column as a java.sql.Timestamp. + * @exception SQLException If an error occurs. + */ + Timestamp getTimestamp(int columnIndex, Calendar cal) + throws SQLException; + + /** + * This method returns the specified column value as a + * java.sql.Timestamp. The specified Calendar is used + * to generate a value for the timestamp if the database does not support + * timezones. + * + * @param name The name of the column value to return. + * @param cal The Calendar to use for calculating timezones. + * + * @return The value of the column as a java.sql.Timestamp. + * + * @exception SQLException If an error occurs. + */ + Timestamp getTimestamp(String columnName, Calendar cal) + throws SQLException; + + /** + * @since 1.4 + */ + URL getURL(int columnIndex) throws SQLException; + + /** + * @since 1.4 + */ + URL getURL(String columnName) throws SQLException; + + /** + * @since 1.4 + */ + void updateRef(int columnIndex, Ref x) throws SQLException; + + /** + * @since 1.4 + */ + void updateRef(String columnName, Ref x) throws SQLException; + + /** + * @since 1.4 + */ + void updateBlob(int columnIndex, Blob x) throws SQLException; + + /** + * @since 1.4 + */ + void updateBlob(String columnName, Blob x) throws SQLException; + + /** + * @since 1.4 + */ + void updateClob(int columnIndex, Clob x) throws SQLException; + + /** + * @since 1.4 + */ + void updateClob(String columnName, Clob x) throws SQLException; + + /** + * @since 1.4 + */ + void updateArray(int columnIndex, Array x) throws SQLException; + + /** + * @since 1.4 + */ + void updateArray(String columnName, Array x) throws SQLException; +} diff --git a/libjava/classpath/java/sql/ResultSetMetaData.java b/libjava/classpath/java/sql/ResultSetMetaData.java new file mode 100644 index 0000000..0086677 --- /dev/null +++ b/libjava/classpath/java/sql/ResultSetMetaData.java @@ -0,0 +1,281 @@ +/* ResultSetMetaData.java -- Returns information about the ResultSet + Copyright (C) 1999, 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 java.sql; + +/** + * This interface provides a mechanism for obtaining information about + * the columns that are present in a ResultSet. + *

    + * Note that in this class column indexes start at 1, not 0. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface ResultSetMetaData +{ + /** + * The column does not allow NULL's. + */ + int columnNoNulls = 0; + + /** + * The column allows NULL's. + */ + int columnNullable = 1; + + /** + * It is unknown whether or not the column allows NULL's. + */ + int columnNullableUnknown = 2; + + /** + * This method returns the number of columns in the result set. + * + * @return The number of columns in the result set. + * @exception SQLException If an error occurs. + */ + int getColumnCount() throws SQLException; + + /** + * This method test whether or not the column is an auto-increment column. + * Auto-increment columns are read-only. + * + * @param index The index of the column to test. + * @return true if the column is auto-increment, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean isAutoIncrement(int column) throws SQLException; + + /** + * This method tests whether or not a column is case sensitive in its values. + * + * @param index The index of the column to test. + * @return true if the column value is case sensitive, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isCaseSensitive(int column) throws SQLException; + + /** + * This method tests whether not the specified column can be used in + * a WHERE clause. + * + * @param index The index of the column to test. + * @return true if the column may be used in a WHERE clause, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isSearchable(int column) throws SQLException; + + /** + * This method tests whether or not the column stores a monetary value. + * + * @param index The index of the column to test. + * @return true if the column contains a monetary value, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isCurrency(int column) throws SQLException; + + /** + * This method returns a value indicating whether or not the specified + * column may contain a NULL value. + * + * @param index The index of the column to test. + * @return A constant indicating whether or not the column can contain NULL, + * which will be one of columnNoNulls, + * columnNullable, or columnNullableUnknown. + * @exception SQLException If an error occurs. + */ + int isNullable(int column) throws SQLException; + + /** + * This method tests whether or not the value of the specified column + * is signed or unsigned. + * + * @param index The index of the column to test. + * @return true if the column value is signed, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean isSigned(int column) throws SQLException; + + /** + * This method returns the maximum number of characters that can be used + * to display a value in this column. + * + * @param index The index of the column to check. + * @return The maximum number of characters that can be used to display a + * value for this column. + * @exception SQLException If an error occurs. + */ + int getColumnDisplaySize(int column) throws SQLException; + + /** + * This method returns a string that should be used as a caption for this + * column for user display purposes. + * + * @param index The index of the column to check. + * @return A display string for the column. + * @exception SQLException If an error occurs. + */ + String getColumnLabel(int column) throws SQLException; + + /** + * This method returns the name of the specified column. + * + * @param index The index of the column to return the name of. + * @return The name of the column. + * @exception SQLException If an error occurs. + */ + String getColumnName(int column) throws SQLException; + + /** + * This method returns the name of the schema that contains the specified + * column. + * + * @param index The index of the column to check the schema name for. + * @return The name of the schema that contains the column. + * @exception SQLException If an error occurs. + */ + String getSchemaName(int column) throws SQLException; + + /** + * This method returns the precision of the specified column, which is the + * number of decimal digits it contains. + * + * @param index The index of the column to check the precision on. + * @return The precision of the specified column. + * @exception SQLException If an error occurs. + */ + int getPrecision(int column) throws SQLException; + + /** + * This method returns the scale of the specified column, which is the + * number of digits to the right of the decimal point. + * + * @param index The index column to check the scale of. + * @return The scale of the column. + * @exception SQLException If an error occurs. + */ + int getScale(int column) throws SQLException; + + /** + * This method returns the name of the table containing the specified + * column. + * + * @param index The index of the column to check the table name for. + * @return The name of the table containing the column. + * @exception SQLException If an error occurs. + */ + String getTableName(int column) throws SQLException; + + /** + * This method returns the name of the catalog containing the specified + * column. + * + * @param index The index of the column to check the catalog name for. + * @return The name of the catalog containing the column. + * @exception SQLException If an error occurs. + */ + String getCatalogName(int column) throws SQLException; + + /** + * This method returns the SQL type of the specified column. This will + * be one of the constants from Types. + * + * @param index The index of the column to check the SQL type of. + * @return The SQL type for this column. + * @exception SQLException If an error occurs. + * @see Types + */ + int getColumnType(int column) throws SQLException; + + /** + * This method returns the name of the SQL type for this column. + * + * @param index The index of the column to check the SQL type name for. + * @return The name of the SQL type for this column. + * @exception SQLException If an error occurs. + */ + String getColumnTypeName(int column) throws SQLException; + + /** + * This method tests whether or not the specified column is read only. + * + * @param index The index of the column to check. + * @return true if the column is read only, false + * otherwise. + * @exception SQLException If an error occurs. + */ + boolean isReadOnly(int column) throws SQLException; + + /** + * This method tests whether or not the column may be writable. This + * does not guarantee that a write will be successful. + * + * @param index The index of the column to check for writability. + * @return true if the column may be writable, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isWritable(int column) throws SQLException; + + /** + * This method tests whether or not the column is writable. This + * does guarantee that a write will be successful. + * + * @param index The index of the column to check for writability. + * @return true if the column is writable, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean isDefinitelyWritable(int column) throws SQLException; + + /** + * This method returns the name of the Java class which will be used to + * create objects representing the data in this column. + * + * @param index The index of the column to check. + * @return The name of the Java class that will be used for values in + * this column. + * @exception SQLException If an error occurs. + */ + String getColumnClassName(int column) throws SQLException; +} diff --git a/libjava/classpath/java/sql/SQLData.java b/libjava/classpath/java/sql/SQLData.java new file mode 100644 index 0000000..2ba1fb1 --- /dev/null +++ b/libjava/classpath/java/sql/SQLData.java @@ -0,0 +1,72 @@ +/* SQLData.java -- Custom mapping for a user defined datatype + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.sql; + +/** + * This interface is used for mapping SQL data to user defined datatypes. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface SQLData +{ + /** + * This method returns the user defined datatype name for this object. + * + * @return The user defined data type name for this object. + * @exception SQLException If an error occurs. + */ + String getSQLTypeName() throws SQLException; + + /** + * This method populates the data in the object from the specified stream. + * + * @param stream The stream to read the data from. + * @param name The data type name of the data on the stream. + * @exception SQLException If an error occurs. + */ + void readSQL(SQLInput stream, String typeName) throws SQLException; + + /** + * This method writes the data in this object to the specified stream. + * + * @param stream The stream to write the data to. + * @exception SQLException If an error occurs. + */ + void writeSQL(SQLOutput stream) throws SQLException; +} diff --git a/libjava/classpath/java/sql/SQLException.java b/libjava/classpath/java/sql/SQLException.java new file mode 100644 index 0000000..8c502f2 --- /dev/null +++ b/libjava/classpath/java/sql/SQLException.java @@ -0,0 +1,167 @@ +/* SQLException.java -- General SQL exception + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.sql; + +/** + * This exception is thrown when a database error occurs. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class SQLException extends Exception +{ + static final long serialVersionUID = 2135244094396331484L; + + /** + * This is the next exception in the chain + */ + private SQLException next; + + /** + * This is the state of the SQL statement at the time of the error. + */ + private String SQLState; + + /** + * The vendor error code for this error + */ + private int vendorCode; + + /** + * This method initializes a nwe instance of SQLException + * with the specified descriptive error message, SQL state string, and + * vendor code. + * + * @param message A string describing the nature of the error. + * @param SQLState A string containing the SQL state of the error. + * @param vendorCode The vendor error code associated with this error. + */ + public SQLException(String message, String SQLState, int vendorCode) + { + super(message); + this.SQLState = SQLState; + this.vendorCode = vendorCode; + } + + /** + * This method initializes a new instance of SQLException + * with the specified descriptive error message and SQL state string. + * The vendor error code of this instance will be 0. + * + * @param message A string describing the nature of the error. + * @param SQLState A string containing the SQL state of the error. + */ + public SQLException(String message, String SQLState) + { + this(message, SQLState, 0); + } + + /** + * This method initializes a new instance of SQLException + * with the specified descriptive error message. The SQL state of this + * instance will be null and the vendor error code will be 0. + * + * @param message A string describing the nature of the error. + */ + public SQLException(String message) + { + this(message, null, 0); + } + + /** + * This method initializes a new instance of SQLException + * that does not have a descriptive messages and SQL state, and which + * has a vendor error code of 0. + */ + public SQLException() + { + this(null, null, 0); + } + + /** + * This method returns the SQLState information associated with this + * error. The value returned is a String which is formatted + * using the XOPEN SQL state conventions. + * + * @return The SQL state, which may be null. + */ + public String getSQLState() + { + return SQLState; + } + + /** + * This method returns the vendor specific error code associated with + * this error. + * + * @return The vendor specific error code associated with this error. + */ + public int getErrorCode() + { + return vendorCode; + } + + /** + * This method returns the exception that is chained to this object. + * + * @return The exception chained to this object, which may be + * null. + */ + public SQLException getNextException() + { + return next; + } + + /** + * This method adds a new exception to the end of the chain of exceptions + * that are chained to this object. + * + * @param e The exception to add to the end of the chain. + */ + public void setNextException(SQLException e) + { + if (e == null) + return; + + SQLException list_entry = this; + while (list_entry.getNextException() != null) + list_entry = list_entry.getNextException(); + + list_entry.next = e; + } +} diff --git a/libjava/classpath/java/sql/SQLInput.java b/libjava/classpath/java/sql/SQLInput.java new file mode 100644 index 0000000..730627d --- /dev/null +++ b/libjava/classpath/java/sql/SQLInput.java @@ -0,0 +1,259 @@ +/* SQLInput.java -- Read SQL values from a stream + Copyright (C) 1999, 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 java.sql; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; + +/** + * This interface provides methods for reading values from a stream + * that is connected to a SQL structured or distinct type. It is used + * for custom mapping of user defined data types. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface SQLInput +{ + /** + * This method reads the next item from the stream a Java + * String. + * + * @return The value read from the stream as a String. + * @exception SQLException If an error occurs. + */ + String readString() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * boolean. + * + * @return The value read from the stream as a boolean. + * @exception SQLException If an error occurs. + */ + boolean readBoolean() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * byte. + * + * @return The value read from the stream as a byte. + * @exception SQLException If an error occurs. + */ + byte readByte() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * short. + * + * @return The value read from the stream as a short. + * @exception SQLException If an error occurs. + */ + short readShort() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * int. + * + * @return The value read from the stream as an int. + * @exception SQLException If an error occurs. + */ + int readInt() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * long. + * + * @return The value read from the stream as a long. + * @exception SQLException If an error occurs. + */ + long readLong() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * float. + * + * @return The value read from the stream as a float. + * @exception SQLException If an error occurs. + */ + float readFloat() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * double. + * + * @return The value read from the stream as a double. + * @exception SQLException If an error occurs. + */ + double readDouble() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * BigDecimal. + * + * @return The value read from the stream as a BigDecimal. + * @exception SQLException If an error occurs. + */ + BigDecimal readBigDecimal() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * byte array + * + * @return The value read from the stream as a byte array. + * @exception SQLException If an error occurs. + */ + byte[] readBytes() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * java.sql.Date. + * + * @return The value read from the stream as a java.sql.Date. + * @exception SQLException If an error occurs. + */ + Date readDate() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * java.sql.Time. + * + * @return The value read from the stream as a java.sql.Time. + * @exception SQLException If an error occurs. + */ + Time readTime() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * java.sql.Timestamp. + * + * @return The value read from the stream as a java.sql.Timestamp. + * @exception SQLException If an error occurs. + */ + Timestamp readTimestamp() throws SQLException; + + /** + * This method reads the next item from the stream a character + * Reader. + * + * @return The value read from the stream as a Reader. + * @exception SQLException If an error occurs. + */ + Reader readCharacterStream() throws SQLException; + + /** + * This method reads the next item from the stream a ASCII text + * InputStream. + * + * @return The value read from the stream as an InputStream. + * @exception SQLException If an error occurs. + */ + InputStream readAsciiStream() throws SQLException; + + /** + * This method reads the next item from the stream a binary + * InputStream. + * + * @return The value read from the stream as an InputStream. + * @exception SQLException If an error occurs. + */ + InputStream readBinaryStream() throws SQLException; + + /** + * This method reads the next item from the stream a Java + * Object. + * + * @return The value read from the stream as an Object. + * @exception SQLException If an error occurs. + */ + Object readObject() throws SQLException; + + /** + * This method reads the next item from the stream a Java SQL + * Ref. + * + * @return The value read from the stream as an Ref. + * @exception SQLException If an error occurs. + */ + Ref readRef() throws SQLException; + + /** + * This method reads the next item from the stream a Java SQL + * Blob. + * + * @return The value read from the stream as a Blob. + * @exception SQLException If an error occurs. + */ + Blob readBlob() throws SQLException; + + /** + * This method reads the next item from the stream a Java SQL + * Clob. + * + * @return The value read from the stream as a Clob. + * @exception SQLException If an error occurs. + */ + Clob readClob() throws SQLException; + + /** + * This method reads the next item from the stream a Java SQL + * Array. + * + * @return The value read from the stream as an Array. + * @exception SQLException If an error occurs. + */ + Array readArray() throws SQLException; + + /** + * This method tests whether or not the last value read was a SQL + * NULL value. + * + * @return true if the last value read was a NULL, + * false otherwise. + * @exception SQLException If an error occurs. + */ + boolean wasNull() throws SQLException; + + /** + * @since 1.4 + */ + URL readURL() throws SQLException; +} + diff --git a/libjava/classpath/java/sql/SQLOutput.java b/libjava/classpath/java/sql/SQLOutput.java new file mode 100644 index 0000000..8e6c88f --- /dev/null +++ b/libjava/classpath/java/sql/SQLOutput.java @@ -0,0 +1,257 @@ +/* SQLOutput.java -- Write SQL values to a stream + Copyright (C) 1999, 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 java.sql; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; + +/** + * This interface provides methods for writing Java types to a SQL stream. + * It is used for implemented custom type mappings for user defined data + * types. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface SQLOutput +{ + /** + * This method writes the specified Java String + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeString(String x) throws SQLException; + + /** + * This method writes the specified Java boolean + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeBoolean(boolean x) throws SQLException; + + /** + * This method writes the specified Java byte + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeByte(byte x) throws SQLException; + + /** + * This method writes the specified Java short + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeShort(short x) throws SQLException; + + /** + * This method writes the specified Java int + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeInt(int x) throws SQLException; + + /** + * This method writes the specified Java long + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeLong(long x) throws SQLException; + + /** + * This method writes the specified Java float + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeFloat(float x) throws SQLException; + + /** + * This method writes the specified Java double + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeDouble(double x) throws SQLException; + + /** + * This method writes the specified Java BigDecimal + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeBigDecimal(BigDecimal x) throws SQLException; + + /** + * This method writes the specified Java byte array + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeBytes(byte[] x) throws SQLException; + + /** + * This method writes the specified Java java.sql.Date + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeDate(Date x) throws SQLException; + + /** + * This method writes the specified Java java.sql.Time + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeTime(Time x) throws SQLException; + + /** + * This method writes the specified Java java.sql.Timestamp + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeTimestamp(Timestamp x) throws SQLException; + + /** + * This method writes the specified Java character stream + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeCharacterStream(Reader x) throws SQLException; + + /** + * This method writes the specified ASCII text stream + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeAsciiStream(InputStream x) throws SQLException; + + /** + * This method writes the specified uninterpreted binary byte stream + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeBinaryStream(InputStream x) throws SQLException; + + /** + * This method writes the specified Java SQLData object + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeObject(SQLData x) throws SQLException; + + /** + * This method writes the specified Java SQL Ref object + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeRef(Ref x) throws SQLException; + + /** + * This method writes the specified Java SQL Blob object + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeBlob(Blob x) throws SQLException; + + /** + * This method writes the specified Java SQL Clob object + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeClob(Clob x) throws SQLException; + + /** + * This method writes the specified Java SQL Struct object + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeStruct(Struct x) throws SQLException; + + /** + * This method writes the specified Java SQL Array object + * to the SQL stream. + * + * @param value The value to write to the stream. + * @exception SQLException If an error occurs. + */ + void writeArray(Array x) throws SQLException; + + /** + * @since 1.4 + */ + void writeURL(URL x) throws SQLException; +} diff --git a/libjava/classpath/java/sql/SQLPermission.java b/libjava/classpath/java/sql/SQLPermission.java new file mode 100644 index 0000000..101fa01 --- /dev/null +++ b/libjava/classpath/java/sql/SQLPermission.java @@ -0,0 +1,57 @@ +/* SQLPermission.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 java.sql; + +import java.security.BasicPermission; + +/** + * @since 1.3 + */ +public final class SQLPermission extends BasicPermission +{ + public SQLPermission(String name) + { + super(name); + } + + public SQLPermission(String name, String actions) + { + super(name, actions); + } +} diff --git a/libjava/classpath/java/sql/SQLWarning.java b/libjava/classpath/java/sql/SQLWarning.java new file mode 100644 index 0000000..841d137 --- /dev/null +++ b/libjava/classpath/java/sql/SQLWarning.java @@ -0,0 +1,120 @@ +/* SQLWarning.java -- Database access warnings. + Copyright (C) 1999, 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 java.sql; + +/** + * This exception is thrown when a database warning occurs. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class SQLWarning extends SQLException +{ + static final long serialVersionUID = 3917336774604784856L; + + /** + * This method initializes a nwe instance of SQLWarning + * with the specified descriptive error message, SQL state string, and + * vendor code. + * + * @param message A string describing the nature of the error. + * @param SQLState A string containing the SQL state of the error. + * @param vendorCode The vendor error code associated with this error. + */ + public SQLWarning(String reason, String SQLState, int vendorCode) + { + super(reason, SQLState, vendorCode); + } + + /** + * This method initializes a new instance of SQLWarning + * with the specified descriptive error message and SQL state string. + * The vendor error code of this instance will be 0. + * + * @param message A string describing the nature of the error. + * @param SQLState A string containing the SQL state of the error. + */ + public SQLWarning(String message, String SQLState) + { + super(message, SQLState); + } + + /** + * This method initializes a new instance of SQLWarning + * with the specified descriptive error message. The SQL state of this + * instance will be null and the vendor error code will be 0. + * + * @param message A string describing the nature of the error. + */ + public SQLWarning(String message) + { + super(message); + } + + /** + * This method initializes a new instance of SQLWarning + * that does not have a descriptive messages and SQL state, and which + * has a vendor error code of 0. + */ + public SQLWarning() + { + super(); + } + + /** + * This method returns the exception that is chained to this object. + * + * @return The exception chained to this object, which may be + * null. + */ + public SQLWarning getNextWarning() + { + return (SQLWarning) super.getNextException(); + } + + /** + * This method adds a new exception to the end of the chain of exceptions + * that are chained to this object. + * + * @param w The exception to add to the end of the chain. + */ + public void setNextWarning(SQLWarning w) + { + super.setNextException(w); + } +} diff --git a/libjava/classpath/java/sql/Savepoint.java b/libjava/classpath/java/sql/Savepoint.java new file mode 100644 index 0000000..a4d89ae --- /dev/null +++ b/libjava/classpath/java/sql/Savepoint.java @@ -0,0 +1,55 @@ +/* SavePoint.java -- Returns information about the ResultSet + 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 java.sql; + +/** + * @since 1.4 + */ +public interface Savepoint +{ + /** + * @since 1.4 + */ + int getSavepointId() throws SQLException; + + /** + * @since 1.4 + */ + String getSavepointName() throws SQLException; +} diff --git a/libjava/classpath/java/sql/Statement.java b/libjava/classpath/java/sql/Statement.java new file mode 100644 index 0000000..42e8e8e --- /dev/null +++ b/libjava/classpath/java/sql/Statement.java @@ -0,0 +1,366 @@ +/* Statement.java -- Interface for executing SQL statements. + Copyright (C) 1999, 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 java.sql; + +/** + * This interface provides a mechanism for executing SQL statements. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Statement +{ + int CLOSE_CURRENT_RESULT = 1; + int KEEP_CURRENT_RESULT = 2; + int CLOSE_ALL_RESULTS = 3; + int SUCCESS_NO_INFO = -2; + int EXECUTE_FAILED = -3; + int RETURN_GENERATED_KEYS = 1; + int NO_GENERATED_KEYS = 2; + + /** + * This method executes the specified SQL SELECT statement and returns a + * (possibly empty) ResultSet with the results of the query. + * + * @param sql The SQL statement to execute. + * @return The result set of the SQL statement. + * @exception SQLException If an error occurs. + */ + ResultSet executeQuery(String sql) throws SQLException; + + /** + * This method executes the specified SQL INSERT, UPDATE, or DELETE statement + * and returns the number of rows affected, which may be 0. + * + * @param sql The SQL statement to execute. + * @return The number of rows affected by the SQL statement. + * @exception SQLException If an error occurs. + */ + int executeUpdate(String sql) throws SQLException; + + /** + * This method closes the statement and frees any associated resources. + * + * @exception SQLException If an error occurs. + */ + void close() throws SQLException; + + /** + * This method returns the maximum length of any column value in bytes. + * + * @return The maximum length of any column value in bytes. + * @exception SQLException If an error occurs. + */ + int getMaxFieldSize() throws SQLException; + + /** + * This method sets the limit for the maximum length of any column in bytes. + * + * @param maxsize The new maximum length of any column in bytes. + * @exception SQLException If an error occurs. + */ + void setMaxFieldSize(int max) throws SQLException; + + /** + * This method returns the maximum possible number of rows in a result set. + * + * @return The maximum possible number of rows in a result set. + * @exception SQLException If an error occurs. + */ + int getMaxRows() throws SQLException; + + /** + * This method sets the maximum number of rows that can be present in a + * result set. + * + * @param maxrows The maximum possible number of rows in a result set. + * @exception SQLException If an error occurs. + */ + void setMaxRows(int max) throws SQLException; + + /** + * This method sets the local escape processing mode on or off. The + * default value is on. + * + * @param escape true to enable local escape processing, + * false to disable it. + * @exception SQLException If an error occurs. + */ + void setEscapeProcessing(boolean enable) throws SQLException; + + /** + * The method returns the number of seconds a statement may be in process + * before timing out. A value of 0 means there is no timeout. + * + * @return The SQL statement timeout in seconds. + * @exception SQLException If an error occurs. + */ + int getQueryTimeout() throws SQLException; + + /** + * This method sets the number of seconds a statement may be in process + * before timing out. A value of 0 means there is no timeout. + * + * @param timeout The new SQL statement timeout value. + * @exception SQLException If an error occurs. + */ + void setQueryTimeout(int seconds) throws SQLException; + + /** + * This method cancels an outstanding statement, if the database supports + * that operation. + * + * @exception SQLException If an error occurs. + */ + void cancel() throws SQLException; + + /** + * This method returns the first SQL warning attached to this statement. + * Subsequent warnings will be chained to this one. + * + * @return The first SQL warning for this statement. + * @exception SQLException If an error occurs. + */ + SQLWarning getWarnings() throws SQLException; + + /** + * This method clears any SQL warnings that have been attached to this + * statement. + * + * @exception SQLException If an error occurs. + */ + void clearWarnings() throws SQLException; + + /** + * This method sets the cursor name that will be used by the result set. + * + * @param name The cursor name to use for this statement. + * @exception SQLException If an error occurs. + */ + void setCursorName(String name) throws SQLException; + + /** + * This method executes an arbitrary SQL statement of any time. The + * methods getResultSet, getMoreResults and + * getUpdateCount retrieve the results. + * + * @return true if a result set was returned, false + * if an update count was returned. + * @exception SQLException If an error occurs. + */ + boolean execute(String sql) throws SQLException; + + /** + * This method returns the result set of the SQL statement that was + * executed. This should be called only once per result set returned. + * + * @return The result set of the query, or null if there was + * no result set (for example, if the statement was an UPDATE). + * @exception SQLException If an error occurs. + * @see execute + */ + ResultSet getResultSet() throws SQLException; + + /** + * This method returns the update count of the SQL statement that was + * executed. This should be called only once per executed SQL statement. + * + * @return The update count of the query, or -1 if there was no update + * count (for example, if the statement was a SELECT). + * @exception SQLException If an error occurs. + * @see execute + */ + int getUpdateCount() throws SQLException; + + /** + * This method advances the result set pointer to the next result set, + * which can then be retrieved using getResultSet + * + * @return true if there is another result set, + * false otherwise (for example, the next result is an + * update count). + * @exception SQLException If an error occurs. + * @see execute + */ + boolean getMoreResults() throws SQLException; + + /** + * This method informs the driver which direction the result set will + * be accessed in. + * + * @param direction The direction the result set will be accessed in (?????) + * @exception SQLException If an error occurs. + */ + void setFetchDirection(int direction) throws SQLException; + + /** + * This method returns the current direction that the driver thinks the + * result set will be accessed int. + * + * @return The direction the result set will be accessed in (????) + * @exception SQLException If an error occurs. + */ + int getFetchDirection() throws SQLException; + + /** + * This method informs the driver how many rows it should fetch from the + * database at a time. + * + * @param numrows The number of rows the driver should fetch at a time + * to populate the result set. + * @exception SQLException If an error occurs. + */ + void setFetchSize(int rows) throws SQLException; + + /** + * This method returns the number of rows the driver believes should be + * fetched from the database at a time. + * + * @return The number of rows that will be fetched from the database at a time. + * @exception SQLException If an error occurs. + */ + int getFetchSize() throws SQLException; + + /** + * This method returns the concurrency type of the result set for this + * statement. This will be one of the concurrency types defined in + * ResultSet. + * + * @return The concurrency type of the result set for this statement. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + int getResultSetConcurrency() throws SQLException; + + /** + * This method returns the result set type for this statement. This will + * be one of the result set types defined in ResultSet. + * + * @return The result set type for this statement. + * @exception SQLException If an error occurs. + * @see ResultSet + */ + int getResultSetType() throws SQLException; + + /** + * This method adds a SQL statement to a SQL batch. A driver is not + * required to implement this method. + * + * @param sql The sql statement to add to the batch. + * @exception SQLException If an error occurs. + */ + void addBatch(String sql) throws SQLException; + + /** + * This method clears out any SQL statements that have been populated in + * the current batch. A driver is not required to implement this method. + * + * @exception SQLException If an error occurs. + */ + void clearBatch() throws SQLException; + + /** + * This method executes the SQL batch and returns an array of update + * counts - one for each SQL statement in the batch - ordered in the same + * order the statements were added to the batch. A driver is not required + * to implement this method. + * + * @return An array of update counts for this batch. + * @exception SQLException If an error occurs. + */ + int[] executeBatch() throws SQLException; + + /** + * This method returns the Connection instance that was + * used to create this object. + * + * @return The connection used to create this object. + * @exception SQLException If an error occurs. + */ + Connection getConnection() throws SQLException; + + /** + * @since 1.4 + */ + boolean getMoreResults(int current) throws SQLException; + + /** + * @since 1.4 + */ + ResultSet getGeneratedKeys() throws SQLException; + + /** + * @since 1.4 + */ + int executeUpdate(String sql, int autoGeneratedKeys) + throws SQLException; + + /** + * @since 1.4 + */ + int executeUpdate(String sql, int[] columnIndexes) + throws SQLException; + + /** + * @since 1.4 + */ + int executeUpdate(String sql, String[] columnNames) + throws SQLException; + + /** + * @since 1.4 + */ + boolean execute(String sql, int autoGeneratedKeys) + throws SQLException; + + /** + * @since 1.4 + */ + boolean execute(String sql, int[] columnIndexes) throws SQLException; + + /** + * @since 1.4 + */ + boolean execute(String sql, String[] columnNames) + throws SQLException; + + /** + * @since 1.4 + */ + int getResultSetHoldability() throws SQLException; +} diff --git a/libjava/classpath/java/sql/Struct.java b/libjava/classpath/java/sql/Struct.java new file mode 100644 index 0000000..5cbc88e --- /dev/null +++ b/libjava/classpath/java/sql/Struct.java @@ -0,0 +1,77 @@ +/* Struct.java -- Mapping for a SQL structured type. + Copyright (C) 1999, 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 java.sql; + +import java.util.Map; + +/** + * This interface implements the standard type mapping for a SQL + * structured type. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Struct +{ + /** + * This method returns the name of the SQL structured type for this + * object. + * + * @return The SQL structured type name. + * @exception SQLException If an error occurs. + */ + String getSQLTypeName() throws SQLException; + + /** + * This method returns the attributes of this SQL structured type. + * + * @return The attributes of this structure type. + * @exception SQLException If an error occurs. + */ + Object[] getAttributes() throws SQLException; + + /** + * This method returns the attributes of this SQL structured type. + * The specified map of type mappings overrides the default mappings. + * + * @param map The map of SQL type mappings. + * @return The attributes of this structure type. + * @exception SQLException If a error occurs. + */ + Object[] getAttributes(Map map) throws SQLException; +} diff --git a/libjava/classpath/java/sql/Time.java b/libjava/classpath/java/sql/Time.java new file mode 100644 index 0000000..eb6ef2d --- /dev/null +++ b/libjava/classpath/java/sql/Time.java @@ -0,0 +1,205 @@ +/* Time.java -- Wrapper around java.util.Date + Copyright (C) 1999, 2000, 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 java.sql; + +import java.text.ParseException; +import java.text.SimpleDateFormat; + +/** + * This class is a wrapper around java.util.Date to allow the JDBC + * driver to identify the value as a SQL Time. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Time extends java.util.Date +{ + static final long serialVersionUID = 8397324403548013681L; + + /** + * Used for parsing and formatting this date. + */ + private static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public int getDate() throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public int getDay() throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public int getMonth() throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public int getYear() throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public void setDate(int newValue) throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public void setMonth(int newValue) throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method always throws an IllegalArgumentException. + * + * @throws IllegalArgumentException when it's called. + * @deprecated + */ + public void setYear(int newValue) throws IllegalArgumentException + { + throw new IllegalArgumentException(); + } + + /** + * This method returns a new instance of this class by parsing a + * date in JDBC format into a Java date. + * + * @param str The string to parse. + * @return The resulting java.sql.Time value. + * + * @deprecated + */ + public static Time valueOf (String str) + { + try + { + java.util.Date d = (java.util.Date) sdf.parseObject(str); + + if (d == null) + throw new IllegalArgumentException(str); + else + return new Time(d.getTime()); + } + catch (ParseException e) + { + throw new IllegalArgumentException(str); + } + } + + /** + * This method initializes a new instance of this class with the + * specified year, month, and day. + * + * @param hour The hour for this Time (0-23) + * @param minute The minute for this time (0-59) + * @param second The second for this time (0-59) + * @deprecated + */ + public Time(int hour, int minute, int second) + { + super(System.currentTimeMillis()); + + setHours(hour); + setMinutes(minute); + setSeconds(second); + } + + /** + * This method initializes a new instance of this class with the + * specified time value representing the number of seconds since + * Jan 1, 1970 at 12:00 midnight GMT. + * + * @param time The time value to intialize this Time to. + */ + public Time(long date) + { + super(date); + } + + /** + * This method returns this date in JDBC format. + * + * @return This date as a string. + * + * @deprecated + */ + public String toString () + { + return sdf.format (this); + } + +} + diff --git a/libjava/classpath/java/sql/Timestamp.java b/libjava/classpath/java/sql/Timestamp.java new file mode 100644 index 0000000..f3459b2 --- /dev/null +++ b/libjava/classpath/java/sql/Timestamp.java @@ -0,0 +1,315 @@ +/* Time.java -- Wrapper around java.util.Date + Copyright (C) 1999, 2000, 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 java.sql; + +import java.text.DecimalFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +/** + * This class is a wrapper around java.util.Date to allow the JDBC + * driver to identify the value as a SQL Timestamp. Note that this + * class also adds an additional field for nano-seconds, and so + * is not completely identical to java.util.Date as + * the java.sql.Date and java.sql.Time + * classes are. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Timestamp extends java.util.Date +{ + static final long serialVersionUID = 2745179027874758501L; + + /** + * Used for parsing and formatting this date. + */ + private static SimpleDateFormat dateFormat = + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private static DecimalFormat decimalFormat = new DecimalFormat("000000000"); + private static StringBuffer sbuf = new StringBuffer(29); + + /** + * The nanosecond value for this object + */ + private int nanos; + + /** + * This method returns a new instance of this class by parsing a + * date in JDBC format into a Java date. + * + * @param str The string to parse. + * @return The resulting java.sql.Timestamp value. + */ + public static Timestamp valueOf(String str) + { + int nanos = 0; + int dot = str.indexOf('.'); + if (dot != -1) + { + if (str.lastIndexOf('.') != dot) + throw new IllegalArgumentException(str); + + int len = str.length() - dot - 1; + if (len < 1 || len > 9) + throw new IllegalArgumentException(str); + + nanos = Integer.parseInt(str.substring(dot + 1)); + for (int i = len; i < 9; i++) + nanos *= 10; + + str = str.substring(0, dot); + + } + + try + { + java.util.Date d; + synchronized (dateFormat) + { + d = (java.util.Date) dateFormat.parseObject(str); + } + + if (d == null) + throw new IllegalArgumentException(str); + + Timestamp ts = new Timestamp(d.getTime() + nanos / 1000000); + ts.nanos = nanos; + return ts; + } + catch (ParseException e) + { + throw new IllegalArgumentException(str); + } + } + + /** + * This method initializes a new instance of this class with the + * specified year, month, and day. + * + * @param year The year for this Timestamp (year - 1900) + * @param month The month for this Timestamp (0-11) + * @param day The day for this Timestamp (1-31) + * @param hour The hour for this Timestamp (0-23) + * @param minute The minute for this Timestamp (0-59) + * @param second The second for this Timestamp (0-59) + * @param nanos The nanosecond value for this Timestamp (0 to 999,999,9999) + * @deprecated + */ + public Timestamp(int year, int month, int day, int hour, int minute, + int second, int nanos) + { + super(year, month, day, hour, minute, second); + this.nanos = nanos; + } + + /** + * This method initializes a new instance of this class with the + * specified time value representing the number of milliseconds since + * Jan 1, 1970 at 12:00 midnight GMT. + * + * @param time The time value to intialize this Time to. + */ + public Timestamp(long date) + { + super(date - (date % 1000)); + nanos = (int) (date % 1000) * 1000000; + } + + /** + * Return the value of this Timestamp as the number of milliseconds + * since Jan 1, 1970 at 12:00 midnight GMT. + */ + public long getTime() + { + return super.getTime() + (nanos / 1000000); + } + + /** + * This method returns this date in JDBC format. + * + * @return This date as a string. + */ + public String toString() + { + synchronized (dateFormat) + { + sbuf.setLength(0); + dateFormat.format(this, sbuf, null); + sbuf.append('.'); + decimalFormat.format(nanos, sbuf, null); + int end = sbuf.length() - 1; + while (end > 20 && sbuf.charAt(end) == '0') + end--; + return sbuf.substring(0, end + 1); + } + } + + /** + * This method returns the nanosecond value for this object. + * @return The nanosecond value for this object. + */ + public int getNanos() + { + return nanos; + } + + /** + * This method sets the nanosecond value for this object. + * + * @param nanos The nanosecond value for this object. + */ + public void setNanos(int nanos) + { + this.nanos = nanos; + } + + /** + * This methods tests whether this object is earlier than the specified + * object. + * + * @param ts The other Timestamp to test against. + * @return true if this object is earlier than the other object, + * false otherwise. + */ + public boolean before(Timestamp ts) + { + long time1 = getTime(); + long time2 = ts.getTime(); + if (time1 < time2 || (time1 == time2 && getNanos() < ts.getNanos())) + return true; + return false; + } + + /** + * This methods tests whether this object is later than the specified + * object. + * + * @param ts The other Timestamp to test against. + * + * @return true if this object is later than the other object, + * false otherwise. + */ + public boolean after(Timestamp ts) + { + long time1 = getTime(); + long time2 = ts.getTime(); + if (time1 > time2 || (time1 == time2 && getNanos() > ts.getNanos())) + return true; + return false; + } + + /** + * This method these the specified Object for equality + * against this object. This will be true if an only if the specified + * object is an instance of Timestamp and has the same + * time value fields. + * + * @param obj The object to test against for equality. + * + * @return true if the specified object is equal to this + * object, false otherwise. + */ + public boolean equals(Object obj) + { + if (!(obj instanceof Timestamp)) + return false; + + return equals((Timestamp) obj); + } + + /** + * This method tests the specified timestamp for equality against this + * object. This will be true if and only if the specified object is + * not null and contains all the same time value fields + * as this object. + * + * @param ts The Timestamp to test against for equality. + * + * @return true if the specified object is equal to this + * object, false otherwise. + */ + public boolean equals(Timestamp ts) + { + if (ts == null) + return false; + + if (ts.getTime() != getTime()) + return false; + + if (ts.getNanos() != getNanos()) + return false; + + return true; + } + + /** + * Compare two Timestamp + * @param when the other Timestamp. + * @return 0, if the date represented + * by obj is exactly the same as the time represented by this + * object, a negative if this Timestamp is before the other Timestamp, and + * a positive value otherwise. + * @since 1.2 + */ + public int compareTo(Timestamp ts) + { + int s = super.compareTo((java.util.Date) ts); + if (s != 0) + return s; + // If Date components were equal, then we check the nanoseconds. + return nanos - ts.nanos; + } + + /** + * Compares this Timestamp to another. This behaves like + * compareTo(Timestamp), but it may throw a + * ClassCastException + * @param obj the other Timestamp. + * @return 0, if the Timestamp represented + * by obj is exactly the same as the time represented by this + * object, a negative if this Timestamp is before the other Timestamp, and + * a positive value otherwise. + * @exception ClassCastException if obj is not of type Timestamp. + * @since 1.2 + */ + public int compareTo(Object obj) + { + return compareTo((Timestamp) obj); + } +} diff --git a/libjava/classpath/java/sql/Types.java b/libjava/classpath/java/sql/Types.java new file mode 100644 index 0000000..7dd4141 --- /dev/null +++ b/libjava/classpath/java/sql/Types.java @@ -0,0 +1,85 @@ +/* Types.java -- SQL type constants + Copyright (C) 1999, 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 java.sql; + +/** + * This class contains constants that are used to identify SQL data types. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Types +{ + // These should be self explanatory. People need a SQL book, not + // Javadoc comments for these. + public static final int BIT = -7; + public static final int TINYINT = -6; + public static final int SMALLINT = 5; + public static final int INTEGER = 4; + public static final int BIGINT = -5; + public static final int FLOAT = 6; + public static final int REAL = 7; + public static final int DOUBLE = 8; + public static final int NUMERIC = 2; + public static final int DECIMAL = 3; + public static final int CHAR = 1; + public static final int VARCHAR = 12; + public static final int LONGVARCHAR = -1; + public static final int DATE = 91; + public static final int TIME = 92; + public static final int TIMESTAMP = 93; + public static final int BINARY = -2; + public static final int VARBINARY = -3; + public static final int LONGVARBINARY = -4; + public static final int NULL = 0; + public static final int OTHER = 1111; + public static final int JAVA_OBJECT = 2000; + public static final int DISTINCT = 2001; + public static final int STRUCT = 2002; + public static final int ARRAY = 2003; + public static final int BLOB = 2004; + public static final int CLOB = 2005; + public static final int REF = 2006; + public static final int DATALINK = 70; + public static final int BOOLEAN = 16; + + // This class can't be instantiated. + private Types() + { + } +} diff --git a/libjava/classpath/java/sql/package.html b/libjava/classpath/java/sql/package.html new file mode 100644 index 0000000..e8982f5 --- /dev/null +++ b/libjava/classpath/java/sql/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - java.sql + + +

    Interfaces and classes to connect to a database and wrappers for data +in the database and result queries.

    + + + diff --git a/libjava/classpath/java/text/Annotation.java b/libjava/classpath/java/text/Annotation.java new file mode 100644 index 0000000..cecb44a --- /dev/null +++ b/libjava/classpath/java/text/Annotation.java @@ -0,0 +1,113 @@ +/* Annotation.java -- Wrapper for a text attribute object + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +/** + * This class is used as a wrapper for a text attribute object. Annotation + * objects are associated with a specific range of text. Changing either + * the text range or the underlying text invalidates the object. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Annotation +{ + +/* + * Instance Variables + */ + +/** + * This is the attribute object being wrappered + */ +private Object attrib; + +/*************************************************************************/ + +/** + * Constructors + */ + +/** + * This method initializes a new instance of Annotation to + * wrapper the specified text attribute object. + * + * @param attrib The text attribute Object to wrapper. + */ +public +Annotation(Object attrib) +{ + this.attrib = attrib; +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * This method returns the text attribute object this Annotation + * instance is wrappering. + * + * @return The text attribute object for this Annotation. + */ +public Object +getValue() +{ + return(attrib); +} + +/*************************************************************************/ + +/** + * This method returns a String representation of this + * object. + * + * @return This object as a String. + */ +public String +toString() +{ + return(getClass().getName() + "[value=" + attrib.toString() + "]"); +} + +} // class Annotation + diff --git a/libjava/classpath/java/text/AttributedCharacterIterator.java b/libjava/classpath/java/text/AttributedCharacterIterator.java new file mode 100644 index 0000000..e5686ba --- /dev/null +++ b/libjava/classpath/java/text/AttributedCharacterIterator.java @@ -0,0 +1,268 @@ +/* AttributedCharacterIterator.java -- Iterate over attributes + Copyright (C) 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 java.text; + +import java.io.InvalidObjectException; +import java.io.Serializable; +import java.util.Map; +import java.util.Set; + +/** + * This interface extends the CharacterIterator interface + * in order to support iteration over character attributes as well as + * over the characters themselves. + *

    + * In addition to attributes of specific characters, this interface + * supports the concept of the "attribute run", which is an attribute + * that is defined for a particular value across an entire range of + * characters or which is undefined over a range of characters. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface AttributedCharacterIterator extends CharacterIterator +{ + /** + * This class defines attribute keys that are used as text attributes. + */ + public static class Attribute implements Serializable + { + private static final long serialVersionUID = -9142742483513960612L; + + /** + * This is the attribute for the language of the text. The value of + * attributes of this key type are instances of Locale. + */ + public static final Attribute LANGUAGE = new Attribute ("LANGUAGE"); + + /** + * This is the attribute for the reading form of text. This is used + * for storing pronunciation along with the written text for languages + * which need it. The value of attributes of this key type are + * instances of Annotation which wrappers a String. + */ + public static final Attribute READING = new Attribute ("READING"); + + /** + * This is the attribute for input method segments. The value of attributes + * of this key type are instances of Annotation which wrapper + * a String. + */ + public static final Attribute INPUT_METHOD_SEGMENT = + new Attribute ("INPUT_METHOD_SEGMENT"); + + /** + * This is the name of the attribute key + * @serial + */ + private String name; + + /** + * This method initializes a new instance of this class with the specified + * name. + * + * @param name The name of this attribute key. + */ + protected Attribute (String name) + { + this.name = name; + } + + /** + * This method returns the name of this attribute. + * + * @return The attribute name + */ + protected String getName() + { + return name; + } + + /** + * This method resolves an instance of AttributedCharacterIterator.Attribute + * that is being deserialized to one of the three pre-defined attribute + * constants. It does this by comparing the names of the attributes. The + * constant that the deserialized object resolves to is returned. + * + * @return The resolved contant value + * + * @exception InvalidObjectException If the object being deserialized cannot be resolved. + */ + protected Object readResolve() throws InvalidObjectException + { + if (this.equals (READING)) + return READING; + + if (this.equals (LANGUAGE)) + return LANGUAGE; + + if (this.equals (INPUT_METHOD_SEGMENT)) + return INPUT_METHOD_SEGMENT; + + throw new InvalidObjectException ("Can't resolve Attribute: " + getName()); + } + + /** + * This method tests this object for equality against the specified object. + * The two objects will be considered equal if and only if: + *

      + *
    • The specified object is not null. + *
    • The specified object is an instance of AttributedCharacterIterator.Attribute. + *
    • The specified object has the same attribute name as this object. + *
    + * + * @param The Object to test for equality against this object. + * + * @return true if the specified object is equal to this one, false otherwise. + */ + public final boolean equals (Object obj) + { + if (obj == this) + return true; + else + return false; + } + + /** + * This method returns a hash value for this object. + * + * @return A hash value for this object. + */ + public final int hashCode() + { + return super.hashCode(); + } + + /** + * This method returns a String representation of this object. + * + * @return A String representation of this object. + */ + public String toString() + { + return getClass().getName() + "(" + getName() + ")"; + } + + } // Inner class Attribute + + /** + * This method returns a list of all keys that are defined for the + * text range. This can be an empty list if no attributes are defined. + * + * @return A list of keys + */ + Set getAllAttributeKeys(); + + /** + * This method returns a Map of the attributed defined for + * the current character. + * + * @return A Map of the attributes for the current character. + */ + Map getAttributes(); + + /** + * This method returns the value of the specified attribute for the + * current character. If the attribute is not defined for the current + * character, null is returned. + * + * @param attrib The attribute to retrieve the value of. + * + * @return The value of the specified attribute + */ + Object getAttribute (AttributedCharacterIterator.Attribute attrib); + + /** + * This method returns the index of the first character in the run that + * contains all attributes defined for the current character. + * + * @return The start index of the run + */ + int getRunStart(); + + /** + * This method returns the index of the first character in the run that + * contains all attributes in the specified Set defined for + * the current character. + * + * @param attribs The Set of attributes. + * + * @return The start index of the run. + */ + int getRunStart (Set attribs); + + /** + * This method returns the index of the first character in the run that + * contains the specified attribute defined for the current character. + * + * @param attrib The attribute. + * + * @return The start index of the run. + */ + int getRunStart (AttributedCharacterIterator.Attribute attrib); + + /** + * This method returns the index of the character after the end of the run + * that contains all attributed defined for the current character. + * + * @return The end index of the run. + */ + int getRunLimit(); + + /** + * This method returns the index of the character after the end of the run + * that contains all attributes in the specified Set defined + * for the current character. + * + * @param attribs The Set of attributes. + * + * @return The end index of the run. + */ + int getRunLimit (Set attribs); + + /** + * This methods returns the index of the character after the end of the run + * that contains the specified attribute defined for the current character. + * + * @param attrib The attribute. + * + * @return The end index of the run. + */ + int getRunLimit (AttributedCharacterIterator.Attribute attrib); + +} // interface AttributedCharacterIterator diff --git a/libjava/classpath/java/text/AttributedString.java b/libjava/classpath/java/text/AttributedString.java new file mode 100644 index 0000000..b9ced8f --- /dev/null +++ b/libjava/classpath/java/text/AttributedString.java @@ -0,0 +1,425 @@ +/* AttributedString.java -- Models text with attributes + Copyright (C) 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 java.text; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * This class models a String with attributes over various + * subranges of the string. It allows applications to access this + * information via the AttributedCharcterIterator interface. + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class AttributedString +{ + +/*************************************************************************/ + +/* + * Inner Classes + */ + +/** + * This class contains the attributes and ranges of text over which + * that attributes apply. + */ +final class AttributeRange +{ + +/* + * Instance Variables + */ + +/** + * A Map of the attributes + */ +Map attribs; + +/** + * The beginning index of the attributes + */ +int begin_index; + +/** + * The ending index of the attributes + */ +int end_index; + +/*************************************************************************/ + +/* + * Constructors + */ + +AttributeRange(Map attribs, int begin_index, int end_index) +{ + this.attribs = attribs; + this.begin_index = begin_index; + this.end_index = end_index; +} + +} // Inner class AttributeRange + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * This object holds the string we are representing. + */ +private StringCharacterIterator sci; + +/** + * This is the attribute information + */ +private AttributeRange[] attribs; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * This method initializes a new instance of AttributedString + * that represents the specified String with no attributes. + * + * @param str The String to be attributed. + */ +public +AttributedString(String str) +{ + sci = new StringCharacterIterator(str); + attribs = new AttributeRange[0]; +} + +/*************************************************************************/ + +/** + * This method initializes a new instance of AttributedString + * that represents that specified String with the specified + * attributes over the entire length of the String. + * + * @param str The String to be attributed. + * @param attributes The attribute list. + */ +public +AttributedString(String str, Map attributes) +{ + this(str); + + attribs = new AttributeRange[1]; + attribs[0] = new AttributeRange(attributes, 0, str.length()); +} + +/*************************************************************************/ + +/** + * This method initializes a new instance of AttributedString + * that will use the text and attribute information from the specified + * AttributedCharacterIterator. + * + * @param aci The AttributedCharacterIterator containing the text and attribute information. + */ +public +AttributedString(AttributedCharacterIterator aci) +{ + this(aci, aci.getBeginIndex(), aci.getEndIndex(), null); +} + +/*************************************************************************/ + +/** + * This method initializes a new instance of AttributedString + * that will use the text and attribute information from the specified + * subrange of the specified AttributedCharacterIterator. + * + * @param aci The AttributedCharacterIterator containing the text and attribute information. + * @param begin_index The beginning index of the text subrange. + * @param end_index The ending index of the text subrange. + */ +public +AttributedString(AttributedCharacterIterator aci, int begin_index, + int end_index) +{ + this(aci, begin_index, end_index, null); +} + +/*************************************************************************/ + +/** + * This method initializes a new instance of AttributedString + * that will use the text and attribute information from the specified + * subrange of the specified AttributedCharacterIterator. + * Only attributes from the source iterator that are present in the + * specified array of attributes will be included in the attribute list + * for this object. + * + * @param aci The AttributedCharacterIterator containing the text and attribute information. + * @param begin_index The beginning index of the text subrange. + * @param end_index The ending index of the text subrange. + * @param attributes A list of attributes to include from the iterator, or null to include all attributes. + */ +public +AttributedString(AttributedCharacterIterator aci, int begin_index, + int end_index, AttributedCharacterIterator.Attribute[] attributes) +{ + // Validate some arguments + if ((begin_index < 0) || (end_index < begin_index)) + throw new IllegalArgumentException("Bad index values"); + + StringBuffer sb = new StringBuffer(""); + + // Get the valid attribute list + Set all_attribs = aci.getAllAttributeKeys(); + if (attributes != null) + all_attribs.retainAll(Arrays.asList(attributes)); + + // Loop through and extract the attributes + char c = aci.setIndex(begin_index); + + ArrayList accum = new ArrayList(); + do + { + sb.append(c); + + Iterator iter = all_attribs.iterator(); + while(iter.hasNext()) + { + Object obj = iter.next(); + + // What should we do if this is not true? + if (!(obj instanceof AttributedCharacterIterator.Attribute)) + continue; + + AttributedCharacterIterator.Attribute attrib = + (AttributedCharacterIterator.Attribute)obj; + + // Make sure the attribute is defined. + int rl = aci.getRunLimit(attrib); + if (rl == -1) + continue; + if (rl > end_index) + rl = end_index; + rl -= begin_index; + + // Check to see if we already processed this one + int rs = aci.getRunStart(attrib); + if ((rs < aci.getIndex()) && (aci.getIndex() != begin_index)) + continue; + + // If the attribute run starts before the beginning index, we + // need to junk it if it is an Annotation. + Object attrib_obj = aci.getAttribute(attrib); + if (rs < begin_index) + { + if (attrib_obj instanceof Annotation) + continue; + + rs = begin_index; + } + else + { + rs -= begin_index; + } + + // Create a map object. Yes this will only contain one attribute + Map new_map = new Hashtable(); + new_map.put(attrib, attrib_obj); + + // Add it to the attribute list. + accum.add(new AttributeRange(new_map, rs, rl)); + } + + c = aci.next(); + } + while(c != CharacterIterator.DONE); + + attribs = new AttributeRange[accum.size()]; + attribs = (AttributeRange[]) accum.toArray(attribs); + + sci = new StringCharacterIterator(sb.toString()); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * This method adds a new attribute that will cover the entire string. + * + * @param attrib The attribute to add. + * @param value The value of the attribute. + */ +public void +addAttribute(AttributedCharacterIterator.Attribute attrib, Object value) +{ + addAttribute(attrib, value, 0, sci.getEndIndex()); +} + +/*************************************************************************/ + +/** + * This method adds a new attribute that will cover the specified subrange + * of the string. + * + * @param attrib The attribute to add. + * @param value The value of the attribute, which may be null. + * @param begin_index The beginning index of the subrange. + * @param end_index The ending index of the subrange. + * + * @exception IllegalArgumentException If attribute is null or the subrange is not valid. + */ +public void +addAttribute(AttributedCharacterIterator.Attribute attrib, Object value, + int begin_index, int end_index) +{ + if (attrib == null) + throw new IllegalArgumentException("null attribute"); + + HashMap hm = new HashMap(); + hm.put(attrib, value); + + addAttributes(hm, begin_index, end_index); +} + +/*************************************************************************/ + +/** + * This method adds all of the attributes in the specified list to the + * specified subrange of the string. + * + * @param attributes The list of attributes. + * @param begin_index The beginning index. + * @param end_index The ending index + * + * @param IllegalArgumentException If the list is null or the subrange is not valid. + */ +public void +addAttributes(Map attributes, int begin_index, int end_index) +{ + if (attributes == null) + throw new IllegalArgumentException("null attribute"); + + if ((begin_index < 0) || (end_index > sci.getEndIndex()) || + (end_index < begin_index)) + throw new IllegalArgumentException("bad range"); + + AttributeRange[] new_list = new AttributeRange[attribs.length + 1]; + System.arraycopy(attribs, 0, new_list, 0, attribs.length); + attribs = new_list; + attribs[attribs.length - 1] = new AttributeRange(attributes, begin_index, + end_index); +} + +/*************************************************************************/ + +/** + * This method returns an AttributedCharacterIterator that + * will iterate over the entire string. + * + * @return An AttributedCharacterIterator for the entire string. + */ +public AttributedCharacterIterator +getIterator() +{ + return(new AttributedStringIterator(sci, attribs, 0, sci.getEndIndex(), null)); +} + +/*************************************************************************/ + +/** + * This method returns an AttributedCharacterIterator that + * will iterate over the entire string. This iterator will return information + * about the list of attributes in the specified array. Attributes not in + * the array may or may not be returned by the iterator. If the specified + * array is null, all attributes will be returned. + * + * @param attributes A list of attributes to include in the returned iterator. + * + * @return An AttributedCharacterIterator for this string. + */ +public AttributedCharacterIterator +getIterator(AttributedCharacterIterator.Attribute[] attributes) +{ + return(getIterator(attributes, 0, sci.getEndIndex())); +} + +/*************************************************************************/ + +/** + * This method returns an AttributedCharacterIterator that + * will iterate over the specified subrange. This iterator will return information + * about the list of attributes in the specified array. Attributes not in + * the array may or may not be returned by the iterator. If the specified + * array is null, all attributes will be returned. + * + * @param attributes A list of attributes to include in the returned iterator. + * @param begin_index The beginning index of the subrange. + * @param end_index The ending index of the subrange. + * + * @return An AttributedCharacterIterator for this string. + */ +public AttributedCharacterIterator +getIterator(AttributedCharacterIterator.Attribute[] attributes, + int begin_index, int end_index) +{ + if ((begin_index < 0) || (end_index > sci.getEndIndex()) || + (end_index < begin_index)) + throw new IllegalArgumentException("bad range"); + + return(new AttributedStringIterator(sci, attribs, begin_index, end_index, + attributes)); +} + +} // class AttributedString + diff --git a/libjava/classpath/java/text/AttributedStringIterator.java b/libjava/classpath/java/text/AttributedStringIterator.java new file mode 100644 index 0000000..7d7bf27 --- /dev/null +++ b/libjava/classpath/java/text/AttributedStringIterator.java @@ -0,0 +1,348 @@ +/* AttributedStringIterator.java -- Class to iterate over AttributedString + Copyright (C) 1998, 1999, 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 java.text; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * This class implements the AttributedCharacterIterator interface. It + * is used by AttributedString.getIterator(). + * + * @version 0.0 + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +class AttributedStringIterator implements AttributedCharacterIterator +{ + +/*************************************************************************/ + +/** + * Instance Variables + */ + +/** + * The character iterator containing the text + */ +private CharacterIterator ci; + +/** + * The list of attributes and ranges + */ +private AttributedString.AttributeRange[] attribs; + +/** + * The list of attributes that the user is interested in. We may, + * at our option, not return any other attributes. + */ +private AttributedCharacterIterator.Attribute[] restricts; + +/*************************************************************************/ + +/* + * Constructors + */ + +AttributedStringIterator(StringCharacterIterator sci, + AttributedString.AttributeRange[] attribs, + int begin_index, int end_index, + AttributedCharacterIterator.Attribute[] restricts) +{ + this.ci = new StringCharacterIterator(sci, begin_index, end_index); + this.attribs = attribs; + this.restricts = restricts; +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +// First we have a bunch of stupid redirects. If StringCharacterIterator +// weren't final, I just would have extended that for this class. Alas, no. + +public Object +clone() +{ + return(ci.clone()); +} + +public char +current() +{ + return(ci.current()); +} + +public char +next() +{ + return(ci.next()); +} + +public char +previous() +{ + return(ci.previous()); +} + +public char +first() +{ + return(ci.first()); +} + +public char +last() +{ + return(ci.last()); +} + +public int +getIndex() +{ + return(ci.getIndex()); +} + +public char +setIndex(int index) +{ + return(ci.setIndex(index)); +} + +public int +getBeginIndex() +{ + return(ci.getBeginIndex()); +} + +public int +getEndIndex() +{ + return(ci.getEndIndex()); +} + +/* + * Here is where the AttributedCharacterIterator methods start. + */ + +/*************************************************************************/ + +/** + * Returns a list of all the attribute keys that are defined anywhere + * on this string. + */ +public Set +getAllAttributeKeys() +{ + HashSet s = new HashSet(); + if (attribs == null) + return(s); + + for (int i = 0; i < attribs.length; i++) + { + if (attribs[i].begin_index > getEndIndex() + || attribs[i].end_index <= getBeginIndex()) + continue; + + Set key_set = attribs[i].attribs.keySet(); + Iterator iter = key_set.iterator(); + while (iter.hasNext()) + { + s.add(iter.next()); + } + } + + return(s); +} + +/*************************************************************************/ + +/** + * Various methods that determine how far the run extends for various + * attribute combinations. + */ + +public int +getRunLimit() +{ + return(getRunLimit(getAttributes().keySet())); +} + +public int +getRunLimit(AttributedCharacterIterator.Attribute attrib) +{ + HashSet s = new HashSet(); + s.add(attrib); + + return(getRunLimit(s)); +} + +public synchronized int +getRunLimit(Set attribute_set) +{ + boolean hit = false; + int runLimit = ci.getEndIndex (); + int pos = ci.getIndex (); + + for (int i = 0; i < attribs.length; ++i) + { + if (pos >= attribs[i].begin_index && + pos < attribs[i].end_index) + { + Iterator iter = attribute_set.iterator(); + while(iter.hasNext()) + if (attribs[i].attribs.containsKey(iter.next())) + { + hit = true; + runLimit = Math.min(runLimit, attribs[i].end_index); + } + } + } + if (hit) + return runLimit; + else + return ci.getEndIndex(); +} + +/*************************************************************************/ + +/** + * Various methods that determine where the run begins for various + * attribute combinations. + */ + +public int +getRunStart() +{ + return(getRunStart(getAttributes().keySet())); +} + +public int +getRunStart(AttributedCharacterIterator.Attribute attrib) +{ + HashSet s = new HashSet(); + s.add(attrib); + + return(getRunStart(s)); +} + +public int +getRunStart(Set attribute_set) +{ + boolean hit = false; + int runBegin = 0; + int pos = ci.getIndex (); + + for (int i = 0; i < attribs.length; ++i) + { + if (pos >= attribs[i].begin_index && + pos <= attribs[i].end_index) + { + Iterator iter = attribute_set.iterator(); + while(iter.hasNext()) + if (attribs[i].attribs.containsKey(iter.next())) + { + hit = true; + runBegin = Math.max(runBegin, attribs[i].begin_index); + } + } + } + if (hit) + return runBegin; + else + return -1; +} + +/*************************************************************************/ + +public Object +getAttribute(AttributedCharacterIterator.Attribute attrib) +{ + if (attribs == null) + return(null); + + for (int i = 0; i < attribs.length; i++) + { + Set key_set = attribs[i].attribs.keySet(); + Iterator iter = key_set.iterator(); + while (iter.hasNext()) + { + Object obj = iter.next(); + + // Check for attribute match and range match + if (obj.equals(attrib)) + if ((ci.getIndex() >= attribs[i].begin_index) && + (ci.getIndex() < attribs[i].end_index)) + return(attribs[i].attribs.get(obj)); + } + } + + return(null); +} + +/*************************************************************************/ + +/** + * Return a list of all the attributes and values defined for this + * character + */ +public Map +getAttributes() +{ + HashMap m = new HashMap(); + if (attribs == null) + return(m); + + for (int i = 0; i < attribs.length; i++) + { + if ((ci.getIndex() >= attribs[i].begin_index) && + (ci.getIndex() < attribs[i].end_index)) + m.putAll(attribs[i].attribs); + } + + return(m); +} + +} // class AttributedStringIterator + diff --git a/libjava/classpath/java/text/BreakIterator.java b/libjava/classpath/java/text/BreakIterator.java new file mode 100644 index 0000000..d021dce --- /dev/null +++ b/libjava/classpath/java/text/BreakIterator.java @@ -0,0 +1,374 @@ +/* BreakIterator.java -- Breaks text into elements + Copyright (C) 1998, 1999, 2001, 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 java.text; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * This class iterates over text elements such as words, lines, sentences, + * and characters. It can only iterate over one of these text elements at + * a time. An instance of this class configured for the desired iteration + * type is created by calling one of the static factory methods, not + * by directly calling a constructor. + * + * The standard iterators created by the factory methods in this + * class will be valid upon creation. That is, their methods will + * not cause exceptions if called before you call setText(). + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @date March 19, 1999 + */ +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct to 1.1. + */ +public abstract class BreakIterator implements Cloneable +{ + /** + * This value is returned by the next() and + * previous in order to indicate that the end of the + * text has been reached. + */ + // The value was discovered by writing a test program. + public static final int DONE = -1; + + /** + * This method initializes a new instance of BreakIterator. + * This protected constructor is available to subclasses as a default + * no-arg superclass constructor. + */ + protected BreakIterator () + { + } + + /** + * Create a clone of this object. + */ + public Object clone () + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + return null; + } + } + + /** + * This method returns the index of the current text element boundary. + * + * @return The current text boundary. + */ + public abstract int current (); + + /** + * This method returns the first text element boundary in the text being + * iterated over. + * + * @return The first text boundary. + */ + public abstract int first (); + + /** + * This methdod returns the offset of the text element boundary following + * the specified offset. + * + * @param offset The text index from which to find the next text boundary. + * + * @param The next text boundary following the specified index. + */ + public abstract int following (int pos); + + /** + * This method returns a list of locales for which instances of + * BreakIterator are available. + * + * @return A list of available locales + */ + public static synchronized Locale[] getAvailableLocales () + { + Locale[] l = new Locale[1]; + l[0] = Locale.US; + return l; + } + + private static BreakIterator getInstance (String type, Locale loc) + { + String className; + try + { + ResourceBundle res + = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + loc, ClassLoader.getSystemClassLoader()); + className = res.getString(type); + } + catch (MissingResourceException x) + { + return null; + } + try + { + Class k = Class.forName(className); + return (BreakIterator) k.newInstance(); + } + catch (ClassNotFoundException x1) + { + return null; + } + catch (InstantiationException x2) + { + return null; + } + catch (IllegalAccessException x3) + { + return null; + } + } + + /** + * This method returns an instance of BreakIterator that will + * iterate over characters as defined in the default locale. + * + * @return A BreakIterator instance for the default locale. + */ + public static BreakIterator getCharacterInstance () + { + return getCharacterInstance (Locale.getDefault()); + } + + /** + * This method returns an instance of BreakIterator that will + * iterate over characters as defined in the specified locale. If the + * desired locale is not available, the default locale is used. + * + * @param locale The desired locale. + * + * @return A BreakIterator instance for the default locale. + */ + public static BreakIterator getCharacterInstance (Locale loc) + { + BreakIterator r = getInstance ("CharacterIterator", loc); + if (r == null) + r = new gnu.java.text.CharacterBreakIterator (); + return r; + } + + /** + * This method returns an instance of BreakIterator that will + * iterate over line breaks as defined in the default locale. + * + * @return A BreakIterator instance for the default locale. + */ + public static BreakIterator getLineInstance () + { + return getLineInstance (Locale.getDefault()); + } + + /** + * This method returns an instance of BreakIterator that will + * iterate over line breaks as defined in the specified locale. If the + * desired locale is not available, the default locale is used. + * + * @param locale The desired locale. + * + * @return A BreakIterator instance for the default locale. + */ + public static BreakIterator getLineInstance (Locale loc) + { + BreakIterator r = getInstance ("LineIterator", loc); + if (r == null) + r = new gnu.java.text.LineBreakIterator (); + return r; + } + + /** + * This method returns an instance of BreakIterator that will + * iterate over sentences as defined in the default locale. + * + * @return A BreakIterator instance for the default locale. + */ + public static BreakIterator getSentenceInstance () + { + return getSentenceInstance (Locale.getDefault()); + } + + /** + * This method returns an instance of BreakIterator that will + * iterate over sentences as defined in the specified locale. If the + * desired locale is not available, the default locale is used. + * + * @param locale The desired locale. + * + * @return A BreakIterator instance for the default locale. + */ + public static BreakIterator getSentenceInstance (Locale loc) + { + BreakIterator r = getInstance ("SentenceIterator", loc); + if (r == null) + r = new gnu.java.text.SentenceBreakIterator (); + return r; + } + + /** + * This method returns the text this object is iterating over as a + * CharacterIterator. + * + * @param The text being iterated over. + */ + public abstract CharacterIterator getText (); + + /** + * This method returns an instance of BreakIterator that will + * iterate over words as defined in the default locale. + * + * @return A BreakIterator instance for the default locale. + */ + public static BreakIterator getWordInstance () + { + return getWordInstance (Locale.getDefault()); + } + + /** + * This method returns an instance of BreakIterator that will + * iterate over words as defined in the specified locale. If the + * desired locale is not available, the default locale is used. + * + * @param locale The desired locale. + * + * @return A BreakIterator instance for the default locale. + */ + public static BreakIterator getWordInstance (Locale loc) + { + BreakIterator r = getInstance ("WordIterator", loc); + if (r == null) + r = new gnu.java.text.WordBreakIterator (); + return r; + } + + /** + * This method tests whether or not the specified position is a text + * element boundary. + * + * @param offset The text position to test. + * + * @return true if the position is a boundary, + * false otherwise. + */ + public boolean isBoundary (int pos) + { + if (pos == 0) + return true; + return following (pos - 1) == pos; + } + + /** + * This method returns the last text element boundary in the text being + * iterated over. + * + * @return The last text boundary. + */ + public abstract int last (); + + /** + * This method returns the text element boundary following the current + * text position. + * + * @return The next text boundary. + */ + public abstract int next (); + + /** + * This method returns the n'th text element boundary following the current + * text position. + * + * @param n The number of text element boundaries to skip. + * + * @return The next text boundary. + */ + public abstract int next (int n); + + /** + * This methdod returns the offset of the text element boundary preceding + * the specified offset. + * + * @param offset The text index from which to find the preceding + * text boundary. + * + * @returns The next text boundary preceding the specified index. + */ + public int preceding (int pos) + { + if (following (pos) == DONE) + last (); + while (previous () >= pos) + ; + return current (); + } + + /** + * This method returns the text element boundary preceding the current + * text position. + * + * @return The previous text boundary. + */ + public abstract int previous (); + + /** + * This method sets the text string to iterate over. + * + * @param str The String to iterate over. + */ + public void setText (String newText) + { + setText (new StringCharacterIterator (newText)); + } + + /** + * This method sets the text to iterate over from the specified + * CharacterIterator. + * + * @param ci The desired CharacterIterator. + */ + public abstract void setText (CharacterIterator newText); +} diff --git a/libjava/classpath/java/text/CharacterIterator.java b/libjava/classpath/java/text/CharacterIterator.java new file mode 100644 index 0000000..6b3f951 --- /dev/null +++ b/libjava/classpath/java/text/CharacterIterator.java @@ -0,0 +1,144 @@ +/* CharacterIterator.java -- Iterate over a character range + Copyright (C) 1998, 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 java.text; + +/** + * This interface defines a mechanism for iterating over a range of + * characters. For a given range of text, a beginning and ending index, + * as well as a current index are defined. These values can be queried + * by the methods in this interface. Additionally, various methods allow + * the index to be set. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface CharacterIterator extends Cloneable +{ + /** + * This is a special constant value that is returned when the beginning or + * end of the character range has been reached. + */ + char DONE = '\uFFFF'; + + /** + * This method returns the character at the current index position + * + * @return The character at the current index position. + */ + char current(); + + /** + * This method increments the current index and then returns the character + * at the new index value. If the index is already at getEndIndex() - 1, + * it will not be incremented. + * + * @return The character at the position of the incremented index value, + * or DONE if the index has reached getEndIndex() - 1 + */ + char next(); + + /** + * This method decrements the current index and then returns the character + * at the new index value. If the index value is already at the beginning + * index, it will not be decremented. + * + * @return The character at the position of the decremented index value, + * or DONE if index was already equal to the beginning index value. + */ + char previous(); + + /** + * This method sets the index value to the beginning of the range and returns + * the character there. + * + * @return The character at the beginning of the range, or DONE if the range is empty. + */ + char first(); + + /** + * This method sets the index value to getEndIndex() - 1 and + * returns the character there. If the range is empty, then the index value + * will be set equal to the beginning index. + * + * @return The character at the end of the range, or DONE if the range is empty. + */ + char last(); + + /** + * This method returns the current value of the index. + * + * @return The current index value + */ + int getIndex(); + + /** + * This method sets the value of the index to the specified value, then + * returns the character at that position. + * + * @param index The new index value. + * + * @return The character at the new index value or DONE if the index value is equal to getEndIndex. + */ + char setIndex (int index) throws IllegalArgumentException; + + /** + * This method returns the character position of the first character in the + * range. + * + * @return The index of the first character in the range. + */ + int getBeginIndex(); + + /** + * This method returns the character position of the end of the text range. + * This will actually be the index of the first character following the + * end of the range. In the event the text range is empty, this will be + * equal to the first character in the range. + * + * @return The index of the end of the range. + */ + int getEndIndex(); + + /** + * This method creates a copy of this CharacterIterator. + * + * @return A copy of this CharacterIterator. + */ + Object clone(); + +} // interface CharacterIterator diff --git a/libjava/classpath/java/text/ChoiceFormat.java b/libjava/classpath/java/text/ChoiceFormat.java new file mode 100644 index 0000000..23c8a8c --- /dev/null +++ b/libjava/classpath/java/text/ChoiceFormat.java @@ -0,0 +1,503 @@ +/* ChoiceFormat.java -- Format over a range of numbers + Copyright (C) 1998, 1999, 2000, 2001, 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 java.text; + +import java.util.Vector; + +/** + * This class allows a format to be specified based on a range of numbers. + * To use this class, first specify two lists of formats and range terminators. + * These lists must be arrays of equal length. The format of index + * i will be selected for value X if + * terminator[i] <= X < limit[i + 1]. If the value X is not + * included in any range, then either the first or last format will be + * used depending on whether the value X falls outside the range. + *

    + * This sounds complicated, but that is because I did a poor job of + * explaining it. Consider the following example: + *

    + * +

    terminators = { 1, ChoiceFormat.nextDouble(1) }
    +formats = { "file", "files" }
    + * + *

    + * In this case if the actual number tested is one or less, then the word + * "file" is used as the format value. If the number tested is greater than + * one, then "files" is used. This allows plurals to be handled + * gracefully. Note the use of the method nextDouble. This + * method selects the next highest double number than its argument. This + * effectively makes any double greater than 1.0 cause the "files" string + * to be selected. (Note that all terminator values are specified as + * doubles. + *

    + * Note that in order for this class to work properly, the range terminator + * array must be sorted in ascending order and the format string array + * must be the same length as the terminator array. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @date March 9, 1999 + */ +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct to 1.1. + */ +public class ChoiceFormat extends NumberFormat +{ + /** + * This method sets new range terminators and format strings for this + * object based on the specified pattern. This pattern is of the form + * "term#string|term#string...". For example "1#Sunday|2#Monday|#Tuesday". + * + * @param pattern The pattern of terminators and format strings. + * + * @exception IllegalArgumentException If the pattern is not valid + */ + public void applyPattern (String newPattern) + { + // Note: we assume the same kind of quoting rules apply here. + // This isn't explicitly documented. But for instance we accept + // '#' as a literal hash in a format string. + int index = 0, max = newPattern.length(); + Vector stringVec = new Vector (); + Vector limitVec = new Vector (); + StringBuffer buf = new StringBuffer (); + + while (true) + { + // Find end of double. + int dstart = index; + while (index < max) + { + char c = newPattern.charAt(index); + if (c == '#' || c == '\u2064' || c == '<') + break; + ++index; + } + + if (index == max) + throw new IllegalArgumentException ("unexpected end of text"); + Double d = new Double (newPattern.substring(dstart, index)); + + if (newPattern.charAt(index) == '<') + d = new Double (nextDouble (d.doubleValue())); + + limitVec.addElement(d); + + // Scan text. + ++index; + buf.setLength(0); + while (index < max) + { + char c = newPattern.charAt(index); + if (c == '\'' && index < max + 1 + && newPattern.charAt(index + 1) == '\'') + { + buf.append(c); + ++index; + } + else if (c == '\'' && index < max + 2) + { + buf.append(newPattern.charAt(index + 1)); + index += 2; + } + else if (c == '|') + break; + else + buf.append(c); + ++index; + } + + stringVec.addElement(buf.toString()); + if (index == max) + break; + ++index; + } + + choiceFormats = new String[stringVec.size()]; + stringVec.copyInto(choiceFormats); + + choiceLimits = new double[limitVec.size()]; + for (int i = 0; i < choiceLimits.length; ++i) + { + Double d = (Double) limitVec.elementAt(i); + choiceLimits[i] = d.doubleValue(); + } + } + + /** + * This method initializes a new instance of ChoiceFormat that + * generates its range terminator and format string arrays from the + * specified pattern. This pattern is of the form + * "term#string|term#string...". For example "1#Sunday|2#Monday|#Tuesday". + * This is the same pattern type used by the applyPattern + * method. + * + * @param pattern The pattern of terminators and format strings. + * + * @exception IllegalArgumentException If the pattern is not valid + */ + public ChoiceFormat (String newPattern) + { + super (); + applyPattern (newPattern); + } + + /** + * This method initializes a new instance of ChoiceFormat that + * will use the specified range terminators and format strings. + * + * @param choiceLimits The array of range terminators + * @param choiceFormats The array of format strings + */ + public ChoiceFormat (double[] choiceLimits, String[] choiceFormats) + { + super (); + setChoices (choiceLimits, choiceFormats); + } + + /** + * This method tests this object for equality with the specified + * object. This will be true if and only if: + *

      + *
    • The specified object is not null.
    • + *
    • The specified object is an instance of ChoiceFormat.
    • + *
    • The termination ranges and format strings are identical to + * this object's.
    • + *
    + * + * @param obj The object to test for equality against. + * + * @return true if the specified object is equal to + * this one, false otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof ChoiceFormat)) + return false; + ChoiceFormat cf = (ChoiceFormat) obj; + if (choiceLimits.length != cf.choiceLimits.length) + return false; + for (int i = choiceLimits.length - 1; i >= 0; --i) + { + if (choiceLimits[i] != cf.choiceLimits[i] + || !choiceFormats[i].equals(cf.choiceFormats[i])) + return false; + } + return true; + } + + /** + * This method appends the appropriate format string to the specified + * StringBuffer based on the supplied long + * argument. + * + * @param number The number used for determine (based on the range + * terminators) which format string to append. + * @param sb The StringBuffer to append the format string to. + * @param status Unused. + * + * @return The StringBuffer with the format string appended. + */ + public StringBuffer format (long num, StringBuffer appendBuf, + FieldPosition pos) + { + return format ((double) num, appendBuf, pos); + } + + /** + * This method appends the appropriate format string to the specified + * StringBuffer based on the supplied double + * argument. + * + * @param number The number used for determine (based on the range + * terminators) which format string to append. + * @param sb The StringBuffer to append the format string to. + * @param status Unused. + * + * @return The StringBuffer with the format string appended. + */ + public StringBuffer format (double num, StringBuffer appendBuf, + FieldPosition pos) + { + if (choiceLimits.length == 0) + return appendBuf; + + int index = 0; + if (! Double.isNaN(num) && num >= choiceLimits[0]) + { + for (; index < choiceLimits.length - 1; ++index) + { + if (choiceLimits[index] <= num && num < choiceLimits[index + 1]) + break; + } + } + + return appendBuf.append(choiceFormats[index]); + } + + /** + * This method returns the list of format strings in use. + * + * @return The list of format objects. + */ + public Object[] getFormats () + { + return (Object[]) choiceFormats.clone(); + } + + /** + * This method returns the list of range terminators in use. + * + * @return The list of range terminators. + */ + public double[] getLimits () + { + return (double[]) choiceLimits.clone(); + } + + /** + * This method returns a hash value for this object + * + * @return A hash value for this object. + */ + public int hashCode () + { + int hash = 0; + for (int i = 0; i < choiceLimits.length; ++i) + { + long v = Double.doubleToLongBits(choiceLimits[i]); + hash ^= (v ^ (v >>> 32)); + hash ^= choiceFormats[i].hashCode(); + } + return hash; + } + + /** + * This method returns the lowest possible double greater than the + * specified double. If the specified double value is equal to + * Double.NaN then that is the value returned. + * + * @param d The specified double + * + * @return The lowest double value greater than the specified double. + */ + public static final double nextDouble (double d) + { + return nextDouble (d, true); + } + + /** + * This method returns a double that is either the next highest double + * or next lowest double compared to the specified double depending on the + * value of the passed boolean parameter. If the boolean parameter is + * true, then the lowest possible double greater than the + * specified double will be returned. Otherwise the highest possible + * double less than the specified double will be returned. + * + * @param d The specified double + * @param positive true to return the next highest + * double, false otherwise. + * + * @return The next highest or lowest double value. + */ + public static double nextDouble (double d, boolean next) + { + if (Double.isInfinite(d) || Double.isNaN(d)) + return d; + + long bits = Double.doubleToLongBits(d); + + long mantMask = (1L << mantissaBits) - 1; + long mantissa = bits & mantMask; + + long expMask = (1L << exponentBits) - 1; + long exponent = (bits >>> mantissaBits) & expMask; + + if (next ^ (bits < 0)) // Increment magnitude + { + if (mantissa == (1L << mantissaBits) - 1) + { + mantissa = 0L; + exponent++; + + // Check for absolute overflow. + if (exponent >= (1L << mantissaBits)) + return (bits > 0) ? Double.POSITIVE_INFINITY + : Double.NEGATIVE_INFINITY; + } + else + mantissa++; + } + else // Decrement magnitude + { + if (exponent == 0L && mantissa == 0L) + { + // The only case where there is a change of sign + return next ? Double.MIN_VALUE : -Double.MIN_VALUE; + } + else + { + if (mantissa == 0L) + { + mantissa = (1L << mantissaBits) - 1; + exponent--; + } + else + mantissa--; + } + } + + long result = bits < 0 ? 1 : 0; + result = (result << exponentBits) | exponent; + result = (result << mantissaBits) | mantissa; + return Double.longBitsToDouble(result); + } + + /** + * I'm not sure what this method is really supposed to do, as it is + * not documented. + */ + public Number parse (String sourceStr, ParsePosition pos) + { + int index = pos.getIndex(); + for (int i = 0; i < choiceLimits.length; ++i) + { + if (sourceStr.startsWith(choiceFormats[i], index)) + { + pos.setIndex(index + choiceFormats[i].length()); + return new Double (choiceLimits[i]); + } + } + pos.setErrorIndex(index); + return new Double (Double.NaN); + } + + /** + * This method returns the highest possible double less than the + * specified double. If the specified double value is equal to + * Double.NaN then that is the value returned. + * + * @param d The specified double + * + * @return The highest double value less than the specified double. + */ + public static final double previousDouble (double d) + { + return nextDouble (d, false); + } + + /** + * This method sets new range terminators and format strings for this + * object. + * + * @param choiceLimits The new range terminators + * @param choiceFormats The new choice formats + */ + public void setChoices (double[] choiceLimits, String[] choiceFormats) + { + if (choiceLimits == null || choiceFormats == null) + throw new NullPointerException (); + if (choiceLimits.length != choiceFormats.length) + throw new IllegalArgumentException (); + this.choiceFormats = (String[]) choiceFormats.clone(); + this.choiceLimits = (double[]) choiceLimits.clone(); + } + + private void quoteString (StringBuffer dest, String text) + { + int max = text.length(); + for (int i = 0; i < max; ++i) + { + char c = text.charAt(i); + if (c == '\'') + { + dest.append(c); + dest.append(c); + } + else if (c == '#' || c == '|' || c == '\u2064' || c == '<') + { + dest.append('\''); + dest.append(c); + dest.append('\''); + } + else + dest.append(c); + } + } + + /** + * This method returns the range terminator list and format string list + * as a String suitable for using with the + * applyPattern method. + * + * @return A pattern string for this object + */ + public String toPattern () + { + StringBuffer result = new StringBuffer (); + for (int i = 0; i < choiceLimits.length; ++i) + { + result.append(choiceLimits[i]); + result.append('#'); + quoteString (result, choiceFormats[i]); + } + return result.toString(); + } + + /** + * This is the list of format strings. Note that this variable is + * specified by the serialization spec of this class. + */ + private String[] choiceFormats; + + /** + * This is the list of range terminator values. Note that this variable is + * specified by the serialization spec of this class. + */ + private double[] choiceLimits; + + // Number of mantissa bits in double. + private static final int mantissaBits = 52; + // Number of exponent bits in a double. + private static final int exponentBits = 11; + + private static final long serialVersionUID = 1795184449645032964L; +} diff --git a/libjava/classpath/java/text/CollationElementIterator.java b/libjava/classpath/java/text/CollationElementIterator.java new file mode 100644 index 0000000..60b148e --- /dev/null +++ b/libjava/classpath/java/text/CollationElementIterator.java @@ -0,0 +1,467 @@ +/* CollationElementIterator.java -- Walks through collation elements + Copyright (C) 1998, 1999, 2001, 2002, 2003, 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 java.text; + +import java.util.ArrayList; + +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct to JDK 1.1. + */ + +/** + * This class walks through the character collation elements of a + * String as defined by the collation rules in an instance of + * RuleBasedCollator. There is no public constructor for + * this class. An instance is created by calling the + * getCollationElementIterator method on + * RuleBasedCollator. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @author Guilhem Lavaux (guilhem.lavaux@free.fr) + */ +public final class CollationElementIterator +{ + /** + * This is a constant value that is returned to indicate that the end of + * the string was encountered. + */ + public static final int NULLORDER = -1; + + /** + * This is the RuleBasedCollator this object was created from. + */ + RuleBasedCollator collator; + + /** + * This is the String that is being iterated over. + */ + String text; + + /** + * This is the index into the collation decomposition where we are currently scanning. + */ + int index; + + /** + * This is the index into the String where we are currently scanning. + */ + int textIndex; + + /** + * Array containing the collation decomposition of the + * text given to the constructor. + */ + private RuleBasedCollator.CollationElement[] text_decomposition; + + /** + * Array containing the index of the specified block. + */ + private int[] text_indexes; + + /** + * This method initializes a new instance of CollationElementIterator + * to iterate over the specified String using the rules in the + * specified RuleBasedCollator. + * + * @param collator The RuleBasedCollation used for calculating collation values + * @param text The String to iterate over. + */ + CollationElementIterator(RuleBasedCollator collator, String text) + { + this.collator = collator; + + setText (text); + } + + RuleBasedCollator.CollationElement nextBlock() + { + if (index >= text_decomposition.length) + return null; + + RuleBasedCollator.CollationElement e = text_decomposition[index]; + + textIndex = text_indexes[index+1]; + + index++; + + return e; + } + + RuleBasedCollator.CollationElement previousBlock() + { + if (index == 0) + return null; + + index--; + RuleBasedCollator.CollationElement e = text_decomposition[index]; + + textIndex = text_indexes[index+1]; + + return e; + } + + /** + * This method returns the collation ordering value of the next character sequence + * in the string (it may be an extended character following collation rules). + * This method will return NULLORDER if the + * end of the string was reached. + * + * @return The collation ordering value. + */ + public int next() + { + RuleBasedCollator.CollationElement e = nextBlock(); + + if (e == null) + return NULLORDER; + + return e.getValue(); + } + + /** + * This method returns the collation ordering value of the previous character + * in the string. This method will return NULLORDER if the + * beginning of the string was reached. + * + * @return The collation ordering value. + */ + public int previous() + { + RuleBasedCollator.CollationElement e = previousBlock(); + + if (e == null) + return NULLORDER; + + return e.getValue(); + } + + /** + * This method returns the primary order value for the given collation + * value. + * + * @param value The collation value returned from next() or previous(). + * + * @return The primary order value of the specified collation value. This is the high 16 bits. + */ + public static int primaryOrder(int order) + { + // From the JDK 1.2 spec. + return order >>> 16; + } + + /** + * This method resets the internal position pointer to read from the + * beginning of the String again. + */ + public void reset() + { + index = 0; + textIndex = 0; + } + + /** + * This method returns the secondary order value for the given collation + * value. + * + * @param value The collation value returned from next() or previous(). + * + * @return The secondary order value of the specified collation value. This is the bits 8-15. + */ + public static short secondaryOrder(int order) + { + // From the JDK 1.2 spec. + return (short) ((order >>> 8) & 255); + } + + /** + * This method returns the tertiary order value for the given collation + * value. + * + * @param value The collation value returned from next() or previous(). + * + * @return The tertiary order value of the specified collation value. This is the low eight bits. + */ + public static short tertiaryOrder(int order) + { + // From the JDK 1.2 spec. + return (short) (order & 255); + } + + /** + * This method sets the String that it is iterating over + * to the specified String. + * + * @param text The new String to iterate over. + * + * @since 1.2 + */ + public void setText(String text) + { + int idx = 0; + int idx_idx = 0; + int alreadyExpanded = 0; + int idxToMove = 0; + + this.text = text; + this.index = 0; + + String work_text = text.intern(); + + ArrayList a_element = new ArrayList(); + ArrayList a_idx = new ArrayList(); + + // Build element collection ordered as they come in "text". + while (idx < work_text.length()) + { + String key, key_old; + + Object object = null; + int p = 1; + + // IMPROVE: use a TreeMap with a prefix-ordering rule. + key_old = key = null; + do + { + if (object != null) + key_old = key; + key = work_text.substring (idx, idx+p); + object = collator.prefix_tree.get (key); + if (object != null && idx < alreadyExpanded) + { + RuleBasedCollator.CollationElement prefix = (RuleBasedCollator.CollationElement)object; + if (prefix.expansion != null && + prefix.expansion.startsWith(work_text.substring(0, idx))) + { + object = null; + key = key_old; + } + } + p++; + } + while (idx+p <= work_text.length()); + + if (object == null) + key = key_old; + + RuleBasedCollator.CollationElement prefix = + (RuleBasedCollator.CollationElement) collator.prefix_tree.get (key); + + /* + * First case: There is no such sequence in the database. + * We will have to build one from the context. + */ + if (prefix == null) + { + /* + * We are dealing with sequences in an expansion. They + * are treated as accented characters (tertiary order). + */ + if (alreadyExpanded > 0) + { + RuleBasedCollator.CollationElement e = + collator.getDefaultAccentedElement (work_text.charAt (idx)); + + a_element.add (e); + a_idx.add (new Integer(idx_idx)); + idx++; + alreadyExpanded--; + if (alreadyExpanded == 0) + { + /* There is not any characters left in the expansion set. + * We can increase the pointer in the source string. + */ + idx_idx += idxToMove; + idxToMove = 0; + } + else + idx_idx++; + } + else + { + /* This is a normal character. */ + RuleBasedCollator.CollationElement e = + collator.getDefaultElement (work_text.charAt (idx)); + Integer i_ref = new Integer(idx_idx); + + /* Don't forget to mark it as a special sequence so the + * string can be ordered. + */ + a_element.add (RuleBasedCollator.SPECIAL_UNKNOWN_SEQ); + a_idx.add (i_ref); + a_element.add (e); + a_idx.add (i_ref); + idx_idx++; + idx++; + } + continue; + } + + /* + * Second case: Here we have found a matching sequence. + * Here we have an expansion string prepend it to the "work text" and + * add the corresponding sorting element. We must also mark + */ + if (prefix.expansion != null) + { + work_text = prefix.expansion + + work_text.substring (idx+prefix.key.length()); + idx = 0; + a_element.add (prefix); + a_idx.add (new Integer(idx_idx)); + if (alreadyExpanded == 0) + idxToMove = prefix.key.length(); + alreadyExpanded += prefix.expansion.length()-prefix.key.length(); + } + else + { + /* Third case: the simplest. We have got the prefix and it + * has not to be expanded. + */ + a_element.add (prefix); + a_idx.add (new Integer(idx_idx)); + idx += prefix.key.length(); + /* If the sequence is in an expansion, we must decrease the + * counter. + */ + if (alreadyExpanded > 0) + { + alreadyExpanded -= prefix.key.length(); + if (alreadyExpanded == 0) + { + idx_idx += idxToMove; + idxToMove = 0; + } + } + else + idx_idx += prefix.key.length(); + } + } + + text_decomposition = (RuleBasedCollator.CollationElement[]) + a_element.toArray(new RuleBasedCollator.CollationElement[a_element.size()]); + text_indexes = new int[a_idx.size()+1]; + for (int i = 0; i < a_idx.size(); i++) + { + text_indexes[i] = ((Integer)a_idx.get(i)).intValue(); + } + text_indexes[a_idx.size()] = text.length(); + } + + /** + * This method sets the String that it is iterating over + * to the String represented by the specified + * CharacterIterator. + * + * @param source The CharacterIterator containing the new + * String to iterate over. + */ + public void setText(CharacterIterator source) + { + StringBuffer expand = new StringBuffer(); + + // For now assume we read from the beginning of the string. + for (char c = source.first(); + c != CharacterIterator.DONE; + c = source.next()) + expand.append(c); + + setText(expand.toString()); + } + + /** + * This method returns the current offset into the String + * that is being iterated over. + * + * @return The iteration index position. + * + * @since 1.2 + */ + public int getOffset() + { + return textIndex; + } + + /** + * This method sets the iteration index position into the current + * String to the specified value. This value must not + * be negative and must not be greater than the last index position + * in the String. + * + * @param offset The new iteration index position. + * + * @exception IllegalArgumentException If the new offset is not valid. + */ + public void setOffset(int offset) + { + if (offset < 0) + throw new IllegalArgumentException("Negative offset: " + offset); + + if (offset > (text.length() - 1)) + throw new IllegalArgumentException("Offset too large: " + offset); + + for (index = 0; index < text_decomposition.length; index++) + { + if (offset <= text_indexes[index]) + break; + } + /* + * As text_indexes[0] == 0, we should not have to take care whether index is + * greater than 0. It is always. + */ + if (text_indexes[index] == offset) + textIndex = offset; + else + textIndex = text_indexes[index-1]; + } + + /** + * This method returns the maximum length of any expansion sequence that + * ends with the specified collation order value. (Whatever that means). + * + * @param value The collation order value + * + * @param The maximum length of an expansion sequence. + */ + public int getMaxExpansion(int value) + { + return 1; + } +} diff --git a/libjava/classpath/java/text/CollationKey.java b/libjava/classpath/java/text/CollationKey.java new file mode 100644 index 0000000..f7e3a24 --- /dev/null +++ b/libjava/classpath/java/text/CollationKey.java @@ -0,0 +1,199 @@ +/* CollationKey.java -- Precomputed collation value + Copyright (C) 1998, 1999, 2000, 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 java.text; + +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This class represents a pre-computed series of bits representing a + * String for under a particular Collator. This + * value may be compared bitwise against another CollationKey + * representing a different String under the same + * Collator in a manner than is usually more efficient than + * using the raw Collator compare methods. There is overhead + * associated with calculating this value, so it is generally not + * advisable to compute CollationKey's unless multiple + * comparisons against a String will be done. (For example, + * in a sort routine). + *

    + * This class cannot be instantiated directly. Instead, a + * CollationKey is created by calling the + * getCollationKey method on an instance of Collator. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @date March 25, 1999 + */ +public final class CollationKey implements Comparable +{ + /** + * This is the Collator this object was created from. + */ + private Collator collator; + + /** + * This is the String this object represents. + */ + private String originalText; + + /** + * This is the bit value for this key. + */ + private byte[] key; + + CollationKey (Collator collator, String originalText, byte[] key) + { + this.collator = collator; + this.originalText = originalText; + this.key = key; + } + + /** + * This method compares the specified object to this one. An integer is + * returned which indicates whether the specified object is less than, + * greater than, or equal to this object. + * + * @param ck The CollationKey to compare against this one. + * + * @return A negative integer if this object is less than the specified object, 0 if it is equal or a positive integer if it is greater than the specified object. + */ + public int compareTo (CollationKey ck) + { + int max = Math.min (key.length, ck.key.length); + + for (int i = 0; i < max; ++i) + { + if (key[i] != ck.key[i]) + return key[i] - ck.key[i]; + } + + return key.length - ck.key.length; + } + + /** + * This method compares the specified object to this one. The specified + * object must be an instance of CollationKey or an exception + * will be thrown. An integer is returned which indicates whether the + * specified object is less than, greater than, or equal to this object. + * + * @param obj The Object to compare against this one. + * + * @return A negative integer if this object is less than the specified object, 0 if it is equal or a positive integer if it is greater than the specified object. + */ + public int compareTo (Object obj) + { + return compareTo ((CollationKey) obj); + } + + /** + * This method tests the specified Object for equality with + * this object. This will be true if and only if: + *

    + *

      + *
    • The specified object must not be null
    • + *
    • The specified object is an instance of CollationKey.
    • + *
    • The specified object was created from the same Collator + * as this object.
    • + *
    • The specified object has the same source string and bit key as + * this object.
    • + *
    + * + * @param obj The Object to test for equality. + * + * @return true if the specified object is equal to this one, false otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof CollationKey)) + return false; + + CollationKey ck = (CollationKey) obj; + + if (ck.collator != collator) + return false; + + if (!ck.getSourceString ().equals (getSourceString ())) + return false; + + if (!ck.toByteArray ().equals (toByteArray ())) + return false; + + return true; + } + + /** + * This method returns the String that this object was created + * from. + * + * @return The source String for this object. + */ + public String getSourceString() + { + return originalText; + } + + /** + * This method returns a hash value for this object. The hash value + * returned will be the hash code of the bit key so that identical bit + * keys will return the same value. + * + * @return A hash value for this object. + */ + public int hashCode() + { + // We just follow BitSet instead of thinking up something new. + long h = originalText.hashCode(); + for (int i = key.length - 1; i >= 0; --i) + h ^= key[i] * (i + 1); + return (int) ((h >> 32) ^ h); + } + + /** + * This method returns the collation bit sequence as a byte array. + * + * @param A byte array containing the collation bit sequence. + */ + public byte[] toByteArray() + { + return key; + } +} diff --git a/libjava/classpath/java/text/Collator.java b/libjava/classpath/java/text/Collator.java new file mode 100644 index 0000000..633bc67 --- /dev/null +++ b/libjava/classpath/java/text/Collator.java @@ -0,0 +1,400 @@ +/* Collator.java -- Perform locale dependent String comparisons. + Copyright (C) 1998, 1999, 2000, 2001, 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 java.text; + +import java.util.Comparator; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * This class is the abstract superclass of classes which perform + * locale dependent String comparisons. A caller requests + * an instance of Collator for a particular locale using + * the getInstance() static method in this class. That method + * will return a locale specific subclass of Collator which + * can be used to perform String comparisons for that locale. + * If a subclass of Collator cannot be located for a particular + * locale, a default instance for the current locale will be returned. + * + * In addition to setting the correct locale, there are two additional + * settings that can be adjusted to affect String comparisons: + * strength and decomposition. The strength value determines the level + * of signficance of character differences required for them to sort + * differently. (For example, whether or not capital letters are considered + * different from lower case letters). The decomposition value affects how + * variants of the same character are treated for sorting purposes. (For + * example, whether or not an accent is signficant or not). These settings + * are described in detail in the documentation for the methods and values + * that are related to them. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @date March 18, 1999 + */ +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Mostly complete, but parts stubbed out. Look for FIXME. + */ +public abstract class Collator implements Comparator, Cloneable +{ + /** + * This constant is a strength value which indicates that only primary + * differences between characters will be considered signficant. As an + * example, two completely different English letters such as 'a' and 'b' + * are considered to have a primary difference. + */ + public static final int PRIMARY = 0; + + /** + * This constant is a strength value which indicates that only secondary + * or primary differences between characters will be considered + * significant. An example of a secondary difference between characters + * are instances of the same letter with different accented forms. + */ + public static final int SECONDARY = 1; + + /** + * This constant is a strength value which indicates that tertiary, + * secondary, and primary differences will be considered during sorting. + * An example of a tertiary difference is capitalization of a given letter. + * This is the default value for the strength setting. + */ + public static final int TERTIARY = 2; + + /** + * This constant is a strength value which indicates that any difference + * at all between character values are considered significant. + */ + public static final int IDENTICAL = 3; + + /** + * This constant indicates that accented characters won't be decomposed + * when performing comparisons. This will yield the fastest results, but + * will only work correctly in call cases for languages which do not + * use accents such as English. + */ + public static final int NO_DECOMPOSITION = 0; + + /** + * This constant indicates that only characters which are canonical variants + * in Unicode 2.0 will be decomposed prior to performing comparisons. This + * will cause accented languages to be sorted correctly. This is the + * default decomposition value. + */ + public static final int CANONICAL_DECOMPOSITION = 1; + + /** + * This constant indicates that both canonical variants and compatibility + * variants in Unicode 2.0 will be decomposed prior to performing + * comparisons. This is the slowest mode, but is required to get the + * correct sorting for certain languages with certain special formats. + */ + public static final int FULL_DECOMPOSITION = 2; + + /** + * This method initializes a new instance of Collator to have + * the default strength (TERTIARY) and decomposition + * (CANONICAL_DECOMPOSITION) settings. This constructor is protected and + * is for use by subclasses only. Non-subclass callers should use the + * static getInstance() methods of this class to instantiate + * Collation objects for the desired locale. + */ + protected Collator () + { + strength = TERTIARY; + decmp = CANONICAL_DECOMPOSITION; + } + + /** + * This method compares the two String's and returns an + * integer indicating whether or not the first argument is less than, + * equal to, or greater than the second argument. The comparison is + * performed according to the rules of the locale for this + * Collator and the strength and decomposition rules in + * effect. + * + * @param str1 The first object to compare + * @param str2 The second object to compare + * + * @return A negative integer if str1 < str2, 0 if str1 == str2, or + * a positive integer if str1 > str2. + */ + public abstract int compare (String source, String target); + + /** + * This method compares the two Object's and returns an + * integer indicating whether or not the first argument is less than, + * equal to, or greater than the second argument. These two objects + * must be String's or an exception will be thrown. + * + * @param obj1 The first object to compare + * @param obj2 The second object to compare + * + * @return A negative integer if obj1 < obj2, 0 if obj1 == obj2, or + * a positive integer if obj1 > obj2. + * + * @exception ClassCastException If the arguments are not instances + * of String. + */ + public int compare (Object o1, Object o2) + { + return compare ((String) o1, (String) o2); + } + + /** + * This method tests the specified object for equality against this + * object. This will be true if and only if the following conditions are + * met: + *
      + *
    • The specified object is not null.
    • + *
    • The specified object is an instance of Collator.
    • + *
    • The specified object has the same strength and decomposition + * settings as this object.
    • + *
    + * + * @param obj The Object to test for equality against + * this object. + * + * @return true if the specified object is equal to + * this one, false otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof Collator)) + return false; + Collator c = (Collator) obj; + return decmp == c.decmp && strength == c.strength; + } + + /** + * This method tests whether the specified String's are equal + * according to the collation rules for the locale of this object and + * the current strength and decomposition settings. + * + * @param str1 The first String to compare + * @param str2 The second String to compare + * + * @return true if the two strings are equal, + * false otherwise. + */ + public boolean equals (String source, String target) + { + return compare (source, target) == 0; + } + + /** + * This method returns a copy of this Collator object. + * + * @return A duplicate of this object. + */ + public Object clone () + { + try + { + return super.clone (); + } + catch (CloneNotSupportedException _) + { + return null; + } + } + + /** + * This method returns an array of Locale objects which is + * the list of locales for which Collator objects exist. + * + * @return The list of locales for which Collator's exist. + */ + public static synchronized Locale[] getAvailableLocales () + { + // FIXME + Locale[] l = new Locale[1]; + l[0] = Locale.US; + return l; + } + + /** + * This method transforms the specified String into a + * CollationKey for faster comparisons. This is useful when + * comparisons against a string might be performed multiple times, such + * as during a sort operation. + * + * @param str The String to convert. + * + * @return A CollationKey for the specified String. + */ + public abstract CollationKey getCollationKey (String source); + + /** + * This method returns the current decomposition setting for this + * object. This * will be one of NO_DECOMPOSITION, + * CANONICAL_DECOMPOSITION, or * FULL_DECOMPOSITION. See the + * documentation for those constants for an * explanation of this + * setting. + * + * @return The current decomposition setting. + */ + public synchronized int getDecomposition () + { + return decmp; + } + + /** + * This method returns an instance of Collator for the + * default locale. + * + * @return A Collator for the default locale. + */ + public static Collator getInstance () + { + return getInstance (Locale.getDefault()); + } + + /** + * This method returns an instance of Collator for the + * specified locale. If no Collator exists for the desired + * locale, a Collator for the default locale will be returned. + * + * @param locale The desired localed to load a Collator for. + * + * @return A Collator for the requested locale + */ + public static Collator getInstance (Locale loc) + { + ResourceBundle res; + String pattern; + try + { + res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + loc, ClassLoader.getSystemClassLoader()); + pattern = res.getString("collation_rules"); + } + catch (MissingResourceException x) + { + pattern = "<0<1<2<3<4<5<6<7<8<9= allFields.length || calendarField < 0) + throw new IllegalArgumentException("no such calendar field (" + + calendarField + ")"); + + return allFields[calendarField]; + } + + protected Object readResolve() throws InvalidObjectException + { + String s = getName(); + + for (int i=0;iDateFormat
    . + */ + protected DateFormat () + { + } + + /** + * This method tests this object for equality against the specified object. + * The two objects will be considered equal if an only if the specified + * object: + *

    + *

      + *
    • Is not null.
    • + *
    • Is an instance of DateFormat.
    • + *
    • Has the same numberFormat field value as this object.
    • + *
    + * + * @param obj The object to test for equality against. + * + * @return true if the specified object is equal to this object, + * false otherwise. + */ + public boolean equals (Object obj) + { + if (!(obj instanceof DateFormat)) + return false; + + DateFormat d = (DateFormat) obj; + + return numberFormat.equals(d.numberFormat); + } + + /** + * This method returns a copy of this object. + * + * @return A copy of this object. + */ + public Object clone () + { + // We know the superclass just call's Object's generic cloner. + return super.clone (); + } + + /** + * This method formats the specified Object into a date string + * and appends it to the specified StringBuffer. + * The specified object must be an instance of Number or + * Date or an IllegalArgumentException will be + * thrown. + * + * @param obj The Object to format. + * @param toAppendTo The StringBuffer to append the resultant + * String to. + * @param fieldPosition Is updated to the start and end index of the + * specified field. + * + * @return The StringBuffer supplied on input, with the + * formatted date/time appended. + */ + public final StringBuffer format (Object obj, + StringBuffer buf, FieldPosition pos) + { + if (obj instanceof Number) + obj = new Date(((Number) obj).longValue()); + else if (! (obj instanceof Date)) + throw new IllegalArgumentException + ("Cannot format given Object as a Date"); + + return format ((Date) obj, buf, pos); + } + + /** + * Formats the date argument according to the pattern specified. + * + * @param date The formatted date. + */ + public final String format (Date date) + { + StringBuffer sb = new StringBuffer (); + format (date, sb, new FieldPosition (MONTH_FIELD)); + return sb.toString(); + } + + /** + * This method formats a Date into a string and appends it + * to the specified StringBuffer. + * + * @param date The Date value to format. + * @param toAppendTo The StringBuffer to append the resultant + * String to. + * @param fieldPosition Is updated to the start and end index of the + * specified field. + * + * @return The StringBuffer supplied on input, with the + * formatted date/time appended. + */ + public abstract StringBuffer format (Date date, + StringBuffer buf, FieldPosition pos); + + /** + * This method returns a list of available locales supported by this + * class. + */ + public static Locale[] getAvailableLocales() + { + return Locale.getAvailableLocales(); + } + + /** + * This method returns the Calendar object being used by + * this object to parse/format datetimes. + * + * @return The Calendar being used by this object. + * + * @see java.util.Calendar + */ + public Calendar getCalendar () + { + return calendar; + } + + private static DateFormat computeInstance (int style, Locale loc, + boolean use_date, boolean use_time) + { + return computeInstance (style, style, loc, use_date, use_time); + } + + private static DateFormat computeInstance (int dateStyle, int timeStyle, + Locale loc, boolean use_date, + boolean use_time) + { + ResourceBundle res; + try + { + res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + loc, ClassLoader.getSystemClassLoader()); + } + catch (MissingResourceException x) + { + res = null; + } + + String pattern = null; + if (use_date) + { + String name, def; + switch (dateStyle) + { + case FULL: + name = "fullDateFormat"; + def = "EEEE MMMM d, yyyy G"; + break; + case LONG: + name = "longDateFormat"; + def = "MMMM d, yyyy"; + break; + case MEDIUM: + name = "mediumDateFormat"; + def = "d-MMM-yy"; + break; + case SHORT: + name = "shortDateFormat"; + def = "M/d/yy"; + break; + default: + throw new IllegalArgumentException (); + } + try + { + pattern = res == null ? def : res.getString(name); + } + catch (MissingResourceException x) + { + pattern = def; + } + } + + if (use_time) + { + if (pattern == null) + pattern = ""; + else + pattern += " "; + + String name, def; + switch (timeStyle) + { + case FULL: + name = "fullTimeFormat"; + def = "h:mm:ss;S 'o''clock' a z"; + break; + case LONG: + name = "longTimeFormat"; + def = "h:mm:ss a z"; + break; + case MEDIUM: + name = "mediumTimeFormat"; + def = "h:mm:ss a"; + break; + case SHORT: + name = "shortTimeFormat"; + def = "h:mm a"; + break; + default: + throw new IllegalArgumentException (); + } + + String s; + try + { + s = res == null ? def : res.getString(name); + } + catch (MissingResourceException x) + { + s = def; + } + pattern += s; + } + + return new SimpleDateFormat (pattern, loc); + } + + /** + * This method returns an instance of DateFormat that will + * format using the default formatting style for dates. + * + * @return A new DateFormat instance. + */ + public static final DateFormat getDateInstance () + { + return getDateInstance (DEFAULT, Locale.getDefault()); + } + + /** + * This method returns an instance of DateFormat that will + * format using the specified formatting style for dates. + * + * @param style The type of formatting to perform. + * + * @return A new DateFormat instance. + */ + public static final DateFormat getDateInstance (int style) + { + return getDateInstance (style, Locale.getDefault()); + } + + /** + * This method returns an instance of DateFormat that will + * format using the specified formatting style for dates. The specified + * localed will be used in place of the default. + * + * @param style The type of formatting to perform. + * @param aLocale The desired locale. + * + * @return A new DateFormat instance. + */ + public static final DateFormat getDateInstance (int style, Locale loc) + { + return computeInstance (style, loc, true, false); + } + + /** + * This method returns a new instance of DateFormat that + * formats both dates and times using the SHORT style. + * + * @return A new DateFormatinstance. + */ + public static final DateFormat getDateTimeInstance () + { + return getDateTimeInstance (DEFAULT, DEFAULT, Locale.getDefault()); + } + + /** + * This method returns a new instance of DateFormat that + * formats both dates and times using the DEFAULT style. + * + * @return A new DateFormatinstance. + */ + public static final DateFormat getDateTimeInstance (int dateStyle, + int timeStyle) + { + return getDateTimeInstance (dateStyle, timeStyle, Locale.getDefault()); + } + + /** + * This method returns a new instance of DateFormat that + * formats both dates and times using the specified styles. + * + * @param dateStyle The desired style for date formatting. + * @param timeStyle The desired style for time formatting + * + * @return A new DateFormatinstance. + */ + public static final DateFormat getDateTimeInstance (int dateStyle, + int timeStyle, + Locale loc) + { + return computeInstance (dateStyle, timeStyle, loc, true, true); + } + + /** + * This method returns a new instance of DateFormat that + * formats both dates and times using the SHORT style. + * + * @return A new DateFormatinstance. + */ + public static final DateFormat getInstance () + { + // JCL book says SHORT. + return getDateTimeInstance (SHORT, SHORT, Locale.getDefault()); + } + + /** + * This method returns the NumberFormat object being used + * by this object to parse/format time values. + * + * @return The NumberFormat in use by this object. + */ + public NumberFormat getNumberFormat () + { + return numberFormat; + } + + /** + * This method returns an instance of DateFormat that will + * format using the default formatting style for times. + * + * @return A new DateFormat instance. + */ + public static final DateFormat getTimeInstance () + { + return getTimeInstance (DEFAULT, Locale.getDefault()); + } + + /** + * This method returns an instance of DateFormat that will + * format using the specified formatting style for times. + * + * @param style The type of formatting to perform. + * + * @return A new DateFormat instance. + */ + public static final DateFormat getTimeInstance (int style) + { + return getTimeInstance (style, Locale.getDefault()); + } + + /** + * This method returns an instance of DateFormat that will + * format using the specified formatting style for times. The specified + * localed will be used in place of the default. + * + * @param style The type of formatting to perform. + * @param aLocale The desired locale. + * + * @return A new DateFormat instance. + */ + public static final DateFormat getTimeInstance (int style, Locale loc) + { + return computeInstance (style, loc, false, true); + } + + /** + * This method returns the TimeZone object being used by + * this instance. + * + * @return The time zone in use. + */ + public TimeZone getTimeZone () + { + return calendar.getTimeZone(); + } + + /** + * This method returns a hash value for this object. + * + * @return A hash value for this object. + */ + public int hashCode () + { + if (numberFormat != null) + return numberFormat.hashCode(); + else + return 0; + } + + /** + * This method indicates whether or not the parsing of date and time + * values should be done in a lenient value. + * + * @return true if date/time parsing is lenient, + * false otherwise. + */ + public boolean isLenient () + { + return calendar.isLenient(); + } + + /** + * This method parses the specified date/time string. + * + * @param source The string to parse. + * @return The resultant date. + * + * @exception ParseException If the specified string cannot be parsed. + */ + public Date parse (String source) throws ParseException + { + ParsePosition pos = new ParsePosition(0); + Date result = parse (source, pos); + if (result == null) + { + int index = pos.getErrorIndex(); + if (index < 0) + index = pos.getIndex(); + throw new ParseException("invalid Date syntax in \"" + + source + '\"', index); + } + return result; + } + + /** + * This method parses the specified String into a + * Date. The pos argument contains the + * starting parse position on method entry and the ending parse + * position on method exit. + * + * @param text The string to parse. + * @param pos The starting parse position in entry, the ending parse + * position on exit. + * + * @return The parsed date, or null if the string cannot + * be parsed. + */ + public abstract Date parse (String source, ParsePosition pos); + + /** + * This method is identical to parse(String, ParsePosition), + * but returns its result as an Object instead of a + * Date. + * + * @param source The string to parse. + * @param pos The starting parse position in entry, the ending parse + * position on exit. + * + * @return The parsed date, or null if the string cannot + * be parsed. + */ + public Object parseObject (String source, ParsePosition pos) + { + return parse(source, pos); + } + + /** + * This method specified the Calendar that should be used + * by this object to parse/format datetimes. + * + * @param The new Calendar for this object. + * + * @see java.util.Calendar + */ + public void setCalendar (Calendar calendar) + { + this.calendar = calendar; + } + + /** + * This method specifies whether or not this object should be lenient in + * the syntax it accepts while parsing date/time values. + * + * @param lenient true if parsing should be lenient, + * false otherwise. + */ + public void setLenient (boolean lenient) + { + calendar.setLenient(lenient); + } + + /** + * This method specifies the NumberFormat object that should + * be used by this object to parse/format times. + * + * @param The NumberFormat in use by this object. + */ + public void setNumberFormat (NumberFormat numberFormat) + { + this.numberFormat = numberFormat; + } + + /** + * This method sets the time zone that should be used by this object. + * + * @param The new time zone. + */ + public void setTimeZone (TimeZone timeZone) + { + calendar.setTimeZone(timeZone); + } +} diff --git a/libjava/classpath/java/text/DateFormatSymbols.java b/libjava/classpath/java/text/DateFormatSymbols.java new file mode 100644 index 0000000..543a5c1 --- /dev/null +++ b/libjava/classpath/java/text/DateFormatSymbols.java @@ -0,0 +1,525 @@ +/* DateFormatSymbols.java -- Format over a range of numbers + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.StringTokenizer; + +/** + * This class acts as container for locale specific date/time formatting + * information such as the days of the week and the months of the year. + * @author Per Bothner (bothner@cygnus.com) + * @date October 24, 1998. + */ +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3. + * Status: Believed complete and correct. + */ +public class DateFormatSymbols implements java.io.Serializable, Cloneable +{ + String[] ampms; + String[] eras; + private String localPatternChars; + String[] months; + String[] shortMonths; + String[] shortWeekdays; + String[] weekdays; + private String[][] zoneStrings; + + private static final long serialVersionUID = -5987973545549424702L; + + // The order of these prefixes must be the same as in DateFormat + private static final String[] formatPrefixes = + { + "full", "long", "medium", "short" + }; + + // These are each arrays with a value for SHORT, MEDIUM, LONG, FULL, + // and DEFAULT (constants defined in java.text.DateFormat). While + // not part of the official spec, we need a way to get at locale-specific + // default formatting patterns. They are declared package scope so + // as to be easily accessible where needed (DateFormat, SimpleDateFormat). + transient String[] dateFormats; + transient String[] timeFormats; + + private static String[] getStringArray(ResourceBundle res, String name) + { + return res.getString(name).split("\u00ae"); + } + + private String[][] getZoneStrings(ResourceBundle res) + { + try + { + int index = 0; + String data = res.getString("zoneStrings"); + String[] zones = data.split("\u00a9"); + String[][] array = new String[zones.length][]; + for (int a = 0; a < zones.length; ++a) + array[a] = zones[a].split("\u00ae"); + return array; + } + catch (MissingResourceException e) + { + return new String[0][]; + } + } + + private String[] formatsForKey(ResourceBundle res, String key) + { + String[] values = new String[formatPrefixes.length]; + + for (int i = 0; i < formatPrefixes.length; i++) + values[i] = res.getString(formatPrefixes[i] + key); + + return values; + } + + /** + * This method initializes a new instance of DateFormatSymbols + * by loading the date format information for the specified locale. + * + * @param locale The locale for which date formatting symbols should + * be loaded. + */ + public DateFormatSymbols (Locale locale) throws MissingResourceException + { + ResourceBundle res + = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", locale, + ClassLoader.getSystemClassLoader()); + + ampms = getStringArray(res, "ampms"); + eras = getStringArray(res, "eras"); + localPatternChars = res.getString("localPatternChars"); + months = getStringArray(res, "months"); + shortMonths = getStringArray(res, "shortMonths"); + shortWeekdays = getStringArray(res, "shortWeekdays"); + weekdays = getStringArray(res, "weekdays"); + zoneStrings = getZoneStrings(res); + dateFormats = formatsForKey(res, "DateFormat"); + timeFormats = formatsForKey(res, "TimeFormat"); + } + + /** + * This method loads the format symbol information for the default + * locale. + */ + public DateFormatSymbols () throws MissingResourceException + { + this (Locale.getDefault()); + } + + /** + * This method returns the list of strings used for displaying AM or PM. + * This is a two element String array indexed by + * Calendar.AM and Calendar.PM + * + * @return The list of AM/PM display strings. + */ + public String[] getAmPmStrings() + { + return ampms; + } + + /** + * This method returns the list of strings used for displaying eras + * (e.g., "BC" and "AD"). This is a two element String + * array indexed by Calendar.BC and Calendar.AD. + * + * @return The list of era disply strings. + */ + public String[] getEras() + { + return eras; + } + + /** + * This method returns the pattern character information for this + * object. This is an 18 character string that contains the characters + * that are used in creating the date formatting strings in + * SimpleDateFormat. The following are the character + * positions in the string and which format character they correspond + * to (the character in parentheses is the default value in the US English + * locale): + *

    + *

      + *
    • 0 - era (G)
    • + *
    • 1 - year (y)
    • + *
    • 2 - month (M)
    • + *
    • 3 - day of month (d)
    • + *
    • 4 - hour out of 12, from 1-12 (h)
    • + *
    • 5 - hour out of 24, from 0-23 (H)
    • + *
    • 6 - minute (m)
    • + *
    • 7 - second (s)
    • + *
    • 8 - millisecond (S)
    • + *
    • 9 - date of week (E)
    • + *
    • 10 - date of year (D)
    • + *
    • 11 - day of week in month, eg. "4th Thur in Nov" (F)
    • + *
    • 12 - week in year (w)
    • + *
    • 13 - week in month (W)
    • + *
    • 14 - am/pm (a)
    • + *
    • 15 - hour out of 24, from 1-24 (k)
    • + *
    • 16 - hour out of 12, from 0-11 (K)
    • + *
    • 17 - time zone (z)
    • + *
    + * + * @return The format patter characters + */ + public String getLocalPatternChars() + { + return localPatternChars; + } + + /** + * This method returns the list of strings used for displaying month + * names (e.g., "January" and "February"). This is a thirteen element + * string array indexed by Calendar.JANUARY through + * Calendar.UNDECEMBER. Note that there are thirteen + * elements because some calendars have thriteen months. + * + * @return The list of month display strings. + */ + public String[] getMonths () + { + return months; + } + + /** + * This method returns the list of strings used for displaying abbreviated + * month names (e.g., "Jan" and "Feb"). This is a thirteen element + * String array indexed by Calendar.JANUARY + * through Calendar.UNDECEMBER. Note that there are thirteen + * elements because some calendars have thirteen months. + * + * @return The list of abbreviated month display strings. + */ + public String[] getShortMonths () + { + return shortMonths; + } + + /** + * This method returns the list of strings used for displaying abbreviated + * weekday names (e.g., "Sun" and "Mon"). This is an eight element + * String array indexed by Calendar.SUNDAY + * through Calendar.SATURDAY. Note that the first element + * of this array is ignored. + * + * @return This list of abbreviated weekday display strings. + */ + public String[] getShortWeekdays () + { + return shortWeekdays; + } + + /** + * This method returns the list of strings used for displaying weekday + * names (e.g., "Sunday" and "Monday"). This is an eight element + * String array indexed by Calendar.SUNDAY + * through Calendar.SATURDAY. Note that the first element + * of this array is ignored. + * + * @return This list of weekday display strings. + */ + public String[] getWeekdays () + { + return weekdays; + } + + /** + * This method returns this list of localized timezone display strings. + * This is a two dimensional String array where each row in + * the array contains five values: + *

    + *

      + *
    • 0 - The non-localized time zone id string.
    • + *
    • 1 - The long name of the time zone (standard time).
    • + *
    • 2 - The short name of the time zone (standard time).
    • + *
    • 3 - The long name of the time zone (daylight savings time).
    • + *
    • 4 - the short name of the time zone (daylight savings time).
    • + *
    + * + * @return The list of time zone display strings. + */ + public String[] [] getZoneStrings () + { + return zoneStrings; + } + + /** + * This method sets the list of strings used to display AM/PM values to + * the specified list. + * This is a two element String array indexed by + * Calendar.AM and Calendar.PM + * + * @param ampms The new list of AM/PM display strings. + */ + public void setAmPmStrings (String[] value) + { + ampms = value; + } + + /** + * This method sets the list of strings used to display time eras to + * to the specified list. + * This is a two element String + * array indexed by Calendar.BC and Calendar.AD. + * + * @param eras The new list of era disply strings. + */ + public void setEras (String[] value) + { + eras = value; + } + + /** + * This method sets the list of characters used to specific date/time + * formatting strings. + * This is an 18 character string that contains the characters + * that are used in creating the date formatting strings in + * SimpleDateFormat. The following are the character + * positions in the string and which format character they correspond + * to (the character in parentheses is the default value in the US English + * locale): + *

    + *

      + *
    • 0 - era (G)
    • + *
    • 1 - year (y)
    • + *
    • 2 - month (M)
    • + *
    • 3 - day of month (d)
    • + *
    • 4 - hour out of 12, from 1-12 (h)
    • + *
    • 5 - hour out of 24, from 0-23 (H)
    • + *
    • 6 - minute (m)
    • + *
    • 7 - second (s)
    • + *
    • 8 - millisecond (S)
    • + *
    • 9 - date of week (E)
    • + *
    • 10 - date of year (D)
    • + *
    • 11 - day of week in month, eg. "4th Thur in Nov" (F)
    • + *
    • 12 - week in year (w)
    • + *
    • 13 - week in month (W)
    • + *
    • 14 - am/pm (a)
    • + *
    • 15 - hour out of 24, from 1-24 (k)
    • + *
    • 16 - hour out of 12, from 0-11 (K)
    • + *
    • 17 - time zone (z)
    • + *
    + * + * @param localPatternChars The new format patter characters + */ + public void setLocalPatternChars (String value) + { + localPatternChars = value; + } + + /** + * This method sets the list of strings used to display month names. + * This is a thirteen element + * string array indexed by Calendar.JANUARY through + * Calendar.UNDECEMBER. Note that there are thirteen + * elements because some calendars have thriteen months. + * + * @param months The list of month display strings. + */ + public void setMonths (String[] value) + { + months = value; + } + + /** + * This method sets the list of strings used to display abbreviated month + * names. + * This is a thirteen element + * String array indexed by Calendar.JANUARY + * through Calendar.UNDECEMBER. Note that there are thirteen + * elements because some calendars have thirteen months. + * + * @param shortMonths The new list of abbreviated month display strings. + */ + public void setShortMonths (String[] value) + { + shortMonths = value; + } + + /** + * This method sets the list of strings used to display abbreviated + * weekday names. + * This is an eight element + * String array indexed by Calendar.SUNDAY + * through Calendar.SATURDAY. Note that the first element + * of this array is ignored. + * + * @param shortWeekdays This list of abbreviated weekday display strings. + */ + public void setShortWeekdays (String[] value) + { + shortWeekdays = value; + } + + /** + * This method sets the list of strings used to display weekday names. + * This is an eight element + * String array indexed by Calendar.SUNDAY + * through Calendar.SATURDAY. Note that the first element + * of this array is ignored. + * + * @param weekdays This list of weekday display strings. + */ + public void setWeekdays (String[] value) + { + weekdays = value; + } + + /** + * This method sets the list of display strings for time zones. + * This is a two dimensional String array where each row in + * the array contains five values: + *

    + *

      + *
    • 0 - The non-localized time zone id string.
    • + *
    • 1 - The long name of the time zone (standard time).
    • + *
    • 2 - The short name of the time zone (standard time).
    • + *
    • 3 - The long name of the time zone (daylight savings time).
    • + *
    • 4 - the short name of the time zone (daylight savings time).
    • + *
    + * + * @return The list of time zone display strings. + */ + public void setZoneStrings (String[][] value) + { + zoneStrings = value; + } + + /* Does a "deep" equality test - recurses into arrays. */ + private static boolean equals (Object x, Object y) + { + if (x == y) + return true; + if (x == null || y == null) + return false; + if (! (x instanceof Object[]) || ! (y instanceof Object[])) + return x.equals(y); + Object[] xa = (Object[]) x; + Object[] ya = (Object[]) y; + if (xa.length != ya.length) + return false; + for (int i = xa.length; --i >= 0; ) + { + if (! equals(xa[i], ya[i])) + return false; + } + return true; + } + + private static int hashCode (Object x) + { + if (x == null) + return 0; + if (! (x instanceof Object[])) + return x.hashCode(); + Object[] xa = (Object[]) x; + int hash = 0; + for (int i = 0; i < xa.length; i++) + hash = 37 * hashCode(xa[i]); + return hash; + } + + /** + * This method tests a specified object for equality against this object. + * This will be true if and only if the specified object: + *

    + *

      + *
    • Is not null.
    • + *
    • Is an instance of DateFormatSymbols.
    • + *
    • Contains identical formatting symbols to this object.
    • + *
    + * + * @param obj The Object to test for equality against. + * + * @return true if the specified object is equal to this one, + * false otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof DateFormatSymbols)) + return false; + DateFormatSymbols other = (DateFormatSymbols) obj; + return (equals(ampms, other.ampms) + && equals(eras, other.eras) + && equals(localPatternChars, other.localPatternChars) + && equals(months, other.months) + && equals(shortMonths, other.shortMonths) + && equals(shortWeekdays, other.shortWeekdays) + && equals(weekdays, other.weekdays) + && equals(zoneStrings, other.zoneStrings)); + } + + /** + * Returns a new copy of this object. + * + * @param A copy of this object + */ + public Object clone () + { + try + { + return super.clone (); + } + catch (CloneNotSupportedException e) + { + return null; + } + } + + /** + * This method returns a hash value for this object. + * + * @return A hash value for this object. + */ + public int hashCode () + { + return (hashCode(ampms) + ^ hashCode(eras) + ^ hashCode(localPatternChars) + ^ hashCode(months) + ^ hashCode(shortMonths) + ^ hashCode(shortWeekdays) + ^ hashCode(weekdays) + ^ hashCode(zoneStrings)); + } +} diff --git a/libjava/classpath/java/text/DecimalFormat.java b/libjava/classpath/java/text/DecimalFormat.java new file mode 100644 index 0000000..6dadb0ce --- /dev/null +++ b/libjava/classpath/java/text/DecimalFormat.java @@ -0,0 +1,1435 @@ +/* DecimalFormat.java -- Formats and parses numbers + Copyright (C) 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 java.text; + +import gnu.java.text.AttributedFormatBuffer; +import gnu.java.text.FormatBuffer; +import gnu.java.text.FormatCharacterIterator; +import gnu.java.text.StringFormatBuffer; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.Currency; +import java.util.HashMap; +import java.util.Locale; + +/** + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @date March 4, 1999 + */ +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct to 1.2. + * Note however that the docs are very unclear about how format parsing + * should work. No doubt there are problems here. + */ +public class DecimalFormat extends NumberFormat +{ + // This is a helper for applyPatternWithSymbols. It reads a prefix + // or a suffix. It can cause some side-effects. + private int scanFix (String pattern, int index, FormatBuffer buf, + String patChars, DecimalFormatSymbols syms, + boolean is_suffix) + { + int len = pattern.length(); + boolean quoteStarted = false; + buf.clear(); + + boolean multiplierSet = false; + while (index < len) + { + char c = pattern.charAt(index); + + if (quoteStarted) + { + if (c == '\'') + quoteStarted = false; + else + buf.append(c); + index++; + continue; + } + + if (c == '\'' && index + 1 < len + && pattern.charAt(index + 1) == '\'') + { + buf.append(c); + index++; + } + else if (c == '\'') + { + quoteStarted = true; + } + else if (c == '\u00a4') + { + /* Currency interpreted later */ + buf.append(c); + } + else if (c == syms.getPercent()) + { + if (multiplierSet) + throw new IllegalArgumentException ("multiplier already set " + + "- index: " + index); + multiplierSet = true; + multiplier = 100; + buf.append(c, NumberFormat.Field.PERCENT); + } + else if (c == syms.getPerMill()) + { + if (multiplierSet) + throw new IllegalArgumentException ("multiplier already set " + + "- index: " + index); + multiplierSet = true; + multiplier = 1000; + buf.append(c, NumberFormat.Field.PERMILLE); + } + else if (patChars.indexOf(c) != -1) + { + // This is a pattern character. + break; + } + else + { + buf.append(c); + } + index++; + } + + if (quoteStarted) + throw new IllegalArgumentException ("pattern is lacking a closing quote"); + + return index; + } + + // A helper which reads a number format. + private int scanFormat (String pattern, int index, String patChars, + DecimalFormatSymbols syms, boolean is_positive) + { + int max = pattern.length(); + + int countSinceGroup = 0; + int zeroCount = 0; + boolean saw_group = false; + + // + // Scan integer part. + // + while (index < max) + { + char c = pattern.charAt(index); + + if (c == syms.getDigit()) + { + if (zeroCount > 0) + throw new IllegalArgumentException ("digit mark following " + + "zero - index: " + index); + ++countSinceGroup; + } + else if (c == syms.getZeroDigit()) + { + ++zeroCount; + ++countSinceGroup; + } + else if (c == syms.getGroupingSeparator()) + { + countSinceGroup = 0; + saw_group = true; + } + else + break; + + ++index; + } + + // We can only side-effect when parsing the positive format. + if (is_positive) + { + groupingUsed = saw_group; + groupingSize = (byte) countSinceGroup; + minimumIntegerDigits = zeroCount; + } + + // Early termination. + if (index == max || pattern.charAt(index) == syms.getGroupingSeparator()) + { + if (is_positive) + decimalSeparatorAlwaysShown = false; + return index; + } + + if (pattern.charAt(index) == syms.getDecimalSeparator()) + { + ++index; + + // + // Scan fractional part. + // + int hashCount = 0; + zeroCount = 0; + while (index < max) + { + char c = pattern.charAt(index); + if (c == syms.getZeroDigit()) + { + if (hashCount > 0) + throw new IllegalArgumentException ("zero mark " + + "following digit - index: " + index); + ++zeroCount; + } + else if (c == syms.getDigit()) + { + ++hashCount; + } + else if (c != syms.getExponential() + && c != syms.getPatternSeparator() + && c != syms.getPercent() + && c != syms.getPerMill() + && patChars.indexOf(c) != -1) + throw new IllegalArgumentException ("unexpected special " + + "character - index: " + index); + else + break; + + ++index; + } + + if (is_positive) + { + maximumFractionDigits = hashCount + zeroCount; + minimumFractionDigits = zeroCount; + } + + if (index == max) + return index; + } + + if (pattern.charAt(index) == syms.getExponential()) + { + // + // Scan exponential format. + // + zeroCount = 0; + ++index; + while (index < max) + { + char c = pattern.charAt(index); + if (c == syms.getZeroDigit()) + ++zeroCount; + else if (c == syms.getDigit()) + { + if (zeroCount > 0) + throw new + IllegalArgumentException ("digit mark following zero " + + "in exponent - index: " + + index); + } + else if (patChars.indexOf(c) != -1) + throw new IllegalArgumentException ("unexpected special " + + "character - index: " + + index); + else + break; + + ++index; + } + + if (is_positive) + { + useExponentialNotation = true; + minExponentDigits = (byte) zeroCount; + } + + maximumIntegerDigits = groupingSize; + groupingSize = 0; + if (maximumIntegerDigits > minimumIntegerDigits && maximumIntegerDigits > 0) + { + minimumIntegerDigits = 1; + exponentRound = maximumIntegerDigits; + } + else + exponentRound = 1; + } + + return index; + } + + // This helper function creates a string consisting of all the + // characters which can appear in a pattern and must be quoted. + private String patternChars (DecimalFormatSymbols syms) + { + StringBuffer buf = new StringBuffer (); + buf.append(syms.getDecimalSeparator()); + buf.append(syms.getDigit()); + buf.append(syms.getExponential()); + buf.append(syms.getGroupingSeparator()); + // Adding this one causes pattern application to fail. + // Of course, omitting is causes toPattern to fail. + // ... but we already have bugs there. FIXME. + // buf.append(syms.getMinusSign()); + buf.append(syms.getPatternSeparator()); + buf.append(syms.getPercent()); + buf.append(syms.getPerMill()); + buf.append(syms.getZeroDigit()); + buf.append('\u00a4'); + return buf.toString(); + } + + private void applyPatternWithSymbols(String pattern, DecimalFormatSymbols syms) + { + // Initialize to the state the parser expects. + negativePrefix = ""; + negativeSuffix = ""; + positivePrefix = ""; + positiveSuffix = ""; + decimalSeparatorAlwaysShown = false; + groupingSize = 0; + minExponentDigits = 0; + multiplier = 1; + useExponentialNotation = false; + groupingUsed = false; + maximumFractionDigits = 0; + maximumIntegerDigits = MAXIMUM_INTEGER_DIGITS; + minimumFractionDigits = 0; + minimumIntegerDigits = 1; + + AttributedFormatBuffer buf = new AttributedFormatBuffer (); + String patChars = patternChars (syms); + + int max = pattern.length(); + int index = scanFix (pattern, 0, buf, patChars, syms, false); + buf.sync(); + positivePrefix = buf.getBuffer().toString(); + positivePrefixRanges = buf.getRanges(); + positivePrefixAttrs = buf.getAttributes(); + + index = scanFormat (pattern, index, patChars, syms, true); + + index = scanFix (pattern, index, buf, patChars, syms, true); + buf.sync(); + positiveSuffix = buf.getBuffer().toString(); + positiveSuffixRanges = buf.getRanges(); + positiveSuffixAttrs = buf.getAttributes(); + + if (index == pattern.length()) + { + // No negative info. + negativePrefix = null; + negativeSuffix = null; + } + else + { + if (pattern.charAt(index) != syms.getPatternSeparator()) + throw new IllegalArgumentException ("separator character " + + "expected - index: " + index); + + index = scanFix (pattern, index + 1, buf, patChars, syms, false); + buf.sync(); + negativePrefix = buf.getBuffer().toString(); + negativePrefixRanges = buf.getRanges(); + negativePrefixAttrs = buf.getAttributes(); + + // We parse the negative format for errors but we don't let + // it side-effect this object. + index = scanFormat (pattern, index, patChars, syms, false); + + index = scanFix (pattern, index, buf, patChars, syms, true); + buf.sync(); + negativeSuffix = buf.getBuffer().toString(); + negativeSuffixRanges = buf.getRanges(); + negativeSuffixAttrs = buf.getAttributes(); + + if (index != pattern.length()) + throw new IllegalArgumentException ("end of pattern expected " + + "- index: " + index); + } + } + + public void applyLocalizedPattern (String pattern) + { + // JCL p. 638 claims this throws a ParseException but p. 629 + // contradicts this. Empirical tests with patterns of "0,###.0" + // and "#.#.#" corroborate the p. 629 statement that an + // IllegalArgumentException is thrown. + applyPatternWithSymbols (pattern, symbols); + } + + public void applyPattern (String pattern) + { + // JCL p. 638 claims this throws a ParseException but p. 629 + // contradicts this. Empirical tests with patterns of "0,###.0" + // and "#.#.#" corroborate the p. 629 statement that an + // IllegalArgumentException is thrown. + applyPatternWithSymbols (pattern, nonLocalizedSymbols); + } + + public Object clone () + { + DecimalFormat c = (DecimalFormat) super.clone (); + c.symbols = (DecimalFormatSymbols) symbols.clone (); + return c; + } + + /** + * Constructs a DecimalFormat which uses the default + * pattern and symbols. + */ + public DecimalFormat () + { + this ("#,##0.###"); + } + + /** + * Constructs a DecimalFormat which uses the given + * pattern and the default symbols for formatting and parsing. + * + * @param pattern the non-localized pattern to use. + * @throws NullPointerException if any argument is null. + * @throws IllegalArgumentException if the pattern is invalid. + */ + public DecimalFormat (String pattern) + { + this (pattern, new DecimalFormatSymbols ()); + } + + /** + * Constructs a DecimalFormat using the given pattern + * and formatting symbols. This construction method is used to give + * complete control over the formatting process. + * + * @param pattern the non-localized pattern to use. + * @param symbols the set of symbols used for parsing and formatting. + * @throws NullPointerException if any argument is null. + * @throws IllegalArgumentException if the pattern is invalid. + */ + public DecimalFormat(String pattern, DecimalFormatSymbols symbols) + { + this.symbols = (DecimalFormatSymbols) symbols.clone(); + applyPattern(pattern); + } + + private boolean equals(String s1, String s2) + { + if (s1 == null || s2 == null) + return s1 == s2; + return s1.equals(s2); + } + + /** + * Tests this instance for equality with an arbitrary object. This method + * returns true if: + *
      + *
    • obj is not null;
    • + *
    • obj is an instance of DecimalFormat;
    • + *
    • this instance and obj have the same attributes;
    • + *
    + * + * @param obj the object (null permitted). + * + * @return A boolean. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof DecimalFormat)) + return false; + DecimalFormat dup = (DecimalFormat) obj; + return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown + && groupingUsed == dup.groupingUsed + && groupingSize == dup.groupingSize + && multiplier == dup.multiplier + && useExponentialNotation == dup.useExponentialNotation + && minExponentDigits == dup.minExponentDigits + && minimumIntegerDigits == dup.minimumIntegerDigits + && maximumIntegerDigits == dup.maximumIntegerDigits + && minimumFractionDigits == dup.minimumFractionDigits + && maximumFractionDigits == dup.maximumFractionDigits + && equals(negativePrefix, dup.negativePrefix) + && equals(negativeSuffix, dup.negativeSuffix) + && equals(positivePrefix, dup.positivePrefix) + && equals(positiveSuffix, dup.positiveSuffix) + && symbols.equals(dup.symbols)); + } + + private void formatInternal (double number, FormatBuffer dest, + FieldPosition fieldPos) + { + // A very special case. + if (Double.isNaN(number)) + { + dest.append(symbols.getNaN()); + if (fieldPos != null && + (fieldPos.getField() == INTEGER_FIELD || + fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER)) + { + int index = dest.length(); + fieldPos.setBeginIndex(index - symbols.getNaN().length()); + fieldPos.setEndIndex(index); + } + return; + } + + boolean is_neg = number < 0; + if (is_neg) + { + if (negativePrefix != null) + { + dest.append(substituteCurrency(negativePrefix, number), + negativePrefixRanges, negativePrefixAttrs); + } + else + { + dest.append(symbols.getMinusSign(), NumberFormat.Field.SIGN); + dest.append(substituteCurrency(positivePrefix, number), + positivePrefixRanges, positivePrefixAttrs); + } + number = - number; + } + else + { + dest.append(substituteCurrency(positivePrefix, number), + positivePrefixRanges, positivePrefixAttrs); + } + int integerBeginIndex = dest.length(); + int integerEndIndex = 0; + int zeroStart = symbols.getZeroDigit() - '0'; + + if (Double.isInfinite (number)) + { + dest.append(symbols.getInfinity()); + integerEndIndex = dest.length(); + } + else + { + number *= multiplier; + + // Compute exponent. + long exponent = 0; + double baseNumber; + if (useExponentialNotation) + { + exponent = (long) Math.floor (Math.log(number) / Math.log(10)); + exponent = exponent - (exponent % exponentRound); + if (minimumIntegerDigits > 0) + exponent -= minimumIntegerDigits - 1; + baseNumber = (number / Math.pow(10.0, exponent)); + } + else + baseNumber = number; + + // Round to the correct number of digits. + baseNumber += 5 * Math.pow(10.0, - maximumFractionDigits - 1); + + int index = dest.length(); + //double intPart = Math.floor(baseNumber); + String intPart = Long.toString((long)Math.floor(baseNumber)); + int count, groupPosition = intPart.length(); + + dest.setDefaultAttribute(NumberFormat.Field.INTEGER); + + for (count = 0; count < minimumIntegerDigits-intPart.length(); count++) + dest.append(symbols.getZeroDigit()); + + for (count = 0; + count < maximumIntegerDigits && count < intPart.length(); + count++) + { + int dig = intPart.charAt(count); + + // Append group separator if required. + if (groupingUsed && count > 0 && groupingSize != 0 && groupPosition % groupingSize == 0) + { + dest.append(symbols.getGroupingSeparator(), NumberFormat.Field.GROUPING_SEPARATOR); + dest.setDefaultAttribute(NumberFormat.Field.INTEGER); + } + dest.append((char) (zeroStart + dig)); + + groupPosition--; + } + dest.setDefaultAttribute(null); + + integerEndIndex = dest.length(); + + int decimal_index = integerEndIndex; + int consecutive_zeros = 0; + int total_digits = 0; + + int localMaximumFractionDigits = maximumFractionDigits; + + if (useExponentialNotation) + localMaximumFractionDigits += minimumIntegerDigits - count; + + // Strip integer part from NUMBER. + double fracPart = baseNumber - Math.floor(baseNumber); + + if ( ((fracPart != 0 || minimumFractionDigits > 0) && localMaximumFractionDigits > 0) + || decimalSeparatorAlwaysShown) + { + dest.append (symbols.getDecimalSeparator(), NumberFormat.Field.DECIMAL_SEPARATOR); + } + + int fraction_begin = dest.length(); + dest.setDefaultAttribute(NumberFormat.Field.FRACTION); + for (count = 0; + count < localMaximumFractionDigits + && (fracPart != 0 || count < minimumFractionDigits); + ++count) + { + ++total_digits; + fracPart *= 10; + long dig = (long) fracPart; + if (dig == 0) + ++consecutive_zeros; + else + consecutive_zeros = 0; + dest.append((char) (symbols.getZeroDigit() + dig)); + + // Strip integer part from FRACPART. + fracPart = fracPart - Math.floor (fracPart); + } + + // Strip extraneous trailing `0's. We can't always detect + // these in the loop. + int extra_zeros = Math.min (consecutive_zeros, + total_digits - minimumFractionDigits); + if (extra_zeros > 0) + { + dest.cutTail(extra_zeros); + total_digits -= extra_zeros; + if (total_digits == 0 && !decimalSeparatorAlwaysShown) + dest.cutTail(1); + } + + if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD) + { + fieldPos.setBeginIndex(fraction_begin); + fieldPos.setEndIndex(dest.length()); + } + + // Finally, print the exponent. + if (useExponentialNotation) + { + dest.append(symbols.getExponential(), NumberFormat.Field.EXPONENT_SYMBOL); + if (exponent < 0) + { + dest.append (symbols.getMinusSign (), NumberFormat.Field.EXPONENT_SIGN); + exponent = - exponent; + } + index = dest.length(); + dest.setDefaultAttribute(NumberFormat.Field.EXPONENT); + String exponentString = Long.toString ((long) exponent); + + for (count = 0; count < minExponentDigits-exponentString.length(); + count++) + dest.append((char) symbols.getZeroDigit()); + + for (count = 0; + count < exponentString.length(); + ++count) + { + int dig = exponentString.charAt(count); + dest.append((char) (zeroStart + dig)); + } + } + } + + if (fieldPos != null && + (fieldPos.getField() == INTEGER_FIELD || + fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER)) + { + fieldPos.setBeginIndex(integerBeginIndex); + fieldPos.setEndIndex(integerEndIndex); + } + + if (is_neg && negativeSuffix != null) + { + dest.append(substituteCurrency(negativeSuffix, number), + negativeSuffixRanges, negativeSuffixAttrs); + } + else + { + dest.append(substituteCurrency(positiveSuffix, number), + positiveSuffixRanges, positiveSuffixAttrs); + } + } + + public StringBuffer format (double number, StringBuffer dest, + FieldPosition fieldPos) + { + formatInternal (number, new StringFormatBuffer(dest), fieldPos); + return dest; + } + + public AttributedCharacterIterator formatToCharacterIterator (Object value) + { + AttributedFormatBuffer sbuf = new AttributedFormatBuffer(); + + if (value instanceof Number) + formatInternal(((Number) value).doubleValue(), sbuf, null); + else + throw new IllegalArgumentException + ("Cannot format given Object as a Number"); + + sbuf.sync(); + return new FormatCharacterIterator(sbuf.getBuffer().toString(), + sbuf.getRanges(), + sbuf.getAttributes()); + } + + public StringBuffer format (long number, StringBuffer dest, + FieldPosition fieldPos) + { + // If using exponential notation, we just format as a double. + if (useExponentialNotation) + return format ((double) number, dest, fieldPos); + + boolean is_neg = number < 0; + if (is_neg) + { + if (negativePrefix != null) + dest.append(substituteCurrency(negativePrefix, number)); + else + { + dest.append(symbols.getMinusSign()); + dest.append(substituteCurrency(positivePrefix, number)); + } + number = - number; + } + else + dest.append(substituteCurrency(positivePrefix, number)); + + int integerBeginIndex = dest.length(); + int index = dest.length(); + int count = 0; + + /* Handle percentages, etc. */ + number *= multiplier; + while (count < maximumIntegerDigits + && (number > 0 || count < minimumIntegerDigits)) + { + long dig = number % 10; + number /= 10; + // NUMBER and DIG will be less than 0 if the original number + // was the most negative long. + if (dig < 0) + { + dig = - dig; + number = - number; + } + + // Append group separator if required. + if (groupingUsed && count > 0 && groupingSize != 0 && count % groupingSize == 0) + dest.insert(index, symbols.getGroupingSeparator()); + + dest.insert(index, (char) (symbols.getZeroDigit() + dig)); + + ++count; + } + + if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD) + { + fieldPos.setBeginIndex(integerBeginIndex); + fieldPos.setEndIndex(dest.length()); + } + + if (decimalSeparatorAlwaysShown || minimumFractionDigits > 0) + { + dest.append(symbols.getDecimalSeparator()); + if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD) + { + fieldPos.setBeginIndex(dest.length()); + fieldPos.setEndIndex(dest.length() + minimumFractionDigits); + } + } + + for (count = 0; count < minimumFractionDigits; ++count) + dest.append(symbols.getZeroDigit()); + + dest.append((is_neg && negativeSuffix != null) + ? substituteCurrency(negativeSuffix, number) + : substituteCurrency(positiveSuffix, number)); + return dest; + } + + /** + * Returns the currency corresponding to the currency symbol stored + * in the instance of DecimalFormatSymbols used by this + * DecimalFormat. + * + * @return A new instance of Currency if + * the currency code matches a known one, null otherwise. + */ + public Currency getCurrency() + { + return symbols.getCurrency(); + } + + /** + * Returns a copy of the symbols used by this instance. + * + * @return A copy of the symbols. + */ + public DecimalFormatSymbols getDecimalFormatSymbols() + { + return (DecimalFormatSymbols) symbols.clone(); + } + + public int getGroupingSize () + { + return groupingSize; + } + + public int getMultiplier () + { + return multiplier; + } + + public String getNegativePrefix () + { + return negativePrefix; + } + + public String getNegativeSuffix () + { + return negativeSuffix; + } + + public String getPositivePrefix () + { + return positivePrefix; + } + + public String getPositiveSuffix () + { + return positiveSuffix; + } + + /** + * Returns a hash code for this object. + * + * @return A hash code. + */ + public int hashCode() + { + return toPattern().hashCode(); + } + + public boolean isDecimalSeparatorAlwaysShown () + { + return decimalSeparatorAlwaysShown; + } + + public Number parse (String str, ParsePosition pos) + { + /* + * Our strategy is simple: copy the text into separate buffers: one for the int part, + * one for the fraction part and for the exponential part. + * We translate or omit locale-specific information. + * If exponential is sufficiently big we merge the fraction and int part and + * remove the '.' and then we use Long to convert the number. In the other + * case, we use Double to convert the full number. + */ + + boolean is_neg = false; + int index = pos.getIndex(); + StringBuffer int_buf = new StringBuffer (); + + // We have to check both prefixes, because one might be empty. We + // want to pick the longest prefix that matches. + boolean got_pos = str.startsWith(positivePrefix, index); + String np = (negativePrefix != null + ? negativePrefix + : positivePrefix + symbols.getMinusSign()); + boolean got_neg = str.startsWith(np, index); + + if (got_pos && got_neg) + { + // By checking this way, we preserve ambiguity in the case + // where the negative format differs only in suffix. We + // check this again later. + if (np.length() > positivePrefix.length()) + { + is_neg = true; + index += np.length(); + } + else + index += positivePrefix.length(); + } + else if (got_neg) + { + is_neg = true; + index += np.length(); + } + else if (got_pos) + index += positivePrefix.length(); + else + { + pos.setErrorIndex (index); + return null; + } + + // FIXME: handle Inf and NaN. + + // FIXME: do we have to respect minimum digits? + // What about multiplier? + + StringBuffer buf = int_buf; + StringBuffer frac_buf = null; + StringBuffer exp_buf = null; + int start_index = index; + int max = str.length(); + int exp_index = -1; + int last = index + maximumIntegerDigits; + + if (maximumFractionDigits > 0) + last += maximumFractionDigits + 1; + + if (useExponentialNotation) + last += minExponentDigits + 1; + + if (last > 0 && max > last) + max = last; + + char zero = symbols.getZeroDigit(); + int last_group = -1; + boolean int_part = true; + boolean exp_part = false; + for (; index < max; ++index) + { + char c = str.charAt(index); + + // FIXME: what about grouping size? + if (groupingUsed && c == symbols.getGroupingSeparator()) + { + if (last_group != -1 + && groupingSize != 0 + && (index - last_group) % groupingSize != 0) + { + pos.setErrorIndex(index); + return null; + } + last_group = index+1; + } + else if (c >= zero && c <= zero + 9) + { + buf.append((char) (c - zero + '0')); + } + else if (parseIntegerOnly) + break; + else if (c == symbols.getDecimalSeparator()) + { + if (last_group != -1 + && groupingSize != 0 + && (index - last_group) % groupingSize != 0) + { + pos.setErrorIndex(index); + return null; + } + buf = frac_buf = new StringBuffer(); + frac_buf.append('.'); + int_part = false; + } + else if (c == symbols.getExponential()) + { + buf = exp_buf = new StringBuffer(); + int_part = false; + exp_part = true; + exp_index = index+1; + } + else if (exp_part + && (c == '+' || c == '-' || c == symbols.getMinusSign())) + { + // For exponential notation. + buf.append(c); + } + else + break; + } + + if (index == start_index) + { + // Didn't see any digits. + pos.setErrorIndex(index); + return null; + } + + // Check the suffix. We must do this before converting the + // buffer to a number to handle the case of a number which is + // the most negative Long. + boolean got_pos_suf = str.startsWith(positiveSuffix, index); + String ns = (negativePrefix == null ? positiveSuffix : negativeSuffix); + boolean got_neg_suf = str.startsWith(ns, index); + if (is_neg) + { + if (! got_neg_suf) + { + pos.setErrorIndex(index); + return null; + } + } + else if (got_pos && got_neg && got_neg_suf) + { + is_neg = true; + } + else if (got_pos != got_pos_suf && got_neg != got_neg_suf) + { + pos.setErrorIndex(index); + return null; + } + else if (! got_pos_suf) + { + pos.setErrorIndex(index); + return null; + } + + String suffix = is_neg ? ns : positiveSuffix; + long parsedMultiplier = 1; + boolean use_long; + + if (is_neg) + int_buf.insert(0, '-'); + + // Now handle the exponential part if there is one. + if (exp_buf != null) + { + int exponent_value; + + try + { + exponent_value = Integer.parseInt(exp_buf.toString()); + } + catch (NumberFormatException x1) + { + pos.setErrorIndex(exp_index); + return null; + } + + if (frac_buf == null) + { + // We only have to add some zeros to the int part. + // Build a multiplier. + for (int i = 0; i < exponent_value; i++) + int_buf.append('0'); + + use_long = true; + } + else + { + boolean long_sufficient; + + if (exponent_value < frac_buf.length()-1) + { + int lastNonNull = -1; + /* We have to check the fraction buffer: it may only be full of '0' + * or be sufficiently filled with it to convert the number into Long. + */ + for (int i = 1; i < frac_buf.length(); i++) + if (frac_buf.charAt(i) != '0') + lastNonNull = i; + + long_sufficient = (lastNonNull < 0 || lastNonNull <= exponent_value); + } + else + long_sufficient = true; + + if (long_sufficient) + { + for (int i = 1; i < frac_buf.length() && i < exponent_value; i++) + int_buf.append(frac_buf.charAt(i)); + for (int i = frac_buf.length()-1; i < exponent_value; i++) + int_buf.append('0'); + use_long = true; + } + else + { + /* + * A long type is not sufficient, we build the full buffer to + * be parsed by Double. + */ + int_buf.append(frac_buf); + int_buf.append('E'); + int_buf.append(exp_buf); + use_long = false; + } + } + } + else + { + if (frac_buf != null) + { + /* Check whether the fraction buffer contains only '0' */ + int i; + for (i = 1; i < frac_buf.length(); i++) + if (frac_buf.charAt(i) != '0') + break; + + if (i != frac_buf.length()) + { + use_long = false; + int_buf.append(frac_buf); + } + else + use_long = true; + } + else + use_long = true; + } + + String t = int_buf.toString(); + Number result = null; + if (use_long) + { + try + { + result = new Long (t); + } + catch (NumberFormatException x1) + { + } + } + else + { + try + { + result = new Double (t); + } + catch (NumberFormatException x2) + { + } + } + if (result == null) + { + pos.setErrorIndex(index); + return null; + } + + pos.setIndex(index + suffix.length()); + + return result; + } + + /** + * Sets the Currency on the + * DecimalFormatSymbols used, which also sets the + * currency symbols on those symbols. + */ + public void setCurrency(Currency currency) + { + symbols.setCurrency(currency); + } + + /** + * Sets the symbols used by this instance. This method makes a copy of + * the supplied symbols. + * + * @param newSymbols the symbols (null not permitted). + */ + public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) + { + symbols = (DecimalFormatSymbols) newSymbols.clone(); + } + + public void setDecimalSeparatorAlwaysShown (boolean newValue) + { + decimalSeparatorAlwaysShown = newValue; + } + + public void setGroupingSize (int groupSize) + { + groupingSize = (byte) groupSize; + } + + public void setMaximumFractionDigits (int newValue) + { + super.setMaximumFractionDigits(Math.min(newValue, 340)); + } + + public void setMaximumIntegerDigits (int newValue) + { + super.setMaximumIntegerDigits(Math.min(newValue, 309)); + } + + public void setMinimumFractionDigits (int newValue) + { + super.setMinimumFractionDigits(Math.min(newValue, 340)); + } + + public void setMinimumIntegerDigits (int newValue) + { + super.setMinimumIntegerDigits(Math.min(newValue, 309)); + } + + public void setMultiplier (int newValue) + { + multiplier = newValue; + } + + public void setNegativePrefix (String newValue) + { + negativePrefix = newValue; + } + + public void setNegativeSuffix (String newValue) + { + negativeSuffix = newValue; + } + + public void setPositivePrefix (String newValue) + { + positivePrefix = newValue; + } + + public void setPositiveSuffix (String newValue) + { + positiveSuffix = newValue; + } + + private void quoteFix(StringBuffer buf, String text, String patChars) + { + int len = text.length(); + for (int index = 0; index < len; ++index) + { + char c = text.charAt(index); + if (patChars.indexOf(c) != -1) + { + buf.append('\''); + buf.append(c); + buf.append('\''); + } + else + buf.append(c); + } + } + + private String computePattern(DecimalFormatSymbols syms) + { + StringBuffer mainPattern = new StringBuffer (); + // We have to at least emit a zero for the minimum number of + // digits. Past that we need hash marks up to the grouping + // separator (and one beyond). + int total_digits = Math.max(minimumIntegerDigits, + groupingUsed ? groupingSize + 1: groupingSize); + for (int i = 0; i < total_digits - minimumIntegerDigits; ++i) + mainPattern.append(syms.getDigit()); + for (int i = total_digits - minimumIntegerDigits; i < total_digits; ++i) + mainPattern.append(syms.getZeroDigit()); + // Inserting the gropuing operator afterwards is easier. + if (groupingUsed) + mainPattern.insert(mainPattern.length() - groupingSize, + syms.getGroupingSeparator()); + // See if we need decimal info. + if (minimumFractionDigits > 0 || maximumFractionDigits > 0 + || decimalSeparatorAlwaysShown) + mainPattern.append(syms.getDecimalSeparator()); + for (int i = 0; i < minimumFractionDigits; ++i) + mainPattern.append(syms.getZeroDigit()); + for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i) + mainPattern.append(syms.getDigit()); + if (useExponentialNotation) + { + mainPattern.append(syms.getExponential()); + for (int i = 0; i < minExponentDigits; ++i) + mainPattern.append(syms.getZeroDigit()); + if (minExponentDigits == 0) + mainPattern.append(syms.getDigit()); + } + + String main = mainPattern.toString(); + String patChars = patternChars (syms); + mainPattern.setLength(0); + + quoteFix (mainPattern, positivePrefix, patChars); + mainPattern.append(main); + quoteFix (mainPattern, positiveSuffix, patChars); + + if (negativePrefix != null) + { + quoteFix (mainPattern, negativePrefix, patChars); + mainPattern.append(main); + quoteFix (mainPattern, negativeSuffix, patChars); + } + + return mainPattern.toString(); + } + + public String toLocalizedPattern () + { + return computePattern (symbols); + } + + public String toPattern () + { + return computePattern (nonLocalizedSymbols); + } + + private static final int MAXIMUM_INTEGER_DIGITS = 309; + + // These names are fixed by the serialization spec. + private boolean decimalSeparatorAlwaysShown; + private byte groupingSize; + private byte minExponentDigits; + private int exponentRound; + private int multiplier; + private String negativePrefix; + private String negativeSuffix; + private String positivePrefix; + private String positiveSuffix; + private int[] negativePrefixRanges, positivePrefixRanges; + private HashMap[] negativePrefixAttrs, positivePrefixAttrs; + private int[] negativeSuffixRanges, positiveSuffixRanges; + private HashMap[] negativeSuffixAttrs, positiveSuffixAttrs; + private int serialVersionOnStream = 1; + private DecimalFormatSymbols symbols; + private boolean useExponentialNotation; + private static final long serialVersionUID = 864413376551465018L; + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + if (serialVersionOnStream < 1) + { + useExponentialNotation = false; + serialVersionOnStream = 1; + } + } + + // The locale-independent pattern symbols happen to be the same as + // the US symbols. + private static final DecimalFormatSymbols nonLocalizedSymbols + = new DecimalFormatSymbols (Locale.US); + + /** + *

    + * Substitutes the currency symbol into the given string, + * based on the value used. Currency symbols can either + * be a simple series of characters (e.g. '$'), which are + * simply used as is, or they can be of a more complex + * form: + *

    + *

    + * (lower bound)|(mid value)|(upper bound) + *

    + *

    + * where each bound has the syntax '(value)(# or <)(symbol)', + * to indicate the bounding value and the symbol used. + *

    + *

    + * The currency symbol replaces the currency specifier, '\u00a4', + * an unlocalised character, which thus is used as such in all formats. + * If this symbol occurs twice, the international currency code is used + * instead. + *

    + * + * @param string The string containing the currency specifier, '\u00a4'. + * @param number the number being formatted. + * @return a string formatted for the correct currency. + */ + private String substituteCurrency(String string, double number) + { + int index; + int length; + char currentChar; + StringBuffer buf; + + index = 0; + length = string.length(); + buf = new StringBuffer(); + + while (index < length) + { + currentChar = string.charAt(index); + if (string.charAt(index) == '\u00a4') + { + if ((index + 1) < length && string.charAt(index + 1) == '\u00a4') + { + buf.append(symbols.getInternationalCurrencySymbol()); + index += 2; + } + else + { + String symbol; + + symbol = symbols.getCurrencySymbol(); + if (symbol.startsWith("=")) + { + String[] bounds; + int[] boundValues; + String[] boundSymbols; + + bounds = symbol.substring(1).split("\\|"); + boundValues = new int[3]; + boundSymbols = new String[3]; + for (int a = 0; a < 3; ++a) + { + String[] bound; + + bound = bounds[a].split("[#<]"); + boundValues[a] = Integer.parseInt(bound[0]); + boundSymbols[a] = bound[1]; + } + if (number <= boundValues[0]) + { + buf.append(boundSymbols[0]); + } + else if (number >= boundValues[2]) + { + buf.append(boundSymbols[2]); + } + else + { + buf.append(boundSymbols[1]); + } + ++index; + } + else + { + buf.append(symbol); + ++index; + } + } + } + else + { + buf.append(string.charAt(index)); + ++index; + } + } + return buf.toString(); + } + +} diff --git a/libjava/classpath/java/text/DecimalFormatSymbols.java b/libjava/classpath/java/text/DecimalFormatSymbols.java new file mode 100644 index 0000000..81ea001 --- /dev/null +++ b/libjava/classpath/java/text/DecimalFormatSymbols.java @@ -0,0 +1,688 @@ +/* DecimalFormatSymbols.java -- Format symbols used by DecimalFormat + Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.util.Currency; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * This class is a container for the symbols used by + * DecimalFormat to format numbers and currency + * for a particular locale. These are + * normally handled automatically, but an application can override + * values as desired using this class. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @date February 24, 1999 + * @see java.text.DecimalFormat + */ +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct to 1.2. + */ +public final class DecimalFormatSymbols implements Cloneable, Serializable +{ + public Object clone () + { + try + { + return super.clone (); + } + catch(CloneNotSupportedException e) + { + return null; + } + } + + /** + * This method initializes a new instance of + * DecimalFormatSymbols for the default locale. + */ + public DecimalFormatSymbols () + { + this (Locale.getDefault()); + } + + /** + * Retrieves a valid string, either using the supplied resource + * bundle or the default value. + * + * @param bundle the resource bundle to use to find the string. + * @param name key for the string in the resource bundle. + * @param def default value for the string. + */ + private String safeGetString(ResourceBundle bundle, + String name, String def) + { + if (bundle != null) + { + try + { + return bundle.getString(name); + } + catch (MissingResourceException x) + { + } + } + return def; + } + + private char safeGetChar(ResourceBundle bundle, + String name, char def) + { + String r = null; + if (bundle != null) + { + try + { + r = bundle.getString(name); + } + catch (MissingResourceException x) + { + } + } + if (r == null || r.length() < 1) + return def; + return r.charAt(0); + } + + /** + * This method initializes a new instance of + * DecimalFormatSymbols for the specified locale. + * Note: if the locale does not have an associated + * Currency instance, the currency symbol and + * international currency symbol will be set to the strings "?" + * and "XXX" respectively. This generally happens with language + * locales (those with no specified country), such as + * Locale.ENGLISH. + * + * @param locale The local to load symbols for. + * @throws NullPointerException if the locale is null. + */ + public DecimalFormatSymbols (Locale loc) + { + ResourceBundle res; + + currency = Currency.getInstance("XXX"); + currencySymbol = "?"; + intlCurrencySymbol = "XXX"; + try + { + res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + loc, ClassLoader.getSystemClassLoader()); + } + catch (MissingResourceException x) + { + res = null; + } + try + { + Currency localeCurrency = Currency.getInstance(loc); + if (localeCurrency != null) + { + setCurrency(localeCurrency); + } + } + catch(IllegalArgumentException exception) + { + /* Locale has an invalid currency */ + } + decimalSeparator = safeGetChar (res, "decimalSeparator", '.'); + digit = safeGetChar (res, "digit", '#'); + exponential = safeGetChar (res, "exponential", 'E'); + groupingSeparator = safeGetChar (res, "groupingSeparator", ','); + infinity = safeGetString (res, "infinity", "\u221e"); + try + { + monetarySeparator = safeGetChar (res, "monetarySeparator", '.'); + } + catch (MissingResourceException x) + { + monetarySeparator = decimalSeparator; + } + minusSign = safeGetChar (res, "minusSign", '-'); + NaN = safeGetString (res, "NaN", "\ufffd"); + patternSeparator = safeGetChar (res, "patternSeparator", ';'); + percent = safeGetChar (res, "percent", '%'); + perMill = safeGetChar (res, "perMill", '\u2030'); + zeroDigit = safeGetChar (res, "zeroDigit", '0'); + locale = loc; + } + + /** + * This method this this object for equality against the specified object. + * This will be true if and only if the following criteria are met with + * regard to the specified object: + *

    + *

      + *
    • It is not null.
    • + *
    • It is an instance of DecimalFormatSymbols.
    • + *
    • All of its symbols are identical to the symbols in this object.
    • + *
    + * + * @return true if the specified object is equal to this + * object, false otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof DecimalFormatSymbols)) + return false; + DecimalFormatSymbols dfs = (DecimalFormatSymbols) obj; + return (currencySymbol.equals(dfs.currencySymbol) + && decimalSeparator == dfs.decimalSeparator + && digit == dfs.digit + && exponential == dfs.exponential + && groupingSeparator == dfs.groupingSeparator + && infinity.equals(dfs.infinity) + && intlCurrencySymbol.equals(dfs.intlCurrencySymbol) + && minusSign == dfs.minusSign + && monetarySeparator == dfs.monetarySeparator + && NaN.equals(dfs.NaN) + && patternSeparator == dfs.patternSeparator + && percent == dfs.percent + && perMill == dfs.perMill + && zeroDigit == dfs.zeroDigit); + } + + /** + * Returns the currency corresponding to the currency symbol stored + * in this instance of DecimalFormatSymbols. + * + * @return An instance of Currency which matches + * the currency used, or null if there is no corresponding + * instance. + */ + public Currency getCurrency () + { + return currency; + } + + /** + * This method returns the currency symbol in local format. For example, + * "$" for Canadian dollars. + * + * @return The currency symbol in local format. + */ + public String getCurrencySymbol () + { + return currencySymbol; + } + + /** + * This method returns the character used as the decimal point. + * + * @return The character used as the decimal point. + */ + public char getDecimalSeparator () + { + return decimalSeparator; + } + + /** + * This method returns the character used to represent a digit in a + * format pattern string. + * + * @return The character used to represent a digit in a format + * pattern string. + */ + public char getDigit () + { + return digit; + } + + /** + * This method returns the character used to represent the exponential + * format. This is a GNU Classpath extension. + * + * @return the character used to represent an exponential in a format + * pattern string. + */ + char getExponential () + { + return exponential; + } + + /** + * This method sets the character used to separate groups of digits. For + * example, the United States uses a comma (,) to separate thousands in + * a number. + * + * @return The character used to separate groups of digits. + */ + public char getGroupingSeparator () + { + return groupingSeparator; + } + + /** + * This method returns the character used to represent infinity. + * + * @return The character used to represent infinity. + */ + public String getInfinity () + { + return infinity; + } + + /** + * This method returns the ISO 4217 currency code for + * the currency used. + * + * @return the ISO 4217 currency code. + */ + public String getInternationalCurrencySymbol () + { + return intlCurrencySymbol; + } + + /** + * This method returns the character used to represent the minus sign. + * + * @return The character used to represent the minus sign. + */ + public char getMinusSign () + { + return minusSign; + } + + /** + * This method returns the character used to represent the decimal + * point for currency values. + * + * @return The decimal point character used in currency values. + */ + public char getMonetaryDecimalSeparator () + { + return monetarySeparator; + } + + /** + * This method returns the string used to represent the NaN (not a number) + * value. + * + * @return The string used to represent NaN + */ + public String getNaN () + { + return NaN; + } + + /** + * This method returns the character used to separate positive and negative + * subpatterns in a format pattern. + * + * @return The character used to separate positive and negative subpatterns + * in a format pattern. + */ + public char getPatternSeparator () + { + return patternSeparator; + } + + /** + * This method returns the character used as the percent sign. + * + * @return The character used as the percent sign. + */ + public char getPercent () + { + return percent; + } + + /** + * This method returns the character used as the per mille character. + * + * @return The per mille character. + */ + public char getPerMill () + { + return perMill; + } + + /** + * This method returns the character used to represent the digit zero. + * + * @return The character used to represent the digit zero. + */ + public char getZeroDigit () + { + return zeroDigit; + } + + /** + * This method returns a hash value for this object. + * + * @return A hash value for this object. + */ + public int hashCode () + { + // Compute based on zero digit, grouping separator, and decimal + // separator -- JCL book. This probably isn't a very good hash + // code. + return zeroDigit << 16 + groupingSeparator << 8 + decimalSeparator; + } + + /** + * This method sets the currency symbol and ISO 4217 currency + * code to the values obtained from the supplied currency. + * + * @param currency the currency from which to obtain the values. + * @throws NullPointerException if the currency is null. + */ + public void setCurrency (Currency currency) + { + intlCurrencySymbol = currency.getCurrencyCode(); + currencySymbol = currency.getSymbol(); + this.currency = currency; + } + + /** + * This method sets the currency symbol to the specified value. + * + * @param currencySymbol The new currency symbol + */ + public void setCurrencySymbol (String currency) + { + currencySymbol = currency; + } + + /** + * This method sets the decimal point character to the specified value. + * + * @param decimalSeparator The new decimal point character + */ + public void setDecimalSeparator (char decimalSep) + { + decimalSeparator = decimalSep; + } + + /** + * This method sets the character used to represents a digit in a format + * string to the specified value. + * + * @param digit The character used to represent a digit in a format pattern. + */ + public void setDigit (char digit) + { + this.digit = digit; + } + + /** + * This method sets the exponential character used in the format string to + * the specified value. This is a GNU Classpath extension. + * + * @param exp the character used for the exponential in a format pattern. + */ + void setExponential (char exp) + { + exponential = exp; + } + + /** + * This method sets the character used to separate groups of digits. + * + * @param groupingSeparator The character used to separate groups of digits. + */ + public void setGroupingSeparator (char groupSep) + { + groupingSeparator = groupSep; + } + + /** + * This method sets the string used to represents infinity. + * + * @param infinity The string used to represent infinity. + */ + public void setInfinity (String infinity) + { + this.infinity = infinity; + } + + /** + * This method sets the international currency symbol to the + * specified value. If a valid Currency instance + * exists for the international currency code, then this is + * used for the currency attribute, and the currency symbol + * is set to the corresponding value from this instance. + * Otherwise, the currency attribute is set to null and the + * symbol is left unmodified. + * + * @param currencyCode The new international currency symbol. + */ + public void setInternationalCurrencySymbol (String currencyCode) + { + intlCurrencySymbol = currencyCode; + try + { + currency = Currency.getInstance(currencyCode); + } + catch (IllegalArgumentException exception) + { + currency = null; + } + if (currency != null) + { + setCurrencySymbol(currency.getSymbol(locale)); + } + } + + /** + * This method sets the character used to represent the minus sign. + * + * @param minusSign The character used to represent the minus sign. + */ + public void setMinusSign (char minusSign) + { + this.minusSign = minusSign; + } + + /** + * This method sets the character used for the decimal point in currency + * values. + * + * @param monetarySeparator The decimal point character used in + * currency values. + */ + public void setMonetaryDecimalSeparator (char decimalSep) + { + monetarySeparator = decimalSep; + } + + /** + * This method sets the string used to represent the NaN (not a + * number) value. + * + * @param NaN The string used to represent NaN + */ + public void setNaN (String nan) + { + NaN = nan; + } + + /** + * This method sets the character used to separate positive and negative + * subpatterns in a format pattern. + * + * @param patternSeparator The character used to separate positive and + * negative subpatterns in a format pattern. + */ + public void setPatternSeparator (char patternSep) + { + patternSeparator = patternSep; + } + + /** + * This method sets the character used as the percent sign. + * + * @param percent The character used as the percent sign. + */ + public void setPercent (char percent) + { + this.percent = percent; + } + + /** + * This method sets the character used as the per mille character. + * + * @param perMill The per mille character. + */ + public void setPerMill (char perMill) + { + this.perMill = perMill; + } + + /** + * This method sets the character used to represent the digit zero. + * + * @param zeroDigit The character used to represent the digit zero. + */ + public void setZeroDigit (char zeroDigit) + { + this.zeroDigit = zeroDigit; + } + + /** + * @serial A string used for the local currency + */ + private String currencySymbol; + /** + * @serial The char used to separate decimals in a number. + */ + private char decimalSeparator; + /** + * @serial This is the char used to represent a digit in + * a format specification. + */ + private char digit; + /** + * @serial This is the char used to represent the exponent + * separator in exponential notation. + */ + private char exponential; + /** + * @serial This separates groups of thousands in numbers. + */ + private char groupingSeparator; + /** + * @serial This string represents infinity. + */ + private String infinity; + /** + * @serial This string represents the local currency in an international + * context, eg, "C$" for Canadian dollars. + */ + private String intlCurrencySymbol; + /** + * @serial This is the character used to represent the minus sign. + */ + private char minusSign; + /** + * @serial This character is used to separate decimals when formatting + * currency values. + */ + private char monetarySeparator; + /** + * @serial This string is used the represent the Java NaN value for + * "not a number". + */ + private String NaN; + /** + * @serial This is the character used to separate positive and negative + * subpatterns in a format pattern. + */ + private char patternSeparator; + /** + * @serial This is the percent symbols + */ + private char percent; + /** + * @serial This character is used for the mille percent sign. + */ + private char perMill; + /** + * @serial This value represents the type of object being de-serialized. + * 0 indicates a pre-Java 1.1.6 version, 1 indicates 1.1.6 or later. + * 0 indicates a pre-Java 1.1.6 version, 1 indicates 1.1.6 or later, + * 2 indicates 1.4 or later + */ + private int serialVersionOnStream = 2; + /** + * @serial This is the character used to represent 0. + */ + private char zeroDigit; + + /** + * @serial The locale of these currency symbols. + */ + private Locale locale; + + /** + * The currency used for the symbols in this instance. + * This is stored temporarily for efficiency reasons, + * as well as to ensure that the correct instance + * is restored from the currency code. + * + * @serial Ignored. + */ + private transient Currency currency; + + private static final long serialVersionUID = 5772796243397350300L; + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + if (serialVersionOnStream < 1) + { + monetarySeparator = decimalSeparator; + exponential = 'E'; + } + if (serialVersionOnStream < 2) + locale = Locale.getDefault(); + + serialVersionOnStream = 2; + } +} diff --git a/libjava/classpath/java/text/FieldPosition.java b/libjava/classpath/java/text/FieldPosition.java new file mode 100644 index 0000000..427c07e --- /dev/null +++ b/libjava/classpath/java/text/FieldPosition.java @@ -0,0 +1,232 @@ +/* FieldPosition.java -- Keeps track of field positions while formatting + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +/** + * This class is used by the java.text formatting classes to track + * field positions. A field position is defined by an identifier value + * and begin and end index positions. The formatting classes in java.text + * typically define constant values for the field identifiers. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + */ +public class FieldPosition +{ + /** + * This is the field identifier value. + */ + private int field_id; + + /** + * This is the beginning index of the field. + */ + private int begin; + + /** + * This is the ending index of the field. + */ + private int end; + + /** + * This is the field attribute value. + */ + private Format.Field field_attribute; + + /** + * This method initializes a new instance of FieldPosition + * to have the specified field attribute. The attribute will be used as + * an id. It is formally equivalent to calling FieldPosition(field, -1). + * + * @param field The field format attribute. + */ + public FieldPosition (Format.Field field) + { + this(field, -1); + } + + /** + * This method initializes a new instance of FieldPosition + * to have the specified field attribute. The attribute will be used as + * an id is non null. The integer field id is only used if the Format.Field + * attribute is not used by the formatter. + * + * @param field The field format attribute. + * @param field_id The field identifier value. + */ + public FieldPosition (Format.Field field, int field_id) + { + this.field_attribute = field; + this.field_id = field_id; + } + + /** + * This method initializes a new instance of FieldPosition to + * have the specified field id. + * + * @param field_id The field identifier value. + */ + public FieldPosition (int field_id) + { + this.field_id = field_id; + } + + /** + * This method returns the field identifier value for this object. + * + * @return The field identifier. + */ + public int getField () + { + return field_id; + } + + public Format.Field getFieldAttribute () + { + return field_attribute; + } + + /** + * This method returns the beginning index for this field. + * + * @return The beginning index. + */ + public int getBeginIndex () + { + return begin; + } + + /** + * This method sets the beginning index of this field to the specified value. + * + * @param begin The new beginning index. + */ + public void setBeginIndex (int begin) + { + this.begin = begin; + } + + /** + * This method returns the ending index for the field. + * + * @return The ending index. + */ + public int getEndIndex () + { + return end; + } + + /** + * This method sets the ending index of this field to the specified value. + * + * @param end The new ending index. + */ + public void setEndIndex (int end) + { + this.end = end; + } + + /** + * This method tests this object for equality against the specified object. + * The objects will be considered equal if and only if: + *

    + *

      + *
    • The specified object is not null. + *
    • The specified object has the same class as this object. + *
    • The specified object has the same field identifier, field attribute + * and beginning and ending index as this object. + *
    + * + * @param obj The object to test for equality to this object. + * + * @return true if the specified object is equal to + * this object, false otherwise. + */ + public boolean equals (Object obj) + { + if (this == obj) + return true; + + if (obj == null || obj.getClass() != this.getClass()) + return false; + + FieldPosition fp = (FieldPosition) obj; + return (field_id == fp.field_id + && (field_attribute == fp.field_attribute + || (field_attribute != null + && field_attribute.equals(fp.field_attribute))) + && begin == fp.begin + && end == fp.end); + } + + + /** + * This method returns a hash value for this object + * + * @return A hash value for this object. + */ + public int hashCode () + { + int hash = 5; + + hash = 31 * hash + field_id; + hash = 31 * hash + begin; + hash = 31 * hash + end; + hash = 31 * hash + + (null == field_attribute ? 0 : field_attribute.hashCode()); + + return hash; + } + + /** + * This method returns a String representation of this + * object. + * + * @return A String representation of this object. + */ + public String toString () + { + return (getClass ().getName () + + "[field=" + getField () + + ",attribute=" + getFieldAttribute () + + ",beginIndex=" + getBeginIndex () + + ",endIndex=" + getEndIndex () + + "]"); + } +} diff --git a/libjava/classpath/java/text/Format.java b/libjava/classpath/java/text/Format.java new file mode 100644 index 0000000..38fda34 --- /dev/null +++ b/libjava/classpath/java/text/Format.java @@ -0,0 +1,181 @@ +/* Format.java -- Abstract superclass for formatting/parsing strings. + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +import gnu.java.text.FormatCharacterIterator; + +import java.io.Serializable; + +/** + * This class is the abstract superclass of classes that format and parse + * data to/from Strings. It is guaranteed that any + * String produced by a concrete subclass of Format + * will be parseable by that same subclass. + *

    + * In addition to implementing the abstract methods in this class, subclasses + * should provide static factory methods of the form + * getInstance() and getInstance(Locale) if the + * subclass loads different formatting/parsing schemes based on locale. + * These subclasses should also implement a static method called + * getAvailableLocales() which returns an array of + * available locales in the current runtime environment. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + */ +public abstract class Format implements Serializable, Cloneable +{ + /** + * For compatability with Sun's JDK 1.4.2 rev. 5 + */ + static final long serialVersionUID = -299282585814624189L; + + public static class Field extends AttributedCharacterIterator.Attribute + { + static final long serialVersionUID = 276966692217360283L; + + protected Field(String name) + { + super(name); + } + } + + /** + * This method initializes a new instance of Format. + * It performs no actions, but acts as a default constructor for + * subclasses. + */ + public Format () + { + } + + /** + * This method formats an Object into a String. + * + * @param obj The Object to format. + * + * @return The formatted String. + * + * @exception IllegalArgumentException If the Object + * cannot be formatted. + */ + public final String format(Object obj) throws IllegalArgumentException + { + StringBuffer sb = new StringBuffer (); + format (obj, sb, new FieldPosition (0)); + return sb.toString (); + } + + /** + * This method formats an Object into a String and + * appends the String to a StringBuffer. + * + * @param obj The Object to format. + * @param sb The StringBuffer to append to. + * @param pos The desired FieldPosition, which is also + * updated by this call. + * + * @return The updated StringBuffer. + * + * @exception IllegalArgumentException If the Object + * cannot be formatted. + */ + public abstract StringBuffer format (Object obj, StringBuffer sb, + FieldPosition pos) + throws IllegalArgumentException; + + /** + * This method parses a String and converts the parsed + * contents into an Object. + * + * @param str The String to parse. + * + * @return The resulting Object. + * + * @exception ParseException If the String cannot be parsed. + */ + public Object parseObject (String str) throws ParseException + { + ParsePosition pos = new ParsePosition(0); + Object result = parseObject (str, pos); + if (result == null) + { + int index = pos.getErrorIndex(); + if (index < 0) + index = pos.getIndex(); + throw new ParseException("parseObject failed", index); + } + return result; + } + + /** + * This method parses a String and converts the parsed + * contents into an Object. + * + * @param str The String to parse. + * @param pos The starting parse index on input, the ending parse + * index on output. + * + * @return The parsed Object, or null in + * case of error. + */ + public abstract Object parseObject (String str, ParsePosition pos); + + public AttributedCharacterIterator formatToCharacterIterator(Object obj) + { + return new FormatCharacterIterator(format(obj), null, null); + } + + /** + * Creates a copy of this object. + * + * @return The copied Object. + */ + public Object clone () + { + try + { + return super.clone (); + } + catch (CloneNotSupportedException e) + { + return null; + } + } +} diff --git a/libjava/classpath/java/text/MessageFormat.java b/libjava/classpath/java/text/MessageFormat.java new file mode 100644 index 0000000..f7a9f16 --- /dev/null +++ b/libjava/classpath/java/text/MessageFormat.java @@ -0,0 +1,832 @@ +/* MessageFormat.java - Localized message formatting. + Copyright (C) 1999, 2001, 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 java.text; + +import gnu.java.text.FormatCharacterIterator; + +import java.io.InvalidObjectException; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Vector; + +public class MessageFormat extends Format +{ + /** + * @author Tom Tromey (tromey@cygnus.com) + * @author Jorge Aliss (jaliss@hotmail.com) + * @date March 3, 1999 + */ + /* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct to 1.2, except serialization. + * and parsing. + */ + private static final class MessageFormatElement + { + // Argument number. + int argNumber; + // Formatter to be used. This is the format set by setFormat. + Format setFormat; + // Formatter to be used based on the type. + Format format; + + // Argument will be checked to make sure it is an instance of this + // class. + Class formatClass; + + // Formatter type. + String type; + // Formatter style. + String style; + + // Text to follow this element. + String trailer; + + // Recompute the locale-based formatter. + void setLocale (Locale loc) + { + if (type == null) + ; + else if (type.equals("number")) + { + formatClass = java.lang.Number.class; + + if (style == null) + format = NumberFormat.getInstance(loc); + else if (style.equals("currency")) + format = NumberFormat.getCurrencyInstance(loc); + else if (style.equals("percent")) + format = NumberFormat.getPercentInstance(loc); + else if (style.equals("integer")) + { + NumberFormat nf = NumberFormat.getNumberInstance(loc); + nf.setMaximumFractionDigits(0); + nf.setGroupingUsed(false); + format = nf; + } + else + { + format = NumberFormat.getNumberInstance(loc); + DecimalFormat df = (DecimalFormat) format; + df.applyPattern(style); + } + } + else if (type.equals("time") || type.equals("date")) + { + formatClass = java.util.Date.class; + + int val = DateFormat.DEFAULT; + boolean styleIsPattern = false; + if (style == null) + ; + else if (style.equals("short")) + val = DateFormat.SHORT; + else if (style.equals("medium")) + val = DateFormat.MEDIUM; + else if (style.equals("long")) + val = DateFormat.LONG; + else if (style.equals("full")) + val = DateFormat.FULL; + else + styleIsPattern = true; + + if (type.equals("time")) + format = DateFormat.getTimeInstance(val, loc); + else + format = DateFormat.getDateInstance(val, loc); + + if (styleIsPattern) + { + SimpleDateFormat sdf = (SimpleDateFormat) format; + sdf.applyPattern(style); + } + } + else if (type.equals("choice")) + { + formatClass = java.lang.Number.class; + + if (style == null) + throw new + IllegalArgumentException ("style required for choice format"); + format = new ChoiceFormat (style); + } + } + } + + private static final long serialVersionUID = 6479157306784022952L; + + public static class Field extends Format.Field + { + static final long serialVersionUID = 7899943957617360810L; + + /** + * This is the attribute set for all characters produced + * by MessageFormat during a formatting. + */ + public static final MessageFormat.Field ARGUMENT = new MessageFormat.Field("argument"); + + // For deserialization + private Field() + { + super(""); + } + + protected Field(String s) + { + super(s); + } + + /** + * invoked to resolve the true static constant by + * comparing the deserialized object to know name. + * + * @return object constant + */ + protected Object readResolve() throws InvalidObjectException + { + if (getName().equals(ARGUMENT.getName())) + return ARGUMENT; + + throw new InvalidObjectException("no such MessageFormat field called " + getName()); + } + + } + + // Helper that returns the text up to the next format opener. The + // text is put into BUFFER. Returns index of character after end of + // string. Throws IllegalArgumentException on error. + private static int scanString(String pat, int index, StringBuffer buffer) + { + int max = pat.length(); + buffer.setLength(0); + boolean quoted = false; + for (; index < max; ++index) + { + char c = pat.charAt(index); + if (quoted) + { + // In a quoted context, a single quote ends the quoting. + if (c == '\'') + quoted = false; + else + buffer.append(c); + } + // Check for '', which is a single quote. + else if (c == '\'' && index + 1 < max && pat.charAt(index + 1) == '\'') + { + buffer.append(c); + ++index; + } + else if (c == '\'') + { + // Start quoting. + quoted = true; + } + else if (c == '{') + break; + else + buffer.append(c); + } + // Note that we explicitly allow an unterminated quote. This is + // done for compatibility. + return index; + } + + // This helper retrieves a single part of a format element. Returns + // the index of the terminating character. + private static int scanFormatElement(String pat, int index, + StringBuffer buffer, char term) + { + int max = pat.length(); + buffer.setLength(0); + int brace_depth = 1; + boolean quoted = false; + + for (; index < max; ++index) + { + char c = pat.charAt(index); + // First see if we should turn off quoting. + if (quoted) + { + if (c == '\'') + quoted = false; + // In both cases we fall through to inserting the + // character here. + } + // See if we have just a plain quote to insert. + else if (c == '\'' && index + 1 < max + && pat.charAt(index + 1) == '\'') + { + buffer.append(c); + ++index; + } + // See if quoting should turn on. + else if (c == '\'') + quoted = true; + else if (c == '{') + ++brace_depth; + else if (c == '}') + { + if (--brace_depth == 0) + break; + } + // Check for TERM after braces, because TERM might be `}'. + else if (c == term) + break; + // All characters, including opening and closing quotes, are + // inserted here. + buffer.append(c); + } + return index; + } + + // This is used to parse a format element and whatever non-format + // text might trail it. + private static int scanFormat(String pat, int index, StringBuffer buffer, + Vector elts, Locale locale) + { + MessageFormatElement mfe = new MessageFormatElement (); + elts.addElement(mfe); + + int max = pat.length(); + + // Skip the opening `{'. + ++index; + + // Fetch the argument number. + index = scanFormatElement (pat, index, buffer, ','); + try + { + mfe.argNumber = Integer.parseInt(buffer.toString()); + } + catch (NumberFormatException nfx) + { + IllegalArgumentException iae = new IllegalArgumentException(pat); + iae.initCause(nfx); + throw iae; + } + + // Extract the element format. + if (index < max && pat.charAt(index) == ',') + { + index = scanFormatElement (pat, index + 1, buffer, ','); + mfe.type = buffer.toString(); + + // Extract the style. + if (index < max && pat.charAt(index) == ',') + { + index = scanFormatElement (pat, index + 1, buffer, '}'); + mfe.style = buffer.toString (); + } + } + + // Advance past the last terminator. + if (index >= max || pat.charAt(index) != '}') + throw new IllegalArgumentException("Missing '}' at end of message format"); + ++index; + + // Now fetch trailing string. + index = scanString (pat, index, buffer); + mfe.trailer = buffer.toString (); + + mfe.setLocale(locale); + + return index; + } + + /** + * Applies the specified pattern to this MessageFormat. + * + * @param aPattern The Pattern + */ + public void applyPattern (String newPattern) + { + pattern = newPattern; + + StringBuffer tempBuffer = new StringBuffer (); + + int index = scanString (newPattern, 0, tempBuffer); + leader = tempBuffer.toString(); + + Vector elts = new Vector (); + while (index < newPattern.length()) + index = scanFormat (newPattern, index, tempBuffer, elts, locale); + + elements = new MessageFormatElement[elts.size()]; + elts.copyInto(elements); + } + + /** + * Overrides Format.clone() + */ + public Object clone () + { + MessageFormat c = (MessageFormat) super.clone (); + c.elements = (MessageFormatElement[]) elements.clone (); + return c; + } + + /** + * Overrides Format.equals(Object obj) + */ + public boolean equals (Object obj) + { + if (! (obj instanceof MessageFormat)) + return false; + MessageFormat mf = (MessageFormat) obj; + return (pattern.equals(mf.pattern) + && locale.equals(mf.locale)); + } + + /** + * A convinience method to format patterns. + * + * @param aPattern The pattern used when formatting. + * @param arguments The array containing the objects to be formatted. + */ + public AttributedCharacterIterator formatToCharacterIterator (Object arguments) + { + Object[] arguments_array = (Object[])arguments; + FormatCharacterIterator iterator = new FormatCharacterIterator(); + + formatInternal(arguments_array, new StringBuffer(), null, iterator); + + return iterator; + } + + /** + * A convinience method to format patterns. + * + * @param aPattern The pattern used when formatting. + * @param arguments The array containing the objects to be formatted. + */ + public static String format (String pattern, Object arguments[]) + { + MessageFormat mf = new MessageFormat (pattern); + StringBuffer sb = new StringBuffer (); + FieldPosition fp = new FieldPosition (NumberFormat.INTEGER_FIELD); + return mf.formatInternal(arguments, sb, fp, null).toString(); + } + + /** + * Returns the pattern with the formatted objects. + * + * @param source The array containing the objects to be formatted. + * @param result The StringBuffer where the text is appened. + * @param fp A FieldPosition object (it is ignored). + */ + public final StringBuffer format (Object arguments[], StringBuffer appendBuf, + FieldPosition fp) + { + return formatInternal(arguments, appendBuf, fp, null); + } + + private StringBuffer formatInternal (Object arguments[], + StringBuffer appendBuf, + FieldPosition fp, + FormatCharacterIterator output_iterator) + { + appendBuf.append(leader); + if (output_iterator != null) + output_iterator.append(leader); + + for (int i = 0; i < elements.length; ++i) + { + Object thisArg = null; + boolean unavailable = false; + if (arguments == null || elements[i].argNumber >= arguments.length) + unavailable = true; + else + thisArg = arguments[elements[i].argNumber]; + + AttributedCharacterIterator iterator = null; + + Format formatter = null; + + if (fp != null && i == fp.getField() && fp.getFieldAttribute() == Field.ARGUMENT) + fp.setBeginIndex(appendBuf.length()); + + if (unavailable) + appendBuf.append("{" + elements[i].argNumber + "}"); + else + { + if (elements[i].setFormat != null) + formatter = elements[i].setFormat; + else if (elements[i].format != null) + { + if (elements[i].formatClass != null + && ! elements[i].formatClass.isInstance(thisArg)) + throw new IllegalArgumentException("Wrong format class"); + + formatter = elements[i].format; + } + else if (thisArg instanceof Number) + formatter = NumberFormat.getInstance(locale); + else if (thisArg instanceof Date) + formatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale); + else + appendBuf.append(thisArg); + } + + if (fp != null && fp.getField() == i && fp.getFieldAttribute() == Field.ARGUMENT) + fp.setEndIndex(appendBuf.length()); + + if (formatter != null) + { + // Special-case ChoiceFormat. + if (formatter instanceof ChoiceFormat) + { + StringBuffer buf = new StringBuffer (); + formatter.format(thisArg, buf, fp); + MessageFormat mf = new MessageFormat (); + mf.setLocale(locale); + mf.applyPattern(buf.toString()); + mf.format(arguments, appendBuf, fp); + } + else + { + if (output_iterator != null) + iterator = formatter.formatToCharacterIterator(thisArg); + else + formatter.format(thisArg, appendBuf, fp); + } + + elements[i].format = formatter; + } + + if (output_iterator != null) + { + HashMap hash_argument = new HashMap(); + int position = output_iterator.getEndIndex(); + + hash_argument.put (MessageFormat.Field.ARGUMENT, + new Integer(elements[i].argNumber)); + + + if (iterator != null) + { + output_iterator.append(iterator); + output_iterator.addAttributes(hash_argument, position, + output_iterator.getEndIndex()); + } + else + output_iterator.append(thisArg.toString(), hash_argument); + + output_iterator.append(elements[i].trailer); + } + + appendBuf.append(elements[i].trailer); + } + + return appendBuf; + } + + /** + * Returns the pattern with the formatted objects. The first argument + * must be a array of Objects. + * This is equivalent to format((Object[]) objectArray, appendBuf, fpos) + * + * @param objectArray The object array to be formatted. + * @param appendBuf The StringBuffer where the text is appened. + * @param fpos A FieldPosition object (it is ignored). + */ + public final StringBuffer format (Object objectArray, StringBuffer appendBuf, + FieldPosition fpos) + { + return format ((Object[])objectArray, appendBuf, fpos); + } + + /** + * Returns an array with the Formats for + * the arguments. + */ + public Format[] getFormats () + { + Format[] f = new Format[elements.length]; + for (int i = elements.length - 1; i >= 0; --i) + f[i] = elements[i].setFormat; + return f; + } + + /** + * Returns the locale. + */ + public Locale getLocale () + { + return locale; + } + + /** + * Overrides Format.hashCode() + */ + public int hashCode () + { + // FIXME: not a very good hash. + return pattern.hashCode() + locale.hashCode(); + } + + private MessageFormat () + { + } + + /** + * Creates a new MessageFormat object with + * the specified pattern + * + * @param pattern The Pattern + */ + public MessageFormat(String pattern) + { + this(pattern, Locale.getDefault()); + } + + /** + * Creates a new MessageFormat object with + * the specified pattern + * + * @param pattern The Pattern + * @param locale The Locale to use + * + * @since 1.4 + */ + public MessageFormat(String pattern, Locale locale) + { + this.locale = locale; + applyPattern (pattern); + } + + /** + * Parse a string sourceStr against the pattern specified + * to the MessageFormat constructor. + * + * @param sourceStr the string to be parsed. + * @param pos the current parse position (and eventually the error position). + * @return the array of parsed objects sorted according to their argument number + * in the pattern. + */ + public Object[] parse (String sourceStr, ParsePosition pos) + { + // Check initial text. + int index = pos.getIndex(); + if (! sourceStr.startsWith(leader, index)) + { + pos.setErrorIndex(index); + return null; + } + index += leader.length(); + + Vector results = new Vector (elements.length, 1); + // Now check each format. + for (int i = 0; i < elements.length; ++i) + { + Format formatter = null; + if (elements[i].setFormat != null) + formatter = elements[i].setFormat; + else if (elements[i].format != null) + formatter = elements[i].format; + + Object value = null; + if (formatter instanceof ChoiceFormat) + { + // We must special-case a ChoiceFormat because it might + // have recursive formatting. + ChoiceFormat cf = (ChoiceFormat) formatter; + String[] formats = (String[]) cf.getFormats(); + double[] limits = (double[]) cf.getLimits(); + MessageFormat subfmt = new MessageFormat (); + subfmt.setLocale(locale); + ParsePosition subpos = new ParsePosition (index); + + int j; + for (j = 0; value == null && j < limits.length; ++j) + { + subfmt.applyPattern(formats[j]); + subpos.setIndex(index); + value = subfmt.parse(sourceStr, subpos); + } + if (value != null) + { + index = subpos.getIndex(); + value = new Double (limits[j]); + } + } + else if (formatter != null) + { + pos.setIndex(index); + value = formatter.parseObject(sourceStr, pos); + if (value != null) + index = pos.getIndex(); + } + else + { + // We have a String format. This can lose in a number + // of ways, but we give it a shot. + int next_index; + if (elements[i].trailer.length() > 0) + next_index = sourceStr.indexOf(elements[i].trailer, index); + else + next_index = sourceStr.length(); + if (next_index == -1) + { + pos.setErrorIndex(index); + return null; + } + value = sourceStr.substring(index, next_index); + index = next_index; + } + + if (value == null + || ! sourceStr.startsWith(elements[i].trailer, index)) + { + pos.setErrorIndex(index); + return null; + } + + if (elements[i].argNumber >= results.size()) + results.setSize(elements[i].argNumber + 1); + results.setElementAt(value, elements[i].argNumber); + + index += elements[i].trailer.length(); + } + + Object[] r = new Object[results.size()]; + results.copyInto(r); + return r; + } + + public Object[] parse (String sourceStr) throws ParseException + { + ParsePosition pp = new ParsePosition (0); + Object[] r = parse (sourceStr, pp); + if (r == null) + throw new ParseException ("couldn't parse string", pp.getErrorIndex()); + return r; + } + + public Object parseObject (String sourceStr, ParsePosition pos) + { + return parse (sourceStr, pos); + } + + /** + * Sets the format for the argument at an specified + * index. + * + * @param index The index. + * @format The Format object. + */ + public void setFormat (int variableNum, Format newFormat) + { + elements[variableNum].setFormat = newFormat; + } + + /** + * Sets the formats for the arguments. + * + * @param formats An array of Format objects. + */ + public void setFormats (Format[] newFormats) + { + if (newFormats.length < elements.length) + throw new IllegalArgumentException("Not enough format objects"); + + int len = Math.min(newFormats.length, elements.length); + for (int i = 0; i < len; ++i) + elements[i].setFormat = newFormats[i]; + } + + /** + * Sets the locale. + * + * @param locale A Locale + */ + public void setLocale (Locale loc) + { + locale = loc; + if (elements != null) + { + for (int i = 0; i < elements.length; ++i) + elements[i].setLocale(loc); + } + } + + /** + * Returns the pattern. + */ + public String toPattern () + { + return pattern; + } + + /** + * Return the formatters used sorted by argument index. It uses the + * internal table to fill in this array: if a format has been + * set using setFormat or setFormatByArgumentIndex + * then it returns it at the right index. If not it uses the detected + * formatters during a format call. If nothing is known + * about that argument index it just puts null at that position. + * To get useful informations you may have to call format + * at least once. + * + * @return an array of formatters sorted by argument index. + */ + public Format[] getFormatsByArgumentIndex() + { + int argNumMax = 0; + // First, find the greatest argument number. + for (int i=0;i argNumMax) + argNumMax = elements[i].argNumber; + + Format[] formats = new Format[argNumMax]; + for (int i=0;i + * To create an instance of a concrete subclass of NumberFormat, + * do not call a class constructor directly. Instead, use one of the + * static factory methods in this class such as + * getCurrencyInstance. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @date March 4, 1999 + */ +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct to 1.2, except getAvailableLocales. + */ +public abstract class NumberFormat extends Format implements Cloneable +{ + /** + * This is a constant used to create a FieldPosition object + * that will return the integer portion of a formatted number. + */ + public static final int INTEGER_FIELD = 0; + + /** + * This is a constant used to create a FieldPosition object + * that will return the fractional portion of a formatted number. + */ + public static final int FRACTION_FIELD = 1; + + public static class Field extends Format.Field + { + static final long serialVersionUID = 7494728892700160890L; + + /** + * Attribute set to all characters containing digits of the integer + * part. + */ + public static final NumberFormat.Field INTEGER + = new Field("integer"); + + /** + * Attribute set to all characters containing digits of the fractional + * part. + */ + public static final NumberFormat.Field FRACTION + = new Field("fraction"); + + /** + * Attribute set to all characters containing digits of the exponential + * part. + */ + public static final NumberFormat.Field EXPONENT + = new Field("exponent"); + + /** + * Attribute set to all characters containing a decimal separator. + */ + public static final NumberFormat.Field DECIMAL_SEPARATOR + = new Field("decimal separator"); + + /** + * Attribute set to all characters containing a sign (plus or minus). + */ + public static final NumberFormat.Field SIGN + = new Field("sign"); + + /** + * Attribute set to all characters containing a grouping separator (e.g. + * a comma, a white space,...). + */ + public static final NumberFormat.Field GROUPING_SEPARATOR + = new Field("grouping separator"); + + /** + * Attribute set to all characters containing an exponential symbol (e.g. + * 'E') + */ + public static final NumberFormat.Field EXPONENT_SYMBOL + = new Field("exponent symbol"); + + /** + * Attribute set to all characters containing a percent symbol (e.g. '%') + */ + public static final NumberFormat.Field PERCENT + = new Field("percent"); + + /** + * Attribute set to all characters containing a permille symbol. + */ + public static final NumberFormat.Field PERMILLE + = new Field("permille"); + + /** + * Attribute set to all characters containing the currency unit. + */ + public static final NumberFormat.Field CURRENCY + = new Field("currency"); + + /** + * Attribute set to all characters containing the exponent sign. + */ + public static final NumberFormat.Field EXPONENT_SIGN + = new Field("exponent sign"); + + /** + * Private fields to register all fields contained in this descriptor. + */ + private static final NumberFormat.Field[] allFields = + { + INTEGER, FRACTION, EXPONENT, DECIMAL_SEPARATOR, SIGN, + GROUPING_SEPARATOR, EXPONENT_SYMBOL, PERCENT, + PERMILLE, CURRENCY, EXPONENT_SIGN + }; + + /** + * This constructor is only used by the deserializer. Without it, + * it would fail to construct a valid object. + */ + private Field() + { + super(""); + } + + /** + * Create a Field instance with the specified field name. + * + * @param field_name Field name for the new Field instance. + */ + protected Field(String field_name) + { + super (field_name); + } + + /** + * This function is used by the deserializer to know which object + * to use when it encounters an encoded NumberFormat.Field in a + * serialization stream. If the stream is valid it should return + * one of the above field. In the other case we throw an exception. + * + * @return a valid official NumberFormat.Field instance. + * + * @throws InvalidObjectException if the field name is invalid. + */ + protected Object readResolve() throws InvalidObjectException + { + String s = getName(); + for (int i = 0; i < allFields.length; i++) + if (s.equals(allFields[i].getName())) + return allFields[i]; + + throw new InvalidObjectException("no such NumberFormat field called " + + s); + } + } + + /** + * This method is a specialization of the format method that performs + * a simple formatting of the specified long number. + * + * @param number The long to format. + * + * @return The formatted number + */ + public final String format (long number) + { + StringBuffer sbuf = new StringBuffer(50); + format (number, sbuf, null); + return sbuf.toString(); + } + + public final StringBuffer format (Object obj, StringBuffer sbuf, + FieldPosition pos) + { + if (obj instanceof Number) + return format(((Number) obj).doubleValue(), sbuf, pos); + else + throw new IllegalArgumentException + ("Cannot format given Object as a Number"); + } + + /** + * This method formats the specified double and appends it to + * a StringBuffer. + * + * @param number The double to format. + * @param sb The StringBuffer to append the formatted number to. + * @param pos The desired FieldPosition. + * + * @return The StringBuffer with the appended number. + */ + public abstract StringBuffer format (double number, + StringBuffer sbuf, FieldPosition pos); + + /** + * This method formats the specified long and appends it to + * a StringBuffer. + * + * @param number The long to format. + * @param sb The StringBuffer to append the formatted number to. + * @param pos The desired FieldPosition. + * + * @return The StringBuffer with the appended number. + */ + public abstract StringBuffer format (long number, + StringBuffer sbuf, FieldPosition pos); + + /** + * This method tests the specified object for equality against this object. + * This will be true if the following conditions are met: + *

    + *

      + *
    • The specified object is not null. + *
    • The specified object is an instance of NumberFormat. + *
    + *

    + * Since this method does not test much, it is highly advised that + * concrete subclasses override this method. + * + * @param obj The Object to test against equality with + * this object. + * + * @return true if the specified object is equal to + * this object, false otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof NumberFormat)) + return false; + NumberFormat nf = (NumberFormat) obj; + return (groupingUsed == nf.groupingUsed + && maximumFractionDigits == nf.maximumFractionDigits + && maximumIntegerDigits == nf.maximumIntegerDigits + && minimumFractionDigits == nf.minimumFractionDigits + && minimumIntegerDigits == nf.minimumIntegerDigits + && parseIntegerOnly == nf.parseIntegerOnly); + } + + /** + * This method returns a list of locales for which concrete instances + * of NumberFormat subclasses may be created. + * + * @return The list of available locales. + */ + public static Locale[] getAvailableLocales () + { + Locale[] list = new Locale[1]; + list[0] = Locale.US; + return list; + } + + private static NumberFormat computeInstance(Locale loc, String resource, + String def) + { + ResourceBundle res; + try + { + res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + loc, ClassLoader.getSystemClassLoader()); + } + catch (MissingResourceException x) + { + res = null; + } + String fmt; + try + { + fmt = res == null ? def : res.getString(resource); + } + catch (MissingResourceException x) + { + fmt = def; + } + DecimalFormatSymbols dfs = new DecimalFormatSymbols (loc); + return new DecimalFormat (fmt, dfs); + } + + /** + * This method returns an instance of NumberFormat suitable + * for formatting and parsing currency values in the default locale. + * + * @return An instance of NumberFormat for handling currencies. + */ + public static final NumberFormat getCurrencyInstance () + { + return getCurrencyInstance (Locale.getDefault()); + } + + /** + * This method returns an instance of NumberFormat suitable + * for formatting and parsing currency values in the specified locale. + * + * @return An instance of NumberFormat for handling currencies. + */ + public static NumberFormat getCurrencyInstance (Locale loc) + { + NumberFormat format; + + format = computeInstance (loc, "currencyFormat", "$#,##0.00;($#,##0.00)"); + format.setMaximumFractionDigits(format.getCurrency().getDefaultFractionDigits()); + return format; + } + + /** + * This method returns a default instance for the default locale. This + * will be a concrete subclass of NumberFormat, but the + * actual class returned is dependent on the locale. + * + * @return An instance of the default NumberFormat class. + */ + public static final NumberFormat getInstance () + { + return getInstance (Locale.getDefault()); + } + + /** + * This method returns a default instance for the specified locale. This + * will be a concrete subclass of NumberFormat, but the + * actual class returned is dependent on the locale. + * + * @param locale The desired locale. + * + * @return An instance of the default NumberFormat class. + */ + public static NumberFormat getInstance (Locale loc) + { + // For now always return a number instance. + return getNumberInstance (loc); + } + + /** + * This method returns the maximum number of digits allowed in the fraction + * portion of a number. + * + * @return The maximum number of digits allowed in the fraction + * portion of a number. + */ + public int getMaximumFractionDigits () + { + return maximumFractionDigits; + } + + /** + * This method returns the maximum number of digits allowed in the integer + * portion of a number. + * + * @return The maximum number of digits allowed in the integer + * portion of a number. + */ + public int getMaximumIntegerDigits () + { + return maximumIntegerDigits; + } + + /** + * This method returns the minimum number of digits allowed in the fraction + * portion of a number. + * + * @return The minimum number of digits allowed in the fraction + * portion of a number. + */ + public int getMinimumFractionDigits () + { + return minimumFractionDigits; + } + + /** + * This method returns the minimum number of digits allowed in the integer + * portion of a number. + * + * @return The minimum number of digits allowed in the integer + * portion of a number. + */ + public int getMinimumIntegerDigits () + { + return minimumIntegerDigits; + } + + /** + * This method returns a default instance for the specified locale. This + * will be a concrete subclass of NumberFormat, but the + * actual class returned is dependent on the locale. + * + * @param locale The desired locale. + * + * @return An instance of the default NumberFormat class. + */ + public static final NumberFormat getNumberInstance () + { + return getNumberInstance (Locale.getDefault()); + } + + /** + * This method returns a general purpose number formatting and parsing + * class for the default locale. This will be a concrete subclass of + * NumberFormat, but the actual class returned is dependent + * on the locale. + * + * @return An instance of a generic number formatter for the default locale. + */ + public static NumberFormat getNumberInstance (Locale loc) + { + return computeInstance (loc, "numberFormat", "#,##0.###"); + } + + /** + * This method returns an integer formatting and parsing class for the + * default locale. This will be a concrete subclass of NumberFormat, + * but the actual class returned is dependent on the locale. + * + * @return An instance of an integer number formatter for the default locale. + * @since 1.4 + */ + public static final NumberFormat getIntegerInstance() + { + return getIntegerInstance (Locale.getDefault()); + } + + /** + * This method returns an integer formatting and parsing class for the + * default locale. This will be a concrete subclass of NumberFormat, + * but the actual class returned is dependent on the locale. + * + * @param locale the desired locale. + * + * @return An instance of an integer number formatter for the desired locale. + * @since 1.4 + */ + public static NumberFormat getIntegerInstance(Locale locale) + { + NumberFormat format = computeInstance (locale, "numberFormat", "#,##0"); + format.setMaximumFractionDigits(0); + format.setParseIntegerOnly (true); + return format; + } + + /** + * This method returns an instance of NumberFormat suitable + * for formatting and parsing percentage values in the default locale. + * + * @return An instance of NumberFormat for handling percentages. + */ + public static final NumberFormat getPercentInstance () + { + return getPercentInstance (Locale.getDefault()); + } + + /** + * This method returns an instance of NumberFormat suitable + * for formatting and parsing percentage values in the specified locale. + * + * @param locale The desired locale. + * + * @return An instance of NumberFormat for handling percentages. + */ + public static NumberFormat getPercentInstance (Locale loc) + { + return computeInstance (loc, "percentFormat", "#,##0%"); + } + + /** + * This method returns a hash value for this object. + * + * @return The hash code. + */ + public int hashCode () + { + int hash = super.hashCode(); + hash ^= (maximumFractionDigits + maximumIntegerDigits + + minimumFractionDigits + minimumIntegerDigits); + if (groupingUsed) + hash ^= 0xf0f0; + if (parseIntegerOnly) + hash ^= 0x0f0f; + return hash; + } + + /** + * This method tests whether or not grouping is in use. Grouping is + * a method of marking separations in numbers, such as thousand separators + * in the US English locale. The grouping positions and symbols are all + * locale specific. As an example, with grouping disabled, the number one + * million would appear as "1000000". With grouping enabled, this number + * might appear as "1,000,000". (Both of these assume the US English + * locale). + * + * @return true if grouping is enabled, + * false otherwise. + */ + public boolean isGroupingUsed () + { + return groupingUsed; + } + + /** + * This method tests whether or not only integer values should be parsed. + * If this class is parsing only integers, parsing stops at the decimal + * point. + * + * @return true if only integers are parsed, + * false otherwise. + */ + public boolean isParseIntegerOnly () + { + return parseIntegerOnly; + } + + /** + * This is a default constructor for use by subclasses. + */ + public NumberFormat () + { + } + + /** + * This method parses the specified string into a Number. This + * will be a Long if possible, otherwise it will be a + * Double. If no number can be parsed, no exception is + * thrown. Instead, the parse position remains at its initial index. + * + * @param str The string to parse. + * @param pp The desired ParsePosition. + * + * @return The parsed Number + */ + public abstract Number parse (String sourceStr, ParsePosition pos); + + /** + * This method parses the specified string into a Number. This + * will be a Long if possible, otherwise it will be a + * Double. If no number can be parsed, an exception will be + * thrown. + * + * @param str The string to parse. + * + * @return The parsed Number + * + * @exception ParseException If no number can be parsed. + */ + public Number parse (String sourceStr) throws ParseException + { + ParsePosition pp = new ParsePosition (0); + Number r = parse (sourceStr, pp); + if (r == null) + { + int index = pp.getErrorIndex(); + if (index < 0) + index = pp.getIndex(); + throw new ParseException ("couldn't parse number", index); + } + return r; + } + + /** + * This method parses the specified string into an Object. This + * will be a Long if possible, otherwise it will be a + * Double. If no number can be parsed, no exception is + * thrown. Instead, the parse position remains at its initial index. + * + * @param str The string to parse. + * @param pp The desired ParsePosition. + * + * @return The parsed Object + */ + public final Object parseObject (String sourceStr, ParsePosition pos) + { + return parse (sourceStr, pos); + } + + /** + * This method sets the grouping behavior of this formatter. Grouping is + * a method of marking separations in numbers, such as thousand separators + * in the US English locale. The grouping positions and symbols are all + * locale specific. As an example, with grouping disabled, the number one + * million would appear as "1000000". With grouping enabled, this number + * might appear as "1,000,000". (Both of these assume the US English + * locale). + * + * @param groupingUsed true to enable grouping, + * false to disable it. + */ + public void setGroupingUsed (boolean newValue) + { + groupingUsed = newValue; + } + + /** + * This method sets the maximum number of digits allowed in the fraction + * portion of a number to the specified value. If this is less than the + * current minimum allowed digits, the minimum allowed digits value will + * be lowered to be equal to the new maximum allowed digits value. + * + * @param maximumFractionDigits The new maximum fraction digits value. + */ + public void setMaximumFractionDigits (int newValue) + { + maximumFractionDigits = newValue; + if (getMinimumFractionDigits () > maximumFractionDigits) + setMinimumFractionDigits (maximumFractionDigits); + } + + /** + * This method sets the maximum number of digits allowed in the integer + * portion of a number to the specified value. If this is less than the + * current minimum allowed digits, the minimum allowed digits value will + * be lowered to be equal to the new maximum allowed digits value. + * + * @param maximumIntegerDigits The new maximum integer digits value. + */ + public void setMaximumIntegerDigits (int newValue) + { + maximumIntegerDigits = newValue; + if (getMinimumIntegerDigits () > maximumIntegerDigits) + setMinimumIntegerDigits (maximumIntegerDigits); + } + + /** + * This method sets the minimum number of digits allowed in the fraction + * portion of a number to the specified value. If this is greater than the + * current maximum allowed digits, the maximum allowed digits value will + * be raised to be equal to the new minimum allowed digits value. + * + * @param minimumFractionDigits The new minimum fraction digits value. + */ + public void setMinimumFractionDigits (int newValue) + { + minimumFractionDigits = newValue; + if (getMaximumFractionDigits () < minimumFractionDigits) + setMaximumFractionDigits (minimumFractionDigits); + } + + /** + * This method sets the minimum number of digits allowed in the integer + * portion of a number to the specified value. If this is greater than the + * current maximum allowed digits, the maximum allowed digits value will + * be raised to be equal to the new minimum allowed digits value. + * + * @param minimumIntegerDigits The new minimum integer digits value. + */ + public void setMinimumIntegerDigits (int newValue) + { + minimumIntegerDigits = newValue; + if (getMaximumIntegerDigits () < minimumIntegerDigits) + setMaximumIntegerDigits (minimumIntegerDigits); + } + + /** + * This method sets the parsing behavior of this object to parse only + * integers or not. + * + * @param parseIntegerOnly true to parse only integers, + * false otherwise. + */ + public void setParseIntegerOnly (boolean value) + { + parseIntegerOnly = value; + } + + /** + * This method is a specialization of the format method that performs + * a simple formatting of the specified double number. + * + * @param number The double to format. + * + * @return The formatted number + */ + public final String format (double number) + { + StringBuffer sbuf = new StringBuffer(50); + format (number, sbuf, null); + return sbuf.toString(); + } + + // These field names are fixed by the serialization spec. + boolean groupingUsed; + int maximumFractionDigits; + private byte maxFractionDigits; + int maximumIntegerDigits; + private byte maxIntegerDigits; + int minimumFractionDigits; + private byte minFractionDigits; + int minimumIntegerDigits; + private byte minIntegerDigits; + boolean parseIntegerOnly; + private int serialVersionOnStream; + private static final long serialVersionUID = -2308460125733713944L; + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + if (serialVersionOnStream < 1) + { + maximumFractionDigits = maxFractionDigits; + maximumIntegerDigits = maxIntegerDigits; + minimumFractionDigits = minFractionDigits; + minimumIntegerDigits = minIntegerDigits; + serialVersionOnStream = 1; + } + } + + private void writeObject(ObjectOutputStream stream) throws IOException + { + maxFractionDigits = maximumFractionDigits < Byte.MAX_VALUE ? + (byte) maximumFractionDigits : Byte.MAX_VALUE; + maxIntegerDigits = maximumIntegerDigits < Byte.MAX_VALUE ? + (byte) maximumIntegerDigits : Byte.MAX_VALUE; + minFractionDigits = minimumFractionDigits < Byte.MAX_VALUE ? + (byte) minimumFractionDigits : Byte.MAX_VALUE; + minIntegerDigits = minimumIntegerDigits < Byte.MAX_VALUE ? + (byte) minimumIntegerDigits : Byte.MAX_VALUE; + serialVersionOnStream = 1; + stream.defaultWriteObject(); + } + + /** + * Returns the currency used by this number format when formatting currency + * values. + * + * The default implementation throws UnsupportedOperationException. + * + * @return The used currency object, or null. + * + * @throws UnsupportedOperationException If the number format class doesn't + * implement currency formatting. + * + * @since 1.4 + */ + public Currency getCurrency() + { + throw new UnsupportedOperationException(); + } + + /** + * Sets the currency used by this number format when formatting currency + * values. + * + * The default implementation throws UnsupportedOperationException. + * + * @param currency The new currency to be used by this number format. + * + * @throws NullPointerException If currenc is null. + * @throws UnsupportedOperationException If the number format class doesn't + * implement currency formatting. + * + * @since 1.4 + */ + public void setCurrency(Currency currency) + { + if (currency == null) + throw new NullPointerException("currency may not be null"); + + throw new UnsupportedOperationException(); + } +} diff --git a/libjava/classpath/java/text/ParseException.java b/libjava/classpath/java/text/ParseException.java new file mode 100644 index 0000000..6d014ef --- /dev/null +++ b/libjava/classpath/java/text/ParseException.java @@ -0,0 +1,86 @@ +/* ParseException.java -- an error occurred while parsing + Copyright (C) 1998, 1999, 2001, 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 java.text; + +/** + * This exception is thrown when an unexpected error occurs during parsing. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + * @see Format + * @see FieldPosition + * @status updated to 1.4 + */ +public class ParseException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 2703218443322787634L; + + /** + * This is the position where the error was encountered. + * + * @serial the zero-based offset in the string where the error occurred + */ + private final int errorOffset; + + /** + * This method initializes a new instance of ParseException + * with a detailed error message and a error position. + * + * @param msg the descriptive message describing the error + * @param offset the position where the error was encountered + */ + public ParseException(String s, int offset) + { + super(s); + errorOffset = offset; + } + + /** + * This method returns the position where the error occurred. + * + * @return the position where the error occurred + */ + public int getErrorOffset() + { + return errorOffset; + } +} // class ParseException diff --git a/libjava/classpath/java/text/ParsePosition.java b/libjava/classpath/java/text/ParsePosition.java new file mode 100644 index 0000000..782f5e0 --- /dev/null +++ b/libjava/classpath/java/text/ParsePosition.java @@ -0,0 +1,151 @@ +/* ParsePosition.java -- Keep track of position while parsing. + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +/** + * This class is used to keep track of the current position during parsing + * operations. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + */ +public class ParsePosition +{ + /** + * This is the index of the current parse position. + */ + private int index; + + /** + * This is the index of the position where an error occurred during parsing. + */ + private int error_index; + + /** + * This method initializes a new instance of ParsePosition to + * have the specified initial index value. + * + * @param index The initial parsing index. + */ + public ParsePosition (int index) + { + this.index = index; + error_index = -1; + } + + /** + * This method returns the current parsing index. + * + * @return The current parsing index + */ + public int getIndex () + { + return index; + } + + /** + * This method sets the current parsing index to the specified value. + * + * @param index The new parsing index. + */ + public void setIndex (int index) + { + this.index = index; + } + + /** + * This method returns the error index value. This value defaults to -1 + * unless explicitly set to another value. + * + * @return The error index. + */ + public int getErrorIndex () + { + return error_index; + } + + /** + * This method sets the error index to the specified value. + * + * @param error_index The new error index + */ + public void setErrorIndex (int error_index) + { + this.error_index = error_index; + } + + /** + * This method tests the specified object for equality with this + * object. The two objects will be considered equal if and only if + * all of the following conditions are met. + *

    + *

      + *
    • The specified object is not null.
    • + *
    • The specified object is an instance of ParsePosition.
    • + *
    • The specified object has the same index and error index as + * this object.
    • + *
    + * + * @param obj The Object to test for equality against + * this object. + * + * @return true if the specified object is equal to + * this object, false otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof ParsePosition)) + return false; + + ParsePosition other = (ParsePosition) obj; + return index == other.index && error_index == other.error_index; + } + + /** + * This method returns a String representation of this + * object. + * + * @return A String that represents this object. + */ + public String toString () + { + return (getClass ().getName () + "[index=" + getIndex () + + ",errorIndex=" + getErrorIndex () + "]"); + } +} diff --git a/libjava/classpath/java/text/RuleBasedCollator.java b/libjava/classpath/java/text/RuleBasedCollator.java new file mode 100644 index 0000000..ae84a41 --- /dev/null +++ b/libjava/classpath/java/text/RuleBasedCollator.java @@ -0,0 +1,1017 @@ +/* RuleBasedCollator.java -- Concrete Collator Class + 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 java.text; + +import java.util.ArrayList; +import java.util.HashMap; + +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct + */ + +/** + * This class is a concrete subclass of Collator suitable + * for string collation in a wide variety of languages. An instance of + * this class is normally returned by the getInstance method + * of Collator with rules predefined for the requested + * locale. However, an instance of this class can be created manually + * with any desired rules. + *

    + * Rules take the form of a String with the following syntax + *

      + *
    • Modifier: '@'
    • + *
    • Relation: '<' | ';' | ',' | '=' : <text>
    • + *
    • Reset: '&' : <text>
    • + *
    + * The modifier character indicates that accents sort backward as is the + * case with French. The modifier applies to all rules after + * the modifier but before the next primary sequence. If placed at the end + * of the sequence if applies to all unknown accented character. + * The relational operators specify how the text + * argument relates to the previous term. The relation characters have + * the following meanings: + *
      + *
    • '<' - The text argument is greater than the prior term at the primary + * difference level.
    • + *
    • ';' - The text argument is greater than the prior term at the secondary + * difference level.
    • + *
    • ',' - The text argument is greater than the prior term at the tertiary + * difference level.
    • + *
    • '=' - The text argument is equal to the prior term
    • + *
    + *

    + * As for the text argument itself, this is any sequence of Unicode + * characters not in the following ranges: 0x0009-0x000D, 0x0020-0x002F, + * 0x003A-0x0040, 0x005B-0x0060, and 0x007B-0x007E. If these characters are + * desired, they must be enclosed in single quotes. If any whitespace is + * encountered, it is ignored. (For example, "a b" is equal to "ab"). + *

    + * The reset operation inserts the following rule at the point where the + * text argument to it exists in the previously declared rule string. This + * makes it easy to add new rules to an existing string by simply including + * them in a reset sequence at the end. Note that the text argument, or + * at least the first character of it, must be present somewhere in the + * previously declared rules in order to be inserted properly. If this + * is not satisfied, a ParseException will be thrown. + *

    + * This system of configuring RuleBasedCollator is needlessly + * complex and the people at Taligent who developed it (along with the folks + * at Sun who accepted it into the Java standard library) deserve a slow + * and agonizing death. + *

    + * Here are a couple of example of rule strings: + *

    + * "< a < b < c" - This string says that a is greater than b which is + * greater than c, with all differences being primary differences. + *

    + * "< a,A < b,B < c,C" - This string says that 'A' is greater than 'a' with + * a tertiary strength comparison. Both 'b' and 'B' are greater than 'a' and + * 'A' during a primary strength comparison. But 'B' is greater than 'b' + * under a tertiary strength comparison. + *

    + * "< a < c & a < b " - This sequence is identical in function to the + * "< a < b < c" rule string above. The '&' reset symbol indicates that + * the rule "< b" is to be inserted after the text argument "a" in the + * previous rule string segment. + *

    + * "< a < b & y < z" - This is an error. The character 'y' does not appear + * anywhere in the previous rule string segment so the rule following the + * reset rule cannot be inserted. + *

    + * "< a & A @ < e & E < f& F" - This sequence is equivalent to the following + * "< a & A < E & e < f & F". + *

    + * For a description of the various comparison strength types, see the + * documentation for the Collator class. + *

    + * As an additional complication to this already overly complex rule scheme, + * if any characters precede the first rule, these characters are considered + * ignorable. They will be treated as if they did not exist during + * comparisons. For example, "- < a < b ..." would make '-' an ignorable + * character such that the strings "high-tech" and "hightech" would + * be considered identical. + *

    + * A ParseException will be thrown for any of the following + * conditions: + *

      + *
    • Unquoted punctuation characters in a text argument.
    • + *
    • A relational or reset operator not followed by a text argument
    • + *
    • A reset operator where the text argument is not present in + * the previous rule string section.
    • + *
    + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @author Guilhem Lavaux (guilhem@kaffe.org) + */ +public class RuleBasedCollator extends Collator +{ + /** + * This class describes what rank has a character (or a sequence of characters) + * in the lexicographic order. Each element in a rule has a collation element. + */ + static final class CollationElement + { + String key; + int primary; + short secondary; + short tertiary; + short equality; + boolean ignore; + String expansion; + + CollationElement(String key, int primary, short secondary, short tertiary, + short equality, String expansion, boolean ignore) + { + this.key = key; + this.primary = primary; + this.secondary = secondary; + this.tertiary = tertiary; + this.equality = equality; + this.ignore = ignore; + this.expansion = expansion; + } + + int getValue() + { + return (primary << 16) + (secondary << 8) + tertiary; + } + } + + /** + * Basic collation instruction (internal format) to build the series of + * collation elements. It contains an instruction which specifies the new + * state of the generator. The sequence of instruction should not contain + * RESET (it is used by + * {@link #mergeRules(int,java.lang.String,java.util.ArrayList,java.util.ArrayList)}) + * as a temporary state while merging two sets of instructions. + */ + static final class CollationSorter + { + static final int GREATERP = 0; + static final int GREATERS = 1; + static final int GREATERT = 2; + static final int EQUAL = 3; + static final int RESET = 4; + static final int INVERSE_SECONDARY = 5; + + int comparisonType; + String textElement; + int hashText; + int offset; + boolean ignore; + + String expansionOrdering; + } + + /** + * This the the original rule string. + */ + private String rules; + + /** + * This is the table of collation element values + */ + private Object[] ce_table; + + /** + * Quick-prefix finder. + */ + HashMap prefix_tree; + + /** + * This is the value of the last sequence entered into + * ce_table. It is used to compute the + * ordering value of unspecified character. + */ + private int last_primary_value; + + /** + * This is the value of the last secondary sequence of the + * primary 0, entered into + * ce_table. It is used to compute the + * ordering value of an unspecified accented character. + */ + private int last_tertiary_value; + + /** + * This variable is true if accents need to be sorted + * in the other direction. + */ + private boolean inverseAccentComparison; + + /** + * This collation element is special to unknown sequence. + * The JDK uses it to mark and sort the characters which has + * no collation rules. + */ + static final CollationElement SPECIAL_UNKNOWN_SEQ = + new CollationElement("", (short) 32767, (short) 0, (short) 0, + (short) 0, null, false); + + /** + * This method initializes a new instance of RuleBasedCollator + * with the specified collation rules. Note that an application normally + * obtains an instance of RuleBasedCollator by calling the + * getInstance method of Collator. That method + * automatically loads the proper set of rules for the desired locale. + * + * @param rules The collation rule string. + * + * @exception ParseException If the rule string contains syntax errors. + */ + public RuleBasedCollator(String rules) throws ParseException + { + if (rules.equals("")) + throw new ParseException("empty rule set", 0); + + this.rules = rules; + + buildCollationVector(parseString(rules)); + buildPrefixAccess(); + } + + /** + * This method returns the number of common characters at the beginning + * of the string of the two parameters. + * + * @param prefix A string considered as a prefix to test against + * the other string. + * @param s A string to test the prefix against. + * @return The number of common characters. + */ + static int findPrefixLength(String prefix, String s) + { + int index; + int len = prefix.length(); + + for (index = 0; index < len && index < s.length(); ++index) + { + if (prefix.charAt(index) != s.charAt(index)) + return index; + } + + + return index; + } + + /** + * Here we are merging two sets of sorting instructions: 'patch' into 'main'. This methods + * checks whether it is possible to find an anchor point for the rules to be merged and + * then insert them at that precise point. + * + * @param offset Offset in the string containing rules of the beginning of the rules + * being merged in. + * @param starter Text of the rules being merged. + * @param main Repository of all already parsed rules. + * @param patch Rules to be merged into the repository. + * @throws ParseException if it is impossible to find an anchor point for the new rules. + */ + private void mergeRules(int offset, String starter, ArrayList main, ArrayList patch) + throws ParseException + { + int insertion_point = -1; + int max_length = 0; + + /* We must check that no rules conflict with another already present. If it + * is the case delete the old rule. + */ + + /* For the moment good old O(N^2) algorithm. + */ + for (int i = 0; i < patch.size(); i++) + { + int j = 0; + + while (j < main.size()) + { + CollationSorter rule1 = (CollationSorter) patch.get(i); + CollationSorter rule2 = (CollationSorter) main.get(j); + + if (rule1.textElement.equals(rule2.textElement)) + main.remove(j); + else + j++; + } + } + + // Find the insertion point... O(N) + for (int i = 0; i < main.size(); i++) + { + CollationSorter sorter = (CollationSorter) main.get(i); + int length = findPrefixLength(starter, sorter.textElement); + + if (length > max_length) + { + max_length = length; + insertion_point = i+1; + } + } + + if (insertion_point < 0) + throw new ParseException("no insertion point found for " + starter, offset); + + if (max_length < starter.length()) + { + /* + * We need to expand the first entry. It must be sorted + * like if it was the reference key itself (like the spec + * said. So the first entry is special: the element is + * replaced by the specified text element for the sorting. + * This text replace the old one for comparisons. However + * to preserve the behaviour we replace the first key (corresponding + * to the found prefix) by a new code rightly ordered in the + * sequence. The rest of the subsequence must be appended + * to the end of the sequence. + */ + CollationSorter sorter = (CollationSorter) patch.get(0); + CollationSorter expansionPrefix = + (CollationSorter) main.get(insertion_point-1); + + sorter.expansionOrdering = starter.substring(max_length); // Skip the first good prefix element + + main.add(insertion_point, sorter); + + /* + * This is a new set of rules. Append to the list. + */ + patch.remove(0); + insertion_point++; + } + + // Now insert all elements of patch at the insertion point. + for (int i = 0; i < patch.size(); i++) + main.add(i+insertion_point, patch.get(i)); + } + + /** + * This method parses a string and build a set of sorting instructions. The parsing + * may only be partial on the case the rules are to be merged sometime later. + * + * @param stop_on_reset If this parameter is true then the parser stops when it + * encounters a reset instruction. In the other case, it tries to parse the subrules + * and merged it in the same repository. + * @param v Output vector for the set of instructions. + * @param base_offset Offset in the string to begin parsing. + * @param rules Rules to be parsed. + * @return -1 if the parser reached the end of the string, an integer representing the + * offset in the string at which it stopped parsing. + * @throws ParseException if something turned wrong during the parsing. To get details + * decode the message. + */ + private int subParseString(boolean stop_on_reset, ArrayList v, + int base_offset, String rules) + throws ParseException + { + boolean ignoreChars = (base_offset == 0); + int operator = -1; + StringBuffer sb = new StringBuffer(); + boolean doubleQuote = false; + boolean eatingChars = false; + boolean nextIsModifier = false; + boolean isModifier = false; + int i; + +main_parse_loop: + for (i = 0; i < rules.length(); i++) + { + char c = rules.charAt(i); + int type = -1; + + if (!eatingChars && + ((c >= 0x09 && c <= 0x0D) || (c == 0x20))) + continue; + + isModifier = nextIsModifier; + nextIsModifier = false; + + if (eatingChars && c != '\'') + { + doubleQuote = false; + sb.append(c); + continue; + } + if (doubleQuote && eatingChars) + { + sb.append(c); + doubleQuote = false; + continue; + } + + switch (c) + { + case '!': + throw new ParseException + ("Modifier '!' is not yet supported by Classpath", i + base_offset); + case '<': + type = CollationSorter.GREATERP; + break; + case ';': + type = CollationSorter.GREATERS; + break; + case ',': + type = CollationSorter.GREATERT; + break; + case '=': + type = CollationSorter.EQUAL; + break; + case '\'': + eatingChars = !eatingChars; + doubleQuote = true; + break; + case '@': + if (ignoreChars) + throw new ParseException + ("comparison list has not yet been started. You may only use" + + "(<,;=&)", i + base_offset); + // Inverse the order of secondaries from now on. + nextIsModifier = true; + type = CollationSorter.INVERSE_SECONDARY; + break; + case '&': + type = CollationSorter.RESET; + if (stop_on_reset) + break main_parse_loop; + break; + default: + if (operator < 0) + throw new ParseException + ("operator missing at " + (i + base_offset), i + base_offset); + if (! eatingChars + && ((c >= 0x21 && c <= 0x2F) + || (c >= 0x3A && c <= 0x40) + || (c >= 0x5B && c <= 0x60) + || (c >= 0x7B && c <= 0x7E))) + throw new ParseException + ("unquoted punctuation character '" + c + "'", i + base_offset); + + //type = ignoreChars ? CollationSorter.IGNORE : -1; + sb.append(c); + break; + } + + if (type < 0) + continue; + + if (operator < 0) + { + operator = type; + continue; + } + + if (sb.length() == 0 && !isModifier) + throw new ParseException + ("text element empty at " + (i+base_offset), i+base_offset); + + if (operator == CollationSorter.RESET) + { + /* Reposition in the sorting list at the position + * indicated by the text element. + */ + String subrules = rules.substring(i); + ArrayList sorted_rules = new ArrayList(); + int idx; + + // Parse the subrules but do not iterate through all + // sublist. This is the priviledge of the first call. + idx = subParseString(true, sorted_rules, base_offset+i, subrules); + + // Merge new parsed rules into the list. + mergeRules(base_offset+i, sb.toString(), v, sorted_rules); + sb.setLength(0); + + // Reset state to none. + operator = -1; + type = -1; + // We have found a new subrule at 'idx' but it has not been parsed. + if (idx >= 0) + { + i += idx-1; + continue main_parse_loop; + } + else + // No more rules. + break main_parse_loop; + } + + CollationSorter sorter = new CollationSorter(); + + if (operator == CollationSorter.GREATERP) + ignoreChars = false; + + sorter.comparisonType = operator; + sorter.textElement = sb.toString(); + sorter.hashText = sorter.textElement.hashCode(); + sorter.offset = base_offset+rules.length(); + sorter.ignore = ignoreChars; + sb.setLength(0); + + v.add(sorter); + operator = type; + } + + if (operator >= 0) + { + CollationSorter sorter = new CollationSorter(); + int pos = rules.length() + base_offset; + + if ((sb.length() != 0 && nextIsModifier) + || (sb.length() == 0 && !nextIsModifier && !eatingChars)) + throw new ParseException("text element empty at " + pos, pos); + + if (operator == CollationSorter.GREATERP) + ignoreChars = false; + + sorter.comparisonType = operator; + sorter.textElement = sb.toString(); + sorter.hashText = sorter.textElement.hashCode(); + sorter.offset = base_offset+pos; + sorter.ignore = ignoreChars; + v.add(sorter); + } + + if (i == rules.length()) + return -1; + else + return i; + } + + /** + * This method creates a copy of this object. + * + * @return A copy of this object. + */ + public Object clone() + { + return super.clone(); + } + + /** + * This method completely parses a string 'rules' containing sorting rules. + * + * @param rules String containing the rules to be parsed. + * @return A set of sorting instructions stored in a Vector. + * @throws ParseException if something turned wrong during the parsing. To get details + * decode the message. + */ + private ArrayList parseString(String rules) + throws ParseException + { + ArrayList v = new ArrayList(); + + // result of the first subParseString is not absolute (may be -1 or a + // positive integer). But we do not care. + subParseString(false, v, 0, rules); + + return v; + } + + /** + * This method uses the sorting instructions built by {@link #parseString} + * to build collation elements which can be directly used to sort strings. + * + * @param parsedElements Parsed instructions stored in a ArrayList. + * @throws ParseException if the order of the instructions are not valid. + */ + private void buildCollationVector(ArrayList parsedElements) + throws ParseException + { + int primary_seq = 0; + int last_tertiary_seq = 0; + short secondary_seq = 0; + short tertiary_seq = 0; + short equality_seq = 0; + boolean inverseComparisons = false; + final boolean DECREASING = false; + final boolean INCREASING = true; + boolean secondaryType = INCREASING; + ArrayList v = new ArrayList(); + + // elts is completely sorted. +element_loop: + for (int i = 0; i < parsedElements.size(); i++) + { + CollationSorter elt = (CollationSorter) parsedElements.get(i); + boolean ignoreChar = false; + + switch (elt.comparisonType) + { + case CollationSorter.GREATERP: + primary_seq++; + if (inverseComparisons) + { + secondary_seq = Short.MAX_VALUE; + secondaryType = DECREASING; + } + else + { + secondary_seq = 0; + secondaryType = INCREASING; + } + tertiary_seq = 0; + equality_seq = 0; + inverseComparisons = false; + break; + case CollationSorter.GREATERS: + if (secondaryType == DECREASING) + secondary_seq--; + else + secondary_seq++; + tertiary_seq = 0; + equality_seq = 0; + break; + case CollationSorter.INVERSE_SECONDARY: + inverseComparisons = true; + continue element_loop; + case CollationSorter.GREATERT: + tertiary_seq++; + if (primary_seq == 0) + last_tertiary_seq = tertiary_seq; + equality_seq = 0; + break; + case CollationSorter.EQUAL: + equality_seq++; + break; + case CollationSorter.RESET: + throw new ParseException + ("Invalid reached state 'RESET'. Internal error", elt.offset); + default: + throw new ParseException + ("Invalid unknown state '" + elt.comparisonType + "'", elt.offset); + } + + v.add(new CollationElement(elt.textElement, primary_seq, + secondary_seq, tertiary_seq, + equality_seq, elt.expansionOrdering, elt.ignore)); + } + + this.inverseAccentComparison = inverseComparisons; + + ce_table = v.toArray(); + + last_primary_value = primary_seq+1; + last_tertiary_value = last_tertiary_seq+1; + } + + /** + * Build a tree where all keys are the texts of collation elements and data is + * the collation element itself. The tree is used when extracting all prefix + * for a given text. + */ + private void buildPrefixAccess() + { + prefix_tree = new HashMap(); + + for (int i = 0; i < ce_table.length; i++) + { + CollationElement e = (CollationElement) ce_table[i]; + + prefix_tree.put(e.key, e); + } + } + + /** + * This method returns an integer which indicates whether the first + * specified String is less than, greater than, or equal to + * the second. The value depends not only on the collation rules in + * effect, but also the strength and decomposition settings of this object. + * + * @param source The first String to compare. + * @param target A second String to compare to the first. + * + * @return A negative integer if source < target, a positive integer + * if source > target, or 0 if source == target. + */ + public int compare(String source, String target) + { + CollationElementIterator cs, ct; + CollationElement ord1block = null; + CollationElement ord2block = null; + boolean advance_block_1 = true; + boolean advance_block_2 = true; + + cs = getCollationElementIterator(source); + ct = getCollationElementIterator(target); + + for(;;) + { + int ord1; + int ord2; + + /* + * We have to check whether the characters are ignorable. + * If it is the case then forget them. + */ + if (advance_block_1) + { + ord1block = cs.nextBlock(); + if (ord1block != null && ord1block.ignore) + continue; + } + + if (advance_block_2) + { + ord2block = ct.nextBlock(); + if (ord2block != null && ord2block.ignore) + { + advance_block_1 = false; + continue; + } + } + else + advance_block_2 = true; + + if (!advance_block_1) + advance_block_1 = true; + + if (ord1block != null) + ord1 = ord1block.getValue(); + else + { + if (ord2block == null) + return 0; + return -1; + } + + if (ord2block == null) + return 1; + + ord2 = ord2block.getValue(); + + // We know chars are totally equal, so skip + if (ord1 == ord2) + { + if (getStrength() == IDENTICAL) + if (!ord1block.key.equals(ord2block.key)) + return ord1block.key.compareTo(ord2block.key); + continue; + } + + // Check for primary strength differences + int prim1 = CollationElementIterator.primaryOrder(ord1); + int prim2 = CollationElementIterator.primaryOrder(ord2); + + if (prim1 == 0 && getStrength() < TERTIARY) + { + advance_block_2 = false; + continue; + } + else if (prim2 == 0 && getStrength() < TERTIARY) + { + advance_block_1 = false; + continue; + } + + if (prim1 < prim2) + return -1; + else if (prim1 > prim2) + return 1; + else if (getStrength() == PRIMARY) + continue; + + // Check for secondary strength differences + int sec1 = CollationElementIterator.secondaryOrder(ord1); + int sec2 = CollationElementIterator.secondaryOrder(ord2); + + if (sec1 < sec2) + return -1; + else if (sec1 > sec2) + return 1; + else if (getStrength() == SECONDARY) + continue; + + // Check for tertiary differences + int tert1 = CollationElementIterator.tertiaryOrder(ord1); + int tert2 = CollationElementIterator.tertiaryOrder(ord2); + + if (tert1 < tert2) + return -1; + else if (tert1 > tert2) + return 1; + else if (getStrength() == TERTIARY) + continue; + + // Apparently JDK does this (at least for my test case). + return ord1block.key.compareTo(ord2block.key); + } + } + + /** + * This method tests this object for equality against the specified + * object. This will be true if and only if the specified object is + * another reference to this object. + * + * @param obj The Object to compare against this object. + * + * @return true if the specified object is equal to this object, + * false otherwise. + */ + public boolean equals(Object obj) + { + if (obj == this) + return true; + else + return false; + } + + /** + * This method builds a default collation element without invoking + * the database created from the rules passed to the constructor. + * + * @param c Character which needs a collation element. + * @return A valid brand new CollationElement instance. + */ + CollationElement getDefaultElement(char c) + { + int v; + + // Preliminary support for generic accent sorting inversion (I don't know if all + // characters in the range should be sorted backward). This is the place + // to fix this if needed. + if (inverseAccentComparison && (c >= 0x02B9 && c <= 0x0361)) + v = 0x0361 - ((int) c - 0x02B9); + else + v = (short) c; + return new CollationElement("" + c, last_primary_value + v, + (short) 0, (short) 0, (short) 0, null, false); + } + + /** + * This method builds a default collation element for an accented character + * without invoking the database created from the rules passed to the constructor. + * + * @param c Character which needs a collation element. + * @return A valid brand new CollationElement instance. + */ + CollationElement getDefaultAccentedElement(char c) + { + int v; + + // Preliminary support for generic accent sorting inversion (I don't know if all + // characters in the range should be sorted backward). This is the place + // to fix this if needed. + if (inverseAccentComparison && (c >= 0x02B9 && c <= 0x0361)) + v = 0x0361 - ((int) c - 0x02B9); + else + v = (short) c; + return new CollationElement("" + c, (short) 0, + (short) 0, (short) (last_tertiary_value + v), (short) 0, null, false); + } + + /** + * This method returns an instance for CollationElementIterator + * for the specified String under the collation rules for this + * object. + * + * @param source The String to return the + * CollationElementIterator instance for. + * + * @return A CollationElementIterator for the specified + * String. + */ + public CollationElementIterator getCollationElementIterator(String source) + { + return new CollationElementIterator(this, source); + } + + /** + * This method returns an instance of CollationElementIterator + * for the String represented by the specified + * CharacterIterator. + * + * @param source The CharacterIterator with the desired String. + * + * @return A CollationElementIterator for the specified String. + */ + public CollationElementIterator getCollationElementIterator(CharacterIterator source) + { + StringBuffer expand = new StringBuffer(""); + + // Right now we assume that we will read from the beginning of the string. + for (char c = source.first(); + c != CharacterIterator.DONE; + c = source.next()) + decomposeCharacter(c, expand); + + return getCollationElementIterator(expand.toString()); + } + + /** + * This method returns an instance of CollationKey for the + * specified String. The object returned will have a + * more efficient mechanism for its comparison function that could + * provide speed benefits if multiple comparisons are performed, such + * as during a sort. + * + * @param source The String to create a CollationKey for. + * + * @return A CollationKey for the specified String. + */ + public CollationKey getCollationKey(String source) + { + CollationElementIterator cei = getCollationElementIterator(source); + ArrayList vect = new ArrayList(); + + int ord = cei.next(); + cei.reset(); //set to start of string + + while (ord != CollationElementIterator.NULLORDER) + { + // If the primary order is null, it means this is an ignorable + // character. + if (CollationElementIterator.primaryOrder(ord) == 0) + { + ord = cei.next(); + continue; + } + switch (getStrength()) + { + case PRIMARY: + ord = CollationElementIterator.primaryOrder(ord); + break; + + case SECONDARY: + ord = CollationElementIterator.primaryOrder(ord) << 8; + ord |= CollationElementIterator.secondaryOrder(ord); + + default: + break; + } + + vect.add(new Integer(ord)); + ord = cei.next(); //increment to next key + } + + Object[] objarr = vect.toArray(); + byte[] key = new byte[objarr.length * 4]; + + for (int i = 0; i < objarr.length; i++) + { + int j = ((Integer) objarr[i]).intValue(); + key [i * 4] = (byte) ((j & 0xFF000000) >> 24); + key [i * 4 + 1] = (byte) ((j & 0x00FF0000) >> 16); + key [i * 4 + 2] = (byte) ((j & 0x0000FF00) >> 8); + key [i * 4 + 3] = (byte) (j & 0x000000FF); + } + + return new CollationKey(this, source, key); + } + + /** + * This method returns a String containing the collation rules + * for this object. + * + * @return The collation rules for this object. + */ + public String getRules() + { + return rules; + } + + /** + * This method returns a hash value for this object. + * + * @return A hash value for this object. + */ + public int hashCode() + { + return System.identityHashCode(this); + } +} diff --git a/libjava/classpath/java/text/SimpleDateFormat.java b/libjava/classpath/java/text/SimpleDateFormat.java new file mode 100644 index 0000000..789cb83 --- /dev/null +++ b/libjava/classpath/java/text/SimpleDateFormat.java @@ -0,0 +1,1257 @@ +/* SimpleDateFormat.java -- A class for parsing/formating simple + date constructs + 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 java.text; + +import gnu.java.text.AttributedFormatBuffer; +import gnu.java.text.FormatBuffer; +import gnu.java.text.FormatCharacterIterator; +import gnu.java.text.StringFormatBuffer; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Iterator; +import java.util.Locale; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * SimpleDateFormat provides convenient methods for parsing and formatting + * dates using Gregorian calendars (see java.util.GregorianCalendar). + */ +public class SimpleDateFormat extends DateFormat +{ + /** + * This class is used by SimpleDateFormat as a + * compiled representation of a format string. The field + * ID, size, and character used are stored for each sequence + * of pattern characters. + */ + private class CompiledField + { + /** + * The ID of the field within the local pattern characters. + * Package private for use in out class. + */ + int field; + + /** + * The size of the character sequence. + * Package private for use in out class. + */ + int size; + + /** + * The character used. + */ + private char character; + + /** + * Constructs a compiled field using the + * the given field ID, size and character + * values. + * + * @param f the field ID. + * @param s the size of the field. + * @param c the character used. + */ + public CompiledField(int f, int s, char c) + { + field = f; + size = s; + character = c; + } + + /** + * Retrieves the ID of the field relative to + * the local pattern characters. + */ + public int getField() + { + return field; + } + + /** + * Retrieves the size of the character sequence. + */ + public int getSize() + { + return size; + } + + /** + * Retrieves the character used in the sequence. + */ + public char getCharacter() + { + return character; + } + + /** + * Returns a String representation + * of the compiled field, primarily for debugging + * purposes. + * + * @return a String representation. + */ + public String toString() + { + StringBuffer builder; + + builder = new StringBuffer(getClass().getName()); + builder.append("[field="); + builder.append(field); + builder.append(", size="); + builder.append(size); + builder.append(", character="); + builder.append(character); + builder.append("]"); + + return builder.toString(); + } + } + + /** + * A list of CompiledFields, + * representing the compiled version of the pattern. + * + * @see CompiledField + * @serial Ignored. + */ + private transient ArrayList tokens; + + /** + * The localised data used in formatting, + * such as the day and month names in the local + * language, and the localized pattern characters. + * + * @see DateFormatSymbols + * @serial The localisation data. May not be null. + */ + private DateFormatSymbols formatData; + + /** + * The date representing the start of the century + * used for interpreting two digit years. For + * example, 24/10/2004 would cause two digit + * years to be interpreted as representing + * the years between 2004 and 2104. + * + * @see get2DigitYearStart() + * @see set2DigitYearStart(java.util.Date) + * @see Date + * @serial The start date of the century for parsing two digit years. + * May not be null. + */ + private Date defaultCenturyStart; + + /** + * The year at which interpretation of two + * digit years starts. + * + * @see get2DigitYearStart() + * @see set2DigitYearStart(java.util.Date) + * @serial Ignored. + */ + private transient int defaultCentury; + + /** + * The non-localized pattern string. This + * only ever contains the pattern characters + * stored in standardChars. Localized patterns + * are translated to this form. + * + * @see applyPattern(String) + * @see applyLocalizedPattern(String) + * @see toPattern() + * @see toLocalizedPattern() + * @serial The non-localized pattern string. May not be null. + */ + private String pattern; + + /** + * The version of serialized data used by this class. + * Version 0 only includes the pattern and formatting + * data. Version 1 adds the start date for interpreting + * two digit years. + * + * @serial This specifies the version of the data being serialized. + * Version 0 (or no version) specifies just pattern + * and formatData. Version 1 adds + * the defaultCenturyStart. This implementation + * always writes out version 1 data. + */ + private int serialVersionOnStream = 1; // 0 indicates JDK1.1.3 or earlier + + /** + * For compatability. + */ + private static final long serialVersionUID = 4774881970558875024L; + + // This string is specified in the root of the CLDR. We set it here + // rather than doing a DateFormatSymbols(Locale.US).getLocalPatternChars() + // since someone could theoretically change those values (though unlikely). + private static final String standardChars = "GyMdkHmsSEDFwWahKzYeugAZ"; + + /** + * Reads the serialized version of this object. + * If the serialized data is only version 0, + * then the date for the start of the century + * for interpreting two digit years is computed. + * The pattern is parsed and compiled following the process + * of reading in the serialized data. + * + * @param stream the object stream to read the data from. + * @throws IOException if an I/O error occurs. + * @throws ClassNotFoundException if the class of the serialized data + * could not be found. + * @throws InvalidObjectException if the pattern is invalid. + */ + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + if (serialVersionOnStream < 1) + { + computeCenturyStart (); + serialVersionOnStream = 1; + } + else + // Ensure that defaultCentury gets set. + set2DigitYearStart(defaultCenturyStart); + + // Set up items normally taken care of by the constructor. + tokens = new ArrayList(); + try + { + compileFormat(pattern); + } + catch (IllegalArgumentException e) + { + throw new InvalidObjectException("The stream pattern was invalid."); + } + } + + /** + * Compiles the supplied non-localized pattern into a form + * from which formatting and parsing can be performed. + * This also detects errors in the pattern, which will + * be raised on later use of the compiled data. + * + * @param pattern the non-localized pattern to compile. + * @throws IllegalArgumentException if the pattern is invalid. + */ + private void compileFormat(String pattern) + { + // Any alphabetical characters are treated as pattern characters + // unless enclosed in single quotes. + + char thisChar; + int pos; + int field; + CompiledField current = null; + + for (int i=0; i= 'A' && thisChar <= 'Z') + || (thisChar >= 'a' && thisChar <= 'z')) { + // Not a valid letter + throw new IllegalArgumentException("Invalid letter " + thisChar + + "encountered at character " + i + + "."); + } else if (thisChar == '\'') { + // Quoted text section; skip to next single quote + pos = pattern.indexOf('\'',i+1); + if (pos == -1) { + throw new IllegalArgumentException("Quotes starting at character " + + i + " not closed."); + } + if ((pos+1 < pattern.length()) && (pattern.charAt(pos+1) == '\'')) { + tokens.add(pattern.substring(i+1,pos+1)); + } else { + tokens.add(pattern.substring(i+1,pos)); + } + i = pos; + } else { + // A special character + tokens.add(new Character(thisChar)); + } + } else { + // A valid field + if ((current != null) && (field == current.field)) { + current.size++; + } else { + current = new CompiledField(field,1,thisChar); + tokens.add(current); + } + } + } + } + + /** + * Returns a string representation of this + * class. + * + * @return a string representation of the SimpleDateFormat + * instance. + */ + public String toString() + { + StringBuffer output = new StringBuffer(getClass().getName()); + output.append("[tokens="); + output.append(tokens); + output.append(", formatData="); + output.append(formatData); + output.append(", defaultCenturyStart="); + output.append(defaultCenturyStart); + output.append(", defaultCentury="); + output.append(defaultCentury); + output.append(", pattern="); + output.append(pattern); + output.append(", serialVersionOnStream="); + output.append(serialVersionOnStream); + output.append(", standardChars="); + output.append(standardChars); + output.append("]"); + return output.toString(); + } + + /** + * Constructs a SimpleDateFormat using the default pattern for + * the default locale. + */ + public SimpleDateFormat() + { + /* + * There does not appear to be a standard API for determining + * what the default pattern for a locale is, so use package-scope + * variables in DateFormatSymbols to encapsulate this. + */ + super(); + Locale locale = Locale.getDefault(); + calendar = new GregorianCalendar(locale); + computeCenturyStart(); + tokens = new ArrayList(); + formatData = new DateFormatSymbols(locale); + pattern = (formatData.dateFormats[DEFAULT] + ' ' + + formatData.timeFormats[DEFAULT]); + compileFormat(pattern); + numberFormat = NumberFormat.getInstance(locale); + numberFormat.setGroupingUsed (false); + numberFormat.setParseIntegerOnly (true); + numberFormat.setMaximumFractionDigits (0); + } + + /** + * Creates a date formatter using the specified non-localized pattern, + * with the default DateFormatSymbols for the default locale. + * + * @param pattern the pattern to use. + * @throws NullPointerException if the pattern is null. + * @throws IllegalArgumentException if the pattern is invalid. + */ + public SimpleDateFormat(String pattern) + { + this(pattern, Locale.getDefault()); + } + + /** + * Creates a date formatter using the specified non-localized pattern, + * with the default DateFormatSymbols for the given locale. + * + * @param pattern the non-localized pattern to use. + * @param locale the locale to use for the formatting symbols. + * @throws NullPointerException if the pattern is null. + * @throws IllegalArgumentException if the pattern is invalid. + */ + public SimpleDateFormat(String pattern, Locale locale) + { + super(); + calendar = new GregorianCalendar(locale); + computeCenturyStart(); + tokens = new ArrayList(); + formatData = new DateFormatSymbols(locale); + compileFormat(pattern); + this.pattern = pattern; + numberFormat = NumberFormat.getInstance(locale); + numberFormat.setGroupingUsed (false); + numberFormat.setParseIntegerOnly (true); + numberFormat.setMaximumFractionDigits (0); + } + + /** + * Creates a date formatter using the specified non-localized + * pattern. The specified DateFormatSymbols will be used when + * formatting. + * + * @param pattern the non-localized pattern to use. + * @param formatData the formatting symbols to use. + * @throws NullPointerException if the pattern or formatData is null. + * @throws IllegalArgumentException if the pattern is invalid. + */ + public SimpleDateFormat(String pattern, DateFormatSymbols formatData) + { + super(); + calendar = new GregorianCalendar(); + computeCenturyStart (); + tokens = new ArrayList(); + if (formatData == null) + throw new NullPointerException("formatData"); + this.formatData = formatData; + compileFormat(pattern); + this.pattern = pattern; + numberFormat = NumberFormat.getInstance(); + numberFormat.setGroupingUsed (false); + numberFormat.setParseIntegerOnly (true); + numberFormat.setMaximumFractionDigits (0); + } + + /** + * This method returns a string with the formatting pattern being used + * by this object. This string is unlocalized. + * + * @return The format string. + */ + public String toPattern() + { + return pattern; + } + + /** + * This method returns a string with the formatting pattern being used + * by this object. This string is localized. + * + * @return The format string. + */ + public String toLocalizedPattern() + { + String localChars = formatData.getLocalPatternChars(); + return translateLocalizedPattern(pattern, standardChars, localChars); + } + + /** + * This method sets the formatting pattern that should be used by this + * object. This string is not localized. + * + * @param pattern The new format pattern. + * @throws NullPointerException if the pattern is null. + * @throws IllegalArgumentException if the pattern is invalid. + */ + public void applyPattern(String pattern) + { + tokens = new ArrayList(); + compileFormat(pattern); + this.pattern = pattern; + } + + /** + * This method sets the formatting pattern that should be used by this + * object. This string is localized. + * + * @param pattern The new format pattern. + * @throws NullPointerException if the pattern is null. + * @throws IllegalArgumentException if the pattern is invalid. + */ + public void applyLocalizedPattern(String pattern) + { + String localChars = formatData.getLocalPatternChars(); + pattern = translateLocalizedPattern(pattern, localChars, standardChars); + applyPattern(pattern); + } + + /** + * Translates either from or to a localized variant of the pattern + * string. For example, in the German locale, 't' (for 'tag') is + * used instead of 'd' (for 'date'). This method translates + * a localized pattern (such as 'ttt') to a non-localized pattern + * (such as 'ddd'), or vice versa. Non-localized patterns use + * a standard set of characters, which match those of the U.S. English + * locale. + * + * @param pattern the pattern to translate. + * @param oldChars the old set of characters (used in the pattern). + * @param newChars the new set of characters (which will be used in the + * pattern). + * @return a version of the pattern using the characters in + * newChars. + */ + private String translateLocalizedPattern(String pattern, + String oldChars, String newChars) + { + int len = pattern.length(); + StringBuffer buf = new StringBuffer(len); + boolean quoted = false; + for (int i = 0; i < len; i++) + { + char ch = pattern.charAt(i); + if (ch == '\'') + quoted = ! quoted; + if (! quoted) + { + int j = oldChars.indexOf(ch); + if (j >= 0) + ch = newChars.charAt(j); + } + buf.append(ch); + } + return buf.toString(); + } + + /** + * Returns the start of the century used for two digit years. + * + * @return A Date representing the start of the century + * for two digit years. + */ + public Date get2DigitYearStart() + { + return defaultCenturyStart; + } + + /** + * Sets the start of the century used for two digit years. + * + * @param date A Date representing the start of the century for + * two digit years. + */ + public void set2DigitYearStart(Date date) + { + defaultCenturyStart = date; + calendar.clear(); + calendar.setTime(date); + int year = calendar.get(Calendar.YEAR); + defaultCentury = year - (year % 100); + } + + /** + * This method returns a copy of the format symbol information used + * for parsing and formatting dates. + * + * @return a copy of the date format symbols. + */ + public DateFormatSymbols getDateFormatSymbols() + { + return (DateFormatSymbols) formatData.clone(); + } + + /** + * This method sets the format symbols information used for parsing + * and formatting dates. + * + * @param formatData The date format symbols. + * @throws NullPointerException if formatData is null. + */ + public void setDateFormatSymbols(DateFormatSymbols formatData) + { + if (formatData == null) + { + throw new + NullPointerException("The supplied format data was null."); + } + this.formatData = formatData; + } + + /** + * This methods tests whether the specified object is equal to this + * object. This will be true if and only if the specified object: + *

    + *

      + *
    • Is not null.
    • + *
    • Is an instance of SimpleDateFormat.
    • + *
    • Is equal to this object at the superclass (i.e., DateFormat) + * level.
    • + *
    • Has the same formatting pattern.
    • + *
    • Is using the same formatting symbols.
    • + *
    • Is using the same century for two digit years.
    • + *
    + * + * @param obj The object to compare for equality against. + * + * @return true if the specified object is equal to this object, + * false otherwise. + */ + public boolean equals(Object o) + { + if (!super.equals(o)) + return false; + + if (!(o instanceof SimpleDateFormat)) + return false; + + SimpleDateFormat sdf = (SimpleDateFormat)o; + + if (defaultCentury != sdf.defaultCentury) + return false; + + if (!toPattern().equals(sdf.toPattern())) + return false; + + if (!getDateFormatSymbols().equals(sdf.getDateFormatSymbols())) + return false; + + return true; + } + + /** + * This method returns a hash value for this object. + * + * @return A hash value for this object. + */ + public int hashCode() + { + return super.hashCode() ^ toPattern().hashCode() ^ defaultCentury ^ + getDateFormatSymbols().hashCode(); + } + + + /** + * Formats the date input according to the format string in use, + * appending to the specified StringBuffer. The input StringBuffer + * is returned as output for convenience. + */ + private void formatWithAttribute(Date date, FormatBuffer buffer, FieldPosition pos) + { + String temp; + AttributedCharacterIterator.Attribute attribute; + calendar.setTime(date); + + // go through vector, filling in fields where applicable, else toString + Iterator iter = tokens.iterator(); + while (iter.hasNext()) + { + Object o = iter.next(); + if (o instanceof CompiledField) + { + CompiledField cf = (CompiledField) o; + int beginIndex = buffer.length(); + + switch (cf.getField()) + { + case ERA_FIELD: + buffer.append (formatData.eras[calendar.get (Calendar.ERA)], DateFormat.Field.ERA); + break; + case YEAR_FIELD: + // If we have two digits, then we truncate. Otherwise, we + // use the size of the pattern, and zero pad. + buffer.setDefaultAttribute (DateFormat.Field.YEAR); + if (cf.getSize() == 2) + { + temp = "00"+String.valueOf (calendar.get (Calendar.YEAR)); + buffer.append (temp.substring (temp.length() - 2)); + } + else + withLeadingZeros (calendar.get (Calendar.YEAR), cf.getSize(), buffer); + break; + case MONTH_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.MONTH); + if (cf.getSize() < 3) + withLeadingZeros (calendar.get (Calendar.MONTH) + 1, cf.getSize(), buffer); + else if (cf.getSize() < 4) + buffer.append (formatData.shortMonths[calendar.get (Calendar.MONTH)]); + else + buffer.append (formatData.months[calendar.get (Calendar.MONTH)]); + break; + case DATE_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_MONTH); + withLeadingZeros (calendar.get (Calendar.DATE), cf.getSize(), buffer); + break; + case HOUR_OF_DAY1_FIELD: // 1-24 + buffer.setDefaultAttribute(DateFormat.Field.HOUR_OF_DAY1); + withLeadingZeros ( ((calendar.get (Calendar.HOUR_OF_DAY) + 23) % 24) + 1, + cf.getSize(), buffer); + break; + case HOUR_OF_DAY0_FIELD: // 0-23 + buffer.setDefaultAttribute (DateFormat.Field.HOUR_OF_DAY0); + withLeadingZeros (calendar.get (Calendar.HOUR_OF_DAY), cf.getSize(), buffer); + break; + case MINUTE_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.MINUTE); + withLeadingZeros (calendar.get (Calendar.MINUTE), + cf.getSize(), buffer); + break; + case SECOND_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.SECOND); + withLeadingZeros(calendar.get (Calendar.SECOND), + cf.getSize(), buffer); + break; + case MILLISECOND_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.MILLISECOND); + withLeadingZeros (calendar.get (Calendar.MILLISECOND), cf.getSize(), buffer); + break; + case DAY_OF_WEEK_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK); + if (cf.getSize() < 4) + buffer.append (formatData.shortWeekdays[calendar.get (Calendar.DAY_OF_WEEK)]); + else + buffer.append (formatData.weekdays[calendar.get (Calendar.DAY_OF_WEEK)]); + break; + case DAY_OF_YEAR_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_YEAR); + withLeadingZeros (calendar.get (Calendar.DAY_OF_YEAR), cf.getSize(), buffer); + break; + case DAY_OF_WEEK_IN_MONTH_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK_IN_MONTH); + withLeadingZeros (calendar.get (Calendar.DAY_OF_WEEK_IN_MONTH), + cf.getSize(), buffer); + break; + case WEEK_OF_YEAR_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_YEAR); + withLeadingZeros (calendar.get (Calendar.WEEK_OF_YEAR), + cf.getSize(), buffer); + break; + case WEEK_OF_MONTH_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_MONTH); + withLeadingZeros (calendar.get (Calendar.WEEK_OF_MONTH), + cf.getSize(), buffer); + break; + case AM_PM_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.AM_PM); + buffer.append (formatData.ampms[calendar.get (Calendar.AM_PM)]); + break; + case HOUR1_FIELD: // 1-12 + buffer.setDefaultAttribute (DateFormat.Field.HOUR1); + withLeadingZeros (((calendar.get (Calendar.HOUR) + 11) % 12) + 1, + cf.getSize(), buffer); + break; + case HOUR0_FIELD: // 0-11 + buffer.setDefaultAttribute (DateFormat.Field.HOUR0); + withLeadingZeros (calendar.get (Calendar.HOUR), cf.getSize(), buffer); + break; + case TIMEZONE_FIELD: + buffer.setDefaultAttribute (DateFormat.Field.TIME_ZONE); + TimeZone zone = calendar.getTimeZone(); + boolean isDST = calendar.get (Calendar.DST_OFFSET) != 0; + // FIXME: XXX: This should be a localized time zone. + String zoneID = zone.getDisplayName + (isDST, cf.getSize() > 3 ? TimeZone.LONG : TimeZone.SHORT); + buffer.append (zoneID); + break; + case RFC822_TIMEZONE_FIELD: + buffer.setDefaultAttribute(DateFormat.Field.RFC822_TIME_ZONE); + int pureMinutes = (calendar.get(Calendar.ZONE_OFFSET) + + calendar.get(Calendar.DST_OFFSET)) / (1000 * 60); + String sign = (pureMinutes < 0) ? "-" : "+"; + int hours = pureMinutes / 60; + int minutes = pureMinutes % 60; + buffer.append(sign); + withLeadingZeros(hours, 2, buffer); + withLeadingZeros(minutes, 2, buffer); + break; + default: + throw new IllegalArgumentException ("Illegal pattern character " + + cf.getCharacter()); + } + if (pos != null && (buffer.getDefaultAttribute() == pos.getFieldAttribute() + || cf.getField() == pos.getField())) + { + pos.setBeginIndex(beginIndex); + pos.setEndIndex(buffer.length()); + } + } + else + { + buffer.append(o.toString(), null); + } + } + } + + public StringBuffer format(Date date, StringBuffer buffer, FieldPosition pos) + { + formatWithAttribute(date, new StringFormatBuffer (buffer), pos); + + return buffer; + } + + public AttributedCharacterIterator formatToCharacterIterator(Object date) + throws IllegalArgumentException + { + if (date == null) + throw new NullPointerException("null argument"); + if (!(date instanceof Date)) + throw new IllegalArgumentException("argument should be an instance of java.util.Date"); + + AttributedFormatBuffer buf = new AttributedFormatBuffer(); + formatWithAttribute((Date)date, buf, + null); + buf.sync(); + + return new FormatCharacterIterator(buf.getBuffer().toString(), + buf.getRanges(), + buf.getAttributes()); + } + + private void withLeadingZeros(int value, int length, FormatBuffer buffer) + { + String valStr = String.valueOf(value); + for (length -= valStr.length(); length > 0; length--) + buffer.append('0'); + buffer.append(valStr); + } + + private boolean expect(String source, ParsePosition pos, char ch) + { + int x = pos.getIndex(); + boolean r = x < source.length() && source.charAt(x) == ch; + if (r) + pos.setIndex(x + 1); + else + pos.setErrorIndex(x); + return r; + } + + /** + * This method parses the specified string into a date. + * + * @param dateStr The date string to parse. + * @param pos The input and output parse position + * + * @return The parsed date, or null if the string cannot be + * parsed. + */ + public Date parse (String dateStr, ParsePosition pos) + { + int fmt_index = 0; + int fmt_max = pattern.length(); + + calendar.clear(); + boolean saw_timezone = false; + int quote_start = -1; + boolean is2DigitYear = false; + try + { + for (; fmt_index < fmt_max; ++fmt_index) + { + char ch = pattern.charAt(fmt_index); + if (ch == '\'') + { + int index = pos.getIndex(); + if (fmt_index < fmt_max - 1 + && pattern.charAt(fmt_index + 1) == '\'') + { + if (! expect (dateStr, pos, ch)) + return null; + ++fmt_index; + } + else + quote_start = quote_start < 0 ? fmt_index : -1; + continue; + } + + if (quote_start != -1 + || ((ch < 'a' || ch > 'z') + && (ch < 'A' || ch > 'Z'))) + { + if (! expect (dateStr, pos, ch)) + return null; + continue; + } + + // We've arrived at a potential pattern character in the + // pattern. + int fmt_count = 1; + while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch) + { + ++fmt_count; + } + + // We might need to limit the number of digits to parse in + // some cases. We look to the next pattern character to + // decide. + boolean limit_digits = false; + if (fmt_index < fmt_max + && standardChars.indexOf(pattern.charAt(fmt_index)) >= 0) + limit_digits = true; + --fmt_index; + + // We can handle most fields automatically: most either are + // numeric or are looked up in a string vector. In some cases + // we need an offset. When numeric, `offset' is added to the + // resulting value. When doing a string lookup, offset is the + // initial index into the string array. + int calendar_field; + boolean is_numeric = true; + int offset = 0; + boolean maybe2DigitYear = false; + boolean oneBasedHour = false; + boolean oneBasedHourOfDay = false; + Integer simpleOffset; + String[] set1 = null; + String[] set2 = null; + switch (ch) + { + case 'd': + calendar_field = Calendar.DATE; + break; + case 'D': + calendar_field = Calendar.DAY_OF_YEAR; + break; + case 'F': + calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH; + break; + case 'E': + is_numeric = false; + offset = 1; + calendar_field = Calendar.DAY_OF_WEEK; + set1 = formatData.getWeekdays(); + set2 = formatData.getShortWeekdays(); + break; + case 'w': + calendar_field = Calendar.WEEK_OF_YEAR; + break; + case 'W': + calendar_field = Calendar.WEEK_OF_MONTH; + break; + case 'M': + calendar_field = Calendar.MONTH; + if (fmt_count <= 2) + offset = -1; + else + { + is_numeric = false; + set1 = formatData.getMonths(); + set2 = formatData.getShortMonths(); + } + break; + case 'y': + calendar_field = Calendar.YEAR; + if (fmt_count <= 2) + maybe2DigitYear = true; + break; + case 'K': + calendar_field = Calendar.HOUR; + break; + case 'h': + calendar_field = Calendar.HOUR; + oneBasedHour = true; + break; + case 'H': + calendar_field = Calendar.HOUR_OF_DAY; + break; + case 'k': + calendar_field = Calendar.HOUR_OF_DAY; + oneBasedHourOfDay = true; + break; + case 'm': + calendar_field = Calendar.MINUTE; + break; + case 's': + calendar_field = Calendar.SECOND; + break; + case 'S': + calendar_field = Calendar.MILLISECOND; + break; + case 'a': + is_numeric = false; + calendar_field = Calendar.AM_PM; + set1 = formatData.getAmPmStrings(); + break; + case 'z': + case 'Z': + // We need a special case for the timezone, because it + // uses a different data structure than the other cases. + is_numeric = false; + calendar_field = Calendar.ZONE_OFFSET; + String[][] zoneStrings = formatData.getZoneStrings(); + int zoneCount = zoneStrings.length; + int index = pos.getIndex(); + boolean found_zone = false; + simpleOffset = computeOffset(dateStr.substring(index), pos); + if (simpleOffset != null) + { + found_zone = true; + saw_timezone = true; + calendar.set(Calendar.DST_OFFSET, 0); + offset = simpleOffset.intValue(); + } + else + { + for (int j = 0; j < zoneCount; j++) + { + String[] strings = zoneStrings[j]; + int k; + for (k = 0; k < strings.length; ++k) + { + if (dateStr.startsWith(strings[k], index)) + break; + } + if (k != strings.length) + { + found_zone = true; + saw_timezone = true; + TimeZone tz = TimeZone.getTimeZone (strings[0]); + // Check if it's a DST zone or ordinary + if(k == 3 || k == 4) + calendar.set (Calendar.DST_OFFSET, tz.getDSTSavings()); + else + calendar.set (Calendar.DST_OFFSET, 0); + offset = tz.getRawOffset (); + pos.setIndex(index + strings[k].length()); + break; + } + } + } + if (! found_zone) + { + pos.setErrorIndex(pos.getIndex()); + return null; + } + break; + default: + pos.setErrorIndex(pos.getIndex()); + return null; + } + + // Compute the value we should assign to the field. + int value; + int index = -1; + if (is_numeric) + { + numberFormat.setMinimumIntegerDigits(fmt_count); + if (limit_digits) + numberFormat.setMaximumIntegerDigits(fmt_count); + if (maybe2DigitYear) + index = pos.getIndex(); + Number n = numberFormat.parse(dateStr, pos); + if (pos == null || ! (n instanceof Long)) + return null; + value = n.intValue() + offset; + } + else if (set1 != null) + { + index = pos.getIndex(); + int i; + boolean found = false; + for (i = offset; i < set1.length; ++i) + { + if (set1[i] != null) + if (dateStr.toUpperCase().startsWith(set1[i].toUpperCase(), + index)) + { + found = true; + pos.setIndex(index + set1[i].length()); + break; + } + } + if (!found && set2 != null) + { + for (i = offset; i < set2.length; ++i) + { + if (set2[i] != null) + if (dateStr.toUpperCase().startsWith(set2[i].toUpperCase(), + index)) + { + found = true; + pos.setIndex(index + set2[i].length()); + break; + } + } + } + if (!found) + { + pos.setErrorIndex(index); + return null; + } + value = i; + } + else + value = offset; + + if (maybe2DigitYear) + { + // Parse into default century if the numeric year string has + // exactly 2 digits. + int digit_count = pos.getIndex() - index; + if (digit_count == 2) + { + is2DigitYear = true; + value += defaultCentury; + } + } + + // Calendar uses 0-based hours. + // I.e. 00:00 AM is midnight, not 12 AM or 24:00 + if (oneBasedHour && value == 12) + value = 0; + + if (oneBasedHourOfDay && value == 24) + value = 0; + + // Assign the value and move on. + calendar.set(calendar_field, value); + } + + if (is2DigitYear) + { + // Apply the 80-20 heuristic to dermine the full year based on + // defaultCenturyStart. + int year = calendar.get(Calendar.YEAR); + if (calendar.getTime().compareTo(defaultCenturyStart) < 0) + calendar.set(Calendar.YEAR, year + 100); + } + if (! saw_timezone) + { + // Use the real rules to determine whether or not this + // particular time is in daylight savings. + calendar.clear (Calendar.DST_OFFSET); + calendar.clear (Calendar.ZONE_OFFSET); + } + return calendar.getTime(); + } + catch (IllegalArgumentException x) + { + pos.setErrorIndex(pos.getIndex()); + return null; + } + } + + /** + *

    + * Computes the time zone offset in milliseconds + * relative to GMT, based on the supplied + * String representation. + *

    + *

    + * The supplied String must be a three + * or four digit signed number, with an optional 'GMT' + * prefix. The first one or two digits represents the hours, + * while the last two represent the minutes. The + * two sets of digits can optionally be separated by + * ':'. The mandatory sign prefix (either '+' or '-') + * indicates the direction of the offset from GMT. + *

    + *

    + * For example, 'GMT+0200' specifies 2 hours after + * GMT, while '-05:00' specifies 5 hours prior to + * GMT. The special case of 'GMT' alone can be used + * to represent the offset, 0. + *

    + *

    + * If the String can not be parsed, + * the result will be null. The resulting offset + * is wrapped in an Integer object, in + * order to allow such failure to be represented. + *

    + * + * @param zoneString a string in the form + * (GMT)? sign hours : minutes + * where sign = '+' or '-', hours + * is a one or two digits representing + * a number between 0 and 23, and + * minutes is two digits representing + * a number between 0 and 59. + * @return the parsed offset, or null if parsing + * failed. + */ + private Integer computeOffset(String zoneString, ParsePosition pos) + { + Pattern pattern = + Pattern.compile("(GMT)?([+-])([012])?([0-9]):?([0-9]{2})"); + Matcher matcher = pattern.matcher(zoneString); + + // Match from start, but ignore trailing parts + boolean hasAll = matcher.lookingAt(); + try + { + // Do we have at least the sign, hour and minute? + matcher.group(2); + matcher.group(4); + matcher.group(5); + } + catch (IllegalStateException ise) + { + hasAll = false; + } + if (hasAll) + { + int sign = matcher.group(2).equals("+") ? 1 : -1; + int hour = Integer.parseInt(matcher.group(4)); + if (!matcher.group(3).equals("")) + hour += (Integer.parseInt(matcher.group(3)) * 10); + int minutes = Integer.parseInt(matcher.group(5)); + + if (hour > 23) + return null; + int offset = sign * ((hour * 60) + minutes) * 60000; + + // advance the index + pos.setIndex(pos.getIndex() + matcher.end()); + return new Integer(offset); + } + else if (zoneString.startsWith("GMT")) + { + pos.setIndex(pos.getIndex() + 3); + return new Integer(0); + } + return null; + } + + // Compute the start of the current century as defined by + // get2DigitYearStart. + private void computeCenturyStart() + { + int year = calendar.get(Calendar.YEAR); + calendar.set(Calendar.YEAR, year - 80); + set2DigitYearStart(calendar.getTime()); + } + + /** + * Returns a copy of this instance of + * SimpleDateFormat. The copy contains + * clones of the formatting symbols and the 2-digit + * year century start date. + */ + public Object clone() + { + SimpleDateFormat clone = (SimpleDateFormat) super.clone(); + clone.setDateFormatSymbols((DateFormatSymbols) formatData.clone()); + clone.set2DigitYearStart((Date) defaultCenturyStart.clone()); + return clone; + } + +} diff --git a/libjava/classpath/java/text/StringCharacterIterator.java b/libjava/classpath/java/text/StringCharacterIterator.java new file mode 100644 index 0000000..e3adc85 --- /dev/null +++ b/libjava/classpath/java/text/StringCharacterIterator.java @@ -0,0 +1,356 @@ +/* StringCharacterIterator.java -- Iterate over a character range in a string + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +/** + * This class iterates over a range of characters in a String. + * For a given range of text, a beginning and ending index, + * as well as a current index are defined. These values can be queried + * by the methods in this interface. Additionally, various methods allow + * the index to be set. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public final class StringCharacterIterator implements CharacterIterator +{ + /** + * This is the string to iterate over + */ + private String text; + + /** + * This is the value of the start position of the text range. + */ + private int begin; + + /** + * This is the value of the ending position of the text range. + */ + private int end; + + /** + * This is the current value of the scan index. + */ + private int index; + + /** + * This method initializes a new instance of + * StringCharacterIterator to iterate over the entire + * text of the specified String. The initial index + * value will be set to the first character in the string. + * + * @param text The String to iterate through. + */ + public StringCharacterIterator (String text) + { + this (text, 0, text.length (), 0); + } + + /*************************************************************************/ + + /** + * This method initializes a new instance of + * StringCharacterIterator to iterate over the entire + * text of the specified String. The initial index + * value will be set to the specified value. + * + * @param text The String to iterate through. + * @param index The initial index position. + */ + public StringCharacterIterator (String text, int index) + { + this (text, 0, text.length (), index); + } + + /*************************************************************************/ + + /** + * This method initializes a new instance of + * StringCharacterIterator that iterates over the text + * in a subrange of the specified String. The + * beginning and end of the range are specified by the caller, as is + * the initial index position. + * + * @param text The String to iterate through. + * @param begin The beginning position in the character range. + * @param end The ending position in the character range. + * @param index The initial index position. + * + * @param IllegalArgumentException If any of the range values are + * invalid. + */ + public StringCharacterIterator (String text, int begin, int end, int index) + { + int len = text.length (); + + if ((begin < 0) || (begin > len)) + throw new IllegalArgumentException ("Bad begin position"); + + if ((end < begin) || (end > len)) + throw new IllegalArgumentException ("Bad end position"); + + if ((index < begin) || (index > end)) + throw new IllegalArgumentException ("Bad initial index position"); + + this.text = text; + this.begin = begin; + this.end = end; + this.index = index; + } + + /** + * This is a package level constructor that copies the text out of + * an existing StringCharacterIterator and resets the beginning and + * ending index. + * + * @param scci The StringCharacterIterator to copy the info from + * @param begin The beginning index of the range we are interested in. + * @param end The ending index of the range we are interested in. + */ + StringCharacterIterator (StringCharacterIterator sci, int begin, int end) + { + this (sci.text, begin, end, begin); + } + + /** + * This method returns the character at the current index position + * + * @return The character at the current index position. + */ + public char current () + { + return (index < end) ? text.charAt (index) : DONE; + } + + /*************************************************************************/ + + /** + * This method increments the current index and then returns the + * character at the new index value. If the index is already at + * getEndIndex () - 1, it will not be incremented. + * + * @return The character at the position of the incremented index + * value, or DONE if the index has reached + * getEndIndex () - 1. + */ + public char next () + { + if (index == end) + return DONE; + + ++index; + return current (); + } + + /*************************************************************************/ + + /** + * This method decrements the current index and then returns the + * character at the new index value. If the index value is already + * at the beginning index, it will not be decremented. + * + * @return The character at the position of the decremented index + * value, or DONE if index was already equal to the + * beginning index value. + */ + public char previous () + { + if (index == begin) + return DONE; + + --index; + return current (); + } + + /*************************************************************************/ + + /** + * This method sets the index value to the beginning of the range and returns + * the character there. + * + * @return The character at the beginning of the range, or + * DONE if the range is empty. + */ + public char first () + { + index = begin; + return current (); + } + + /*************************************************************************/ + + /** + * This method sets the index value to getEndIndex () - 1 and + * returns the character there. If the range is empty, then the index value + * will be set equal to the beginning index. + * + * @return The character at the end of the range, or + * DONE if the range is empty. + */ + public char last () + { + if (end == begin) + return DONE; + + index = end - 1; + return current (); + } + + /*************************************************************************/ + + /** + * This method returns the current value of the index. + * + * @return The current index value + */ + public int getIndex () + { + return index; + } + + /*************************************************************************/ + + /** + * This method sets the value of the index to the specified value, then + * returns the character at that position. + * + * @param index The new index value. + * + * @return The character at the new index value or DONE + * if the index value is equal to getEndIndex. + * + * @exception IllegalArgumentException If the specified index is not valid + */ + public char setIndex (int index) + { + if ((index < begin) || (index > end)) + throw new IllegalArgumentException ("Bad index specified"); + + this.index = index; + return current (); + } + + /*************************************************************************/ + + /** + * This method returns the character position of the first character in the + * range. + * + * @return The index of the first character in the range. + */ + public int getBeginIndex () + { + return begin; + } + + /*************************************************************************/ + + /** + * This method returns the character position of the end of the text range. + * This will actually be the index of the first character following the + * end of the range. In the event the text range is empty, this will be + * equal to the first character in the range. + * + * @return The index of the end of the range. + */ + public int getEndIndex () + { + return end; + } + + /*************************************************************************/ + + /** + * This method creates a copy of this CharacterIterator. + * + * @return A copy of this CharacterIterator. + */ + public Object clone () + { + return new StringCharacterIterator (text, begin, end, index); + } + + /*************************************************************************/ + + /** + * This method tests this object for equality againt the specified + * object. This will be true if and only if the specified object: + *

    + *

      + *
    • is not null.
    • + *
    • is an instance of StringCharacterIterator
    • + *
    • has the same text as this object
    • + *
    • has the same beginning, ending, and current index as this object.
    • + *
    + * + * @param obj The object to test for equality against. + * + * @return true if the specified object is equal to this + * object, false otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof StringCharacterIterator)) + return false; + + StringCharacterIterator sci = (StringCharacterIterator) obj; + + return (begin == sci.begin + && end == sci.end + && index == sci.index + && text.equals (sci.text)); + } + + /*************************************************************************/ + + /** + * This method allows other classes in java.text to change the value + * of the underlying text being iterated through. + * + * @param text The new String to iterate through. + */ + public void setText (String text) + { + this.text = text; + this.begin = 0; + this.end = text.length (); + this.index = 0; + } +} diff --git a/libjava/classpath/java/text/class-dependencies.conf b/libjava/classpath/java/text/class-dependencies.conf new file mode 100644 index 0000000..011b146 --- /dev/null +++ b/libjava/classpath/java/text/class-dependencies.conf @@ -0,0 +1,220 @@ +# This property file contains dependencies of classes, methods, and +# field on other methods or classes. +# +# Syntax: +# +# : [... ] +# +# means that when is included, (... ) must +# be included as well. +# +# and are of the form +# +# +# +# or just +# +# +# +# Within dependencies, variables can be used. A variable is defined as +# follows: +# +# {variable}: value1 value2 ... value +# +# variables can be used on the right side of dependencies as follows: +# +# : com.bla.blu.{variable}.Class.m()V +# +# The use of the variable will expand to dependencies of the form +# +# : com.bla.blu.value1.Class.m()V +# : com.bla.blu.value2.Class.m()V +# ... +# : com.bla.blu.value.Class.m()V +# +# Variables can be redefined when building a system to select the +# required support for features like encodings, protocols, etc. +# +# Hints: +# +# - For methods and fields, the signature is mandatory. For +# specification, please see the Java Virtual Machine Specification by +# SUN. Unlike in the spec, field signatures (types) are in brackets. +# +# - Package names must be separated by '/' (and not '.'). E.g., +# java/lang/Class (this is necessary, because the '.' is used to +# separate method or field names from classes) +# +# - In case refers to a class, only the class itself will be +# included in the resulting binary, NOT necessarily all its methods +# and fields. If you want to refer to all methods and fields, you can +# write class.* as an abbreviation. +# +# - Abbreviations for packages are also possible: my/package/* means all +# methods and fields of all classes in my/package. +# +# - A line with a trailing '\' continues in the next line. + +# end of file + +# All locales supported are loaded via classes from java.text (see below) +# from class gnu/java/locale/LocaleInformation_ +# +# This introduces a dependency for all locales. To allow an easy selection +# and addition of locales, the library variable {text_locales} can be set to +# the set of supported locales. +# + +{text_locales}: \ + af_ZA \ + ar_AE \ + ar_BH \ + ar_DZ \ + ar_EG \ + ar_IN \ + ar_IQ \ + ar_JO \ + ar_KW \ + ar_LB \ + ar_LY \ + ar_MA \ + ar_OM \ + ar_QA \ + ar_SD \ + ar_SY \ + ar_TN \ + ar_YE \ + be_BY \ + bn_IN \ + br_FR \ + bs_BA \ + ca_ES \ + cs_CZ \ + cy_GB \ + da_DK \ + de \ + de_AT \ + de_BE \ + de_CH \ + de_DE \ + de_LU \ + el_GR \ + en \ + en_AU \ + en_BW \ + en_CA \ + en_DK \ + en_GB \ + en_HK \ + en_IE \ + en_IN \ + en_NZ \ + en_PH \ + en_SG \ + en_US \ + en_ZA \ + en_ZW \ + es_AR \ + es_BO \ + es_CL \ + es_CO \ + es_CR \ + es_DO \ + es_EC \ + es_ES \ + es_GT \ + es_HN \ + es_MX \ + es_NI \ + es_PA \ + es_PE \ + es_PR \ + es_PY \ + es_SV \ + es_US \ + es_UY \ + es_VE \ + et_EE \ + eu_ES \ + fa_IR \ + fi_FI \ + fo_FO \ + fr_BE \ + fr_CA \ + fr_CH \ + fr_FR \ + fr_LU \ + ga_IE \ + gd_GB \ + gl_ES \ + gv_GB \ + he_IL \ + hi_IN \ + hr_HR \ + hu_HU \ + id_ID \ + it_CH \ + it_IT \ + iw_IL \ + ja_JP \ + ka_GE \ + kl_GL \ + ko_KR \ + kw_GB \ + lt_LT \ + lv_LV \ + mi_NZ \ + mk_MK \ + mr_IN \ + mt_MT \ + nl \ + nl_BE \ + nl_NL \ + nn_NO \ + no_NO \ + oc_FR \ + pl_PL \ + pt_BR \ + pt_PT \ + ro_RO \ + ru_RU \ + ru_UA \ + se_NO \ + sk_SK \ + sl_SI \ + sq_AL \ + sr_YU \ + sv_FI \ + sv_SE \ + ta_IN \ + te_IN \ + tg_TJ \ + tl_PH \ + tr_TR \ + uk_UA \ + ur_PK \ + uz_UZ \ + vi_VN \ + yi_US \ + zh_CN \ + zh_HK \ + zh_SG \ + zh_TW + +java/text/Collator.getInstance(Ljava/util/Locale;)Ljava/text/Collator;: \ + gnu/java/locale/LocaleInformation_{text_locales}.* + +java/text/DateFormatSymbols.(Ljava/util/Locale;)V: \ + gnu/java/locale/LocaleInformation_{text_locales}.* + +java/text/DecimalFormatSymbols.(Ljava/util/Locale;)V: \ + gnu/java/locale/LocaleInformation_{text_locales}.* + +java/text/BreakIterator.getInstance(Ljava/lang/String;Ljava/util/Locale;)Ljava/text/BreakIterator;: \ + gnu/java/locale/LocaleInformation_{text_locales}.* + +java/text/NumberFormat.computeInstance(Ljava/util/Locale;Ljava/lang/String;Ljava/lang/String;)Ljava/text/NumberFormat;: \ + gnu/java/locale/LocaleInformation_{text_locales}.* + +java/text/DateFormat.computeInstance(IILjava/util/Locale;ZZ)Ljava/text/DateFormat;: \ + gnu/java/locale/LocaleInformation_{text_locales}.* diff --git a/libjava/classpath/java/text/package.html b/libjava/classpath/java/text/package.html new file mode 100644 index 0000000..3c2e22b --- /dev/null +++ b/libjava/classpath/java/text/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - java.text + + +

    Classes to iterate over strings and to format texts according to a +specific locale.

    + + + diff --git a/libjava/classpath/java/util/.cvsignore b/libjava/classpath/java/util/.cvsignore new file mode 100644 index 0000000..d41ae8d --- /dev/null +++ b/libjava/classpath/java/util/.cvsignore @@ -0,0 +1 @@ +LocaleData.java diff --git a/libjava/classpath/java/util/AbstractCollection.java b/libjava/classpath/java/util/AbstractCollection.java new file mode 100644 index 0000000..00ee23e --- /dev/null +++ b/libjava/classpath/java/util/AbstractCollection.java @@ -0,0 +1,470 @@ +/* AbstractCollection.java -- Abstract implementation of most of Collection + Copyright (C) 1998, 2000, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +import java.lang.reflect.Array; + +/** + * A basic implementation of most of the methods in the Collection interface to + * make it easier to create a collection. To create an unmodifiable Collection, + * just subclass AbstractCollection and provide implementations of the + * iterator() and size() methods. The Iterator returned by iterator() need only + * provide implementations of hasNext() and next() (that is, it may throw an + * UnsupportedOperationException if remove() is called). To create a modifiable + * Collection, you must in addition provide an implementation of the + * add(Object) method and the Iterator returned by iterator() must provide an + * implementation of remove(). Other methods should be overridden if the + * backing data structure allows for a more efficient implementation. The + * precise implementation used by AbstractCollection is documented, so that + * subclasses can tell which methods could be implemented more efficiently. + *

    + * + * The programmer should provide a no-argument constructor, and one that + * accepts another Collection, as recommended by the Collection interface. + * Unfortunately, there is no way to enforce this in Java. + * + * @author Original author unknown + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see AbstractSet + * @see AbstractList + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class AbstractCollection implements Collection +{ + /** + * The main constructor, for use by subclasses. + */ + protected AbstractCollection() + { + } + + /** + * Return an Iterator over this collection. The iterator must provide the + * hasNext and next methods and should in addition provide remove if the + * collection is modifiable. + * + * @return an iterator + */ + public abstract Iterator iterator(); + + /** + * Return the number of elements in this collection. If there are more than + * Integer.MAX_VALUE elements, return Integer.MAX_VALUE. + * + * @return the size + */ + public abstract int size(); + + /** + * Add an object to the collection (optional operation). This implementation + * always throws an UnsupportedOperationException - it should be + * overridden if the collection is to be modifiable. If the collection + * does not accept duplicates, simply return false. Collections may specify + * limitations on what may be added. + * + * @param o the object to add + * @return true if the add operation caused the Collection to change + * @throws UnsupportedOperationException if the add operation is not + * supported on this collection + * @throws NullPointerException if the collection does not support null + * @throws ClassCastException if the object is of the wrong type + * @throws IllegalArgumentException if some aspect of the object prevents + * it from being added + */ + public boolean add(Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * Add all the elements of a given collection to this collection (optional + * operation). This implementation obtains an Iterator over the given + * collection and iterates over it, adding each element with the + * add(Object) method (thus this method will fail with an + * UnsupportedOperationException if the add method does). The behavior is + * unspecified if the specified collection is modified during the iteration, + * including the special case of trying addAll(this) on a non-empty + * collection. + * + * @param c the collection to add the elements of to this collection + * @return true if the add operation caused the Collection to change + * @throws UnsupportedOperationException if the add operation is not + * supported on this collection + * @throws NullPointerException if the specified collection is null + * @throws ClassCastException if the type of any element in c is + * not a valid type for addition. + * @throws IllegalArgumentException if some aspect of any element + * in c prevents it being added. + * @throws NullPointerException if any element in c is null and this + * collection doesn't allow null values. + * @see #add(Object) + */ + public boolean addAll(Collection c) + { + Iterator itr = c.iterator(); + boolean modified = false; + int pos = c.size(); + while (--pos >= 0) + modified |= add(itr.next()); + return modified; + } + + /** + * Remove all elements from the collection (optional operation). This + * implementation obtains an iterator over the collection and calls next + * and remove on it repeatedly (thus this method will fail with an + * UnsupportedOperationException if the Iterator's remove method does) + * until there are no more elements to remove. + * Many implementations will have a faster way of doing this. + * + * @throws UnsupportedOperationException if the Iterator returned by + * iterator does not provide an implementation of remove + * @see Iterator#remove() + */ + public void clear() + { + Iterator itr = iterator(); + int pos = size(); + while (--pos >= 0) + { + itr.next(); + itr.remove(); + } + } + + /** + * Test whether this collection contains a given object. That is, if the + * collection has an element e such that (o == null ? e == null : + * o.equals(e)). This implementation obtains an iterator over the collection + * and iterates over it, testing each element for equality with the given + * object. If it is equal, true is returned. Otherwise false is returned when + * the end of the collection is reached. + * + * @param o the object to remove from this collection + * @return true if this collection contains an object equal to o + */ + public boolean contains(Object o) + { + Iterator itr = iterator(); + int pos = size(); + while (--pos >= 0) + if (equals(o, itr.next())) + return true; + return false; + } + + /** + * Tests whether this collection contains all the elements in a given + * collection. This implementation iterates over the given collection, + * testing whether each element is contained in this collection. If any one + * is not, false is returned. Otherwise true is returned. + * + * @param c the collection to test against + * @return true if this collection contains all the elements in the given + * collection + * @throws NullPointerException if the given collection is null + * @see #contains(Object) + */ + public boolean containsAll(Collection c) + { + Iterator itr = c.iterator(); + int pos = c.size(); + while (--pos >= 0) + if (!contains(itr.next())) + return false; + return true; + } + + /** + * Test whether this collection is empty. This implementation returns + * size() == 0. + * + * @return true if this collection is empty. + * @see #size() + */ + public boolean isEmpty() + { + return size() == 0; + } + + /** + * Remove a single instance of an object from this collection (optional + * operation). That is, remove one element e such that + * (o == null ? e == null : o.equals(e)), if such an element + * exists. This implementation obtains an iterator over the collection + * and iterates over it, testing each element for equality with the given + * object. If it is equal, it is removed by the iterator's remove method + * (thus this method will fail with an UnsupportedOperationException if + * the Iterator's remove method does). After the first element has been + * removed, true is returned; if the end of the collection is reached, false + * is returned. + * + * @param o the object to remove from this collection + * @return true if the remove operation caused the Collection to change, or + * equivalently if the collection did contain o. + * @throws UnsupportedOperationException if this collection's Iterator + * does not support the remove method + * @see Iterator#remove() + */ + public boolean remove(Object o) + { + Iterator itr = iterator(); + int pos = size(); + while (--pos >= 0) + if (equals(o, itr.next())) + { + itr.remove(); + return true; + } + return false; + } + + /** + * Remove from this collection all its elements that are contained in a given + * collection (optional operation). This implementation iterates over this + * collection, and for each element tests if it is contained in the given + * collection. If so, it is removed by the Iterator's remove method (thus + * this method will fail with an UnsupportedOperationException if the + * Iterator's remove method does). + * + * @param c the collection to remove the elements of + * @return true if the remove operation caused the Collection to change + * @throws UnsupportedOperationException if this collection's Iterator + * does not support the remove method + * @throws NullPointerException if the collection, c, is null. + * @see Iterator#remove() + */ + public boolean removeAll(Collection c) + { + return removeAllInternal(c); + } + + /** + * Remove from this collection all its elements that are contained in a given + * collection (optional operation). This implementation iterates over this + * collection, and for each element tests if it is contained in the given + * collection. If so, it is removed by the Iterator's remove method (thus + * this method will fail with an UnsupportedOperationException if the + * Iterator's remove method does). This method is necessary for ArrayList, + * which cannot publicly override removeAll but can optimize this call. + * + * @param c the collection to remove the elements of + * @return true if the remove operation caused the Collection to change + * @throws UnsupportedOperationException if this collection's Iterator + * does not support the remove method + * @throws NullPointerException if the collection, c, is null. + * @see Iterator#remove() + */ + // Package visible for use throughout java.util. + boolean removeAllInternal(Collection c) + { + Iterator itr = iterator(); + boolean modified = false; + int pos = size(); + while (--pos >= 0) + if (c.contains(itr.next())) + { + itr.remove(); + modified = true; + } + return modified; + } + + /** + * Remove from this collection all its elements that are not contained in a + * given collection (optional operation). This implementation iterates over + * this collection, and for each element tests if it is contained in the + * given collection. If not, it is removed by the Iterator's remove method + * (thus this method will fail with an UnsupportedOperationException if + * the Iterator's remove method does). + * + * @param c the collection to retain the elements of + * @return true if the remove operation caused the Collection to change + * @throws UnsupportedOperationException if this collection's Iterator + * does not support the remove method + * @throws NullPointerException if the collection, c, is null. + * @see Iterator#remove() + */ + public boolean retainAll(Collection c) + { + return retainAllInternal(c); + } + + /** + * Remove from this collection all its elements that are not contained in a + * given collection (optional operation). This implementation iterates over + * this collection, and for each element tests if it is contained in the + * given collection. If not, it is removed by the Iterator's remove method + * (thus this method will fail with an UnsupportedOperationException if + * the Iterator's remove method does). This method is necessary for + * ArrayList, which cannot publicly override retainAll but can optimize + * this call. + * + * @param c the collection to retain the elements of + * @return true if the remove operation caused the Collection to change + * @throws UnsupportedOperationException if this collection's Iterator + * does not support the remove method + * @throws NullPointerException if the collection, c, is null. + * @see Iterator#remove() + */ + // Package visible for use throughout java.util. + boolean retainAllInternal(Collection c) + { + Iterator itr = iterator(); + boolean modified = false; + int pos = size(); + while (--pos >= 0) + if (!c.contains(itr.next())) + { + itr.remove(); + modified = true; + } + return modified; + } + + /** + * Return an array containing the elements of this collection. This + * implementation creates an Object array of size size() and then iterates + * over the collection, setting each element of the array from the value + * returned by the iterator. The returned array is safe, and is not backed + * by the collection. + * + * @return an array containing the elements of this collection + */ + public Object[] toArray() + { + Iterator itr = iterator(); + int size = size(); + Object[] a = new Object[size]; + for (int pos = 0; pos < size; pos++) + a[pos] = itr.next(); + return a; + } + + /** + * Copy the collection into a given array if it will fit, or into a + * dynamically created array of the same run-time type as the given array if + * not. If there is space remaining in the array, the first element after the + * end of the collection is set to null (this is only useful if the + * collection is known to contain no null elements, however). This + * implementation first tests whether the given array is large enough to hold + * all the elements of the collection. If not, the reflection API is used to + * allocate a new array of the same run-time type. Next an iterator is + * obtained over the collection and the elements are placed in the array as + * they are returned by the iterator. Finally the first spare element, if + * any, of the array is set to null, and the created array is returned. + * The returned array is safe; it is not backed by the collection. Note that + * null may not mark the last element, if the collection allows null + * elements. + * + * @param a the array to copy into, or of the correct run-time type + * @return the array that was produced + * @throws NullPointerException if the given array is null + * @throws ArrayStoreException if the type of the array precludes holding + * one of the elements of the Collection + */ + public Object[] toArray(Object[] a) + { + int size = size(); + if (a.length < size) + a = (Object[]) Array.newInstance(a.getClass().getComponentType(), + size); + else if (a.length > size) + a[size] = null; + + Iterator itr = iterator(); + for (int pos = 0; pos < size; pos++) + a[pos] = itr.next(); + + return a; + } + + /** + * Creates a String representation of the Collection. The string returned is + * of the form "[a, b, ...]" where a and b etc are the results of calling + * toString on the elements of the collection. This implementation obtains an + * Iterator over the Collection and adds each element to a StringBuffer as it + * is returned by the iterator. + * + * @return a String representation of the Collection + */ + public String toString() + { + Iterator itr = iterator(); + StringBuffer r = new StringBuffer("["); + for (int pos = size(); pos > 0; pos--) + { + r.append(itr.next()); + if (pos > 1) + r.append(", "); + } + r.append("]"); + return r.toString(); + } + + /** + * Compare two objects according to Collection semantics. + * + * @param o1 the first object + * @param o2 the second object + * @return o1 == null ? o2 == null : o1.equals(o2) + */ + // Package visible for use throughout java.util. + // It may be inlined since it is final. + static final boolean equals(Object o1, Object o2) + { + return o1 == null ? o2 == null : o1.equals(o2); + } + + /** + * Hash an object according to Collection semantics. + * + * @param o the object to hash + * @return o1 == null ? 0 : o1.hashCode() + */ + // Package visible for use throughout java.util. + // It may be inlined since it is final. + static final int hashCode(Object o) + { + return o == null ? 0 : o.hashCode(); + } +} diff --git a/libjava/classpath/java/util/AbstractList.java b/libjava/classpath/java/util/AbstractList.java new file mode 100644 index 0000000..8a9b6f1 --- /dev/null +++ b/libjava/classpath/java/util/AbstractList.java @@ -0,0 +1,1225 @@ +/* AbstractList.java -- Abstract implementation of most of List + Copyright (C) 1998, 1999, 2000, 2001, 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 java.util; + +/** + * A basic implementation of most of the methods in the List interface to make + * it easier to create a List based on a random-access data structure. If + * the list is sequential (such as a linked list), use AbstractSequentialList. + * To create an unmodifiable list, it is only necessary to override the + * size() and get(int) methods (this contrasts with all other abstract + * collection classes which require an iterator to be provided). To make the + * list modifiable, the set(int, Object) method should also be overridden, and + * to make the list resizable, the add(int, Object) and remove(int) methods + * should be overridden too. Other methods should be overridden if the + * backing data structure allows for a more efficient implementation. + * The precise implementation used by AbstractList is documented, so that + * subclasses can tell which methods could be implemented more efficiently. + *

    + * + * As recommended by Collection and List, the subclass should provide at + * least a no-argument and a Collection constructor. This class is not + * synchronized. + * + * @author Original author unknown + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see List + * @see AbstractSequentialList + * @see AbstractCollection + * @see ListIterator + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class AbstractList extends AbstractCollection implements List +{ + /** + * A count of the number of structural modifications that have been made to + * the list (that is, insertions and removals). Structural modifications + * are ones which change the list size or affect how iterations would + * behave. This field is available for use by Iterator and ListIterator, + * in order to throw a {@link ConcurrentModificationException} in response + * to the next operation on the iterator. This fail-fast behavior + * saves the user from many subtle bugs otherwise possible from concurrent + * modification during iteration. + *

    + * + * To make lists fail-fast, increment this field by just 1 in the + * add(int, Object) and remove(int) methods. + * Otherwise, this field may be ignored. + */ + protected transient int modCount; + + /** + * The main constructor, for use by subclasses. + */ + protected AbstractList() + { + } + + /** + * Returns the elements at the specified position in the list. + * + * @param index the element to return + * @return the element at that position + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public abstract Object get(int index); + + /** + * Insert an element into the list at a given position (optional operation). + * This shifts all existing elements from that position to the end one + * index to the right. This version of add has no return, since it is + * assumed to always succeed if there is no exception. This implementation + * always throws UnsupportedOperationException, and must be overridden to + * make a modifiable List. If you want fail-fast iterators, be sure to + * increment modCount when overriding this. + * + * @param index the location to insert the item + * @param o the object to insert + * @throws UnsupportedOperationException if this list does not support the + * add operation + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + * @see #modCount + */ + public void add(int index, Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * Add an element to the end of the list (optional operation). If the list + * imposes restraints on what can be inserted, such as no null elements, + * this should be documented. This implementation calls + * add(size(), o);, and will fail if that version does. + * + * @param o the object to add + * @return true, as defined by Collection for a modified list + * @throws UnsupportedOperationException if this list does not support the + * add operation + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + * @see #add(int, Object) + */ + public boolean add(Object o) + { + add(size(), o); + return true; + } + + /** + * Insert the contents of a collection into the list at a given position + * (optional operation). Shift all elements at that position to the right + * by the number of elements inserted. This operation is undefined if + * this list is modified during the operation (for example, if you try + * to insert a list into itself). This implementation uses the iterator of + * the collection, repeatedly calling add(int, Object); this will fail + * if add does. This can often be made more efficient. + * + * @param index the location to insert the collection + * @param c the collection to insert + * @return true if the list was modified by this action, that is, if c is + * non-empty + * @throws UnsupportedOperationException if this list does not support the + * addAll operation + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @throws ClassCastException if some element of c cannot be added to this + * list due to its type + * @throws IllegalArgumentException if some element of c cannot be added + * to this list for some other reason + * @throws NullPointerException if the specified collection is null + * @see #add(int, Object) + */ + public boolean addAll(int index, Collection c) + { + Iterator itr = c.iterator(); + int size = c.size(); + for (int pos = size; pos > 0; pos--) + add(index++, itr.next()); + return size > 0; + } + + /** + * Clear the list, such that a subsequent call to isEmpty() would return + * true (optional operation). This implementation calls + * removeRange(0, size()), so it will fail unless remove + * or removeRange is overridden. + * + * @throws UnsupportedOperationException if this list does not support the + * clear operation + * @see #remove(int) + * @see #removeRange(int, int) + */ + public void clear() + { + removeRange(0, size()); + } + + /** + * Test whether this list is equal to another object. A List is defined to be + * equal to an object if and only if that object is also a List, and the two + * lists have the same sequence. Two lists l1 and l2 are equal if and only + * if l1.size() == l2.size(), and for every integer n between 0 + * and l1.size() - 1 inclusive, l1.get(n) == null ? + * l2.get(n) == null : l1.get(n).equals(l2.get(n)). + *

    + * + * This implementation returns true if the object is this, or false if the + * object is not a List. Otherwise, it iterates over both lists (with + * iterator()), returning false if two elements compare false or one list + * is shorter, and true if the iteration completes successfully. + * + * @param o the object to test for equality with this list + * @return true if o is equal to this list + * @see Object#equals(Object) + * @see #hashCode() + */ + public boolean equals(Object o) + { + if (o == this) + return true; + if (! (o instanceof List)) + return false; + int size = size(); + if (size != ((List) o).size()) + return false; + + Iterator itr1 = iterator(); + Iterator itr2 = ((List) o).iterator(); + + while (--size >= 0) + if (! equals(itr1.next(), itr2.next())) + return false; + return true; + } + + /** + * Obtains a hash code for this list. In order to obey the general + * contract of the hashCode method of class Object, this value is + * calculated as follows: + * +

    hashCode = 1;
    +Iterator i = list.iterator();
    +while (i.hasNext())
    +{
    +  Object obj = i.next();
    +  hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
    +}
    + * + * This ensures that the general contract of Object.hashCode() is adhered to. + * + * @return the hash code of this list + * + * @see Object#hashCode() + * @see #equals(Object) + */ + public int hashCode() + { + int hashCode = 1; + Iterator itr = iterator(); + int pos = size(); + while (--pos >= 0) + hashCode = 31 * hashCode + hashCode(itr.next()); + return hashCode; + } + + /** + * Obtain the first index at which a given object is to be found in this + * list. This implementation follows a listIterator() until a match is found, + * or returns -1 if the list end is reached. + * + * @param o the object to search for + * @return the least integer n such that o == null ? get(n) == null : + * o.equals(get(n)), or -1 if there is no such index + */ + public int indexOf(Object o) + { + ListIterator itr = listIterator(); + int size = size(); + for (int pos = 0; pos < size; pos++) + if (equals(o, itr.next())) + return pos; + return -1; + } + + /** + * Obtain an Iterator over this list, whose sequence is the list order. + * This implementation uses size(), get(int), and remove(int) of the + * backing list, and does not support remove unless the list does. This + * implementation is fail-fast if you correctly maintain modCount. + * Also, this implementation is specified by Sun to be distinct from + * listIterator, although you could easily implement it as + * return listIterator(0). + * + * @return an Iterator over the elements of this list, in order + * @see #modCount + */ + public Iterator iterator() + { + // Bah, Sun's implementation forbids using listIterator(0). + return new Iterator() + { + private int pos = 0; + private int size = size(); + private int last = -1; + private int knownMod = modCount; + + // This will get inlined, since it is private. + /** + * Checks for modifications made to the list from + * elsewhere while iteration is in progress. + * + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + private void checkMod() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + } + + /** + * Tests to see if there are any more objects to + * return. + * + * @return True if the end of the list has not yet been + * reached. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public boolean hasNext() + { + checkMod(); + return pos < size; + } + + /** + * Retrieves the next object from the list. + * + * @return The next object. + * @throws NoSuchElementException if there are + * no more objects to retrieve. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public Object next() + { + checkMod(); + if (pos == size) + throw new NoSuchElementException(); + last = pos; + return get(pos++); + } + + /** + * Removes the last object retrieved by next() + * from the list, if the list supports object removal. + * + * @throws ConcurrentModificationException if the list + * has been modified elsewhere. + * @throws IllegalStateException if the iterator is positioned + * before the start of the list or the last object has already + * been removed. + * @throws UnsupportedOperationException if the list does + * not support removing elements. + */ + public void remove() + { + checkMod(); + if (last < 0) + throw new IllegalStateException(); + AbstractList.this.remove(last); + pos--; + size--; + last = -1; + knownMod = modCount; + } + }; + } + + /** + * Obtain the last index at which a given object is to be found in this + * list. This implementation grabs listIterator(size()), then searches + * backwards for a match or returns -1. + * + * @return the greatest integer n such that o == null ? get(n) == null + * : o.equals(get(n)), or -1 if there is no such index + */ + public int lastIndexOf(Object o) + { + int pos = size(); + ListIterator itr = listIterator(pos); + while (--pos >= 0) + if (equals(o, itr.previous())) + return pos; + return -1; + } + + /** + * Obtain a ListIterator over this list, starting at the beginning. This + * implementation returns listIterator(0). + * + * @return a ListIterator over the elements of this list, in order, starting + * at the beginning + */ + public ListIterator listIterator() + { + return listIterator(0); + } + + /** + * Obtain a ListIterator over this list, starting at a given position. + * A first call to next() would return the same as get(index), and a + * first call to previous() would return the same as get(index - 1). + *

    + * + * This implementation uses size(), get(int), set(int, Object), + * add(int, Object), and remove(int) of the backing list, and does not + * support remove, set, or add unless the list does. This implementation + * is fail-fast if you correctly maintain modCount. + * + * @param index the position, between 0 and size() inclusive, to begin the + * iteration from + * @return a ListIterator over the elements of this list, in order, starting + * at index + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @see #modCount + */ + public ListIterator listIterator(final int index) + { + if (index < 0 || index > size()) + throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + + size()); + + return new ListIterator() + { + private int knownMod = modCount; + private int position = index; + private int lastReturned = -1; + private int size = size(); + + // This will get inlined, since it is private. + /** + * Checks for modifications made to the list from + * elsewhere while iteration is in progress. + * + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + private void checkMod() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + } + + /** + * Tests to see if there are any more objects to + * return. + * + * @return True if the end of the list has not yet been + * reached. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public boolean hasNext() + { + checkMod(); + return position < size; + } + + /** + * Tests to see if there are objects prior to the + * current position in the list. + * + * @return True if objects exist prior to the current + * position of the iterator. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public boolean hasPrevious() + { + checkMod(); + return position > 0; + } + + /** + * Retrieves the next object from the list. + * + * @return The next object. + * @throws NoSuchElementException if there are no + * more objects to retrieve. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public Object next() + { + checkMod(); + if (position == size) + throw new NoSuchElementException(); + lastReturned = position; + return get(position++); + } + + /** + * Retrieves the previous object from the list. + * + * @return The next object. + * @throws NoSuchElementException if there are no + * previous objects to retrieve. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public Object previous() + { + checkMod(); + if (position == 0) + throw new NoSuchElementException(); + lastReturned = --position; + return get(lastReturned); + } + + /** + * Returns the index of the next element in the + * list, which will be retrieved by next() + * + * @return The index of the next element. + * @throws ConcurrentModificationException if the list + * has been modified elsewhere. + */ + public int nextIndex() + { + checkMod(); + return position; + } + + /** + * Returns the index of the previous element in the + * list, which will be retrieved by previous() + * + * @return The index of the previous element. + * @throws ConcurrentModificationException if the list + * has been modified elsewhere. + */ + public int previousIndex() + { + checkMod(); + return position - 1; + } + + /** + * Removes the last object retrieved by next() + * or previous() from the list, if the list + * supports object removal. + * + * @throws IllegalStateException if the iterator is positioned + * before the start of the list or the last object has already + * been removed. + * @throws UnsupportedOperationException if the list does + * not support removing elements. + * @throws ConcurrentModificationException if the list + * has been modified elsewhere. + */ + public void remove() + { + checkMod(); + if (lastReturned < 0) + throw new IllegalStateException(); + AbstractList.this.remove(lastReturned); + size--; + position = lastReturned; + lastReturned = -1; + knownMod = modCount; + } + + /** + * Replaces the last object retrieved by next() + * or previous with o, if the list supports object + * replacement and an add or remove operation has not already + * been performed. + * + * @throws IllegalStateException if the iterator is positioned + * before the start of the list or the last object has already + * been removed. + * @throws UnsupportedOperationException if the list doesn't support + * the addition or removal of elements. + * @throws ClassCastException if the type of o is not a valid type + * for this list. + * @throws IllegalArgumentException if something else related to o + * prevents its addition. + * @throws ConcurrentModificationException if the list + * has been modified elsewhere. + */ + public void set(Object o) + { + checkMod(); + if (lastReturned < 0) + throw new IllegalStateException(); + AbstractList.this.set(lastReturned, o); + } + + /** + * Adds the supplied object before the element that would be returned + * by a call to next(), if the list supports addition. + * + * @param o The object to add to the list. + * @throws UnsupportedOperationException if the list doesn't support + * the addition of new elements. + * @throws ClassCastException if the type of o is not a valid type + * for this list. + * @throws IllegalArgumentException if something else related to o + * prevents its addition. + * @throws ConcurrentModificationException if the list + * has been modified elsewhere. + */ + public void add(Object o) + { + checkMod(); + AbstractList.this.add(position++, o); + size++; + lastReturned = -1; + knownMod = modCount; + } + }; + } + + /** + * Remove the element at a given position in this list (optional operation). + * Shifts all remaining elements to the left to fill the gap. This + * implementation always throws an UnsupportedOperationException. + * If you want fail-fast iterators, be sure to increment modCount when + * overriding this. + * + * @param index the position within the list of the object to remove + * @return the object that was removed + * @throws UnsupportedOperationException if this list does not support the + * remove operation + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + * @see #modCount + */ + public Object remove(int index) + { + throw new UnsupportedOperationException(); + } + + /** + * Remove a subsection of the list. This is called by the clear and + * removeRange methods of the class which implements subList, which are + * difficult for subclasses to override directly. Therefore, this method + * should be overridden instead by the more efficient implementation, if one + * exists. Overriding this can reduce quadratic efforts to constant time + * in some cases! + *

    + * + * This implementation first checks for illegal or out of range arguments. It + * then obtains a ListIterator over the list using listIterator(fromIndex). + * It then calls next() and remove() on this iterator repeatedly, toIndex - + * fromIndex times. + * + * @param fromIndex the index, inclusive, to remove from. + * @param toIndex the index, exclusive, to remove to. + * @throws UnsupportedOperationException if the list does + * not support removing elements. + */ + protected void removeRange(int fromIndex, int toIndex) + { + ListIterator itr = listIterator(fromIndex); + for (int index = fromIndex; index < toIndex; index++) + { + itr.next(); + itr.remove(); + } + } + + /** + * Replace an element of this list with another object (optional operation). + * This implementation always throws an UnsupportedOperationException. + * + * @param index the position within this list of the element to be replaced + * @param o the object to replace it with + * @return the object that was replaced + * @throws UnsupportedOperationException if this list does not support the + * set operation + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + */ + public Object set(int index, Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * Obtain a List view of a subsection of this list, from fromIndex + * (inclusive) to toIndex (exclusive). If the two indices are equal, the + * sublist is empty. The returned list should be modifiable if and only + * if this list is modifiable. Changes to the returned list should be + * reflected in this list. If this list is structurally modified in + * any way other than through the returned list, the result of any subsequent + * operations on the returned list is undefined. + *

    + * + * This implementation returns a subclass of AbstractList. It stores, in + * private fields, the offset and size of the sublist, and the expected + * modCount of the backing list. If the backing list implements RandomAccess, + * the sublist will also. + *

    + * + * The subclass's set(int, Object), get(int), + * add(int, Object), remove(int), + * addAll(int, Collection) and + * removeRange(int, int) methods all delegate to the + * corresponding methods on the backing abstract list, after + * bounds-checking the index and adjusting for the offset. The + * addAll(Collection c) method merely returns addAll(size, c). + * The listIterator(int) method returns a "wrapper object" + * over a list iterator on the backing list, which is created with the + * corresponding method on the backing list. The iterator() + * method merely returns listIterator(), and the size() method + * merely returns the subclass's size field. + *

    + * + * All methods first check to see if the actual modCount of the backing + * list is equal to its expected value, and throw a + * ConcurrentModificationException if it is not. + * + * @param fromIndex the index that the returned list should start from + * (inclusive) + * @param toIndex the index that the returned list should go to (exclusive) + * @return a List backed by a subsection of this list + * @throws IndexOutOfBoundsException if fromIndex < 0 + * || toIndex > size() + * @throws IllegalArgumentException if fromIndex > toIndex + * @see ConcurrentModificationException + * @see RandomAccess + */ + public List subList(int fromIndex, int toIndex) + { + // This follows the specification of AbstractList, but is inconsistent + // with the one in List. Don't you love Sun's inconsistencies? + if (fromIndex > toIndex) + throw new IllegalArgumentException(fromIndex + " > " + toIndex); + if (fromIndex < 0 || toIndex > size()) + throw new IndexOutOfBoundsException(); + + if (this instanceof RandomAccess) + return new RandomAccessSubList(this, fromIndex, toIndex); + return new SubList(this, fromIndex, toIndex); + } + + /** + * This class follows the implementation requirements set forth in + * {@link AbstractList#subList(int, int)}. It matches Sun's implementation + * by using a non-public top-level class in the same package. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class SubList extends AbstractList + { + // Package visible, for use by iterator. + /** The original list. */ + final AbstractList backingList; + /** The index of the first element of the sublist. */ + final int offset; + /** The size of the sublist. */ + int size; + + /** + * Construct the sublist. + * + * @param backing the list this comes from + * @param fromIndex the lower bound, inclusive + * @param toIndex the upper bound, exclusive + */ + SubList(AbstractList backing, int fromIndex, int toIndex) + { + backingList = backing; + modCount = backing.modCount; + offset = fromIndex; + size = toIndex - fromIndex; + } + + /** + * This method checks the two modCount fields to ensure that there has + * not been a concurrent modification, returning if all is okay. + * + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + */ + // This can be inlined. Package visible, for use by iterator. + void checkMod() + { + if (modCount != backingList.modCount) + throw new ConcurrentModificationException(); + } + + /** + * This method checks that a value is between 0 and size (inclusive). If + * it is not, an exception is thrown. + * + * @param index the value to check + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + // This will get inlined, since it is private. + private void checkBoundsInclusive(int index) + { + if (index < 0 || index > size) + throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + + size); + } + + /** + * This method checks that a value is between 0 (inclusive) and size + * (exclusive). If it is not, an exception is thrown. + * + * @param index the value to check + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + // This will get inlined, since it is private. + private void checkBoundsExclusive(int index) + { + if (index < 0 || index >= size) + throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + + size); + } + + /** + * Specified by AbstractList.subList to return the private field size. + * + * @return the sublist size + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + */ + public int size() + { + checkMod(); + return size; + } + + /** + * Specified by AbstractList.subList to delegate to the backing list. + * + * @param index the location to modify + * @param o the new value + * @return the old value + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + * @throws UnsupportedOperationException if the backing list does not + * support the set operation + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + * @throws ClassCastException if o cannot be added to the backing list due + * to its type + * @throws IllegalArgumentException if o cannot be added to the backing list + * for some other reason + */ + public Object set(int index, Object o) + { + checkMod(); + checkBoundsExclusive(index); + return backingList.set(index + offset, o); + } + + /** + * Specified by AbstractList.subList to delegate to the backing list. + * + * @param index the location to get from + * @return the object at that location + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object get(int index) + { + checkMod(); + checkBoundsExclusive(index); + return backingList.get(index + offset); + } + + /** + * Specified by AbstractList.subList to delegate to the backing list. + * + * @param index the index to insert at + * @param o the object to add + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @throws UnsupportedOperationException if the backing list does not + * support the add operation. + * @throws ClassCastException if o cannot be added to the backing list due + * to its type. + * @throws IllegalArgumentException if o cannot be added to the backing + * list for some other reason. + */ + public void add(int index, Object o) + { + checkMod(); + checkBoundsInclusive(index); + backingList.add(index + offset, o); + size++; + modCount = backingList.modCount; + } + + /** + * Specified by AbstractList.subList to delegate to the backing list. + * + * @param index the index to remove + * @return the removed object + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + * @throws UnsupportedOperationException if the backing list does not + * support the remove operation + */ + public Object remove(int index) + { + checkMod(); + checkBoundsExclusive(index); + Object o = backingList.remove(index + offset); + size--; + modCount = backingList.modCount; + return o; + } + + /** + * Specified by AbstractList.subList to delegate to the backing list. + * This does no bounds checking, as it assumes it will only be called + * by trusted code like clear() which has already checked the bounds. + * + * @param fromIndex the lower bound, inclusive + * @param toIndex the upper bound, exclusive + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + * @throws UnsupportedOperationException if the backing list does + * not support removing elements. + */ + protected void removeRange(int fromIndex, int toIndex) + { + checkMod(); + + backingList.removeRange(offset + fromIndex, offset + toIndex); + size -= toIndex - fromIndex; + modCount = backingList.modCount; + } + + /** + * Specified by AbstractList.subList to delegate to the backing list. + * + * @param index the location to insert at + * @param c the collection to insert + * @return true if this list was modified, in other words, c is non-empty + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @throws UnsupportedOperationException if this list does not support the + * addAll operation + * @throws ClassCastException if some element of c cannot be added to this + * list due to its type + * @throws IllegalArgumentException if some element of c cannot be added + * to this list for some other reason + * @throws NullPointerException if the specified collection is null + */ + public boolean addAll(int index, Collection c) + { + checkMod(); + checkBoundsInclusive(index); + int csize = c.size(); + boolean result = backingList.addAll(offset + index, c); + size += csize; + modCount = backingList.modCount; + return result; + } + + /** + * Specified by AbstractList.subList to return addAll(size, c). + * + * @param c the collection to insert + * @return true if this list was modified, in other words, c is non-empty + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + * @throws UnsupportedOperationException if this list does not support the + * addAll operation + * @throws ClassCastException if some element of c cannot be added to this + * list due to its type + * @throws IllegalArgumentException if some element of c cannot be added + * to this list for some other reason + * @throws NullPointerException if the specified collection is null + */ + public boolean addAll(Collection c) + { + return addAll(size, c); + } + + /** + * Specified by AbstractList.subList to return listIterator(). + * + * @return an iterator over the sublist + */ + public Iterator iterator() + { + return listIterator(); + } + + /** + * Specified by AbstractList.subList to return a wrapper around the + * backing list's iterator. + * + * @param index the start location of the iterator + * @return a list iterator over the sublist + * @throws ConcurrentModificationException if the backing list has been + * modified externally to this sublist + * @throws IndexOutOfBoundsException if the value is out of range + */ + public ListIterator listIterator(final int index) + { + checkMod(); + checkBoundsInclusive(index); + + return new ListIterator() + { + private final ListIterator i = backingList.listIterator(index + offset); + private int position = index; + + /** + * Tests to see if there are any more objects to + * return. + * + * @return True if the end of the list has not yet been + * reached. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public boolean hasNext() + { + checkMod(); + return position < size; + } + + /** + * Tests to see if there are objects prior to the + * current position in the list. + * + * @return True if objects exist prior to the current + * position of the iterator. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public boolean hasPrevious() + { + checkMod(); + return position > 0; + } + + /** + * Retrieves the next object from the list. + * + * @return The next object. + * @throws NoSuchElementException if there are no + * more objects to retrieve. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public Object next() + { + if (position == size) + throw new NoSuchElementException(); + position++; + return i.next(); + } + + /** + * Retrieves the previous object from the list. + * + * @return The next object. + * @throws NoSuchElementException if there are no + * previous objects to retrieve. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public Object previous() + { + if (position == 0) + throw new NoSuchElementException(); + position--; + return i.previous(); + } + + /** + * Returns the index of the next element in the + * list, which will be retrieved by next() + * + * @return The index of the next element. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public int nextIndex() + { + return i.nextIndex() - offset; + } + + /** + * Returns the index of the previous element in the + * list, which will be retrieved by previous() + * + * @return The index of the previous element. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public int previousIndex() + { + return i.previousIndex() - offset; + } + + /** + * Removes the last object retrieved by next() + * from the list, if the list supports object removal. + * + * @throws IllegalStateException if the iterator is positioned + * before the start of the list or the last object has already + * been removed. + * @throws UnsupportedOperationException if the list does + * not support removing elements. + */ + public void remove() + { + i.remove(); + size--; + position = nextIndex(); + modCount = backingList.modCount; + } + + + /** + * Replaces the last object retrieved by next() + * or previous with o, if the list supports object + * replacement and an add or remove operation has not already + * been performed. + * + * @throws IllegalStateException if the iterator is positioned + * before the start of the list or the last object has already + * been removed. + * @throws UnsupportedOperationException if the list doesn't support + * the addition or removal of elements. + * @throws ClassCastException if the type of o is not a valid type + * for this list. + * @throws IllegalArgumentException if something else related to o + * prevents its addition. + * @throws ConcurrentModificationException if the list + * has been modified elsewhere. + */ + public void set(Object o) + { + i.set(o); + } + + /** + * Adds the supplied object before the element that would be returned + * by a call to next(), if the list supports addition. + * + * @param o The object to add to the list. + * @throws UnsupportedOperationException if the list doesn't support + * the addition of new elements. + * @throws ClassCastException if the type of o is not a valid type + * for this list. + * @throws IllegalArgumentException if something else related to o + * prevents its addition. + * @throws ConcurrentModificationException if the list + * has been modified elsewhere. + */ + public void add(Object o) + { + i.add(o); + size++; + position++; + modCount = backingList.modCount; + } + + // Here is the reason why the various modCount fields are mostly + // ignored in this wrapper listIterator. + // If the backing listIterator is failfast, then the following holds: + // Using any other method on this list will call a corresponding + // method on the backing list *after* the backing listIterator + // is created, which will in turn cause a ConcurrentModException + // when this listIterator comes to use the backing one. So it is + // implicitly failfast. + // If the backing listIterator is NOT failfast, then the whole of + // this list isn't failfast, because the modCount field of the + // backing list is not valid. It would still be *possible* to + // make the iterator failfast wrt modifications of the sublist + // only, but somewhat pointless when the list can be changed under + // us. + // Either way, no explicit handling of modCount is needed. + // However modCount = backingList.modCount must be executed in add + // and remove, and size must also be updated in these two methods, + // since they do not go through the corresponding methods of the subList. + }; + } + } // class SubList + + /** + * This class is a RandomAccess version of SubList, as required by + * {@link AbstractList#subList(int, int)}. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class RandomAccessSubList extends SubList + implements RandomAccess + { + /** + * Construct the sublist. + * + * @param backing the list this comes from + * @param fromIndex the lower bound, inclusive + * @param toIndex the upper bound, exclusive + */ + RandomAccessSubList(AbstractList backing, int fromIndex, int toIndex) + { + super(backing, fromIndex, toIndex); + } + } // class RandomAccessSubList + +} // class AbstractList diff --git a/libjava/classpath/java/util/AbstractMap.java b/libjava/classpath/java/util/AbstractMap.java new file mode 100644 index 0000000..7cd6436 --- /dev/null +++ b/libjava/classpath/java/util/AbstractMap.java @@ -0,0 +1,749 @@ +/* AbstractMap.java -- Abstract implementation of most of Map + Copyright (C) 1998, 1999, 2000, 2001, 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 java.util; + +/** + * An abstract implementation of Map to make it easier to create your own + * implementations. In order to create an unmodifiable Map, subclass + * AbstractMap and implement the entrySet (usually via an + * AbstractSet). To make it modifiable, also implement put, + * and have entrySet().iterator() support remove. + *

    + * + * It is recommended that classes which extend this support at least the + * no-argument constructor, and a constructor which accepts another Map. + * Further methods in this class may be overridden if you have a more + * efficient implementation. + * + * @author Original author unknown + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Map + * @see Collection + * @see HashMap + * @see LinkedHashMap + * @see TreeMap + * @see WeakHashMap + * @see IdentityHashMap + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class AbstractMap implements Map +{ + /** An "enum" of iterator types. */ + // Package visible for use by subclasses. + static final int KEYS = 0, + VALUES = 1, + ENTRIES = 2; + + /** + * The cache for {@link #keySet()}. + */ + // Package visible for use by subclasses. + Set keys; + + /** + * The cache for {@link #values()}. + */ + // Package visible for use by subclasses. + Collection values; + + /** + * The main constructor, for use by subclasses. + */ + protected AbstractMap() + { + } + + /** + * Returns a set view of the mappings in this Map. Each element in the + * set must be an implementation of Map.Entry. The set is backed by + * the map, so that changes in one show up in the other. Modifications + * made while an iterator is in progress cause undefined behavior. If + * the set supports removal, these methods must be valid: + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear. + * Element addition is not supported via this set. + * + * @return the entry set + * @see Map.Entry + */ + public abstract Set entrySet(); + + /** + * Remove all entries from this Map (optional operation). This default + * implementation calls entrySet().clear(). NOTE: If the entry set does + * not permit clearing, then this will fail, too. Subclasses often + * override this for efficiency. Your implementation of entrySet() should + * not call AbstractMap.clear unless you want an infinite loop. + * + * @throws UnsupportedOperationException if entrySet().clear() + * does not support clearing. + * @see Set#clear() + */ + public void clear() + { + entrySet().clear(); + } + + /** + * Create a shallow copy of this Map, no keys or values are copied. The + * default implementation simply calls super.clone(). + * + * @return the shallow clone + * @throws CloneNotSupportedException if a subclass is not Cloneable + * @see Cloneable + * @see Object#clone() + */ + protected Object clone() throws CloneNotSupportedException + { + AbstractMap copy = (AbstractMap) super.clone(); + // Clear out the caches; they are stale. + copy.keys = null; + copy.values = null; + return copy; + } + + /** + * Returns true if this contains a mapping for the given key. This + * implementation does a linear search, O(n), over the + * entrySet(), returning true if a match + * is found, false if the iteration ends. Many subclasses + * can implement this more efficiently. + * + * @param key the key to search for + * @return true if the map contains the key + * @throws NullPointerException if key is null but the map + * does not permit null keys + * @see #containsValue(Object) + */ + public boolean containsKey(Object key) + { + Iterator entries = entrySet().iterator(); + int pos = size(); + while (--pos >= 0) + if (equals(key, ((Map.Entry) entries.next()).getKey())) + return true; + return false; + } + + /** + * Returns true if this contains at least one mapping with the given value. + * This implementation does a linear search, O(n), over the + * entrySet(), returning true if a match + * is found, false if the iteration ends. A match is + * defined as a value, v, where (value == null ? v == null : + * value.equals(v)). Subclasses are unlikely to implement + * this more efficiently. + * + * @param value the value to search for + * @return true if the map contains the value + * @see #containsKey(Object) + */ + public boolean containsValue(Object value) + { + Iterator entries = entrySet().iterator(); + int pos = size(); + while (--pos >= 0) + if (equals(value, ((Map.Entry) entries.next()).getValue())) + return true; + return false; + } + + /** + * Compares the specified object with this map for equality. Returns + * true if the other object is a Map with the same mappings, + * that is,
    + * o instanceof Map && entrySet().equals(((Map) o).entrySet(); + * + * @param o the object to be compared + * @return true if the object equals this map + * @see Set#equals(Object) + */ + public boolean equals(Object o) + { + return (o == this || + (o instanceof Map && + entrySet().equals(((Map) o).entrySet()))); + } + + /** + * Returns the value mapped by the given key. Returns null if + * there is no mapping. However, in Maps that accept null values, you + * must rely on containsKey to determine if a mapping exists. + * This iteration takes linear time, searching entrySet().iterator() of + * the key. Many implementations override this method. + * + * @param key the key to look up + * @return the value associated with the key, or null if key not in map + * @throws NullPointerException if this map does not accept null keys + * @see #containsKey(Object) + */ + public Object get(Object key) + { + Iterator entries = entrySet().iterator(); + int pos = size(); + while (--pos >= 0) + { + Map.Entry entry = (Map.Entry) entries.next(); + if (equals(key, entry.getKey())) + return entry.getValue(); + } + return null; + } + + /** + * Returns the hash code for this map. As defined in Map, this is the sum + * of all hashcodes for each Map.Entry object in entrySet, or basically + * entrySet().hashCode(). + * + * @return the hash code + * @see Map.Entry#hashCode() + * @see Set#hashCode() + */ + public int hashCode() + { + return entrySet().hashCode(); + } + + /** + * Returns true if the map contains no mappings. This is implemented by + * size() == 0. + * + * @return true if the map is empty + * @see #size() + */ + public boolean isEmpty() + { + return size() == 0; + } + + /** + * Returns a set view of this map's keys. The set is backed by the map, + * so changes in one show up in the other. Modifications while an iteration + * is in progress produce undefined behavior. The set supports removal + * if entrySet() does, but does not support element addition. + *

    + * + * This implementation creates an AbstractSet, where the iterator wraps + * the entrySet iterator, size defers to the Map's size, and contains + * defers to the Map's containsKey. The set is created on first use, and + * returned on subsequent uses, although since no synchronization occurs, + * there is a slight possibility of creating two sets. + * + * @return a Set view of the keys + * @see Set#iterator() + * @see #size() + * @see #containsKey(Object) + * @see #values() + */ + public Set keySet() + { + if (keys == null) + keys = new AbstractSet() + { + /** + * Retrieves the number of keys in the backing map. + * + * @return The number of keys. + */ + public int size() + { + return AbstractMap.this.size(); + } + + /** + * Returns true if the backing map contains the + * supplied key. + * + * @param key The key to search for. + * @return True if the key was found, false otherwise. + */ + public boolean contains(Object key) + { + return containsKey(key); + } + + /** + * Returns an iterator which iterates over the keys + * in the backing map, using a wrapper around the + * iterator returned by entrySet(). + * + * @return An iterator over the keys. + */ + public Iterator iterator() + { + return new Iterator() + { + /** + * The iterator returned by entrySet(). + */ + private final Iterator map_iterator = entrySet().iterator(); + + /** + * Returns true if a call to next() will + * return another key. + * + * @return True if the iterator has not yet reached + * the last key. + */ + public boolean hasNext() + { + return map_iterator.hasNext(); + } + + /** + * Returns the key from the next entry retrieved + * by the underlying entrySet() iterator. + * + * @return The next key. + */ + public Object next() + { + return ((Map.Entry) map_iterator.next()).getKey(); + } + + /** + * Removes the map entry which has a key equal + * to that returned by the last call to + * next(). + * + * @throws UnsupportedOperationException if the + * map doesn't support removal. + */ + public void remove() + { + map_iterator.remove(); + } + }; + } + }; + return keys; + } + + /** + * Associates the given key to the given value (optional operation). If the + * map already contains the key, its value is replaced. This implementation + * simply throws an UnsupportedOperationException. Be aware that in a map + * that permits null values, a null return does not always + * imply that the mapping was created. + * + * @param key the key to map + * @param value the value to be mapped + * @return the previous value of the key, or null if there was no mapping + * @throws UnsupportedOperationException if the operation is not supported + * @throws ClassCastException if the key or value is of the wrong type + * @throws IllegalArgumentException if something about this key or value + * prevents it from existing in this map + * @throws NullPointerException if the map forbids null keys or values + * @see #containsKey(Object) + */ + public Object put(Object key, Object value) + { + throw new UnsupportedOperationException(); + } + + /** + * Copies all entries of the given map to this one (optional operation). If + * the map already contains a key, its value is replaced. This implementation + * simply iterates over the map's entrySet(), calling put, + * so it is not supported if puts are not. + * + * @param m the mapping to load into this map + * @throws UnsupportedOperationException if the operation is not supported + * by this map. + * @throws ClassCastException if a key or value is of the wrong type for + * adding to this map. + * @throws IllegalArgumentException if something about a key or value + * prevents it from existing in this map. + * @throws NullPointerException if the map forbids null keys or values. + * @throws NullPointerException if m is null. + * @see #put(Object, Object) + */ + public void putAll(Map m) + { + Iterator entries = m.entrySet().iterator(); + int pos = m.size(); + while (--pos >= 0) + { + Map.Entry entry = (Map.Entry) entries.next(); + put(entry.getKey(), entry.getValue()); + } + } + + /** + * Removes the mapping for this key if present (optional operation). This + * implementation iterates over the entrySet searching for a matching + * key, at which point it calls the iterator's remove method. + * It returns the result of getValue() on the entry, if found, + * or null if no entry is found. Note that maps which permit null values + * may also return null if the key was removed. If the entrySet does not + * support removal, this will also fail. This is O(n), so many + * implementations override it for efficiency. + * + * @param key the key to remove + * @return the value the key mapped to, or null if not present. + * Null may also be returned if null values are allowed + * in the map and the value of this mapping is null. + * @throws UnsupportedOperationException if deletion is unsupported + * @see Iterator#remove() + */ + public Object remove(Object key) + { + Iterator entries = entrySet().iterator(); + int pos = size(); + while (--pos >= 0) + { + Map.Entry entry = (Map.Entry) entries.next(); + if (equals(key, entry.getKey())) + { + // Must get the value before we remove it from iterator. + Object r = entry.getValue(); + entries.remove(); + return r; + } + } + return null; + } + + /** + * Returns the number of key-value mappings in the map. If there are more + * than Integer.MAX_VALUE mappings, return Integer.MAX_VALUE. This is + * implemented as entrySet().size(). + * + * @return the number of mappings + * @see Set#size() + */ + public int size() + { + return entrySet().size(); + } + + /** + * Returns a String representation of this map. This is a listing of the + * map entries (which are specified in Map.Entry as being + * getKey() + "=" + getValue()), separated by a comma and + * space (", "), and surrounded by braces ('{' and '}'). This implementation + * uses a StringBuffer and iterates over the entrySet to build the String. + * Note that this can fail with an exception if underlying keys or + * values complete abruptly in toString(). + * + * @return a String representation + * @see Map.Entry#toString() + */ + public String toString() + { + Iterator entries = entrySet().iterator(); + StringBuffer r = new StringBuffer("{"); + for (int pos = size(); pos > 0; pos--) + { + Map.Entry entry = (Map.Entry) entries.next(); + r.append(entry.getKey()); + r.append('='); + r.append(entry.getValue()); + if (pos > 1) + r.append(", "); + } + r.append("}"); + return r.toString(); + } + + /** + * Returns a collection or bag view of this map's values. The collection + * is backed by the map, so changes in one show up in the other. + * Modifications while an iteration is in progress produce undefined + * behavior. The collection supports removal if entrySet() does, but + * does not support element addition. + *

    + * + * This implementation creates an AbstractCollection, where the iterator + * wraps the entrySet iterator, size defers to the Map's size, and contains + * defers to the Map's containsValue. The collection is created on first + * use, and returned on subsequent uses, although since no synchronization + * occurs, there is a slight possibility of creating two collections. + * + * @return a Collection view of the values + * @see Collection#iterator() + * @see #size() + * @see #containsValue(Object) + * @see #keySet() + */ + public Collection values() + { + if (values == null) + values = new AbstractCollection() + { + /** + * Returns the number of values stored in + * the backing map. + * + * @return The number of values. + */ + public int size() + { + return AbstractMap.this.size(); + } + + /** + * Returns true if the backing map contains + * the supplied value. + * + * @param value The value to search for. + * @return True if the value was found, false otherwise. + */ + public boolean contains(Object value) + { + return containsValue(value); + } + + /** + * Returns an iterator which iterates over the + * values in the backing map, by using a wrapper + * around the iterator returned by entrySet(). + * + * @return An iterator over the values. + */ + public Iterator iterator() + { + return new Iterator() + { + /** + * The iterator returned by entrySet(). + */ + private final Iterator map_iterator = entrySet().iterator(); + + /** + * Returns true if a call to next() will + * return another value. + * + * @return True if the iterator has not yet reached + * the last value. + */ + public boolean hasNext() + { + return map_iterator.hasNext(); + } + + /** + * Returns the value from the next entry retrieved + * by the underlying entrySet() iterator. + * + * @return The next value. + */ + public Object next() + { + return ((Map.Entry) map_iterator.next()).getValue(); + } + + /** + * Removes the map entry which has a key equal + * to that returned by the last call to + * next(). + * + * @throws UnsupportedOperationException if the + * map doesn't support removal. + */ + public void remove() + { + map_iterator.remove(); + } + }; + } + }; + return values; + } + + /** + * Compare two objects according to Collection semantics. + * + * @param o1 the first object + * @param o2 the second object + * @return o1 == null ? o2 == null : o1.equals(o2) + */ + // Package visible for use throughout java.util. + // It may be inlined since it is final. + static final boolean equals(Object o1, Object o2) + { + return o1 == null ? o2 == null : o1.equals(o2); + } + + /** + * Hash an object according to Collection semantics. + * + * @param o the object to hash + * @return o1 == null ? 0 : o1.hashCode() + */ + // Package visible for use throughout java.util. + // It may be inlined since it is final. + static final int hashCode(Object o) + { + return o == null ? 0 : o.hashCode(); + } + + /** + * A class which implements Map.Entry. It is shared by HashMap, TreeMap, + * Hashtable, and Collections. It is not specified by the JDK, but makes + * life much easier. + * + * @author Jon Zeppieri + * @author Eric Blake (ebb9@email.byu.edu) + */ + // XXX - FIXME Use fully qualified implements as gcj 3.1 workaround. + // Bug still exists in 3.4.1 + static class BasicMapEntry implements Map.Entry + { + /** + * The key. Package visible for direct manipulation. + */ + Object key; + + /** + * The value. Package visible for direct manipulation. + */ + Object value; + + /** + * Basic constructor initializes the fields. + * @param newKey the key + * @param newValue the value + */ + BasicMapEntry(Object newKey, Object newValue) + { + key = newKey; + value = newValue; + } + + /** + * Compares the specified object with this entry. Returns true only if + * the object is a mapping of identical key and value. In other words, + * this must be:
    + *

    (o instanceof Map.Entry)
    +     *       && (getKey() == null ? ((HashMap) o).getKey() == null
    +     *           : getKey().equals(((HashMap) o).getKey()))
    +     *       && (getValue() == null ? ((HashMap) o).getValue() == null
    +     *           : getValue().equals(((HashMap) o).getValue()))
    + * + * @param o the object to compare + * @return true if it is equal + */ + public final boolean equals(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + // Optimize for our own entries. + if (o instanceof BasicMapEntry) + { + BasicMapEntry e = (BasicMapEntry) o; + return (AbstractMap.equals(key, e.key) + && AbstractMap.equals(value, e.value)); + } + Map.Entry e = (Map.Entry) o; + return (AbstractMap.equals(key, e.getKey()) + && AbstractMap.equals(value, e.getValue())); + } + + /** + * Get the key corresponding to this entry. + * + * @return the key + */ + public final Object getKey() + { + return key; + } + + /** + * Get the value corresponding to this entry. If you already called + * Iterator.remove(), the behavior undefined, but in this case it works. + * + * @return the value + */ + public final Object getValue() + { + return value; + } + + /** + * Returns the hash code of the entry. This is defined as the exclusive-or + * of the hashcodes of the key and value (using 0 for null). In other + * words, this must be:
    + *
    (getKey() == null ? 0 : getKey().hashCode())
    +     *       ^ (getValue() == null ? 0 : getValue().hashCode())
    + * + * @return the hash code + */ + public final int hashCode() + { + return (AbstractMap.hashCode(key) ^ AbstractMap.hashCode(value)); + } + + /** + * Replaces the value with the specified object. This writes through + * to the map, unless you have already called Iterator.remove(). It + * may be overridden to restrict a null value. + * + * @param newVal the new value to store + * @return the old value + * @throws NullPointerException if the map forbids null values. + * @throws UnsupportedOperationException if the map doesn't support + * put(). + * @throws ClassCastException if the value is of a type unsupported + * by the map. + * @throws IllegalArgumentException if something else about this + * value prevents it being stored in the map. + */ + public Object setValue(Object newVal) + { + Object r = value; + value = newVal; + return r; + } + + /** + * This provides a string representation of the entry. It is of the form + * "key=value", where string concatenation is used on key and value. + * + * @return the string representation + */ + public final String toString() + { + return key + "=" + value; + } + } // class BasicMapEntry +} diff --git a/libjava/classpath/java/util/AbstractSequentialList.java b/libjava/classpath/java/util/AbstractSequentialList.java new file mode 100644 index 0000000..7958322 --- /dev/null +++ b/libjava/classpath/java/util/AbstractSequentialList.java @@ -0,0 +1,235 @@ +/* AbstractSequentialList.java -- List implementation for sequential access + Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * Abstract superclass to make it easier to implement the List interface when + * backed by a sequential-access store, such as a linked list. For random + * access data, use AbstractList. This class implements the random access + * methods (get, set, add, and + * remove) atop the list iterator, opposite of AbstractList's + * approach of implementing the iterator atop random access. + *

    + * + * To implement a list, you need an implementation for size() + * and listIterator. With just hasNext, + * next, hasPrevious, previous, + * nextIndex, and previousIndex, you have an + * unmodifiable list. For a modifiable one, add set, and for + * a variable-size list, add add and remove. + *

    + * + * The programmer should provide a no-argument constructor, and one that + * accepts another Collection, as recommended by the Collection interface. + * Unfortunately, there is no way to enforce this in Java. + * + * @author Original author unknown + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see List + * @see AbstractList + * @see AbstractCollection + * @see ListIterator + * @see LinkedList + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class AbstractSequentialList extends AbstractList +{ + /** + * The main constructor, for use by subclasses. + */ + protected AbstractSequentialList() + { + } + + /** + * Returns a ListIterator over the list, starting from position index. + * Subclasses must provide an implementation of this method. + * + * @param index the starting position of the list + * @return the list iterator + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + public abstract ListIterator listIterator(int index); + + /** + * Insert an element into the list at a given position (optional operation). + * This shifts all existing elements from that position to the end one + * index to the right. This version of add has no return, since it is + * assumed to always succeed if there is no exception. This iteration + * uses listIterator(index).add(o). + * + * @param index the location to insert the item + * @param o the object to insert + * @throws UnsupportedOperationException if this list does not support the + * add operation + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason. + * @throws NullPointerException if o is null and the list does not permit + * the addition of null values. + */ + public void add(int index, Object o) + { + listIterator(index).add(o); + } + + /** + * Insert the contents of a collection into the list at a given position + * (optional operation). Shift all elements at that position to the right + * by the number of elements inserted. This operation is undefined if + * this list is modified during the operation (for example, if you try + * to insert a list into itself). + *

    + * + * This implementation grabs listIterator(index), then proceeds to use add + * for each element returned by c's iterator. Sun's online specs are wrong, + * claiming that this also calls next(): listIterator.add() correctly + * skips the added element. + * + * @param index the location to insert the collection + * @param c the collection to insert + * @return true if the list was modified by this action, that is, if c is + * non-empty + * @throws UnsupportedOperationException if this list does not support the + * addAll operation + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @throws ClassCastException if some element of c cannot be added to this + * list due to its type + * @throws IllegalArgumentException if some element of c cannot be added + * to this list for some other reason + * @throws NullPointerException if the specified collection is null + * @throws NullPointerException if an object, o, in c is null and the list + * does not permit the addition of null values. + * @see #add(int, Object) + */ + public boolean addAll(int index, Collection c) + { + Iterator ci = c.iterator(); + int size = c.size(); + ListIterator i = listIterator(index); + for (int pos = size; pos > 0; pos--) + i.add(ci.next()); + return size > 0; + } + + /** + * Get the element at a given index in this list. This implementation + * returns listIterator(index).next(). + * + * @param index the index of the element to be returned + * @return the element at index index in this list + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object get(int index) + { + // This is a legal listIterator position, but an illegal get. + if (index == size()) + throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + + size()); + return listIterator(index).next(); + } + + /** + * Obtain an Iterator over this list, whose sequence is the list order. This + * implementation returns listIterator(). + * + * @return an Iterator over the elements of this list, in order + */ + public Iterator iterator() + { + return listIterator(); + } + + /** + * Remove the element at a given position in this list (optional operation). + * Shifts all remaining elements to the left to fill the gap. This + * implementation uses listIterator(index) and ListIterator.remove(). + * + * @param index the position within the list of the object to remove + * @return the object that was removed + * @throws UnsupportedOperationException if this list does not support the + * remove operation + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object remove(int index) + { + // This is a legal listIterator position, but an illegal remove. + if (index == size()) + throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + + size()); + ListIterator i = listIterator(index); + Object removed = i.next(); + i.remove(); + return removed; + } + + /** + * Replace an element of this list with another object (optional operation). + * This implementation uses listIterator(index) and ListIterator.set(o). + * + * @param index the position within this list of the element to be replaced + * @param o the object to replace it with + * @return the object that was replaced + * @throws UnsupportedOperationException if this list does not support the + * set operation + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + * @throws NullPointerException if o is null and the list does not allow + * a value to be set to null. + */ + public Object set(int index, Object o) + { + // This is a legal listIterator position, but an illegal set. + if (index == size()) + throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + + size()); + ListIterator i = listIterator(index); + Object old = i.next(); + i.set(o); + return old; + } +} diff --git a/libjava/classpath/java/util/AbstractSet.java b/libjava/classpath/java/util/AbstractSet.java new file mode 100644 index 0000000..f0d7cb1 --- /dev/null +++ b/libjava/classpath/java/util/AbstractSet.java @@ -0,0 +1,139 @@ +/* AbstractSet.java -- Abstract implementation of most of Set + Copyright (C) 1998, 2000, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * An abstract implementation of Set to make it easier to create your own + * implementations. In order to create a Set, subclass AbstractSet and + * implement the same methods that are required for AbstractCollection + * (although these methods must of course meet the requirements that Set puts + * on them - specifically, no element may be in the set more than once). This + * class simply provides implementations of equals() and hashCode() to fulfil + * the requirements placed on them by the Set interface. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see AbstractCollection + * @see Set + * @see HashSet + * @see TreeSet + * @see LinkedHashSet + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class AbstractSet extends AbstractCollection implements Set +{ + /** + * The main constructor, for use by subclasses. + */ + protected AbstractSet() + { + } + + /** + * Tests whether the given object is equal to this Set. This implementation + * first checks whether this set is the given object, and returns + * true if so. Otherwise, if o is a Set and is the same size as this one, it + * returns the result of calling containsAll on the given Set. Otherwise, it + * returns false. + * + * @param o the Object to be tested for equality with this Set + * @return true if the given object is equal to this Set + */ + public boolean equals(Object o) + { + return (o == this || + (o instanceof Set && ((Set) o).size() == size() + && containsAll((Collection) o))); + } + + /** + * Returns a hash code for this Set. The hash code of a Set is the sum of the + * hash codes of all its elements, except that the hash code of null is + * defined to be zero. This implementation obtains an Iterator over the Set, + * and sums the results. + * + * @return a hash code for this Set + */ + public int hashCode() + { + Iterator itr = iterator(); + int hash = 0; + int pos = size(); + while (--pos >= 0) + hash += hashCode(itr.next()); + return hash; + } + + /** + * Removes from this set all elements in the given collection (optional + * operation). This implementation uses size() to determine + * the smaller collection. Then, if this set is smaller, it iterates + * over the set, calling Iterator.remove if the collection contains + * the element. If this set is larger, it iterates over the collection, + * calling Set.remove for all elements in the collection. Note that + * this operation will fail if a remove methods is not supported. + * + * @param c the collection of elements to remove + * @return true if the set was modified as a result + * @throws UnsupportedOperationException if remove is not supported + * @throws NullPointerException if the collection is null + * @see AbstractCollection#remove(Object) + * @see Collection#contains(Object) + * @see Iterator#remove() + */ + public boolean removeAll(Collection c) + { + int oldsize = size(); + int count = c.size(); + Iterator i; + if (oldsize < count) + { + for (i = iterator(), count = oldsize; count > 0; count--) + if (c.contains(i.next())) + i.remove(); + } + else + for (i = c.iterator(); count > 0; count--) + remove(i.next()); + return oldsize != size(); + } + +} diff --git a/libjava/classpath/java/util/ArrayList.java b/libjava/classpath/java/util/ArrayList.java new file mode 100644 index 0000000..82bcca8 --- /dev/null +++ b/libjava/classpath/java/util/ArrayList.java @@ -0,0 +1,591 @@ +/* ArrayList.java -- JDK1.2's answer to Vector; this is an array-backed + implementation of the List interface + Copyright (C) 1998, 1999, 2000, 2001, 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 java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; + +/** + * An array-backed implementation of the List interface. This implements + * all optional list operations, and permits null elements, so that it is + * better than Vector, which it replaces. Random access is roughly constant + * time, and iteration is roughly linear time, so it is nice and fast, with + * less overhead than a LinkedList. + *

    + * + * Each list has a capacity, and as the array reaches that capacity it + * is automatically transferred to a larger array. You also have access to + * ensureCapacity and trimToSize to control the backing array's size, avoiding + * reallocation or wasted memory. + *

    + * + * ArrayList is not synchronized, so if you need multi-threaded access, + * consider using:
    + * List l = Collections.synchronizedList(new ArrayList(...)); + *

    + * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * {@link ConcurrentModificationException} rather than exhibit + * non-deterministic behavior. + * + * @author Jon A. Zeppieri + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see List + * @see LinkedList + * @see Vector + * @see Collections#synchronizedList(List) + * @see AbstractList + * @status updated to 1.4 + */ +public class ArrayList extends AbstractList + implements List, RandomAccess, Cloneable, Serializable +{ + /** + * Compatible with JDK 1.2 + */ + private static final long serialVersionUID = 8683452581122892189L; + + /** + * The default capacity for new ArrayLists. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * The number of elements in this list. + * @serial the list size + */ + private int size; + + /** + * Where the data is stored. + */ + private transient Object[] data; + + /** + * Construct a new ArrayList with the supplied initial capacity. + * + * @param capacity initial capacity of this ArrayList + * @throws IllegalArgumentException if capacity is negative + */ + public ArrayList(int capacity) + { + // Must explicitly check, to get correct exception. + if (capacity < 0) + throw new IllegalArgumentException(); + data = new Object[capacity]; + } + + /** + * Construct a new ArrayList with the default capacity (16). + */ + public ArrayList() + { + this(DEFAULT_CAPACITY); + } + + /** + * Construct a new ArrayList, and initialize it with the elements + * in the supplied Collection. The initial capacity is 110% of the + * Collection's size. + * + * @param c the collection whose elements will initialize this list + * @throws NullPointerException if c is null + */ + public ArrayList(Collection c) + { + this((int) (c.size() * 1.1f)); + addAll(c); + } + + /** + * Trims the capacity of this List to be equal to its size; + * a memory saver. + */ + public void trimToSize() + { + // Not a structural change from the perspective of iterators on this list, + // so don't update modCount. + if (size != data.length) + { + Object[] newData = new Object[size]; + System.arraycopy(data, 0, newData, 0, size); + data = newData; + } + } + + /** + * Guarantees that this list will have at least enough capacity to + * hold minCapacity elements. This implementation will grow the list to + * max(current * 2, minCapacity) if (minCapacity > current). The JCL says + * explictly that "this method increases its capacity to minCap", while + * the JDK 1.3 online docs specify that the list will grow to at least the + * size specified. + * + * @param minCapacity the minimum guaranteed capacity + */ + public void ensureCapacity(int minCapacity) + { + int current = data.length; + + if (minCapacity > current) + { + Object[] newData = new Object[Math.max(current * 2, minCapacity)]; + System.arraycopy(data, 0, newData, 0, size); + data = newData; + } + } + + /** + * Returns the number of elements in this list. + * + * @return the list size + */ + public int size() + { + return size; + } + + /** + * Checks if the list is empty. + * + * @return true if there are no elements + */ + public boolean isEmpty() + { + return size == 0; + } + + /** + * Returns true iff element is in this ArrayList. + * + * @param e the element whose inclusion in the List is being tested + * @return true if the list contains e + */ + public boolean contains(Object e) + { + return indexOf(e) != -1; + } + + /** + * Returns the lowest index at which element appears in this List, or + * -1 if it does not appear. + * + * @param e the element whose inclusion in the List is being tested + * @return the index where e was found + */ + public int indexOf(Object e) + { + for (int i = 0; i < size; i++) + if (equals(e, data[i])) + return i; + return -1; + } + + /** + * Returns the highest index at which element appears in this List, or + * -1 if it does not appear. + * + * @param e the element whose inclusion in the List is being tested + * @return the index where e was found + */ + public int lastIndexOf(Object e) + { + for (int i = size - 1; i >= 0; i--) + if (equals(e, data[i])) + return i; + return -1; + } + + /** + * Creates a shallow copy of this ArrayList (elements are not cloned). + * + * @return the cloned object + */ + public Object clone() + { + ArrayList clone = null; + try + { + clone = (ArrayList) super.clone(); + clone.data = (Object[]) data.clone(); + } + catch (CloneNotSupportedException e) + { + // Impossible to get here. + } + return clone; + } + + /** + * Returns an Object array containing all of the elements in this ArrayList. + * The array is independent of this list. + * + * @return an array representation of this list + */ + public Object[] toArray() + { + Object[] array = new Object[size]; + System.arraycopy(data, 0, array, 0, size); + return array; + } + + /** + * Returns an Array whose component type is the runtime component type of + * the passed-in Array. The returned Array is populated with all of the + * elements in this ArrayList. If the passed-in Array is not large enough + * to store all of the elements in this List, a new Array will be created + * and returned; if the passed-in Array is larger than the size + * of this List, then size() index will be set to null. + * + * @param a the passed-in Array + * @return an array representation of this list + * @throws ArrayStoreException if the runtime type of a does not allow + * an element in this list + * @throws NullPointerException if a is null + */ + public Object[] toArray(Object[] a) + { + if (a.length < size) + a = (Object[]) Array.newInstance(a.getClass().getComponentType(), + size); + else if (a.length > size) + a[size] = null; + System.arraycopy(data, 0, a, 0, size); + return a; + } + + /** + * Retrieves the element at the user-supplied index. + * + * @param index the index of the element we are fetching + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object get(int index) + { + checkBoundExclusive(index); + return data[index]; + } + + /** + * Sets the element at the specified index. The new element, e, + * can be an object of any type or null. + * + * @param index the index at which the element is being set + * @param e the element to be set + * @return the element previously at the specified index + * @throws IndexOutOfBoundsException if index < 0 || index >= 0 + */ + public Object set(int index, Object e) + { + checkBoundExclusive(index); + Object result = data[index]; + data[index] = e; + return result; + } + + /** + * Appends the supplied element to the end of this list. + * The element, e, can be an object of any type or null. + * + * @param e the element to be appended to this list + * @return true, the add will always succeed + */ + public boolean add(Object e) + { + modCount++; + if (size == data.length) + ensureCapacity(size + 1); + data[size++] = e; + return true; + } + + /** + * Adds the supplied element at the specified index, shifting all + * elements currently at that index or higher one to the right. + * The element, e, can be an object of any type or null. + * + * @param index the index at which the element is being added + * @param e the item being added + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + public void add(int index, Object e) + { + checkBoundInclusive(index); + modCount++; + if (size == data.length) + ensureCapacity(size + 1); + if (index != size) + System.arraycopy(data, index, data, index + 1, size - index); + data[index] = e; + size++; + } + + /** + * Removes the element at the user-supplied index. + * + * @param index the index of the element to be removed + * @return the removed Object + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object remove(int index) + { + checkBoundExclusive(index); + Object r = data[index]; + modCount++; + if (index != --size) + System.arraycopy(data, index + 1, data, index, size - index); + // Aid for garbage collection by releasing this pointer. + data[size] = null; + return r; + } + + /** + * Removes all elements from this List + */ + public void clear() + { + if (size > 0) + { + modCount++; + // Allow for garbage collection. + Arrays.fill(data, 0, size, null); + size = 0; + } + } + + /** + * Add each element in the supplied Collection to this List. It is undefined + * what happens if you modify the list while this is taking place; for + * example, if the collection contains this list. c can contain objects + * of any type, as well as null values. + * + * @param c a Collection containing elements to be added to this List + * @return true if the list was modified, in other words c is not empty + * @throws NullPointerException if c is null + */ + public boolean addAll(Collection c) + { + return addAll(size, c); + } + + /** + * Add all elements in the supplied collection, inserting them beginning + * at the specified index. c can contain objects of any type, as well + * as null values. + * + * @param index the index at which the elements will be inserted + * @param c the Collection containing the elements to be inserted + * @throws IndexOutOfBoundsException if index < 0 || index > 0 + * @throws NullPointerException if c is null + */ + public boolean addAll(int index, Collection c) + { + checkBoundInclusive(index); + Iterator itr = c.iterator(); + int csize = c.size(); + + modCount++; + if (csize + size > data.length) + ensureCapacity(size + csize); + int end = index + csize; + if (size > 0 && index != size) + System.arraycopy(data, index, data, end, size - index); + size += csize; + for ( ; index < end; index++) + data[index] = itr.next(); + return csize > 0; + } + + /** + * Removes all elements in the half-open interval [fromIndex, toIndex). + * Does nothing when toIndex is equal to fromIndex. + * + * @param fromIndex the first index which will be removed + * @param toIndex one greater than the last index which will be removed + * @throws IndexOutOfBoundsException if fromIndex > toIndex + */ + protected void removeRange(int fromIndex, int toIndex) + { + int change = toIndex - fromIndex; + if (change > 0) + { + modCount++; + System.arraycopy(data, toIndex, data, fromIndex, size - toIndex); + size -= change; + } + else if (change < 0) + throw new IndexOutOfBoundsException(); + } + + /** + * Checks that the index is in the range of possible elements (inclusive). + * + * @param index the index to check + * @throws IndexOutOfBoundsException if index > size + */ + private void checkBoundInclusive(int index) + { + // Implementation note: we do not check for negative ranges here, since + // use of a negative index will cause an ArrayIndexOutOfBoundsException, + // a subclass of the required exception, with no effort on our part. + if (index > size) + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + + size); + } + + /** + * Checks that the index is in the range of existing elements (exclusive). + * + * @param index the index to check + * @throws IndexOutOfBoundsException if index >= size + */ + private void checkBoundExclusive(int index) + { + // Implementation note: we do not check for negative ranges here, since + // use of a negative index will cause an ArrayIndexOutOfBoundsException, + // a subclass of the required exception, with no effort on our part. + if (index >= size) + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + + size); + } + + /** + * Remove from this list all elements contained in the given collection. + * This is not public, due to Sun's API, but this performs in linear + * time while the default behavior of AbstractList would be quadratic. + * + * @param c the collection to filter out + * @return true if this list changed + * @throws NullPointerException if c is null + */ + boolean removeAllInternal(Collection c) + { + int i; + int j; + for (i = 0; i < size; i++) + if (c.contains(data[i])) + break; + if (i == size) + return false; + + modCount++; + for (j = i++; i < size; i++) + if (! c.contains(data[i])) + data[j++] = data[i]; + size -= i - j; + return true; + } + + /** + * Retain in this vector only the elements contained in the given collection. + * This is not public, due to Sun's API, but this performs in linear + * time while the default behavior of AbstractList would be quadratic. + * + * @param c the collection to filter by + * @return true if this vector changed + * @throws NullPointerException if c is null + * @since 1.2 + */ + boolean retainAllInternal(Collection c) + { + int i; + int j; + for (i = 0; i < size; i++) + if (! c.contains(data[i])) + break; + if (i == size) + return false; + + modCount++; + for (j = i++; i < size; i++) + if (c.contains(data[i])) + data[j++] = data[i]; + size -= i - j; + return true; + } + + /** + * Serializes this object to the given stream. + * + * @param out the stream to write to + * @throws IOException if the underlying stream fails + * @serialData the size field (int), the length of the backing array + * (int), followed by its elements (Objects) in proper order. + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + // The 'size' field. + s.defaultWriteObject(); + // We serialize unused list entries to preserve capacity. + int len = data.length; + s.writeInt(len); + // it would be more efficient to just write "size" items, + // this need readObject read "size" items too. + for (int i = 0; i < size; i++) + s.writeObject(data[i]); + } + + /** + * Deserializes this object from the given stream. + * + * @param in the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData the size field (int), the length of the backing array + * (int), followed by its elements (Objects) in proper order. + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + // the `size' field. + s.defaultReadObject(); + int capacity = s.readInt(); + data = new Object[capacity]; + for (int i = 0; i < size; i++) + data[i] = s.readObject(); + } +} diff --git a/libjava/classpath/java/util/Arrays.java b/libjava/classpath/java/util/Arrays.java new file mode 100644 index 0000000..15c1a5f --- /dev/null +++ b/libjava/classpath/java/util/Arrays.java @@ -0,0 +1,2510 @@ +/* Arrays.java -- Utility class with methods to operate on arrays + 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 java.util; + +import java.io.Serializable; +import java.lang.reflect.Array; + +/** + * This class contains various static utility methods performing operations on + * arrays, and a method to provide a List "view" of an array to facilitate + * using arrays with Collection-based APIs. All methods throw a + * {@link NullPointerException} if the parameter array is null. + *

    + * + * Implementations may use their own algorithms, but must obey the general + * properties; for example, the sort must be stable and n*log(n) complexity. + * Sun's implementation of sort, and therefore ours, is a tuned quicksort, + * adapted from Jon L. Bentley and M. Douglas McIlroy's "Engineering a Sort + * Function", Software-Practice and Experience, Vol. 23(11) P. 1249-1265 + * (November 1993). This algorithm offers n*log(n) performance on many data + * sets that cause other quicksorts to degrade to quadratic performance. + * + * @author Original author unknown + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Comparable + * @see Comparator + * @since 1.2 + * @status updated to 1.4 + */ +public class Arrays +{ + /** + * This class is non-instantiable. + */ + private Arrays() + { + } + + +// binarySearch + /** + * Perform a binary search of a byte array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(byte[] a, byte key) + { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) + { + mid = (low + hi) >> 1; + final byte d = a[mid]; + if (d == key) + return mid; + else if (d > key) + hi = mid - 1; + else + // This gets the insertion point right on the last loop. + low = ++mid; + } + return -mid - 1; + } + + /** + * Perform a binary search of a char array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(char[] a, char key) + { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) + { + mid = (low + hi) >> 1; + final char d = a[mid]; + if (d == key) + return mid; + else if (d > key) + hi = mid - 1; + else + // This gets the insertion point right on the last loop. + low = ++mid; + } + return -mid - 1; + } + + /** + * Perform a binary search of a short array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(short[] a, short key) + { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) + { + mid = (low + hi) >> 1; + final short d = a[mid]; + if (d == key) + return mid; + else if (d > key) + hi = mid - 1; + else + // This gets the insertion point right on the last loop. + low = ++mid; + } + return -mid - 1; + } + + /** + * Perform a binary search of an int array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(int[] a, int key) + { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) + { + mid = (low + hi) >> 1; + final int d = a[mid]; + if (d == key) + return mid; + else if (d > key) + hi = mid - 1; + else + // This gets the insertion point right on the last loop. + low = ++mid; + } + return -mid - 1; + } + + /** + * Perform a binary search of a long array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(long[] a, long key) + { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) + { + mid = (low + hi) >> 1; + final long d = a[mid]; + if (d == key) + return mid; + else if (d > key) + hi = mid - 1; + else + // This gets the insertion point right on the last loop. + low = ++mid; + } + return -mid - 1; + } + + /** + * Perform a binary search of a float array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(float[] a, float key) + { + // Must use Float.compare to take into account NaN, +-0. + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) + { + mid = (low + hi) >> 1; + final int r = Float.compare(a[mid], key); + if (r == 0) + return mid; + else if (r > 0) + hi = mid - 1; + else + // This gets the insertion point right on the last loop + low = ++mid; + } + return -mid - 1; + } + + /** + * Perform a binary search of a double array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(double[] a, double key) + { + // Must use Double.compare to take into account NaN, +-0. + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) + { + mid = (low + hi) >> 1; + final int r = Double.compare(a[mid], key); + if (r == 0) + return mid; + else if (r > 0) + hi = mid - 1; + else + // This gets the insertion point right on the last loop + low = ++mid; + } + return -mid - 1; + } + + /** + * Perform a binary search of an Object array for a key, using the natural + * ordering of the elements. The array must be sorted (as by the sort() + * method) - if it is not, the behaviour of this method is undefined, and may + * be an infinite loop. Further, the key must be comparable with every item + * in the array. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this (JCL) + * implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws ClassCastException if key could not be compared with one of the + * elements of a + * @throws NullPointerException if a null element in a is compared + */ + public static int binarySearch(Object[] a, Object key) + { + return binarySearch(a, key, null); + } + + /** + * Perform a binary search of an Object array for a key, using a supplied + * Comparator. The array must be sorted (as by the sort() method with the + * same Comparator) - if it is not, the behaviour of this method is + * undefined, and may be an infinite loop. Further, the key must be + * comparable with every item in the array. If the array contains the key + * more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this (JCL) implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @param c the comparator by which the array is sorted; or null to + * use the elements' natural order + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws ClassCastException if key could not be compared with one of the + * elements of a + * @throws NullPointerException if a null element is compared with natural + * ordering (only possible when c is null) + */ + public static int binarySearch(Object[] a, Object key, Comparator c) + { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) + { + mid = (low + hi) >> 1; + final int d = Collections.compare(key, a[mid], c); + if (d == 0) + return mid; + else if (d < 0) + hi = mid - 1; + else + // This gets the insertion point right on the last loop + low = ++mid; + } + return -mid - 1; + } + + +// equals + /** + * Compare two boolean arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(boolean[] a1, boolean[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) + return true; + + if (null == a1 || null == a2) + return false; + + // If they're the same length, test each element + if (a1.length == a2.length) + { + int i = a1.length; + while (--i >= 0) + if (a1[i] != a2[i]) + return false; + return true; + } + return false; + } + + /** + * Compare two byte arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(byte[] a1, byte[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) + return true; + + if (null == a1 || null == a2) + return false; + + // If they're the same length, test each element + if (a1.length == a2.length) + { + int i = a1.length; + while (--i >= 0) + if (a1[i] != a2[i]) + return false; + return true; + } + return false; + } + + /** + * Compare two char arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(char[] a1, char[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) + return true; + + if (null == a1 || null == a2) + return false; + + // If they're the same length, test each element + if (a1.length == a2.length) + { + int i = a1.length; + while (--i >= 0) + if (a1[i] != a2[i]) + return false; + return true; + } + return false; + } + + /** + * Compare two short arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(short[] a1, short[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) + return true; + + if (null == a1 || null == a2) + return false; + + // If they're the same length, test each element + if (a1.length == a2.length) + { + int i = a1.length; + while (--i >= 0) + if (a1[i] != a2[i]) + return false; + return true; + } + return false; + } + + /** + * Compare two int arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(int[] a1, int[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) + return true; + + if (null == a1 || null == a2) + return false; + + // If they're the same length, test each element + if (a1.length == a2.length) + { + int i = a1.length; + while (--i >= 0) + if (a1[i] != a2[i]) + return false; + return true; + } + return false; + } + + /** + * Compare two long arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(long[] a1, long[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) + return true; + + if (null == a1 || null == a2) + return false; + + // If they're the same length, test each element + if (a1.length == a2.length) + { + int i = a1.length; + while (--i >= 0) + if (a1[i] != a2[i]) + return false; + return true; + } + return false; + } + + /** + * Compare two float arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(float[] a1, float[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) + return true; + + if (null == a1 || null == a2) + return false; + + // Must use Float.compare to take into account NaN, +-0. + // If they're the same length, test each element + if (a1.length == a2.length) + { + int i = a1.length; + while (--i >= 0) + if (Float.compare(a1[i], a2[i]) != 0) + return false; + return true; + } + return false; + } + + /** + * Compare two double arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(double[] a1, double[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) + return true; + + if (null == a1 || null == a2) + return false; + + // Must use Double.compare to take into account NaN, +-0. + // If they're the same length, test each element + if (a1.length == a2.length) + { + int i = a1.length; + while (--i >= 0) + if (Double.compare(a1[i], a2[i]) != 0) + return false; + return true; + } + return false; + } + + /** + * Compare two Object arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @return true if a1 and a2 are both null, or if a1 is of the same length + * as a2, and for each 0 <= i < a.length, a1[i] == null ? + * a2[i] == null : a1[i].equals(a2[i]). + */ + public static boolean equals(Object[] a1, Object[] a2) + { + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) + return true; + + if (null == a1 || null == a2) + return false; + + // If they're the same length, test each element + if (a1.length == a2.length) + { + int i = a1.length; + while (--i >= 0) + if (! AbstractCollection.equals(a1[i], a2[i])) + return false; + return true; + } + return false; + } + + +// fill + /** + * Fill an array with a boolean value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(boolean[] a, boolean val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a boolean value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(boolean[] a, int fromIndex, int toIndex, boolean val) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Fill an array with a byte value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(byte[] a, byte val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a byte value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(byte[] a, int fromIndex, int toIndex, byte val) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Fill an array with a char value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(char[] a, char val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a char value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(char[] a, int fromIndex, int toIndex, char val) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Fill an array with a short value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(short[] a, short val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a short value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(short[] a, int fromIndex, int toIndex, short val) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Fill an array with an int value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(int[] a, int val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with an int value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(int[] a, int fromIndex, int toIndex, int val) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Fill an array with a long value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(long[] a, long val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a long value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(long[] a, int fromIndex, int toIndex, long val) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Fill an array with a float value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(float[] a, float val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a float value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(float[] a, int fromIndex, int toIndex, float val) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Fill an array with a double value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(double[] a, double val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a double value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(double[] a, int fromIndex, int toIndex, double val) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Fill an array with an Object value. + * + * @param a the array to fill + * @param val the value to fill it with + * @throws ClassCastException if val is not an instance of the element + * type of a. + */ + public static void fill(Object[] a, Object val) + { + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with an Object value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @throws ClassCastException if val is not an instance of the element + * type of a. + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void fill(Object[] a, int fromIndex, int toIndex, Object val) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + +// sort + // Thanks to Paul Fisher (rao@gnu.org) for finding this quicksort algorithm + // as specified by Sun and porting it to Java. The algorithm is an optimised + // quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's + // "Engineering a Sort Function", Software-Practice and Experience, Vol. + // 23(11) P. 1249-1265 (November 1993). This algorithm gives n*log(n) + // performance on many arrays that would take quadratic time with a standard + // quicksort. + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the byte array to sort + */ + public static void sort(byte[] a) + { + qsort(a, 0, a.length); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the byte array to sort + * @param fromIndex the first index to sort (inclusive) + * @param toIndex the last index to sort (exclusive) + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void sort(byte[] a, int fromIndex, int toIndex) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + if (fromIndex < 0) + throw new ArrayIndexOutOfBoundsException(); + qsort(a, fromIndex, toIndex - fromIndex); + } + + /** + * Finds the index of the median of three array elements. + * + * @param a the first index + * @param b the second index + * @param c the third index + * @param d the array + * @return the index (a, b, or c) which has the middle value of the three + */ + private static int med3(int a, int b, int c, byte[] d) + { + return (d[a] < d[b] + ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a) + : (d[b] > d[c] ? b : d[a] > d[c] ? c : a)); + } + + /** + * Swaps the elements at two locations of an array + * + * @param i the first index + * @param j the second index + * @param a the array + */ + private static void swap(int i, int j, byte[] a) + { + byte c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + /** + * Swaps two ranges of an array. + * + * @param i the first range start + * @param j the second range start + * @param n the element count + * @param a the array + */ + private static void vecswap(int i, int j, int n, byte[] a) + { + for ( ; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Performs a recursive modified quicksort. + * + * @param array the array to sort + * @param from the start index (inclusive) + * @param count the number of elements to sort + */ + private static void qsort(byte[] array, int from, int count) + { + // Use an insertion sort on small arrays. + if (count <= 7) + { + for (int i = from + 1; i < from + count; i++) + for (int j = i; j > from && array[j - 1] > array[j]; j--) + swap(j, j - 1, array); + return; + } + + // Determine a good median element. + int mid = count / 2; + int lo = from; + int hi = from + count - 1; + + if (count > 40) + { // big arrays, pseudomedian of 9 + int s = count / 8; + lo = med3(lo, lo + s, lo + 2 * s, array); + mid = med3(mid - s, mid, mid + s, array); + hi = med3(hi - 2 * s, hi - s, hi, array); + } + mid = med3(lo, mid, hi, array); + + int a, b, c, d; + int comp; + + // Pull the median element out of the fray, and use it as a pivot. + swap(from, mid, array); + a = b = from; + c = d = from + count - 1; + + // Repeatedly move b and c to each other, swapping elements so + // that all elements before index b are less than the pivot, and all + // elements after index c are greater than the pivot. a and b track + // the elements equal to the pivot. + while (true) + { + while (b <= c && (comp = array[b] - array[from]) <= 0) + { + if (comp == 0) + { + swap(a, b, array); + a++; + } + b++; + } + while (c >= b && (comp = array[c] - array[from]) >= 0) + { + if (comp == 0) + { + swap(c, d, array); + d--; + } + c--; + } + if (b > c) + break; + swap(b, c, array); + b++; + c--; + } + + // Swap pivot(s) back in place, the recurse on left and right sections. + hi = from + count; + int span; + span = Math.min(a - from, b - a); + vecswap(from, b - span, span, array); + + span = Math.min(d - c, hi - d - 1); + vecswap(b, hi - span, span, array); + + span = b - a; + if (span > 1) + qsort(array, from, span); + + span = d - c; + if (span > 1) + qsort(array, hi - span, span); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the char array to sort + */ + public static void sort(char[] a) + { + qsort(a, 0, a.length); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the char array to sort + * @param fromIndex the first index to sort (inclusive) + * @param toIndex the last index to sort (exclusive) + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void sort(char[] a, int fromIndex, int toIndex) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + if (fromIndex < 0) + throw new ArrayIndexOutOfBoundsException(); + qsort(a, fromIndex, toIndex - fromIndex); + } + + /** + * Finds the index of the median of three array elements. + * + * @param a the first index + * @param b the second index + * @param c the third index + * @param d the array + * @return the index (a, b, or c) which has the middle value of the three + */ + private static int med3(int a, int b, int c, char[] d) + { + return (d[a] < d[b] + ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a) + : (d[b] > d[c] ? b : d[a] > d[c] ? c : a)); + } + + /** + * Swaps the elements at two locations of an array + * + * @param i the first index + * @param j the second index + * @param a the array + */ + private static void swap(int i, int j, char[] a) + { + char c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + /** + * Swaps two ranges of an array. + * + * @param i the first range start + * @param j the second range start + * @param n the element count + * @param a the array + */ + private static void vecswap(int i, int j, int n, char[] a) + { + for ( ; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Performs a recursive modified quicksort. + * + * @param array the array to sort + * @param from the start index (inclusive) + * @param count the number of elements to sort + */ + private static void qsort(char[] array, int from, int count) + { + // Use an insertion sort on small arrays. + if (count <= 7) + { + for (int i = from + 1; i < from + count; i++) + for (int j = i; j > from && array[j - 1] > array[j]; j--) + swap(j, j - 1, array); + return; + } + + // Determine a good median element. + int mid = count / 2; + int lo = from; + int hi = from + count - 1; + + if (count > 40) + { // big arrays, pseudomedian of 9 + int s = count / 8; + lo = med3(lo, lo + s, lo + 2 * s, array); + mid = med3(mid - s, mid, mid + s, array); + hi = med3(hi - 2 * s, hi - s, hi, array); + } + mid = med3(lo, mid, hi, array); + + int a, b, c, d; + int comp; + + // Pull the median element out of the fray, and use it as a pivot. + swap(from, mid, array); + a = b = from; + c = d = from + count - 1; + + // Repeatedly move b and c to each other, swapping elements so + // that all elements before index b are less than the pivot, and all + // elements after index c are greater than the pivot. a and b track + // the elements equal to the pivot. + while (true) + { + while (b <= c && (comp = array[b] - array[from]) <= 0) + { + if (comp == 0) + { + swap(a, b, array); + a++; + } + b++; + } + while (c >= b && (comp = array[c] - array[from]) >= 0) + { + if (comp == 0) + { + swap(c, d, array); + d--; + } + c--; + } + if (b > c) + break; + swap(b, c, array); + b++; + c--; + } + + // Swap pivot(s) back in place, the recurse on left and right sections. + hi = from + count; + int span; + span = Math.min(a - from, b - a); + vecswap(from, b - span, span, array); + + span = Math.min(d - c, hi - d - 1); + vecswap(b, hi - span, span, array); + + span = b - a; + if (span > 1) + qsort(array, from, span); + + span = d - c; + if (span > 1) + qsort(array, hi - span, span); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the short array to sort + */ + public static void sort(short[] a) + { + qsort(a, 0, a.length); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the short array to sort + * @param fromIndex the first index to sort (inclusive) + * @param toIndex the last index to sort (exclusive) + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void sort(short[] a, int fromIndex, int toIndex) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + if (fromIndex < 0) + throw new ArrayIndexOutOfBoundsException(); + qsort(a, fromIndex, toIndex - fromIndex); + } + + /** + * Finds the index of the median of three array elements. + * + * @param a the first index + * @param b the second index + * @param c the third index + * @param d the array + * @return the index (a, b, or c) which has the middle value of the three + */ + private static int med3(int a, int b, int c, short[] d) + { + return (d[a] < d[b] + ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a) + : (d[b] > d[c] ? b : d[a] > d[c] ? c : a)); + } + + /** + * Swaps the elements at two locations of an array + * + * @param i the first index + * @param j the second index + * @param a the array + */ + private static void swap(int i, int j, short[] a) + { + short c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + /** + * Swaps two ranges of an array. + * + * @param i the first range start + * @param j the second range start + * @param n the element count + * @param a the array + */ + private static void vecswap(int i, int j, int n, short[] a) + { + for ( ; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Performs a recursive modified quicksort. + * + * @param array the array to sort + * @param from the start index (inclusive) + * @param count the number of elements to sort + */ + private static void qsort(short[] array, int from, int count) + { + // Use an insertion sort on small arrays. + if (count <= 7) + { + for (int i = from + 1; i < from + count; i++) + for (int j = i; j > from && array[j - 1] > array[j]; j--) + swap(j, j - 1, array); + return; + } + + // Determine a good median element. + int mid = count / 2; + int lo = from; + int hi = from + count - 1; + + if (count > 40) + { // big arrays, pseudomedian of 9 + int s = count / 8; + lo = med3(lo, lo + s, lo + 2 * s, array); + mid = med3(mid - s, mid, mid + s, array); + hi = med3(hi - 2 * s, hi - s, hi, array); + } + mid = med3(lo, mid, hi, array); + + int a, b, c, d; + int comp; + + // Pull the median element out of the fray, and use it as a pivot. + swap(from, mid, array); + a = b = from; + c = d = from + count - 1; + + // Repeatedly move b and c to each other, swapping elements so + // that all elements before index b are less than the pivot, and all + // elements after index c are greater than the pivot. a and b track + // the elements equal to the pivot. + while (true) + { + while (b <= c && (comp = array[b] - array[from]) <= 0) + { + if (comp == 0) + { + swap(a, b, array); + a++; + } + b++; + } + while (c >= b && (comp = array[c] - array[from]) >= 0) + { + if (comp == 0) + { + swap(c, d, array); + d--; + } + c--; + } + if (b > c) + break; + swap(b, c, array); + b++; + c--; + } + + // Swap pivot(s) back in place, the recurse on left and right sections. + hi = from + count; + int span; + span = Math.min(a - from, b - a); + vecswap(from, b - span, span, array); + + span = Math.min(d - c, hi - d - 1); + vecswap(b, hi - span, span, array); + + span = b - a; + if (span > 1) + qsort(array, from, span); + + span = d - c; + if (span > 1) + qsort(array, hi - span, span); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the int array to sort + */ + public static void sort(int[] a) + { + qsort(a, 0, a.length); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the int array to sort + * @param fromIndex the first index to sort (inclusive) + * @param toIndex the last index to sort (exclusive) + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void sort(int[] a, int fromIndex, int toIndex) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + if (fromIndex < 0) + throw new ArrayIndexOutOfBoundsException(); + qsort(a, fromIndex, toIndex - fromIndex); + } + + /** + * Finds the index of the median of three array elements. + * + * @param a the first index + * @param b the second index + * @param c the third index + * @param d the array + * @return the index (a, b, or c) which has the middle value of the three + */ + private static int med3(int a, int b, int c, int[] d) + { + return (d[a] < d[b] + ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a) + : (d[b] > d[c] ? b : d[a] > d[c] ? c : a)); + } + + /** + * Swaps the elements at two locations of an array + * + * @param i the first index + * @param j the second index + * @param a the array + */ + private static void swap(int i, int j, int[] a) + { + int c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + /** + * Swaps two ranges of an array. + * + * @param i the first range start + * @param j the second range start + * @param n the element count + * @param a the array + */ + private static void vecswap(int i, int j, int n, int[] a) + { + for ( ; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Compares two integers in natural order, since a - b is inadequate. + * + * @param a the first int + * @param b the second int + * @return < 0, 0, or > 0 accorting to the comparison + */ + private static int compare(int a, int b) + { + return a < b ? -1 : a == b ? 0 : 1; + } + + /** + * Performs a recursive modified quicksort. + * + * @param array the array to sort + * @param from the start index (inclusive) + * @param count the number of elements to sort + */ + private static void qsort(int[] array, int from, int count) + { + // Use an insertion sort on small arrays. + if (count <= 7) + { + for (int i = from + 1; i < from + count; i++) + for (int j = i; j > from && array[j - 1] > array[j]; j--) + swap(j, j - 1, array); + return; + } + + // Determine a good median element. + int mid = count / 2; + int lo = from; + int hi = from + count - 1; + + if (count > 40) + { // big arrays, pseudomedian of 9 + int s = count / 8; + lo = med3(lo, lo + s, lo + 2 * s, array); + mid = med3(mid - s, mid, mid + s, array); + hi = med3(hi - 2 * s, hi - s, hi, array); + } + mid = med3(lo, mid, hi, array); + + int a, b, c, d; + int comp; + + // Pull the median element out of the fray, and use it as a pivot. + swap(from, mid, array); + a = b = from; + c = d = from + count - 1; + + // Repeatedly move b and c to each other, swapping elements so + // that all elements before index b are less than the pivot, and all + // elements after index c are greater than the pivot. a and b track + // the elements equal to the pivot. + while (true) + { + while (b <= c && (comp = compare(array[b], array[from])) <= 0) + { + if (comp == 0) + { + swap(a, b, array); + a++; + } + b++; + } + while (c >= b && (comp = compare(array[c], array[from])) >= 0) + { + if (comp == 0) + { + swap(c, d, array); + d--; + } + c--; + } + if (b > c) + break; + swap(b, c, array); + b++; + c--; + } + + // Swap pivot(s) back in place, the recurse on left and right sections. + hi = from + count; + int span; + span = Math.min(a - from, b - a); + vecswap(from, b - span, span, array); + + span = Math.min(d - c, hi - d - 1); + vecswap(b, hi - span, span, array); + + span = b - a; + if (span > 1) + qsort(array, from, span); + + span = d - c; + if (span > 1) + qsort(array, hi - span, span); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the long array to sort + */ + public static void sort(long[] a) + { + qsort(a, 0, a.length); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the long array to sort + * @param fromIndex the first index to sort (inclusive) + * @param toIndex the last index to sort (exclusive) + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void sort(long[] a, int fromIndex, int toIndex) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + if (fromIndex < 0) + throw new ArrayIndexOutOfBoundsException(); + qsort(a, fromIndex, toIndex - fromIndex); + } + + /** + * Finds the index of the median of three array elements. + * + * @param a the first index + * @param b the second index + * @param c the third index + * @param d the array + * @return the index (a, b, or c) which has the middle value of the three + */ + private static int med3(int a, int b, int c, long[] d) + { + return (d[a] < d[b] + ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a) + : (d[b] > d[c] ? b : d[a] > d[c] ? c : a)); + } + + /** + * Swaps the elements at two locations of an array + * + * @param i the first index + * @param j the second index + * @param a the array + */ + private static void swap(int i, int j, long[] a) + { + long c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + /** + * Swaps two ranges of an array. + * + * @param i the first range start + * @param j the second range start + * @param n the element count + * @param a the array + */ + private static void vecswap(int i, int j, int n, long[] a) + { + for ( ; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Compares two longs in natural order, since a - b is inadequate. + * + * @param a the first long + * @param b the second long + * @return < 0, 0, or > 0 accorting to the comparison + */ + private static int compare(long a, long b) + { + return a < b ? -1 : a == b ? 0 : 1; + } + + /** + * Performs a recursive modified quicksort. + * + * @param array the array to sort + * @param from the start index (inclusive) + * @param count the number of elements to sort + */ + private static void qsort(long[] array, int from, int count) + { + // Use an insertion sort on small arrays. + if (count <= 7) + { + for (int i = from + 1; i < from + count; i++) + for (int j = i; j > from && array[j - 1] > array[j]; j--) + swap(j, j - 1, array); + return; + } + + // Determine a good median element. + int mid = count / 2; + int lo = from; + int hi = from + count - 1; + + if (count > 40) + { // big arrays, pseudomedian of 9 + int s = count / 8; + lo = med3(lo, lo + s, lo + 2 * s, array); + mid = med3(mid - s, mid, mid + s, array); + hi = med3(hi - 2 * s, hi - s, hi, array); + } + mid = med3(lo, mid, hi, array); + + int a, b, c, d; + int comp; + + // Pull the median element out of the fray, and use it as a pivot. + swap(from, mid, array); + a = b = from; + c = d = from + count - 1; + + // Repeatedly move b and c to each other, swapping elements so + // that all elements before index b are less than the pivot, and all + // elements after index c are greater than the pivot. a and b track + // the elements equal to the pivot. + while (true) + { + while (b <= c && (comp = compare(array[b], array[from])) <= 0) + { + if (comp == 0) + { + swap(a, b, array); + a++; + } + b++; + } + while (c >= b && (comp = compare(array[c], array[from])) >= 0) + { + if (comp == 0) + { + swap(c, d, array); + d--; + } + c--; + } + if (b > c) + break; + swap(b, c, array); + b++; + c--; + } + + // Swap pivot(s) back in place, the recurse on left and right sections. + hi = from + count; + int span; + span = Math.min(a - from, b - a); + vecswap(from, b - span, span, array); + + span = Math.min(d - c, hi - d - 1); + vecswap(b, hi - span, span, array); + + span = b - a; + if (span > 1) + qsort(array, from, span); + + span = d - c; + if (span > 1) + qsort(array, hi - span, span); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the float array to sort + */ + public static void sort(float[] a) + { + qsort(a, 0, a.length); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the float array to sort + * @param fromIndex the first index to sort (inclusive) + * @param toIndex the last index to sort (exclusive) + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void sort(float[] a, int fromIndex, int toIndex) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + if (fromIndex < 0) + throw new ArrayIndexOutOfBoundsException(); + qsort(a, fromIndex, toIndex - fromIndex); + } + + /** + * Finds the index of the median of three array elements. + * + * @param a the first index + * @param b the second index + * @param c the third index + * @param d the array + * @return the index (a, b, or c) which has the middle value of the three + */ + private static int med3(int a, int b, int c, float[] d) + { + return (Float.compare(d[a], d[b]) < 0 + ? (Float.compare(d[b], d[c]) < 0 ? b + : Float.compare(d[a], d[c]) < 0 ? c : a) + : (Float.compare(d[b], d[c]) > 0 ? b + : Float.compare(d[a], d[c]) > 0 ? c : a)); + } + + /** + * Swaps the elements at two locations of an array + * + * @param i the first index + * @param j the second index + * @param a the array + */ + private static void swap(int i, int j, float[] a) + { + float c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + /** + * Swaps two ranges of an array. + * + * @param i the first range start + * @param j the second range start + * @param n the element count + * @param a the array + */ + private static void vecswap(int i, int j, int n, float[] a) + { + for ( ; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Performs a recursive modified quicksort. + * + * @param array the array to sort + * @param from the start index (inclusive) + * @param count the number of elements to sort + */ + private static void qsort(float[] array, int from, int count) + { + // Use an insertion sort on small arrays. + if (count <= 7) + { + for (int i = from + 1; i < from + count; i++) + for (int j = i; + j > from && Float.compare(array[j - 1], array[j]) > 0; + j--) + { + swap(j, j - 1, array); + } + return; + } + + // Determine a good median element. + int mid = count / 2; + int lo = from; + int hi = from + count - 1; + + if (count > 40) + { // big arrays, pseudomedian of 9 + int s = count / 8; + lo = med3(lo, lo + s, lo + 2 * s, array); + mid = med3(mid - s, mid, mid + s, array); + hi = med3(hi - 2 * s, hi - s, hi, array); + } + mid = med3(lo, mid, hi, array); + + int a, b, c, d; + int comp; + + // Pull the median element out of the fray, and use it as a pivot. + swap(from, mid, array); + a = b = from; + c = d = from + count - 1; + + // Repeatedly move b and c to each other, swapping elements so + // that all elements before index b are less than the pivot, and all + // elements after index c are greater than the pivot. a and b track + // the elements equal to the pivot. + while (true) + { + while (b <= c && (comp = Float.compare(array[b], array[from])) <= 0) + { + if (comp == 0) + { + swap(a, b, array); + a++; + } + b++; + } + while (c >= b && (comp = Float.compare(array[c], array[from])) >= 0) + { + if (comp == 0) + { + swap(c, d, array); + d--; + } + c--; + } + if (b > c) + break; + swap(b, c, array); + b++; + c--; + } + + // Swap pivot(s) back in place, the recurse on left and right sections. + hi = from + count; + int span; + span = Math.min(a - from, b - a); + vecswap(from, b - span, span, array); + + span = Math.min(d - c, hi - d - 1); + vecswap(b, hi - span, span, array); + + span = b - a; + if (span > 1) + qsort(array, from, span); + + span = d - c; + if (span > 1) + qsort(array, hi - span, span); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the double array to sort + */ + public static void sort(double[] a) + { + qsort(a, 0, a.length); + } + + /** + * Performs a stable sort on the elements, arranging them according to their + * natural order. + * + * @param a the double array to sort + * @param fromIndex the first index to sort (inclusive) + * @param toIndex the last index to sort (exclusive) + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 + * || toIndex > a.length + */ + public static void sort(double[] a, int fromIndex, int toIndex) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException(); + if (fromIndex < 0) + throw new ArrayIndexOutOfBoundsException(); + qsort(a, fromIndex, toIndex - fromIndex); + } + + /** + * Finds the index of the median of three array elements. + * + * @param a the first index + * @param b the second index + * @param c the third index + * @param d the array + * @return the index (a, b, or c) which has the middle value of the three + */ + private static int med3(int a, int b, int c, double[] d) + { + return (Double.compare(d[a], d[b]) < 0 + ? (Double.compare(d[b], d[c]) < 0 ? b + : Double.compare(d[a], d[c]) < 0 ? c : a) + : (Double.compare(d[b], d[c]) > 0 ? b + : Double.compare(d[a], d[c]) > 0 ? c : a)); + } + + /** + * Swaps the elements at two locations of an array + * + * @param i the first index + * @param j the second index + * @param a the array + */ + private static void swap(int i, int j, double[] a) + { + double c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + /** + * Swaps two ranges of an array. + * + * @param i the first range start + * @param j the second range start + * @param n the element count + * @param a the array + */ + private static void vecswap(int i, int j, int n, double[] a) + { + for ( ; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Performs a recursive modified quicksort. + * + * @param array the array to sort + * @param from the start index (inclusive) + * @param count the number of elements to sort + */ + private static void qsort(double[] array, int from, int count) + { + // Use an insertion sort on small arrays. + if (count <= 7) + { + for (int i = from + 1; i < from + count; i++) + for (int j = i; + j > from && Double.compare(array[j - 1], array[j]) > 0; + j--) + { + swap(j, j - 1, array); + } + return; + } + + // Determine a good median element. + int mid = count / 2; + int lo = from; + int hi = from + count - 1; + + if (count > 40) + { // big arrays, pseudomedian of 9 + int s = count / 8; + lo = med3(lo, lo + s, lo + 2 * s, array); + mid = med3(mid - s, mid, mid + s, array); + hi = med3(hi - 2 * s, hi - s, hi, array); + } + mid = med3(lo, mid, hi, array); + + int a, b, c, d; + int comp; + + // Pull the median element out of the fray, and use it as a pivot. + swap(from, mid, array); + a = b = from; + c = d = from + count - 1; + + // Repeatedly move b and c to each other, swapping elements so + // that all elements before index b are less than the pivot, and all + // elements after index c are greater than the pivot. a and b track + // the elements equal to the pivot. + while (true) + { + while (b <= c && (comp = Double.compare(array[b], array[from])) <= 0) + { + if (comp == 0) + { + swap(a, b, array); + a++; + } + b++; + } + while (c >= b && (comp = Double.compare(array[c], array[from])) >= 0) + { + if (comp == 0) + { + swap(c, d, array); + d--; + } + c--; + } + if (b > c) + break; + swap(b, c, array); + b++; + c--; + } + + // Swap pivot(s) back in place, the recurse on left and right sections. + hi = from + count; + int span; + span = Math.min(a - from, b - a); + vecswap(from, b - span, span, array); + + span = Math.min(d - c, hi - d - 1); + vecswap(b, hi - span, span, array); + + span = b - a; + if (span > 1) + qsort(array, from, span); + + span = d - c; + if (span > 1) + qsort(array, hi - span, span); + } + + /** + * Sort an array of Objects according to their natural ordering. The sort is + * guaranteed to be stable, that is, equal elements will not be reordered. + * The sort algorithm is a mergesort with the merge omitted if the last + * element of one half comes before the first element of the other half. This + * algorithm gives guaranteed O(n*log(n)) time, at the expense of making a + * copy of the array. + * + * @param a the array to be sorted + * @throws ClassCastException if any two elements are not mutually + * comparable + * @throws NullPointerException if an element is null (since + * null.compareTo cannot work) + * @see Comparable + */ + public static void sort(Object[] a) + { + sort(a, 0, a.length, null); + } + + /** + * Sort an array of Objects according to a Comparator. The sort is + * guaranteed to be stable, that is, equal elements will not be reordered. + * The sort algorithm is a mergesort with the merge omitted if the last + * element of one half comes before the first element of the other half. This + * algorithm gives guaranteed O(n*log(n)) time, at the expense of making a + * copy of the array. + * + * @param a the array to be sorted + * @param c a Comparator to use in sorting the array; or null to indicate + * the elements' natural order + * @throws ClassCastException if any two elements are not mutually + * comparable by the Comparator provided + * @throws NullPointerException if a null element is compared with natural + * ordering (only possible when c is null) + */ + public static void sort(Object[] a, Comparator c) + { + sort(a, 0, a.length, c); + } + + /** + * Sort an array of Objects according to their natural ordering. The sort is + * guaranteed to be stable, that is, equal elements will not be reordered. + * The sort algorithm is a mergesort with the merge omitted if the last + * element of one half comes before the first element of the other half. This + * algorithm gives guaranteed O(n*log(n)) time, at the expense of making a + * copy of the array. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element to be sorted + * @param toIndex the index of the last element to be sorted plus one + * @throws ClassCastException if any two elements are not mutually + * comparable + * @throws NullPointerException if an element is null (since + * null.compareTo cannot work) + * @throws ArrayIndexOutOfBoundsException if fromIndex and toIndex + * are not in range. + * @throws IllegalArgumentException if fromIndex > toIndex + */ + public static void sort(Object[] a, int fromIndex, int toIndex) + { + sort(a, fromIndex, toIndex, null); + } + + /** + * Sort an array of Objects according to a Comparator. The sort is + * guaranteed to be stable, that is, equal elements will not be reordered. + * The sort algorithm is a mergesort with the merge omitted if the last + * element of one half comes before the first element of the other half. This + * algorithm gives guaranteed O(n*log(n)) time, at the expense of making a + * copy of the array. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element to be sorted + * @param toIndex the index of the last element to be sorted plus one + * @param c a Comparator to use in sorting the array; or null to indicate + * the elements' natural order + * @throws ClassCastException if any two elements are not mutually + * comparable by the Comparator provided + * @throws ArrayIndexOutOfBoundsException if fromIndex and toIndex + * are not in range. + * @throws IllegalArgumentException if fromIndex > toIndex + * @throws NullPointerException if a null element is compared with natural + * ordering (only possible when c is null) + */ + public static void sort(Object[] a, int fromIndex, int toIndex, Comparator c) + { + if (fromIndex > toIndex) + throw new IllegalArgumentException("fromIndex " + fromIndex + + " > toIndex " + toIndex); + if (fromIndex < 0) + throw new ArrayIndexOutOfBoundsException(); + + // In general, the code attempts to be simple rather than fast, the + // idea being that a good optimising JIT will be able to optimise it + // better than I can, and if I try it will make it more confusing for + // the JIT. First presort the array in chunks of length 6 with insertion + // sort. A mergesort would give too much overhead for this length. + for (int chunk = fromIndex; chunk < toIndex; chunk += 6) + { + int end = Math.min(chunk + 6, toIndex); + for (int i = chunk + 1; i < end; i++) + { + if (Collections.compare(a[i - 1], a[i], c) > 0) + { + // not already sorted + int j = i; + Object elem = a[j]; + do + { + a[j] = a[j - 1]; + j--; + } + while (j > chunk + && Collections.compare(a[j - 1], elem, c) > 0); + a[j] = elem; + } + } + } + + int len = toIndex - fromIndex; + // If length is smaller or equal 6 we are done. + if (len <= 6) + return; + + Object[] src = a; + Object[] dest = new Object[len]; + Object[] t = null; // t is used for swapping src and dest + + // The difference of the fromIndex of the src and dest array. + int srcDestDiff = -fromIndex; + + // The merges are done in this loop + for (int size = 6; size < len; size <<= 1) + { + for (int start = fromIndex; start < toIndex; start += size << 1) + { + // mid is the start of the second sublist; + // end the start of the next sublist (or end of array). + int mid = start + size; + int end = Math.min(toIndex, mid + size); + + // The second list is empty or the elements are already in + // order - no need to merge + if (mid >= end + || Collections.compare(src[mid - 1], src[mid], c) <= 0) + { + System.arraycopy(src, start, + dest, start + srcDestDiff, end - start); + + // The two halves just need swapping - no need to merge + } + else if (Collections.compare(src[start], src[end - 1], c) > 0) + { + System.arraycopy(src, start, + dest, end - size + srcDestDiff, size); + System.arraycopy(src, mid, + dest, start + srcDestDiff, end - mid); + + } + else + { + // Declare a lot of variables to save repeating + // calculations. Hopefully a decent JIT will put these + // in registers and make this fast + int p1 = start; + int p2 = mid; + int i = start + srcDestDiff; + + // The main merge loop; terminates as soon as either + // half is ended + while (p1 < mid && p2 < end) + { + dest[i++] = + src[(Collections.compare(src[p1], src[p2], c) <= 0 + ? p1++ : p2++)]; + } + + // Finish up by copying the remainder of whichever half + // wasn't finished. + if (p1 < mid) + System.arraycopy(src, p1, dest, i, mid - p1); + else + System.arraycopy(src, p2, dest, i, end - p2); + } + } + // swap src and dest ready for the next merge + t = src; + src = dest; + dest = t; + fromIndex += srcDestDiff; + toIndex += srcDestDiff; + srcDestDiff = -srcDestDiff; + } + + // make sure the result ends up back in the right place. Note + // that src and dest may have been swapped above, so src + // contains the sorted array. + if (src != a) + { + // Note that fromIndex == 0. + System.arraycopy(src, 0, a, srcDestDiff, toIndex); + } + } + + /** + * Returns a list "view" of the specified array. This method is intended to + * make it easy to use the Collections API with existing array-based APIs and + * programs. Changes in the list or the array show up in both places. The + * list does not support element addition or removal, but does permit + * value modification. The returned list implements both Serializable and + * RandomAccess. + * + * @param a the array to return a view of + * @return a fixed-size list, changes to which "write through" to the array + * @see Serializable + * @see RandomAccess + * @see Arrays.ArrayList + */ + public static List asList(final Object[] a) + { + return new Arrays.ArrayList(a); + } + + /** + * Inner class used by {@link #asList(Object[])} to provide a list interface + * to an array. The name, though it clashes with java.util.ArrayList, is + * Sun's choice for Serialization purposes. Element addition and removal + * is prohibited, but values can be modified. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ + private static final class ArrayList extends AbstractList + implements Serializable, RandomAccess + { + // We override the necessary methods, plus others which will be much + // more efficient with direct iteration rather than relying on iterator(). + + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -2764017481108945198L; + + /** + * The array we are viewing. + * @serial the array + */ + private final Object[] a; + + /** + * Construct a list view of the array. + * @param a the array to view + * @throws NullPointerException if a is null + */ + ArrayList(Object[] a) + { + // We have to explicitly check. + if (a == null) + throw new NullPointerException(); + this.a = a; + } + + /** + * Returns the object at the specified index in + * the array. + * + * @param index The index to retrieve an object from. + * @return The object at the array index specified. + */ + public Object get(int index) + { + return a[index]; + } + + /** + * Returns the size of the array. + * + * @return The size. + */ + public int size() + { + return a.length; + } + + /** + * Replaces the object at the specified index + * with the supplied element. + * + * @param index The index at which to place the new object. + * @param element The new object. + * @return The object replaced by this operation. + */ + public Object set(int index, Object element) + { + Object old = a[index]; + a[index] = element; + return old; + } + + /** + * Returns true if the array contains the + * supplied object. + * + * @param o The object to look for. + * @return True if the object was found. + */ + public boolean contains(Object o) + { + return lastIndexOf(o) >= 0; + } + + /** + * Returns the first index at which the + * object, o, occurs in the array. + * + * @param o The object to search for. + * @return The first relevant index. + */ + public int indexOf(Object o) + { + int size = a.length; + for (int i = 0; i < size; i++) + if (ArrayList.equals(o, a[i])) + return i; + return -1; + } + + /** + * Returns the last index at which the + * object, o, occurs in the array. + * + * @param o The object to search for. + * @return The last relevant index. + */ + public int lastIndexOf(Object o) + { + int i = a.length; + while (--i >= 0) + if (ArrayList.equals(o, a[i])) + return i; + return -1; + } + + /** + * Transforms the list into an array of + * objects, by simplying cloning the array + * wrapped by this list. + * + * @return A clone of the internal array. + */ + public Object[] toArray() + { + return (Object[]) a.clone(); + } + + /** + * Copies the objects from this list into + * the supplied array. The supplied array + * is shrunk or enlarged to the size of the + * internal array, and filled with its objects. + * + * @param array The array to fill with the objects in this list. + * @return The array containing the objects in this list, + * which may or may not be == to array. + */ + public Object[] toArray(Object[] array) + { + int size = a.length; + if (array.length < size) + array = (Object[]) + Array.newInstance(array.getClass().getComponentType(), size); + else if (array.length > size) + array[size] = null; + + System.arraycopy(a, 0, array, 0, size); + return array; + } + } +} diff --git a/libjava/classpath/java/util/BitSet.java b/libjava/classpath/java/util/BitSet.java new file mode 100644 index 0000000..ce88794 --- /dev/null +++ b/libjava/classpath/java/util/BitSet.java @@ -0,0 +1,744 @@ +/* BitSet.java -- A vector of bits. + Copyright (C) 1998, 1999, 2000, 2001, 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 java.util; +import java.io.Serializable; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * hashCode algorithm taken from JDK 1.2 docs. + */ + +/** + * This class can be thought of in two ways. You can see it as a + * vector of bits or as a set of non-negative integers. The name + * BitSet is a bit misleading. + * + * It is implemented by a bit vector, but its equally possible to see + * it as set of non-negative integer; each integer in the set is + * represented by a set bit at the corresponding index. The size of + * this structure is determined by the highest integer in the set. + * + * You can union, intersect and build (symmetric) remainders, by + * invoking the logical operations and, or, andNot, resp. xor. + * + * This implementation is NOT synchronized against concurrent access from + * multiple threads. Specifically, if one thread is reading from a bitset + * while another thread is simultaneously modifying it, the results are + * undefined. + * + * @author Jochen Hoenicke + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class BitSet implements Cloneable, Serializable +{ + /** + * Compatible with JDK 1.0. + */ + private static final long serialVersionUID = 7997698588986878753L; + + /** + * A common mask. + */ + private static final int LONG_MASK = 0x3f; + + /** + * The actual bits. + * @serial the i'th bit is in bits[i/64] at position i%64 (where position + * 0 is the least significant). + */ + private long[] bits; + + /** + * Create a new empty bit set. All bits are initially false. + */ + public BitSet() + { + this(64); + } + + /** + * Create a new empty bit set, with a given size. This + * constructor reserves enough space to represent the integers + * from 0 to nbits-1. + * + * @param nbits the initial size of the bit set + * @throws NegativeArraySizeException if nbits < 0 + */ + public BitSet(int nbits) + { + if (nbits < 0) + throw new NegativeArraySizeException(); + + int length = nbits >>> 6; + if ((nbits & LONG_MASK) != 0) + ++length; + bits = new long[length]; + } + + /** + * Performs the logical AND operation on this bit set and the + * given set. This means it builds the intersection + * of the two sets. The result is stored into this bit set. + * + * @param bs the second bit set + * @throws NullPointerException if bs is null + */ + public void and(BitSet bs) + { + int max = Math.min(bits.length, bs.bits.length); + int i; + for (i = 0; i < max; ++i) + bits[i] &= bs.bits[i]; + while (i < bits.length) + bits[i++] = 0; + } + + /** + * Performs the logical AND operation on this bit set and the + * complement of the given bs. This means it + * selects every element in the first set, that isn't in the + * second set. The result is stored into this bit set and is + * effectively the set difference of the two. + * + * @param bs the second bit set + * @throws NullPointerException if bs is null + * @since 1.2 + */ + public void andNot(BitSet bs) + { + int i = Math.min(bits.length, bs.bits.length); + while (--i >= 0) + bits[i] &= ~bs.bits[i]; + } + + /** + * Returns the number of bits set to true. + * + * @return the number of true bits + * @since 1.4 + */ + public int cardinality() + { + int card = 0; + for (int i = bits.length - 1; i >= 0; i--) + { + long a = bits[i]; + // Take care of common cases. + if (a == 0) + continue; + if (a == -1) + { + card += 64; + continue; + } + + // Successively collapse alternating bit groups into a sum. + a = ((a >> 1) & 0x5555555555555555L) + (a & 0x5555555555555555L); + a = ((a >> 2) & 0x3333333333333333L) + (a & 0x3333333333333333L); + int b = (int) ((a >>> 32) + a); + b = ((b >> 4) & 0x0f0f0f0f) + (b & 0x0f0f0f0f); + b = ((b >> 8) & 0x00ff00ff) + (b & 0x00ff00ff); + card += ((b >> 16) & 0x0000ffff) + (b & 0x0000ffff); + } + return card; + } + + /** + * Sets all bits in the set to false. + * + * @since 1.4 + */ + public void clear() + { + Arrays.fill(bits, 0); + } + + /** + * Removes the integer pos from this set. That is + * the corresponding bit is cleared. If the index is not in the set, + * this method does nothing. + * + * @param pos a non-negative integer + * @throws IndexOutOfBoundsException if pos < 0 + */ + public void clear(int pos) + { + int offset = pos >> 6; + ensure(offset); + // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException, + // so we'll just let that be our exception. + bits[offset] &= ~(1L << pos); + } + + /** + * Sets the bits between from (inclusive) and to (exclusive) to false. + * + * @param from the start range (inclusive) + * @param to the end range (exclusive) + * @throws IndexOutOfBoundsException if from < 0 || to < 0 || + * from > to + * @since 1.4 + */ + public void clear(int from, int to) + { + if (from < 0 || from > to) + throw new IndexOutOfBoundsException(); + if (from == to) + return; + int lo_offset = from >>> 6; + int hi_offset = to >>> 6; + ensure(hi_offset); + if (lo_offset == hi_offset) + { + bits[hi_offset] &= ((1L << from) - 1) | (-1L << to); + return; + } + + bits[lo_offset] &= (1L << from) - 1; + bits[hi_offset] &= -1L << to; + for (int i = lo_offset + 1; i < hi_offset; i++) + bits[i] = 0; + } + + /** + * Create a clone of this bit set, that is an instance of the same + * class and contains the same elements. But it doesn't change when + * this bit set changes. + * + * @return the clone of this object. + */ + public Object clone() + { + try + { + BitSet bs = (BitSet) super.clone(); + bs.bits = (long[]) bits.clone(); + return bs; + } + catch (CloneNotSupportedException e) + { + // Impossible to get here. + return null; + } + } + + /** + * Returns true if the obj is a bit set that contains + * exactly the same elements as this bit set, otherwise false. + * + * @param obj the object to compare to + * @return true if obj equals this bit set + */ + public boolean equals(Object obj) + { + if (!(obj instanceof BitSet)) + return false; + BitSet bs = (BitSet) obj; + int max = Math.min(bits.length, bs.bits.length); + int i; + for (i = 0; i < max; ++i) + if (bits[i] != bs.bits[i]) + return false; + // If one is larger, check to make sure all extra bits are 0. + for (int j = i; j < bits.length; ++j) + if (bits[j] != 0) + return false; + for (int j = i; j < bs.bits.length; ++j) + if (bs.bits[j] != 0) + return false; + return true; + } + + /** + * Sets the bit at the index to the opposite value. + * + * @param index the index of the bit + * @throws IndexOutOfBoundsException if index is negative + * @since 1.4 + */ + public void flip(int index) + { + int offset = index >> 6; + ensure(offset); + // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException, + // so we'll just let that be our exception. + bits[offset] ^= 1L << index; + } + + /** + * Sets a range of bits to the opposite value. + * + * @param from the low index (inclusive) + * @param to the high index (exclusive) + * @throws IndexOutOfBoundsException if from > to || from < 0 || + * to < 0 + * @since 1.4 + */ + public void flip(int from, int to) + { + if (from < 0 || from > to) + throw new IndexOutOfBoundsException(); + if (from == to) + return; + int lo_offset = from >>> 6; + int hi_offset = to >>> 6; + ensure(hi_offset); + if (lo_offset == hi_offset) + { + bits[hi_offset] ^= (-1L << from) & ((1L << to) - 1); + return; + } + + bits[lo_offset] ^= -1L << from; + bits[hi_offset] ^= (1L << to) - 1; + for (int i = lo_offset + 1; i < hi_offset; i++) + bits[i] ^= -1; + } + + /** + * Returns true if the integer bitIndex is in this bit + * set, otherwise false. + * + * @param pos a non-negative integer + * @return the value of the bit at the specified position + * @throws IndexOutOfBoundsException if the pos is negative + */ + public boolean get(int pos) + { + int offset = pos >> 6; + if (offset >= bits.length) + return false; + // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException, + // so we'll just let that be our exception. + return (bits[offset] & (1L << pos)) != 0; + } + + /** + * Returns a new BitSet composed of a range of bits from + * this one. + * + * @param from the low index (inclusive) + * @param to the high index (exclusive) + * @throws IndexOutOfBoundsException if from > to || from < 0 || + * to < 0 + * @since 1.4 + */ + public BitSet get(int from, int to) + { + if (from < 0 || from > to) + throw new IndexOutOfBoundsException(); + BitSet bs = new BitSet(to - from); + int lo_offset = from >>> 6; + if (lo_offset >= bits.length) + return bs; + + int lo_bit = from & LONG_MASK; + int hi_offset = to >>> 6; + if (lo_bit == 0) + { + int len = Math.min(hi_offset - lo_offset + 1, bits.length - lo_offset); + System.arraycopy(bits, lo_offset, bs.bits, 0, len); + if (hi_offset < bits.length) + bs.bits[hi_offset - lo_offset] &= (1L << to) - 1; + return bs; + } + + int len = Math.min(hi_offset, bits.length - 1); + int reverse = 64 - lo_bit; + int i; + for (i = 0; lo_offset < len; lo_offset++, i++) + bs.bits[i] = ((bits[lo_offset] >>> lo_bit) + | (bits[lo_offset + 1] << reverse)); + if ((to & LONG_MASK) > lo_bit) + bs.bits[i++] = bits[lo_offset] >>> lo_bit; + if (hi_offset < bits.length) + bs.bits[i - 1] &= (1L << (to - from)) - 1; + return bs; + } + + /** + * Returns a hash code value for this bit set. The hash code of + * two bit sets containing the same integers is identical. The algorithm + * used to compute it is as follows: + * + * Suppose the bits in the BitSet were to be stored in an array of + * long integers called bits, in such a manner that + * bit k is set in the BitSet (for non-negative values + * of k) if and only if + * + * ((k/64) < bits.length) + * && ((bits[k/64] & (1L << (bit % 64))) != 0) + * + * + * Then the following definition of the hashCode method + * would be a correct implementation of the actual algorithm: + * + * +

    public int hashCode()
    +{
    +  long h = 1234;
    +  for (int i = bits.length-1; i >= 0; i--)
    +  {
    +    h ^= bits[i] * (i + 1);
    +  }
    +
    +  return (int)((h >> 32) ^ h);
    +}
    + * + * Note that the hash code values changes, if the set is changed. + * + * @return the hash code value for this bit set. + */ + public int hashCode() + { + long h = 1234; + for (int i = bits.length; i > 0; ) + h ^= i * bits[--i]; + return (int) ((h >> 32) ^ h); + } + + /** + * Returns true if the specified BitSet and this one share at least one + * common true bit. + * + * @param set the set to check for intersection + * @return true if the sets intersect + * @throws NullPointerException if set is null + * @since 1.4 + */ + public boolean intersects(BitSet set) + { + int i = Math.min(bits.length, set.bits.length); + while (--i >= 0) + if ((bits[i] & set.bits[i]) != 0) + return true; + return false; + } + + /** + * Returns true if this set contains no true bits. + * + * @return true if all bits are false + * @since 1.4 + */ + public boolean isEmpty() + { + for (int i = bits.length - 1; i >= 0; i--) + if (bits[i] != 0) + return false; + return true; + } + + /** + * Returns the logical number of bits actually used by this bit + * set. It returns the index of the highest set bit plus one. + * Note that this method doesn't return the number of set bits. + * + * @return the index of the highest set bit plus one. + */ + public int length() + { + // Set i to highest index that contains a non-zero value. + int i; + for (i = bits.length - 1; i >= 0 && bits[i] == 0; --i) + ; + + // if i < 0 all bits are cleared. + if (i < 0) + return 0; + + // Now determine the exact length. + long b = bits[i]; + int len = (i + 1) * 64; + // b >= 0 checks if the highest bit is zero. + while (b >= 0) + { + --len; + b <<= 1; + } + + return len; + } + + /** + * Returns the index of the next false bit, from the specified bit + * (inclusive). + * + * @param from the start location + * @return the first false bit + * @throws IndexOutOfBoundsException if from is negative + * @since 1.4 + */ + public int nextClearBit(int from) + { + int offset = from >> 6; + long mask = 1L << from; + while (offset < bits.length) + { + // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException, + // so we'll just let that be our exception. + long h = bits[offset]; + do + { + if ((h & mask) == 0) + return from; + mask <<= 1; + from++; + } + while (mask != 0); + mask = 1; + offset++; + } + return from; + } + + /** + * Returns the index of the next true bit, from the specified bit + * (inclusive). If there is none, -1 is returned. You can iterate over + * all true bits with this loop:
    + * +
    for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1))
    +{
    +  // operate on i here
    +}
    + * + * @param from the start location + * @return the first true bit, or -1 + * @throws IndexOutOfBoundsException if from is negative + * @since 1.4 + */ + public int nextSetBit(int from) + { + int offset = from >> 6; + long mask = 1L << from; + while (offset < bits.length) + { + // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException, + // so we'll just let that be our exception. + long h = bits[offset]; + do + { + if ((h & mask) != 0) + return from; + mask <<= 1; + from++; + } + while (mask != 0); + mask = 1; + offset++; + } + return -1; + } + + /** + * Performs the logical OR operation on this bit set and the + * given set. This means it builds the union + * of the two sets. The result is stored into this bit set, which + * grows as necessary. + * + * @param bs the second bit set + * @throws NullPointerException if bs is null + */ + public void or(BitSet bs) + { + ensure(bs.bits.length - 1); + for (int i = bs.bits.length - 1; i >= 0; i--) + bits[i] |= bs.bits[i]; + } + + /** + * Add the integer bitIndex to this set. That is + * the corresponding bit is set to true. If the index was already in + * the set, this method does nothing. The size of this structure + * is automatically increased as necessary. + * + * @param pos a non-negative integer. + * @throws IndexOutOfBoundsException if pos is negative + */ + public void set(int pos) + { + int offset = pos >> 6; + ensure(offset); + // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException, + // so we'll just let that be our exception. + bits[offset] |= 1L << pos; + } + + /** + * Sets the bit at the given index to the specified value. The size of + * this structure is automatically increased as necessary. + * + * @param index the position to set + * @param value the value to set it to + * @throws IndexOutOfBoundsException if index is negative + * @since 1.4 + */ + public void set(int index, boolean value) + { + if (value) + set(index); + else + clear(index); + } + + /** + * Sets the bits between from (inclusive) and to (exclusive) to true. + * + * @param from the start range (inclusive) + * @param to the end range (exclusive) + * @throws IndexOutOfBoundsException if from < 0 || from > to || + * to < 0 + * @since 1.4 + */ + public void set(int from, int to) + { + if (from < 0 || from > to) + throw new IndexOutOfBoundsException(); + if (from == to) + return; + int lo_offset = from >>> 6; + int hi_offset = to >>> 6; + ensure(hi_offset); + if (lo_offset == hi_offset) + { + bits[hi_offset] |= (-1L << from) & ((1L << to) - 1); + return; + } + + bits[lo_offset] |= -1L << from; + bits[hi_offset] |= (1L << to) - 1; + for (int i = lo_offset + 1; i < hi_offset; i++) + bits[i] = -1; + } + + /** + * Sets the bits between from (inclusive) and to (exclusive) to the + * specified value. + * + * @param from the start range (inclusive) + * @param to the end range (exclusive) + * @param value the value to set it to + * @throws IndexOutOfBoundsException if from < 0 || from > to || + * to < 0 + * @since 1.4 + */ + public void set(int from, int to, boolean value) + { + if (value) + set(from, to); + else + clear(from, to); + } + + /** + * Returns the number of bits actually used by this bit set. Note + * that this method doesn't return the number of set bits, and that + * future requests for larger bits will make this automatically grow. + * + * @return the number of bits currently used. + */ + public int size() + { + return bits.length * 64; + } + + /** + * Returns the string representation of this bit set. This + * consists of a comma separated list of the integers in this set + * surrounded by curly braces. There is a space after each comma. + * A sample string is thus "{1, 3, 53}". + * @return the string representation. + */ + public String toString() + { + StringBuffer r = new StringBuffer("{"); + boolean first = true; + for (int i = 0; i < bits.length; ++i) + { + long bit = 1; + long word = bits[i]; + if (word == 0) + continue; + for (int j = 0; j < 64; ++j) + { + if ((word & bit) != 0) + { + if (! first) + r.append(", "); + r.append(64 * i + j); + first = false; + } + bit <<= 1; + } + } + return r.append("}").toString(); + } + + /** + * Performs the logical XOR operation on this bit set and the + * given set. This means it builds the symmetric + * remainder of the two sets (the elements that are in one set, + * but not in the other). The result is stored into this bit set, + * which grows as necessary. + * + * @param bs the second bit set + * @throws NullPointerException if bs is null + */ + public void xor(BitSet bs) + { + ensure(bs.bits.length - 1); + for (int i = bs.bits.length - 1; i >= 0; i--) + bits[i] ^= bs.bits[i]; + } + + /** + * Make sure the vector is big enough. + * + * @param lastElt the size needed for the bits array + */ + private void ensure(int lastElt) + { + if (lastElt >= bits.length) + { + long[] nd = new long[lastElt + 1]; + System.arraycopy(bits, 0, nd, 0, bits.length); + bits = nd; + } + } +} diff --git a/libjava/classpath/java/util/Calendar.java b/libjava/classpath/java/util/Calendar.java new file mode 100644 index 0000000..88bd76b --- /dev/null +++ b/libjava/classpath/java/util/Calendar.java @@ -0,0 +1,1277 @@ +/* Calendar.java -- + Copyright (C) 1998, 1999, 2000, 2001, 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 java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * This class is an abstract base class for Calendars, which can be + * used to convert between Date objects and a set of + * integer fields which represent YEAR, + * MONTH, DAY, etc. The Date + * object represents a time in milliseconds since the Epoch.
    + * + * This class is locale sensitive. To get the Object matching the + * current locale you can use getInstance. You can even provide + * a locale or a timezone. getInstance returns currently + * a GregorianCalendar for the current date.
    + * + * If you want to convert a date from the Year, Month, Day, DayOfWeek, + * etc. Representation to a Date-Object, you can create + * a new Calendar with getInstance(), + * clear() all fields, set(int,int) the + * fields you need and convert it with getTime().
    + * + * If you want to convert a Date-object to the Calendar + * representation, create a new Calendar, assign the + * Date-Object with setTime(), and read the + * fields with get(int).
    + * + * When computing the date from time fields, it may happen, that there + * are either two few fields set, or some fields are inconsistent. This + * cases will handled in a calendar specific way. Missing fields are + * replaced by the fields of the epoch: 1970 January 1 00:00.
    + * + * To understand, how the day of year is computed out of the fields + * look at the following table. It is traversed from top to bottom, + * and for the first line all fields are set, that line is used to + * compute the day.
    + * + * +
    month + day_of_month
    +month + week_of_month + day_of_week
    +month + day_of_week_of_month + day_of_week
    +day_of_year
    +day_of_week + week_of_year
    + * + * The hour_of_day-field takes precedence over the ampm and + * hour_of_ampm fields.
    + * + * Note: This can differ for non-Gregorian calendar.
    + * + * To convert a calendar to a human readable form and vice versa, use + * the java.text.DateFormat class.
    + * + * Other useful things you can do with an calendar, is + * rolling fields (that means increase/decrease a + * specific field by one, propagating overflows), or + * adding/substracting a fixed amount to a field. + * + * @see Date + * @see GregorianCalendar + * @see TimeZone + * @see java.text.DateFormat + */ +public abstract class Calendar implements Serializable, Cloneable +{ + /** + * Constant representing the era time field. + */ + public static final int ERA = 0; + + /** + * Constant representing the year time field. + */ + public static final int YEAR = 1; + + /** + * Constant representing the month time field. This field + * should contain one of the JANUARY,...,DECEMBER constants below. + */ + public static final int MONTH = 2; + + /** + * Constant representing the week of the year field. + * @see #setFirstDayOfWeek(int) + */ + public static final int WEEK_OF_YEAR = 3; + + /** + * Constant representing the week of the month time field. + * @see #setFirstDayOfWeek(int) + */ + public static final int WEEK_OF_MONTH = 4; + + /** + * Constant representing the day time field, synonym for DAY_OF_MONTH. + */ + public static final int DATE = 5; + + /** + * Constant representing the day time field. + */ + public static final int DAY_OF_MONTH = 5; + + /** + * Constant representing the day of year time field. This is + * 1 for the first day in month. + */ + public static final int DAY_OF_YEAR = 6; + + /** + * Constant representing the day of week time field. This field + * should contain one of the SUNDAY,...,SATURDAY constants below. + */ + public static final int DAY_OF_WEEK = 7; + + /** + * Constant representing the day-of-week-in-month field. For + * instance this field contains 2 for the second thursday in a + * month. If you give a negative number here, the day will count + * from the end of the month. + */ + public static final int DAY_OF_WEEK_IN_MONTH = 8; + + /** + * Constant representing the part of the day for 12-hour clock. This + * should be one of AM or PM. + */ + public static final int AM_PM = 9; + + /** + * Constant representing the hour time field for 12-hour clock. + */ + public static final int HOUR = 10; + + /** + * Constant representing the hour of day time field for 24-hour clock. + */ + public static final int HOUR_OF_DAY = 11; + + /** + * Constant representing the minute of hour time field. + */ + public static final int MINUTE = 12; + + /** + * Constant representing the second time field. + */ + public static final int SECOND = 13; + + /** + * Constant representing the millisecond time field. + */ + public static final int MILLISECOND = 14; + + /** + * Constant representing the time zone offset time field for the + * time given in the other fields. It is measured in + * milliseconds. The default is the offset of the time zone. + */ + public static final int ZONE_OFFSET = 15; + + /** + * Constant representing the daylight saving time offset in + * milliseconds. The default is the value given by the time zone. + */ + public static final int DST_OFFSET = 16; + + /** + * Number of time fields. + */ + public static final int FIELD_COUNT = 17; + + /** + * Constant representing Sunday. + */ + public static final int SUNDAY = 1; + + /** + * Constant representing Monday. + */ + public static final int MONDAY = 2; + + /** + * Constant representing Tuesday. + */ + public static final int TUESDAY = 3; + + /** + * Constant representing Wednesday. + */ + public static final int WEDNESDAY = 4; + + /** + * Constant representing Thursday. + */ + public static final int THURSDAY = 5; + + /** + * Constant representing Friday. + */ + public static final int FRIDAY = 6; + + /** + * Constant representing Saturday. + */ + public static final int SATURDAY = 7; + + /** + * Constant representing January. + */ + public static final int JANUARY = 0; + + /** + * Constant representing February. + */ + public static final int FEBRUARY = 1; + + /** + * Constant representing March. + */ + public static final int MARCH = 2; + + /** + * Constant representing April. + */ + public static final int APRIL = 3; + + /** + * Constant representing May. + */ + public static final int MAY = 4; + + /** + * Constant representing June. + */ + public static final int JUNE = 5; + + /** + * Constant representing July. + */ + public static final int JULY = 6; + + /** + * Constant representing August. + */ + public static final int AUGUST = 7; + + /** + * Constant representing September. + */ + public static final int SEPTEMBER = 8; + + /** + * Constant representing October. + */ + public static final int OCTOBER = 9; + + /** + * Constant representing November. + */ + public static final int NOVEMBER = 10; + + /** + * Constant representing December. + */ + public static final int DECEMBER = 11; + + /** + * Constant representing Undecimber. This is an artificial name useful + * for lunar calendars. + */ + public static final int UNDECIMBER = 12; + + /** + * Useful constant for 12-hour clock. + */ + public static final int AM = 0; + + /** + * Useful constant for 12-hour clock. + */ + public static final int PM = 1; + + /** + * The time fields. The array is indexed by the constants YEAR to + * DST_OFFSET. + * @serial + */ + protected int[] fields = new int[FIELD_COUNT]; + + /** + * The flags which tell if the fields above have a value. + * @serial + */ + protected boolean[] isSet = new boolean[FIELD_COUNT]; + + /** + * The time in milliseconds since the epoch. + * @serial + */ + protected long time; + + /** + * Tells if the above field has a valid value. + * @serial + */ + protected boolean isTimeSet; + + /** + * Tells if the fields have a valid value. This superseeds the isSet + * array. + * @serial + */ + protected boolean areFieldsSet; + + /** + * The time zone of this calendar. Used by sub classes to do UTC / local + * time conversion. Sub classes can access this field with getTimeZone(). + * @serial + */ + private TimeZone zone; + + /** + * This is the default calendar class, that is returned on + * java.util.Calendar.getInstance(). + * XXX - this isn't localized anywhere, is it? + * @see java.util.Calendar#getInstance() + */ + private static final String calendarClassName = "java.util.GregorianCalendar"; + + /** + * Specifies if the date/time interpretation should be lenient. + * If the flag is set, a date such as "February 30, 1996" will be + * treated as the 29th day after the February 1. If this flag + * is false, such dates will cause an exception. + * @serial + */ + private boolean lenient; + + /** + * Sets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @serial + */ + private int firstDayOfWeek; + + /** + * Sets how many days are required in the first week of the year. + * If the first day of the year should be the first week you should + * set this value to 1. If the first week must be a full week, set + * it to 7. + * @serial + */ + private int minimalDaysInFirstWeek; + + /** + * Is set to true if DST_OFFSET is explicitly set. In that case + * it's value overrides the value computed from the current + * time and the timezone. + */ + private boolean explicitDSTOffset = false; + + /** + * The version of the serialized data on the stream. + *
    0 or not present
    + *
    JDK 1.1.5 or later.
    + *
    1
    + *
    JDK 1.1.6 or later. This always writes a correct `time' value + * on the stream, as well as the other fields, to be compatible with + * earlier versions
    + * @since JDK1.1.6 + * @serial + */ + private int serialVersionOnStream = 1; + + /** + * XXX - I have not checked the compatibility. The documentation of + * the serialized-form is quite hairy... + */ + static final long serialVersionUID = -1807547505821590642L; + + /** + * The name of the resource bundle. Used only by getBundle() + */ + private static final String bundleName = "gnu.java.locale.LocaleInformation"; + + /** + * get resource bundle: + * The resources should be loaded via this method only. Iff an application + * uses this method, the resourcebundle is required. + */ + private static ResourceBundle getBundle(Locale locale) + { + return ResourceBundle.getBundle(bundleName, locale, + ClassLoader.getSystemClassLoader()); + } + + /** + * Constructs a new Calendar with the default time zone and the default + * locale. + */ + protected Calendar() + { + this(TimeZone.getDefault(), Locale.getDefault()); + } + + /** + * Constructs a new Calendar with the given time zone and the given + * locale. + * @param zone a time zone. + * @param locale a locale. + */ + protected Calendar(TimeZone zone, Locale locale) + { + this.zone = zone; + lenient = true; + String[] days = { "", "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; + + ResourceBundle rb = getBundle(locale); + String min = (String) rb.getObject("minNumberOfDaysInFirstWeek"); + String first = (String) rb.getObject("firstDayOfWeek"); + try + { + if (min != null) + minimalDaysInFirstWeek = Integer.parseInt(min); + } + catch (NumberFormatException ex) + { + minimalDaysInFirstWeek = 1; + } + + firstDayOfWeek = 1; + if (first != null) + for (int i = 0; i < 8; i++) + if (days[i].equals(first)) + firstDayOfWeek = i; + + clear(); + } + + /** + * Creates a calendar representing the actual time, using the default + * time zone and locale. + */ + public static synchronized Calendar getInstance() + { + return getInstance(TimeZone.getDefault(), Locale.getDefault()); + } + + /** + * Creates a calendar representing the actual time, using the given + * time zone and the default locale. + * @param zone a time zone. + */ + public static synchronized Calendar getInstance(TimeZone zone) + { + return getInstance(zone, Locale.getDefault()); + } + + /** + * Creates a calendar representing the actual time, using the default + * time zone and the given locale. + * @param locale a locale. + */ + public static synchronized Calendar getInstance(Locale locale) + { + return getInstance(TimeZone.getDefault(), locale); + } + + /** + * Cache of locale->calendar-class mappings. This avoids having to do a ResourceBundle + * lookup for every getInstance call. + */ + private static HashMap cache = new HashMap(); + + /** Preset argument types for calendar-class constructor lookup. */ + private static Class[] ctorArgTypes = new Class[] + { + TimeZone.class, Locale.class + }; + + /** + * Creates a calendar representing the actual time, using the given + * time zone and locale. + * @param zone a time zone. + * @param locale a locale. + */ + public static synchronized Calendar getInstance(TimeZone zone, Locale locale) + { + Class calendarClass = (Class) cache.get(locale); + Throwable exception = null; + + try + { + if (calendarClass == null) + { + calendarClass = Class.forName(calendarClassName); + if (Calendar.class.isAssignableFrom(calendarClass)) + cache.put(locale, calendarClass); + } + + // GregorianCalendar is by far the most common case. Optimize by + // avoiding reflection. + if (calendarClass == GregorianCalendar.class) + return new GregorianCalendar(zone, locale); + + if (Calendar.class.isAssignableFrom(calendarClass)) + { + Constructor ctor = calendarClass.getConstructor(ctorArgTypes); + return (Calendar) ctor.newInstance(new Object[] { zone, locale }); + } + } + catch (ClassNotFoundException ex) + { + exception = ex; + } + catch (IllegalAccessException ex) + { + exception = ex; + } + catch (NoSuchMethodException ex) + { + exception = ex; + } + catch (InstantiationException ex) + { + exception = ex; + } + catch (InvocationTargetException ex) + { + exception = ex; + } + + throw new RuntimeException("Error instantiating calendar for locale " + + locale, exception); + } + + /** + * Gets the set of locales for which a Calendar is available. + * @exception MissingResourceException if locale data couldn't be found. + * @return the set of locales. + */ + public static synchronized Locale[] getAvailableLocales() + { + ResourceBundle rb = getBundle(new Locale("", "")); + return (Locale[]) rb.getObject("availableLocales"); + } + + /** + * Converts the time field values (fields) to + * milliseconds since the epoch UTC (time). Override + * this method if you write your own Calendar. */ + protected abstract void computeTime(); + + /** + * Converts the milliseconds since the epoch UTC + * (time) to time fields + * (fields). Override this method if you write your + * own Calendar. + */ + protected abstract void computeFields(); + + /** + * Converts the time represented by this object to a + * Date-Object. + * @return the Date. + */ + public final Date getTime() + { + if (! isTimeSet) + computeTime(); + return new Date(time); + } + + /** + * Sets this Calendar's time to the given Date. All time fields + * are invalidated by this method. + */ + public final void setTime(Date date) + { + setTimeInMillis(date.getTime()); + } + + /** + * Returns the time represented by this Calendar. + * @return the time in milliseconds since the epoch. + * @specnote This was made public in 1.4. + */ + public long getTimeInMillis() + { + if (! isTimeSet) + computeTime(); + return time; + } + + /** + * Sets this Calendar's time to the given Time. All time fields + * are invalidated by this method. + * @param time the time in milliseconds since the epoch + * @specnote This was made public in 1.4. + */ + public void setTimeInMillis(long time) + { + clear(); + this.time = time; + isTimeSet = true; + computeFields(); + } + + /** + * Gets the value of the specified field. They are recomputed + * if they are invalid. + * @param field the time field. One of the time field constants. + * @return the value of the specified field + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @specnote Not final since JDK 1.4 + */ + public int get(int field) + { + // If the requested field is invalid, force all fields to be recomputed. + if (! isSet[field]) + areFieldsSet = false; + complete(); + return fields[field]; + } + + /** + * Gets the value of the specified field. This method doesn't + * recompute the fields, if they are invalid. + * @param field the time field. One of the time field constants. + * @return the value of the specified field, undefined if + * areFieldsSet or isSet[field] is false. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + protected final int internalGet(int field) + { + return fields[field]; + } + + /** + * Sets the time field with the given value. This does invalidate + * the time in milliseconds. + * @param field the time field. One of the time field constants + * @param value the value to be set. + * @throws ArrayIndexOutOfBoundsException if field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @specnote Not final since JDK 1.4 + */ + public void set(int field, int value) + { + if (isTimeSet) + for (int i = 0; i < FIELD_COUNT; i++) + isSet[i] = false; + isTimeSet = false; + fields[field] = value; + isSet[field] = true; + + // The five valid date patterns, in order of priority + // 1 YEAR + MONTH + DAY_OF_MONTH + // 2 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK + // 3 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK + // 4 YEAR + DAY_OF_YEAR + // 5 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR + switch (field) + { + case MONTH: // pattern 1,2 or 3 + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_MONTH: // pattern 1 + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[WEEK_OF_MONTH] = true; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case WEEK_OF_MONTH: // pattern 2 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[DAY_OF_WEEK] = true; + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_WEEK_IN_MONTH: // pattern 3 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[DAY_OF_WEEK] = true; + isSet[DAY_OF_YEAR] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_YEAR: // pattern 4 + isSet[YEAR] = true; + isSet[MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[WEEK_OF_YEAR] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + break; + case WEEK_OF_YEAR: // pattern 5 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[DAY_OF_WEEK] = true; + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + break; + case AM_PM: + isSet[HOUR] = true; + isSet[HOUR_OF_DAY] = false; + break; + case HOUR_OF_DAY: + isSet[AM_PM] = false; + isSet[HOUR] = false; + break; + case HOUR: + isSet[AM_PM] = true; + isSet[HOUR_OF_DAY] = false; + break; + case DST_OFFSET: + explicitDSTOffset = true; + } + + // May have crossed over a DST boundary. + if (! explicitDSTOffset && (field != DST_OFFSET && field != ZONE_OFFSET)) + isSet[DST_OFFSET] = false; + } + + /** + * Sets the fields for year, month, and date + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + */ + public final void set(int year, int month, int date) + { + isTimeSet = false; + fields[YEAR] = year; + fields[MONTH] = month; + fields[DATE] = date; + isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true; + isSet[WEEK_OF_YEAR] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[ERA] = false; + + if (! explicitDSTOffset) + isSet[DST_OFFSET] = false; // May have crossed a DST boundary. + } + + /** + * Sets the fields for year, month, date, hour, and minute + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + * @param hour the hour of day. + * @param minute the minute. + */ + public final void set(int year, int month, int date, int hour, int minute) + { + set(year, month, date); + fields[HOUR_OF_DAY] = hour; + fields[MINUTE] = minute; + isSet[HOUR_OF_DAY] = isSet[MINUTE] = true; + isSet[AM_PM] = false; + isSet[HOUR] = false; + } + + /** + * Sets the fields for year, month, date, hour, and minute + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + * @param hour the hour of day. + * @param minute the minute. + * @param second the second. + */ + public final void set(int year, int month, int date, int hour, int minute, + int second) + { + set(year, month, date, hour, minute); + fields[SECOND] = second; + isSet[SECOND] = true; + } + + /** + * Clears the values of all the time fields. + */ + public final void clear() + { + isTimeSet = false; + areFieldsSet = false; + int zoneOffs = zone.getRawOffset(); + int[] tempFields = + { + 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0, + 0, 0, zoneOffs, 0 + }; + fields = tempFields; + for (int i = 0; i < FIELD_COUNT; i++) + isSet[i] = false; + } + + /** + * Clears the values of the specified time field. + * @param field the time field. One of the time field constants. + * @throws ArrayIndexOutOfBoundsException if field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public final void clear(int field) + { + int[] tempFields = + { + 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0, + 0, 0, zone.getRawOffset(), 0 + }; + isTimeSet = false; + areFieldsSet = false; + isSet[field] = false; + fields[field] = tempFields[field]; + } + + /** + * Determines if the specified field has a valid value. + * @return true if the specified field has a value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public final boolean isSet(int field) + { + return isSet[field]; + } + + /** + * Fills any unset fields in the time field list + */ + protected void complete() + { + if (! isTimeSet) + computeTime(); + if (! areFieldsSet) + computeFields(); + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, that represents + * the same time (but doesn't necessary have the same fields). + */ + public boolean equals(Object o) + { + return (o instanceof Calendar) + && getTimeInMillis() == ((Calendar) o).getTimeInMillis(); + } + + /** + * Returns a hash code for this calendar. + * @return a hash code, which fullfits the general contract of + * hashCode() + */ + public int hashCode() + { + long time = getTimeInMillis(); + return (int) ((time & 0xffffffffL) ^ (time >> 32)); + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, and this calendar + * represents a smaller time than the calendar o. + * @exception ClassCastException if o is not an calendar. + * @since JDK1.2 you don't need to override this method + */ + public boolean before(Object o) + { + return getTimeInMillis() < ((Calendar) o).getTimeInMillis(); + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, and this calendar + * represents a bigger time than the calendar o. + * @exception ClassCastException if o is not an calendar. + * @since JDK1.2 you don't need to override this method + */ + public boolean after(Object o) + { + return getTimeInMillis() > ((Calendar) o).getTimeInMillis(); + } + + /** + * Adds the specified amount of time to the given time field. The + * amount may be negative to subtract the time. If the field overflows + * it does what you expect: Jan, 25 + 10 Days is Feb, 4. + * @param field the time field. One of the time field constants. + * @param amount the amount of time. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public abstract void add(int field, int amount); + + /** + * Rolls the specified time field up or down. This means add one + * to the specified field, but don't change the other fields. If + * the maximum for this field is reached, start over with the + * minimum value.
    + * + * Note: There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically converted to July, 1. + * @param field the time field. One of the time field constants. + * @param up the direction, true for up, false for down. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public abstract void roll(int field, boolean up); + + /** + * Rolls up or down the specified time field by the given amount. + * A negative amount rolls down. The default implementation is + * call roll(int, boolean) for the specified amount. + * + * Subclasses should override this method to do more intuitiv things. + * + * @param field the time field. One of the time field constants. + * @param amount the amount to roll by, positive for rolling up, + * negative for rolling down. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @since JDK1.2 + */ + public void roll(int field, int amount) + { + while (amount > 0) + { + roll(field, true); + amount--; + } + while (amount < 0) + { + roll(field, false); + amount++; + } + } + + /** + * Sets the time zone to the specified value. + * @param zone the new time zone + */ + public void setTimeZone(TimeZone zone) + { + this.zone = zone; + } + + /** + * Gets the time zone of this calendar + * @return the current time zone. + */ + public TimeZone getTimeZone() + { + return zone; + } + + /** + * Specifies if the date/time interpretation should be lenient. + * If the flag is set, a date such as "February 30, 1996" will be + * treated as the 29th day after the February 1. If this flag + * is false, such dates will cause an exception. + * @param lenient true, if the date should be interpreted linient, + * false if it should be interpreted strict. + */ + public void setLenient(boolean lenient) + { + this.lenient = lenient; + } + + /** + * Tells if the date/time interpretation is lenient. + * @return true, if the date should be interpreted linient, + * false if it should be interpreted strict. + */ + public boolean isLenient() + { + return lenient; + } + + /** + * Sets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @param value the first day of week. One of SUNDAY to SATURDAY. + */ + public void setFirstDayOfWeek(int value) + { + firstDayOfWeek = value; + } + + /** + * Gets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @return the first day of week. One of SUNDAY to SATURDAY. + */ + public int getFirstDayOfWeek() + { + return firstDayOfWeek; + } + + /** + * Sets how many days are required in the first week of the year. + * If the first day of the year should be the first week you should + * set this value to 1. If the first week must be a full week, set + * it to 7. + * @param value the minimal days required in the first week. + */ + public void setMinimalDaysInFirstWeek(int value) + { + minimalDaysInFirstWeek = value; + } + + /** + * Gets how many days are required in the first week of the year. + * @return the minimal days required in the first week. + * @see #setMinimalDaysInFirstWeek + */ + public int getMinimalDaysInFirstWeek() + { + return minimalDaysInFirstWeek; + } + + /** + * Gets the smallest value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the smallest value. + */ + public abstract int getMinimum(int field); + + /** + * Gets the biggest value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the biggest value. + */ + public abstract int getMaximum(int field); + + /** + * Gets the greatest minimum value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the greatest minimum value. + */ + public abstract int getGreatestMinimum(int field); + + /** + * Gets the smallest maximum value that is allowed for the + * specified field. For example this is 28 for DAY_OF_MONTH. + * @param field the time field. One of the time field constants. + * @return the least maximum value. + */ + public abstract int getLeastMaximum(int field); + + /** + * Gets the actual minimum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. + * @param field the time field. One of the time field constants. + * @return the actual minimum value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @since jdk1.2 + */ + public int getActualMinimum(int field) + { + Calendar tmp = (Calendar) clone(); // To avoid restoring state + int min = tmp.getGreatestMinimum(field); + int end = tmp.getMinimum(field); + tmp.set(field, min); + for (; min > end; min--) + { + tmp.add(field, -1); // Try to get smaller + if (tmp.get(field) != min - 1) + break; // Done if not successful + } + return min; + } + + /** + * Gets the actual maximum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. + * @param field the time field. One of the time field constants. + * @return the actual maximum value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @since jdk1.2 + */ + public int getActualMaximum(int field) + { + Calendar tmp = (Calendar) clone(); // To avoid restoring state + int max = tmp.getLeastMaximum(field); + int end = tmp.getMaximum(field); + tmp.set(field, max); + for (; max < end; max++) + { + tmp.add(field, 1); + if (tmp.get(field) != max + 1) + break; + } + return max; + } + + /** + * Return a clone of this object. + */ + public Object clone() + { + try + { + Calendar cal = (Calendar) super.clone(); + cal.fields = (int[]) fields.clone(); + cal.isSet = (boolean[]) isSet.clone(); + return cal; + } + catch (CloneNotSupportedException ex) + { + return null; + } + } + + private static final String[] fieldNames = + { + ",ERA=", ",YEAR=", ",MONTH=", + ",WEEK_OF_YEAR=", + ",WEEK_OF_MONTH=", + ",DAY_OF_MONTH=", + ",DAY_OF_YEAR=", ",DAY_OF_WEEK=", + ",DAY_OF_WEEK_IN_MONTH=", + ",AM_PM=", ",HOUR=", + ",HOUR_OF_DAY=", ",MINUTE=", + ",SECOND=", ",MILLISECOND=", + ",ZONE_OFFSET=", ",DST_OFFSET=" + }; + + /** + * Returns a string representation of this object. It is mainly + * for debugging purposes and its content is implementation + * specific. + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append(getClass().getName()).append('['); + sb.append("time="); + if (isTimeSet) + sb.append(time); + else + sb.append("?"); + sb.append(",zone=" + zone); + sb.append(",areFieldsSet=" + areFieldsSet); + for (int i = 0; i < FIELD_COUNT; i++) + { + sb.append(fieldNames[i]); + if (isSet[i]) + sb.append(fields[i]); + else + sb.append("?"); + } + sb.append(",lenient=").append(lenient); + sb.append(",firstDayOfWeek=").append(firstDayOfWeek); + sb.append(",minimalDaysInFirstWeek=").append(minimalDaysInFirstWeek); + sb.append("]"); + return sb.toString(); + } + + /** + * Saves the state of the object to the stream. Ideally we would + * only write the time field, but we need to be compatible with + * earlier versions.
    + * + * This doesn't write the JDK1.1 field nextStamp to the stream, as + * I don't know what it is good for, and because the documentation + * says, that it could be omitted. */ + private void writeObject(ObjectOutputStream stream) throws IOException + { + if (! isTimeSet) + computeTime(); + stream.defaultWriteObject(); + } + + /** + * Reads the object back from stream (deserialization). + */ + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + if (! isTimeSet) + computeTime(); + + if (serialVersionOnStream > 1) + { + // This is my interpretation of the serial number: + // Sun wants to remove all fields from the stream someday + // and will then increase the serialVersion number again. + // We prepare to be compatible. + fields = new int[FIELD_COUNT]; + isSet = new boolean[FIELD_COUNT]; + areFieldsSet = false; + } + } +} diff --git a/libjava/classpath/java/util/Collection.java b/libjava/classpath/java/util/Collection.java new file mode 100644 index 0000000..29e1b37 --- /dev/null +++ b/libjava/classpath/java/util/Collection.java @@ -0,0 +1,288 @@ +/* Collection.java -- Interface that represents a collection of objects + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * Interface that represents a collection of objects. This interface is the + * root of the collection hierarchy, and does not provide any guarantees about + * the order of its elements or whether or not duplicate elements are + * permitted. + *

    + * All methods of this interface that are defined to modify the collection are + * defined as optional. An optional operation may throw an + * UnsupportedOperationException if the data backing this collection does not + * support such a modification. This may mean that the data structure is + * immutable, or that it is read-only but may change ("unmodifiable"), or + * that it is modifiable but of fixed size (such as an array), or any number + * of other combinations. + *

    + * A class that wishes to implement this interface should consider subclassing + * AbstractCollection, which provides basic implementations of most of the + * methods of this interface. Classes that are prepared to make guarantees + * about ordering or about absence of duplicate elements should consider + * implementing List or Set respectively, both of which are subinterfaces of + * Collection. + *

    + * A general-purpose implementation of the Collection interface should in most + * cases provide at least two constructors: One which takes no arguments and + * creates an empty collection, and one which takes a Collection as an argument + * and returns a collection containing the same elements (that is, creates a + * copy of the argument using its own implementation). + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see List + * @see Set + * @see Map + * @see SortedSet + * @see SortedMap + * @see HashSet + * @see TreeSet + * @see ArrayList + * @see LinkedList + * @see Vector + * @see Collections + * @see Arrays + * @see AbstractCollection + * @since 1.2 + * @status updated to 1.4 + */ +public interface Collection +{ + /** + * Add an element to this collection. + * + * @param o the object to add. + * @return true if the collection was modified as a result of this action. + * @throws UnsupportedOperationException if this collection does not + * support the add operation. + * @throws ClassCastException if o cannot be added to this collection due + * to its type. + * @throws NullPointerException if o is null and this collection doesn't + * support the addition of null values. + * @throws IllegalArgumentException if o cannot be added to this + * collection for some other reason. + */ + boolean add(Object o); + + /** + * Add the contents of a given collection to this collection. + * + * @param c the collection to add. + * @return true if the collection was modified as a result of this action. + * @throws UnsupportedOperationException if this collection does not + * support the addAll operation. + * @throws ClassCastException if some element of c cannot be added to this + * collection due to its type. + * @throws NullPointerException if some element of c is null and this + * collection does not support the addition of null values. + * @throws NullPointerException if c itself is null. + * @throws IllegalArgumentException if some element of c cannot be added + * to this collection for some other reason. + */ + boolean addAll(Collection c); + + /** + * Clear the collection, such that a subsequent call to isEmpty() would + * return true. + * + * @throws UnsupportedOperationException if this collection does not + * support the clear operation. + */ + void clear(); + + /** + * Test whether this collection contains a given object as one of its + * elements. + * + * @param o the element to look for. + * @return true if this collection contains at least one element e such that + * o == null ? e == null : o.equals(e). + * @throws ClassCastException if the type of o is not a valid type for this + * collection. + * @throws NullPointerException if o is null and this collection doesn't + * support null values. + */ + boolean contains(Object o); + + /** + * Test whether this collection contains every element in a given collection. + * + * @param c the collection to test for. + * @return true if for every element o in c, contains(o) would return true. + * @throws ClassCastException if the type of any element in c is not a valid + * type for this collection. + * @throws NullPointerException if some element of c is null and this + * collection does not support null values. + * @throws NullPointerException if c itself is null. + */ + boolean containsAll(Collection c); + + /** + * Test whether this collection is equal to some object. The Collection + * interface does not explicitly require any behaviour from this method, and + * it may be left to the default implementation provided by Object. The Set + * and List interfaces do, however, require specific behaviour from this + * method. + *

    + * If an implementation of Collection, which is not also an implementation of + * Set or List, should choose to implement this method, it should take care + * to obey the contract of the equals method of Object. In particular, care + * should be taken to return false when o is a Set or a List, in order to + * preserve the symmetry of the relation. + * + * @param o the object to compare to this collection. + * @return true if the o is equal to this collection. + */ + boolean equals(Object o); + + /** + * Obtain a hash code for this collection. The Collection interface does not + * explicitly require any behaviour from this method, and it may be left to + * the default implementation provided by Object. The Set and List interfaces + * do, however, require specific behaviour from this method. + *

    + * If an implementation of Collection, which is not also an implementation of + * Set or List, should choose to implement this method, it should take care + * to obey the contract of the hashCode method of Object. Note that this + * method renders it impossible to correctly implement both Set and List, as + * the required implementations are mutually exclusive. + * + * @return a hash code for this collection. + */ + int hashCode(); + + /** + * Test whether this collection is empty, that is, if size() == 0. + * + * @return true if this collection contains no elements. + */ + boolean isEmpty(); + + /** + * Obtain an Iterator over this collection. + * + * @return an Iterator over the elements of this collection, in any order. + */ + Iterator iterator(); + + /** + * Remove a single occurrence of an object from this collection. That is, + * remove an element e, if one exists, such that o == null ? e == null + * : o.equals(e). + * + * @param o the object to remove. + * @return true if the collection changed as a result of this call, that is, + * if the collection contained at least one occurrence of o. + * @throws UnsupportedOperationException if this collection does not + * support the remove operation. + * @throws ClassCastException if the type of o is not a valid type + * for this collection. + * @throws NullPointerException if o is null and the collection doesn't + * support null values. + */ + boolean remove(Object o); + + /** + * Remove all elements of a given collection from this collection. That is, + * remove every element e such that c.contains(e). + * + * @param c The collection of objects to be removed. + * @return true if this collection was modified as a result of this call. + * @throws UnsupportedOperationException if this collection does not + * support the removeAll operation. + * @throws ClassCastException if the type of any element in c is not a valid + * type for this collection. + * @throws NullPointerException if some element of c is null and this + * collection does not support removing null values. + * @throws NullPointerException if c itself is null. + */ + boolean removeAll(Collection c); + + /** + * Remove all elements of this collection that are not contained in a given + * collection. That is, remove every element e such that !c.contains(e). + * + * @param c The collection of objects to be retained. + * @return true if this collection was modified as a result of this call. + * @throws UnsupportedOperationException if this collection does not + * support the retainAll operation. + * @throws ClassCastException if the type of any element in c is not a valid + * type for this collection. + * @throws NullPointerException if some element of c is null and this + * collection does not support retaining null values. + * @throws NullPointerException if c itself is null. + */ + boolean retainAll(Collection c); + + /** + * Get the number of elements in this collection. + * + * @return the number of elements in the collection. + */ + int size(); + + /** + * Copy the current contents of this collection into an array. + * + * @return an array of type Object[] and length equal to the size of this + * collection, containing the elements currently in this collection, in + * any order. + */ + Object[] toArray(); + + /** + * Copy the current contents of this collection into an array. If the array + * passed as an argument has length less than the size of this collection, an + * array of the same run-time type as a, and length equal to the size of this + * collection, is allocated using Reflection. Otherwise, a itself is used. + * The elements of this collection are copied into it, and if there is space + * in the array, the following element is set to null. The resultant array is + * returned. + * Note: The fact that the following element is set to null is only useful + * if it is known that this collection does not contain any null elements. + * + * @param a the array to copy this collection into. + * @return an array containing the elements currently in this collection, in + * any order. + * @throws ArrayStoreException if the type of any element of the + * collection is not a subtype of the element type of a. + */ + Object[] toArray(Object[] a); +} diff --git a/libjava/classpath/java/util/Collections.java b/libjava/classpath/java/util/Collections.java new file mode 100644 index 0000000..ed8a005 --- /dev/null +++ b/libjava/classpath/java/util/Collections.java @@ -0,0 +1,5493 @@ +/* Collections.java -- Utility class with methods to operate on collections + Copyright (C) 1998, 1999, 2000, 2001, 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 java.util; + +import java.io.Serializable; + +/** + * Utility class consisting of static methods that operate on, or return + * Collections. Contains methods to sort, search, reverse, fill and shuffle + * Collections, methods to facilitate interoperability with legacy APIs that + * are unaware of collections, a method to return a list which consists of + * multiple copies of one element, and methods which "wrap" collections to give + * them extra properties, such as thread-safety and unmodifiability. + *

    + * + * All methods which take a collection throw a {@link NullPointerException} if + * that collection is null. Algorithms which can change a collection may, but + * are not required, to throw the {@link UnsupportedOperationException} that + * the underlying collection would throw during an attempt at modification. + * For example, + * Collections.singleton("").addAll(Collections.EMPTY_SET) + * does not throw a exception, even though addAll is an unsupported operation + * on a singleton; the reason for this is that addAll did not attempt to + * modify the set. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see Set + * @see List + * @see Map + * @see Arrays + * @since 1.2 + * @status updated to 1.4 + */ +public class Collections +{ + /** + * Constant used to decide cutoff for when a non-RandomAccess list should + * be treated as sequential-access. Basically, quadratic behavior is + * acceptable for small lists when the overhead is so small in the first + * place. I arbitrarily set it to 16, so it may need some tuning. + */ + private static final int LARGE_LIST_SIZE = 16; + + /** + * Determines if a list should be treated as a sequential-access one. + * Rather than the old method of JDK 1.3 of assuming only instanceof + * AbstractSequentialList should be sequential, this uses the new method + * of JDK 1.4 of assuming anything that does NOT implement RandomAccess + * and exceeds a large (unspecified) size should be sequential. + * + * @param l the list to check + * @return true if it should be treated as sequential-access + */ + private static boolean isSequential(List l) + { + return ! (l instanceof RandomAccess) && l.size() > LARGE_LIST_SIZE; + } + + /** + * This class is non-instantiable. + */ + private Collections() + { + } + + /** + * An immutable, serializable, empty Set. + * @see Serializable + */ + public static final Set EMPTY_SET = new EmptySet(); + + /** + * The implementation of {@link #EMPTY_SET}. This class name is required + * for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class EmptySet extends AbstractSet + implements Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 1582296315990362920L; + + /** + * A private constructor adds overhead. + */ + EmptySet() + { + } + + /** + * The size: always 0! + * @return 0. + */ + public int size() + { + return 0; + } + + /** + * Returns an iterator that does not iterate. + * @return A non-iterating iterator. + */ + // This is really cheating! I think it's perfectly valid, though. + public Iterator iterator() + { + return EMPTY_LIST.iterator(); + } + + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractSet. + /** + * The empty set never contains anything. + * @param o The object to search for. + * @return false. + */ + public boolean contains(Object o) + { + return false; + } + + /** + * This is true only if the given collection is also empty. + * @param c The collection of objects which are to be compared + * against the members of this set. + * @return true if c is empty. + */ + public boolean containsAll(Collection c) + { + return c.isEmpty(); + } + + /** + * Equal only if the other set is empty. + * @param o The object to compare with this set. + * @return true if o is an empty instance of Set. + */ + public boolean equals(Object o) + { + return o instanceof Set && ((Set) o).isEmpty(); + } + + /** + * The hashcode is always 0. + * @return 0. + */ + public int hashCode() + { + return 0; + } + + /** + * Always succeeds with a false result. + * @param o The object to remove. + * @return false. + */ + public boolean remove(Object o) + { + return false; + } + + /** + * Always succeeds with a false result. + * @param c The collection of objects which should + * all be removed from this set. + * @return false. + */ + public boolean removeAll(Collection c) + { + return false; + } + + /** + * Always succeeds with a false result. + * @param c The collection of objects which should + * all be retained within this set. + * @return false. + */ + public boolean retainAll(Collection c) + { + return false; + } + + /** + * The array is always empty. + * @return A new array with a size of 0. + */ + public Object[] toArray() + { + return new Object[0]; + } + + /** + * We don't even need to use reflection! + * @param a An existing array, which can be empty. + * @return The original array with any existing + * initial element set to null. + */ + public Object[] toArray(Object[] a) + { + if (a.length > 0) + a[0] = null; + return a; + } + + /** + * The string never changes. + * + * @return the string "[]". + */ + public String toString() + { + return "[]"; + } + } // class EmptySet + + /** + * An immutable, serializable, empty List, which implements RandomAccess. + * @see Serializable + * @see RandomAccess + */ + public static final List EMPTY_LIST = new EmptyList(); + + /** + * The implementation of {@link #EMPTY_LIST}. This class name is required + * for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class EmptyList extends AbstractList + implements Serializable, RandomAccess + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 8842843931221139166L; + + /** + * A private constructor adds overhead. + */ + EmptyList() + { + } + + /** + * The size is always 0. + * @return 0. + */ + public int size() + { + return 0; + } + + /** + * No matter the index, it is out of bounds. This + * method never returns, throwing an exception instead. + * + * @param index The index of the element to retrieve. + * @return the object at the specified index. + * @throws IndexOutOfBoundsException as any given index + * is outside the bounds of an empty array. + */ + public Object get(int index) + { + throw new IndexOutOfBoundsException(); + } + + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractList. + /** + * Never contains anything. + * @param o The object to search for. + * @return false. + */ + public boolean contains(Object o) + { + return false; + } + + /** + * This is true only if the given collection is also empty. + * @param c The collection of objects, which should be compared + * against the members of this list. + * @return true if c is also empty. + */ + public boolean containsAll(Collection c) + { + return c.isEmpty(); + } + + /** + * Equal only if the other list is empty. + * @param o The object to compare against this list. + * @return true if o is also an empty instance of + * List. + */ + public boolean equals(Object o) + { + return o instanceof List && ((List) o).isEmpty(); + } + + /** + * The hashcode is always 1. + * @return 1. + */ + public int hashCode() + { + return 1; + } + + /** + * Returns -1. + * @param o The object to search for. + * @return -1. + */ + public int indexOf(Object o) + { + return -1; + } + + /** + * Returns -1. + * @param o The object to search for. + * @return -1. + */ + public int lastIndexOf(Object o) + { + return -1; + } + + /** + * Always succeeds with false result. + * @param o The object to remove. + * @return -1. + */ + public boolean remove(Object o) + { + return false; + } + + /** + * Always succeeds with false result. + * @param c The collection of objects which should + * all be removed from this list. + * @return false. + */ + public boolean removeAll(Collection c) + { + return false; + } + + /** + * Always succeeds with false result. + * @param c The collection of objects which should + * all be retained within this list. + * @return false. + */ + public boolean retainAll(Collection c) + { + return false; + } + + /** + * The array is always empty. + * @return A new array with a size of 0. + */ + public Object[] toArray() + { + return new Object[0]; + } + + /** + * We don't even need to use reflection! + * @param a An existing array, which can be empty. + * @return The original array with any existing + * initial element set to null. + */ + public Object[] toArray(Object[] a) + { + if (a.length > 0) + a[0] = null; + return a; + } + + /** + * The string never changes. + * + * @return the string "[]". + */ + public String toString() + { + return "[]"; + } + } // class EmptyList + + /** + * An immutable, serializable, empty Map. + * @see Serializable + */ + public static final Map EMPTY_MAP = new EmptyMap(); + + /** + * The implementation of {@link #EMPTY_MAP}. This class name is required + * for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class EmptyMap extends AbstractMap + implements Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 6428348081105594320L; + + /** + * A private constructor adds overhead. + */ + EmptyMap() + { + } + + /** + * There are no entries. + * @return The empty set. + */ + public Set entrySet() + { + return EMPTY_SET; + } + + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractMap. + /** + * No entries! + * @param key The key to search for. + * @return false. + */ + public boolean containsKey(Object key) + { + return false; + } + + /** + * No entries! + * @param value The value to search for. + * @return false. + */ + public boolean containsValue(Object value) + { + return false; + } + + /** + * Equal to all empty maps. + * @param o The object o to compare against this map. + * @return true if o is also an empty instance of + * Map. + */ + public boolean equals(Object o) + { + return o instanceof Map && ((Map) o).isEmpty(); + } + + /** + * No mappings, so this returns null. + * @param o The key of the object to retrieve. + * @return null. + */ + public Object get(Object o) + { + return null; + } + + /** + * The hashcode is always 0. + * @return 0. + */ + public int hashCode() + { + return 0; + } + + /** + * No entries. + * @return The empty set. + */ + public Set keySet() + { + return EMPTY_SET; + } + + /** + * Remove always succeeds, with null result. + * @param o The key of the mapping to remove. + * @return null, as there is never a mapping for o. + */ + public Object remove(Object o) + { + return null; + } + + /** + * Size is always 0. + * @return 0. + */ + public int size() + { + return 0; + } + + /** + * No entries. Technically, EMPTY_SET, while more specific than a general + * Collection, will work. Besides, that's what the JDK uses! + * @return The empty set. + */ + public Collection values() + { + return EMPTY_SET; + } + + /** + * The string never changes. + * + * @return the string "[]". + */ + public String toString() + { + return "[]"; + } + } // class EmptyMap + + + /** + * Compare two objects with or without a Comparator. If c is null, uses the + * natural ordering. Slightly slower than doing it inline if the JVM isn't + * clever, but worth it for removing a duplicate of the search code. + * Note: This code is also used in Arrays (for sort as well as search). + */ + static final int compare(Object o1, Object o2, Comparator c) + { + return c == null ? ((Comparable) o1).compareTo(o2) : c.compare(o1, o2); + } + + /** + * Perform a binary search of a List for a key, using the natural ordering of + * the elements. The list must be sorted (as by the sort() method) - if it is + * not, the behavior of this method is undefined, and may be an infinite + * loop. Further, the key must be comparable with every item in the list. If + * the list contains the key more than once, any one of them may be found. + *

    + * + * This algorithm behaves in log(n) time for {@link RandomAccess} lists, + * and uses a linear search with O(n) link traversals and log(n) comparisons + * with {@link AbstractSequentialList} lists. Note: although the + * specification allows for an infinite loop if the list is unsorted, it will + * not happen in this (Classpath) implementation. + * + * @param l the list to search (must be sorted) + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value + * @throws ClassCastException if key could not be compared with one of the + * elements of l + * @throws NullPointerException if a null element has compareTo called + * @see #sort(List) + */ + public static int binarySearch(List l, Object key) + { + return binarySearch(l, key, null); + } + + /** + * Perform a binary search of a List for a key, using a supplied Comparator. + * The list must be sorted (as by the sort() method with the same Comparator) + * - if it is not, the behavior of this method is undefined, and may be an + * infinite loop. Further, the key must be comparable with every item in the + * list. If the list contains the key more than once, any one of them may be + * found. If the comparator is null, the elements' natural ordering is used. + *

    + * + * This algorithm behaves in log(n) time for {@link RandomAccess} lists, + * and uses a linear search with O(n) link traversals and log(n) comparisons + * with {@link AbstractSequentialList} lists. Note: although the + * specification allows for an infinite loop if the list is unsorted, it will + * not happen in this (Classpath) implementation. + * + * @param l the list to search (must be sorted) + * @param key the value to search for + * @param c the comparator by which the list is sorted + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value + * @throws ClassCastException if key could not be compared with one of the + * elements of l + * @throws NullPointerException if a null element is compared with natural + * ordering (only possible when c is null) + * @see #sort(List, Comparator) + */ + public static int binarySearch(List l, Object key, Comparator c) + { + int pos = 0; + int low = 0; + int hi = l.size() - 1; + + // We use a linear search with log(n) comparisons using an iterator + // if the list is sequential-access. + if (isSequential(l)) + { + ListIterator itr = l.listIterator(); + int i = 0; + Object o = itr.next(); // Assumes list is not empty (see isSequential) + boolean forward = true; + while (low <= hi) + { + pos = (low + hi) >> 1; + if (i < pos) + { + if (!forward) + itr.next(); // Changing direction first. + for ( ; i != pos; i++, o = itr.next()); + forward = true; + } + else + { + if (forward) + itr.previous(); // Changing direction first. + for ( ; i != pos; i--, o = itr.previous()); + forward = false; + } + final int d = compare(key, o, c); + if (d == 0) + return pos; + else if (d < 0) + hi = pos - 1; + else + // This gets the insertion point right on the last loop + low = ++pos; + } + } + else + { + while (low <= hi) + { + pos = (low + hi) >> 1; + final int d = compare(key, l.get(pos), c); + if (d == 0) + return pos; + else if (d < 0) + hi = pos - 1; + else + // This gets the insertion point right on the last loop + low = ++pos; + } + } + + // If we failed to find it, we do the same whichever search we did. + return -pos - 1; + } + + /** + * Copy one list to another. If the destination list is longer than the + * source list, the remaining elements are unaffected. This method runs in + * linear time. + * + * @param dest the destination list + * @param source the source list + * @throws IndexOutOfBoundsException if the destination list is shorter + * than the source list (the destination will be unmodified) + * @throws UnsupportedOperationException if dest.listIterator() does not + * support the set operation + */ + public static void copy(List dest, List source) + { + int pos = source.size(); + if (dest.size() < pos) + throw new IndexOutOfBoundsException("Source does not fit in dest"); + + Iterator i1 = source.iterator(); + ListIterator i2 = dest.listIterator(); + + while (--pos >= 0) + { + i2.next(); + i2.set(i1.next()); + } + } + + /** + * Returns an Enumeration over a collection. This allows interoperability + * with legacy APIs that require an Enumeration as input. + * + * @param c the Collection to iterate over + * @return an Enumeration backed by an Iterator over c + */ + public static Enumeration enumeration(Collection c) + { + final Iterator i = c.iterator(); + return new Enumeration() + { + /** + * Returns true if there are more elements to + * be enumerated. + * + * @return The result of hasNext() + * called on the underlying iterator. + */ + public final boolean hasMoreElements() + { + return i.hasNext(); + } + + /** + * Returns the next element to be enumerated. + * + * @return The result of next() + * called on the underlying iterator. + */ + public final Object nextElement() + { + return i.next(); + } + }; + } + + /** + * Replace every element of a list with a given value. This method runs in + * linear time. + * + * @param l the list to fill. + * @param val the object to vill the list with. + * @throws UnsupportedOperationException if l.listIterator() does not + * support the set operation. + */ + public static void fill(List l, Object val) + { + ListIterator itr = l.listIterator(); + for (int i = l.size() - 1; i >= 0; --i) + { + itr.next(); + itr.set(val); + } + } + + /** + * Returns the starting index where the specified sublist first occurs + * in a larger list, or -1 if there is no matching position. If + * target.size() > source.size(), this returns -1, + * otherwise this implementation uses brute force, checking for + * source.sublist(i, i + target.size()).equals(target) + * for all possible i. + * + * @param source the list to search + * @param target the sublist to search for + * @return the index where found, or -1 + * @since 1.4 + */ + public static int indexOfSubList(List source, List target) + { + int ssize = source.size(); + for (int i = 0, j = target.size(); j <= ssize; i++, j++) + if (source.subList(i, j).equals(target)) + return i; + return -1; + } + + /** + * Returns the starting index where the specified sublist last occurs + * in a larger list, or -1 if there is no matching position. If + * target.size() > source.size(), this returns -1, + * otherwise this implementation uses brute force, checking for + * source.sublist(i, i + target.size()).equals(target) + * for all possible i. + * + * @param source the list to search + * @param target the sublist to search for + * @return the index where found, or -1 + * @since 1.4 + */ + public static int lastIndexOfSubList(List source, List target) + { + int ssize = source.size(); + for (int i = ssize - target.size(), j = ssize; i >= 0; i--, j--) + if (source.subList(i, j).equals(target)) + return i; + return -1; + } + + /** + * Returns an ArrayList holding the elements visited by a given + * Enumeration. This method exists for interoperability between legacy + * APIs and the new Collection API. + * + * @param e the enumeration to put in a list + * @return a list containing the enumeration elements + * @see ArrayList + * @since 1.4 + */ + public static ArrayList list(Enumeration e) + { + ArrayList l = new ArrayList(); + while (e.hasMoreElements()) + l.add(e.nextElement()); + return l; + } + + /** + * Find the maximum element in a Collection, according to the natural + * ordering of the elements. This implementation iterates over the + * Collection, so it works in linear time. + * + * @param c the Collection to find the maximum element of + * @return the maximum element of c + * @exception NoSuchElementException if c is empty + * @exception ClassCastException if elements in c are not mutually comparable + * @exception NullPointerException if null.compareTo is called + */ + public static Object max(Collection c) + { + return max(c, null); + } + + /** + * Find the maximum element in a Collection, according to a specified + * Comparator. This implementation iterates over the Collection, so it + * works in linear time. + * + * @param c the Collection to find the maximum element of + * @param order the Comparator to order the elements by, or null for natural + * ordering + * @return the maximum element of c + * @throws NoSuchElementException if c is empty + * @throws ClassCastException if elements in c are not mutually comparable + * @throws NullPointerException if null is compared by natural ordering + * (only possible when order is null) + */ + public static Object max(Collection c, Comparator order) + { + Iterator itr = c.iterator(); + Object max = itr.next(); // throws NoSuchElementException + int csize = c.size(); + for (int i = 1; i < csize; i++) + { + Object o = itr.next(); + if (compare(max, o, order) < 0) + max = o; + } + return max; + } + + /** + * Find the minimum element in a Collection, according to the natural + * ordering of the elements. This implementation iterates over the + * Collection, so it works in linear time. + * + * @param c the Collection to find the minimum element of + * @return the minimum element of c + * @throws NoSuchElementException if c is empty + * @throws ClassCastException if elements in c are not mutually comparable + * @throws NullPointerException if null.compareTo is called + */ + public static Object min(Collection c) + { + return min(c, null); + } + + /** + * Find the minimum element in a Collection, according to a specified + * Comparator. This implementation iterates over the Collection, so it + * works in linear time. + * + * @param c the Collection to find the minimum element of + * @param order the Comparator to order the elements by, or null for natural + * ordering + * @return the minimum element of c + * @throws NoSuchElementException if c is empty + * @throws ClassCastException if elements in c are not mutually comparable + * @throws NullPointerException if null is compared by natural ordering + * (only possible when order is null) + */ + public static Object min(Collection c, Comparator order) + { + Iterator itr = c.iterator(); + Object min = itr.next(); // throws NoSuchElementExcception + int csize = c.size(); + for (int i = 1; i < csize; i++) + { + Object o = itr.next(); + if (compare(min, o, order) > 0) + min = o; + } + return min; + } + + /** + * Creates an immutable list consisting of the same object repeated n times. + * The returned object is tiny, consisting of only a single reference to the + * object and a count of the number of elements. It is Serializable, and + * implements RandomAccess. You can use it in tandem with List.addAll for + * fast list construction. + * + * @param n the number of times to repeat the object + * @param o the object to repeat + * @return a List consisting of n copies of o + * @throws IllegalArgumentException if n < 0 + * @see List#addAll(Collection) + * @see Serializable + * @see RandomAccess + */ + public static List nCopies(final int n, final Object o) + { + return new CopiesList(n, o); + } + + /** + * The implementation of {@link #nCopies(int, Object)}. This class name + * is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class CopiesList extends AbstractList + implements Serializable, RandomAccess + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 2739099268398711800L; + + /** + * The count of elements in this list. + * @serial the list size + */ + private final int n; + + /** + * The repeated list element. + * @serial the list contents + */ + private final Object element; + + /** + * Constructs the list. + * + * @param n the count + * @param o the object + * @throws IllegalArgumentException if n < 0 + */ + CopiesList(int n, Object o) + { + if (n < 0) + throw new IllegalArgumentException(); + this.n = n; + element = o; + } + + /** + * The size is fixed. + * @return The size of the list. + */ + public int size() + { + return n; + } + + /** + * The same element is returned. + * @param index The index of the element to be returned (irrelevant + * as the list contains only copies of element). + * @return The element used by this list. + */ + public Object get(int index) + { + if (index < 0 || index >= n) + throw new IndexOutOfBoundsException(); + return element; + } + + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractList. + /** + * This list only contains one element. + * @param o The object to search for. + * @return true if o is the element used by this list. + */ + public boolean contains(Object o) + { + return n > 0 && equals(o, element); + } + + /** + * The index is either 0 or -1. + * @param o The object to find the index of. + * @return 0 if o == element, -1 if not. + */ + public int indexOf(Object o) + { + return (n > 0 && equals(o, element)) ? 0 : -1; + } + + /** + * The index is either n-1 or -1. + * @param o The object to find the last index of. + * @return The last index in the list if o == element, + * -1 if not. + */ + public int lastIndexOf(Object o) + { + return equals(o, element) ? n - 1 : -1; + } + + /** + * A subList is just another CopiesList. + * @param from The starting bound of the sublist. + * @param to The ending bound of the sublist. + * @return A list of copies containing from - to + * elements, all of which are equal to the element + * used by this list. + */ + public List subList(int from, int to) + { + if (from < 0 || to > n) + throw new IndexOutOfBoundsException(); + return new CopiesList(to - from, element); + } + + /** + * The array is easy. + * @return An array of size n filled with copies of + * the element used by this list. + */ + public Object[] toArray() + { + Object[] a = new Object[n]; + Arrays.fill(a, element); + return a; + } + + /** + * The string is easy to generate. + * @return A string representation of the list. + */ + public String toString() + { + StringBuffer r = new StringBuffer("{"); + for (int i = n - 1; --i > 0; ) + r.append(element).append(", "); + r.append(element).append("}"); + return r.toString(); + } + } // class CopiesList + + /** + * Replace all instances of one object with another in the specified list. + * The list does not change size. An element e is replaced if + * oldval == null ? e == null : oldval.equals(e). + * + * @param list the list to iterate over + * @param oldval the element to replace + * @param newval the new value for the element + * @return true if a replacement occurred. + * @throws UnsupportedOperationException if the list iterator does not allow + * for the set operation + * @throws ClassCastException if newval is of a type which cannot be added + * to the list + * @throws IllegalArgumentException if some other aspect of newval stops + * it being added to the list + * @since 1.4 + */ + public static boolean replaceAll(List list, Object oldval, Object newval) + { + ListIterator itr = list.listIterator(); + boolean replace_occured = false; + for (int i = list.size(); --i >= 0; ) + if (AbstractCollection.equals(oldval, itr.next())) + { + itr.set(newval); + replace_occured = true; + } + return replace_occured; + } + + /** + * Reverse a given list. This method works in linear time. + * + * @param l the list to reverse + * @throws UnsupportedOperationException if l.listIterator() does not + * support the set operation + */ + public static void reverse(List l) + { + ListIterator i1 = l.listIterator(); + int pos1 = 1; + int pos2 = l.size(); + ListIterator i2 = l.listIterator(pos2); + while (pos1 < pos2) + { + Object o = i1.next(); + i1.set(i2.previous()); + i2.set(o); + ++pos1; + --pos2; + } + } + + /** + * Get a comparator that implements the reverse of natural ordering. In + * other words, this sorts Comparable objects opposite of how their + * compareTo method would sort. This makes it easy to sort into reverse + * order, by simply passing Collections.reverseOrder() to the sort method. + * The return value of this method is Serializable. + * + * @return a comparator that imposes reverse natural ordering + * @see Comparable + * @see Serializable + */ + public static Comparator reverseOrder() + { + return rcInstance; + } + + /** + * The object for {@link #reverseOrder()}. + */ + private static final ReverseComparator rcInstance = new ReverseComparator(); + + /** + * The implementation of {@link #reverseOrder()}. This class name + * is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class ReverseComparator + implements Comparator, Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 7207038068494060240L; + + /** + * A private constructor adds overhead. + */ + ReverseComparator() + { + } + + /** + * Compare two objects in reverse natural order. + * + * @param a the first object + * @param b the second object + * @return <, ==, or > 0 according to b.compareTo(a) + */ + public int compare(Object a, Object b) + { + return ((Comparable) b).compareTo(a); + } + } + + /** + * Rotate the elements in a list by a specified distance. After calling this + * method, the element now at index i was formerly at index + * (i - distance) mod list.size(). The list size is unchanged. + *

    + * + * For example, suppose a list contains [t, a, n, k, s]. After + * either Collections.rotate(l, 4) or + * Collections.rotate(l, -1), the new contents are + * [s, t, a, n, k]. This can be applied to sublists to rotate + * just a portion of the list. For example, to move element a + * forward two positions in the original example, use + * Collections.rotate(l.subList(1, 3+1), -1), which will + * result in [t, n, k, a, s]. + *

    + * + * If the list is small or implements {@link RandomAccess}, the + * implementation exchanges the first element to its destination, then the + * displaced element, and so on until a circuit has been completed. The + * process is repeated if needed on the second element, and so forth, until + * all elements have been swapped. For large non-random lists, the + * implementation breaks the list into two sublists at index + * -distance mod size, calls {@link #reverse(List)} on the + * pieces, then reverses the overall list. + * + * @param list the list to rotate + * @param distance the distance to rotate by; unrestricted in value + * @throws UnsupportedOperationException if the list does not support set + * @since 1.4 + */ + public static void rotate(List list, int distance) + { + int size = list.size(); + if (size == 0) + return; + distance %= size; + if (distance == 0) + return; + if (distance < 0) + distance += size; + + if (isSequential(list)) + { + reverse(list); + reverse(list.subList(0, distance)); + reverse(list.subList(distance, size)); + } + else + { + // Determine the least common multiple of distance and size, as there + // are (distance / LCM) loops to cycle through. + int a = size; + int lcm = distance; + int b = a % lcm; + while (b != 0) + { + a = lcm; + lcm = b; + b = a % lcm; + } + + // Now, make the swaps. We must take the remainder every time through + // the inner loop so that we don't overflow i to negative values. + while (--lcm >= 0) + { + Object o = list.get(lcm); + for (int i = lcm + distance; i != lcm; i = (i + distance) % size) + o = list.set(i, o); + list.set(lcm, o); + } + } + } + + /** + * Shuffle a list according to a default source of randomness. The algorithm + * used iterates backwards over the list, swapping each element with an + * element randomly selected from the elements in positions less than or + * equal to it (using r.nextInt(int)). + *

    + * + * This algorithm would result in a perfectly fair shuffle (that is, each + * element would have an equal chance of ending up in any position) if r were + * a perfect source of randomness. In practice the results are merely very + * close to perfect. + *

    + * + * This method operates in linear time. To do this on large lists which do + * not implement {@link RandomAccess}, a temporary array is used to acheive + * this speed, since it would be quadratic access otherwise. + * + * @param l the list to shuffle + * @throws UnsupportedOperationException if l.listIterator() does not + * support the set operation + */ + public static void shuffle(List l) + { + if (defaultRandom == null) + { + synchronized (Collections.class) + { + if (defaultRandom == null) + defaultRandom = new Random(); + } + } + shuffle(l, defaultRandom); + } + + /** + * Cache a single Random object for use by shuffle(List). This improves + * performance as well as ensuring that sequential calls to shuffle() will + * not result in the same shuffle order occurring: the resolution of + * System.currentTimeMillis() is not sufficient to guarantee a unique seed. + */ + private static Random defaultRandom = null; + + /** + * Shuffle a list according to a given source of randomness. The algorithm + * used iterates backwards over the list, swapping each element with an + * element randomly selected from the elements in positions less than or + * equal to it (using r.nextInt(int)). + *

    + * + * This algorithm would result in a perfectly fair shuffle (that is, each + * element would have an equal chance of ending up in any position) if r were + * a perfect source of randomness. In practise (eg if r = new Random()) the + * results are merely very close to perfect. + *

    + * + * This method operates in linear time. To do this on large lists which do + * not implement {@link RandomAccess}, a temporary array is used to acheive + * this speed, since it would be quadratic access otherwise. + * + * @param l the list to shuffle + * @param r the source of randomness to use for the shuffle + * @throws UnsupportedOperationException if l.listIterator() does not + * support the set operation + */ + public static void shuffle(List l, Random r) + { + int lsize = l.size(); + ListIterator i = l.listIterator(lsize); + boolean sequential = isSequential(l); + Object[] a = null; // stores a copy of the list for the sequential case + + if (sequential) + a = l.toArray(); + + for (int pos = lsize - 1; pos > 0; --pos) + { + // Obtain a random position to swap with. pos + 1 is used so that the + // range of the random number includes the current position. + int swap = r.nextInt(pos + 1); + + // Swap the desired element. + Object o; + if (sequential) + { + o = a[swap]; + a[swap] = i.previous(); + } + else + o = l.set(swap, i.previous()); + + i.set(o); + } + } + + + /** + * Obtain an immutable Set consisting of a single element. The return value + * of this method is Serializable. + * + * @param o the single element + * @return an immutable Set containing only o + * @see Serializable + */ + public static Set singleton(Object o) + { + return new SingletonSet(o); + } + + /** + * The implementation of {@link #singleton(Object)}. This class name + * is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class SingletonSet extends AbstractSet + implements Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 3193687207550431679L; + + + /** + * The single element; package visible for use in nested class. + * @serial the singleton + */ + final Object element; + + /** + * Construct a singleton. + * @param o the element + */ + SingletonSet(Object o) + { + element = o; + } + + /** + * The size: always 1! + * @return 1. + */ + public int size() + { + return 1; + } + + /** + * Returns an iterator over the lone element. + */ + public Iterator iterator() + { + return new Iterator() + { + /** + * Flag to indicate whether or not the element has + * been retrieved. + */ + private boolean hasNext = true; + + /** + * Returns true if elements still remain to be + * iterated through. + * + * @return true if the element has not yet been returned. + */ + public boolean hasNext() + { + return hasNext; + } + + /** + * Returns the element. + * + * @return The element used by this singleton. + * @throws NoSuchElementException if the object + * has already been retrieved. + */ + public Object next() + { + if (hasNext) + { + hasNext = false; + return element; + } + else + throw new NoSuchElementException(); + } + + /** + * Removes the element from the singleton. + * As this set is immutable, this will always + * throw an exception. + * + * @throws UnsupportedOperationException as the + * singleton set doesn't support + * remove(). + */ + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } + + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractSet. + /** + * The set only contains one element. + * + * @param o The object to search for. + * @return true if o == the element of the singleton. + */ + public boolean contains(Object o) + { + return equals(o, element); + } + + /** + * This is true if the other collection only contains the element. + * + * @param c A collection to compare against this singleton. + * @return true if c only contains either no elements or + * elements equal to the element in this singleton. + */ + public boolean containsAll(Collection c) + { + Iterator i = c.iterator(); + int pos = c.size(); + while (--pos >= 0) + if (! equals(i.next(), element)) + return false; + return true; + } + + /** + * The hash is just that of the element. + * + * @return The hashcode of the element. + */ + public int hashCode() + { + return hashCode(element); + } + + /** + * Returning an array is simple. + * + * @return An array containing the element. + */ + public Object[] toArray() + { + return new Object[] {element}; + } + + /** + * Obvious string. + * + * @return The string surrounded by enclosing + * square brackets. + */ + public String toString() + { + return "[" + element + "]"; + } + } // class SingletonSet + + /** + * Obtain an immutable List consisting of a single element. The return value + * of this method is Serializable, and implements RandomAccess. + * + * @param o the single element + * @return an immutable List containing only o + * @see Serializable + * @see RandomAccess + * @since 1.3 + */ + public static List singletonList(Object o) + { + return new SingletonList(o); + } + + /** + * The implementation of {@link #singletonList(Object)}. This class name + * is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class SingletonList extends AbstractList + implements Serializable, RandomAccess + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 3093736618740652951L; + + /** + * The single element. + * @serial the singleton + */ + private final Object element; + + /** + * Construct a singleton. + * @param o the element + */ + SingletonList(Object o) + { + element = o; + } + + /** + * The size: always 1! + * @return 1. + */ + public int size() + { + return 1; + } + + /** + * Only index 0 is valid. + * @param index The index of the element + * to retrieve. + * @return The singleton's element if the + * index is 0. + * @throws IndexOutOfBoundsException if + * index is not 0. + */ + public Object get(int index) + { + if (index == 0) + return element; + throw new IndexOutOfBoundsException(); + } + + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractList. + /** + * The set only contains one element. + * + * @param o The object to search for. + * @return true if o == the singleton element. + */ + public boolean contains(Object o) + { + return equals(o, element); + } + + /** + * This is true if the other collection only contains the element. + * + * @param c A collection to compare against this singleton. + * @return true if c only contains either no elements or + * elements equal to the element in this singleton. + */ + public boolean containsAll(Collection c) + { + Iterator i = c.iterator(); + int pos = c.size(); + while (--pos >= 0) + if (! equals(i.next(), element)) + return false; + return true; + } + + /** + * Speed up the hashcode computation. + * + * @return The hashcode of the list, based + * on the hashcode of the singleton element. + */ + public int hashCode() + { + return 31 + hashCode(element); + } + + /** + * Either the list has it or not. + * + * @param o The object to find the first index of. + * @return 0 if o is the singleton element, -1 if not. + */ + public int indexOf(Object o) + { + return equals(o, element) ? 0 : -1; + } + + /** + * Either the list has it or not. + * + * @param o The object to find the last index of. + * @return 0 if o is the singleton element, -1 if not. + */ + public int lastIndexOf(Object o) + { + return equals(o, element) ? 0 : -1; + } + + /** + * Sublists are limited in scope. + * + * @param from The starting bound for the sublist. + * @param to The ending bound for the sublist. + * @return Either an empty list if both bounds are + * 0 or 1, or this list if the bounds are 0 and 1. + * @throws IllegalArgumentException if from > to + * @throws IndexOutOfBoundsException if either bound is greater + * than 1. + */ + public List subList(int from, int to) + { + if (from == to && (to == 0 || to == 1)) + return EMPTY_LIST; + if (from == 0 && to == 1) + return this; + if (from > to) + throw new IllegalArgumentException(); + throw new IndexOutOfBoundsException(); + } + + /** + * Returning an array is simple. + * + * @return An array containing the element. + */ + public Object[] toArray() + { + return new Object[] {element}; + } + + /** + * Obvious string. + * + * @return The string surrounded by enclosing + * square brackets. + */ + public String toString() + { + return "[" + element + "]"; + } + } // class SingletonList + + /** + * Obtain an immutable Map consisting of a single key-value pair. + * The return value of this method is Serializable. + * + * @param key the single key + * @param value the single value + * @return an immutable Map containing only the single key-value pair + * @see Serializable + * @since 1.3 + */ + public static Map singletonMap(Object key, Object value) + { + return new SingletonMap(key, value); + } + + /** + * The implementation of {@link #singletonMap(Object)}. This class name + * is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class SingletonMap extends AbstractMap + implements Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -6979724477215052911L; + + /** + * The single key. + * @serial the singleton key + */ + private final Object k; + + /** + * The corresponding value. + * @serial the singleton value + */ + private final Object v; + + /** + * Cache the entry set. + */ + private transient Set entries; + + /** + * Construct a singleton. + * @param key the key + * @param value the value + */ + SingletonMap(Object key, Object value) + { + k = key; + v = value; + } + + /** + * There is a single immutable entry. + * + * @return A singleton containing the map entry. + */ + public Set entrySet() + { + if (entries == null) + entries = singleton(new AbstractMap.BasicMapEntry(k, v) + { + /** + * Sets the value of the map entry to the supplied value. + * An exception is always thrown, as the map is immutable. + * + * @param o The new value. + * @return The old value. + * @throws UnsupportedOperationException as setting the value + * is not supported. + */ + public Object setValue(Object o) + { + throw new UnsupportedOperationException(); + } + }); + return entries; + } + + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractMap. + /** + * Single entry. + * + * @param key The key to look for. + * @return true if the key is the same as the one used by + * this map. + */ + public boolean containsKey(Object key) + { + return equals(key, k); + } + + /** + * Single entry. + * + * @param value The value to look for. + * @return true if the value is the same as the one used by + * this map. + */ + public boolean containsValue(Object value) + { + return equals(value, v); + } + + /** + * Single entry. + * + * @param key The key of the value to be retrieved. + * @return The singleton value if the key is the same as the + * singleton key, null otherwise. + */ + public Object get(Object key) + { + return equals(key, k) ? v : null; + } + + /** + * Calculate the hashcode directly. + * + * @return The hashcode computed from the singleton key + * and the singleton value. + */ + public int hashCode() + { + return hashCode(k) ^ hashCode(v); + } + + /** + * Return the keyset. + * + * @return A singleton containing the key. + */ + public Set keySet() + { + if (keys == null) + keys = singleton(k); + return keys; + } + + /** + * The size: always 1! + * + * @return 1. + */ + public int size() + { + return 1; + } + + /** + * Return the values. Technically, a singleton, while more specific than + * a general Collection, will work. Besides, that's what the JDK uses! + * + * @return A singleton containing the value. + */ + public Collection values() + { + if (values == null) + values = singleton(v); + return values; + } + + /** + * Obvious string. + * + * @return A string containing the string representations of the key + * and its associated value. + */ + public String toString() + { + return "{" + k + "=" + v + "}"; + } + } // class SingletonMap + + /** + * Sort a list according to the natural ordering of its elements. The list + * must be modifiable, but can be of fixed size. The sort algorithm is + * precisely that used by Arrays.sort(Object[]), which offers guaranteed + * nlog(n) performance. This implementation dumps the list into an array, + * sorts the array, and then iterates over the list setting each element from + * the array. + * + * @param l the List to sort + * @throws ClassCastException if some items are not mutually comparable + * @throws UnsupportedOperationException if the List is not modifiable + * @throws NullPointerException if some element is null + * @see Arrays#sort(Object[]) + */ + public static void sort(List l) + { + sort(l, null); + } + + /** + * Sort a list according to a specified Comparator. The list must be + * modifiable, but can be of fixed size. The sort algorithm is precisely that + * used by Arrays.sort(Object[], Comparator), which offers guaranteed + * nlog(n) performance. This implementation dumps the list into an array, + * sorts the array, and then iterates over the list setting each element from + * the array. + * + * @param l the List to sort + * @param c the Comparator specifying the ordering for the elements, or + * null for natural ordering + * @throws ClassCastException if c will not compare some pair of items + * @throws UnsupportedOperationException if the List is not modifiable + * @throws NullPointerException if null is compared by natural ordering + * (only possible when c is null) + * @see Arrays#sort(Object[], Comparator) + */ + public static void sort(List l, Comparator c) + { + Object[] a = l.toArray(); + Arrays.sort(a, c); + ListIterator i = l.listIterator(); + for (int pos = 0, alen = a.length; pos < alen; pos++) + { + i.next(); + i.set(a[pos]); + } + } + + /** + * Swaps the elements at the specified positions within the list. Equal + * positions have no effect. + * + * @param l the list to work on + * @param i the first index to swap + * @param j the second index + * @throws UnsupportedOperationException if list.set is not supported + * @throws IndexOutOfBoundsException if either i or j is < 0 or >= + * list.size() + * @since 1.4 + */ + public static void swap(List l, int i, int j) + { + l.set(i, l.set(j, l.get(i))); + } + + + /** + * Returns a synchronized (thread-safe) collection wrapper backed by the + * given collection. Notice that element access through the iterators + * is thread-safe, but if the collection can be structurally modified + * (adding or removing elements) then you should synchronize around the + * iteration to avoid non-deterministic behavior:
    + *

    +   * Collection c = Collections.synchronizedCollection(new Collection(...));
    +   * ...
    +   * synchronized (c)
    +   *   {
    +   *     Iterator i = c.iterator();
    +   *     while (i.hasNext())
    +   *       foo(i.next());
    +   *   }
    +   * 

    + * + * Since the collection might be a List or a Set, and those have incompatible + * equals and hashCode requirements, this relies on Object's implementation + * rather than passing those calls on to the wrapped collection. The returned + * Collection implements Serializable, but can only be serialized if + * the collection it wraps is likewise Serializable. + * + * @param c the collection to wrap + * @return a synchronized view of the collection + * @see Serializable + */ + public static Collection synchronizedCollection(Collection c) + { + return new SynchronizedCollection(c); + } + + /** + * The implementation of {@link #synchronizedCollection(Collection)}. This + * class name is required for compatibility with Sun's JDK serializability. + * Package visible, so that collections such as the one for + * Hashtable.values() can specify which object to synchronize on. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + static class SynchronizedCollection + implements Collection, Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 3053995032091335093L; + + /** + * The wrapped collection. Package visible for use by subclasses. + * @serial the real collection + */ + final Collection c; + + /** + * The object to synchronize on. When an instance is created via public + * methods, it will be this; but other uses like SynchronizedMap.values() + * must specify another mutex. Package visible for use by subclasses. + * @serial the lock + */ + final Object mutex; + + /** + * Wrap a given collection. + * @param c the collection to wrap + * @throws NullPointerException if c is null + */ + SynchronizedCollection(Collection c) + { + this.c = c; + mutex = this; + if (c == null) + throw new NullPointerException(); + } + + /** + * Called only by trusted code to specify the mutex as well as the + * collection. + * @param sync the mutex + * @param c the collection + */ + SynchronizedCollection(Object sync, Collection c) + { + this.c = c; + mutex = sync; + } + + /** + * Adds the object to the underlying collection, first + * obtaining a lock on the mutex. + * + * @param o The object to add. + * @return true if the collection was modified as a result + * of this action. + * @throws UnsupportedOperationException if this collection does not + * support the add operation. + * @throws ClassCastException if o cannot be added to this collection due + * to its type. + * @throws NullPointerException if o is null and this collection doesn't + * support the addition of null values. + * @throws IllegalArgumentException if o cannot be added to this + * collection for some other reason. + */ + public boolean add(Object o) + { + synchronized (mutex) + { + return c.add(o); + } + } + + /** + * Adds the objects in col to the underlying collection, first + * obtaining a lock on the mutex. + * + * @param col The collection to take the new objects from. + * @return true if the collection was modified as a result + * of this action. + * @throws UnsupportedOperationException if this collection does not + * support the addAll operation. + * @throws ClassCastException if some element of col cannot be added to this + * collection due to its type. + * @throws NullPointerException if some element of col is null and this + * collection does not support the addition of null values. + * @throws NullPointerException if col itself is null. + * @throws IllegalArgumentException if some element of col cannot be added + * to this collection for some other reason. + */ + public boolean addAll(Collection col) + { + synchronized (mutex) + { + return c.addAll(col); + } + } + + /** + * Removes all objects from the underlying collection, + * first obtaining a lock on the mutex. + * + * @throws UnsupportedOperationException if this collection does not + * support the clear operation. + */ + public void clear() + { + synchronized (mutex) + { + c.clear(); + } + } + + /** + * Checks for the existence of o within the underlying + * collection, first obtaining a lock on the mutex. + * + * @param o the element to look for. + * @return true if this collection contains at least one + * element e such that o == null ? e == null : o.equals(e). + * @throws ClassCastException if the type of o is not a valid type for this + * collection. + * @throws NullPointerException if o is null and this collection doesn't + * support null values. + */ + public boolean contains(Object o) + { + synchronized (mutex) + { + return c.contains(o); + } + } + + /** + * Checks for the existence of each object in cl + * within the underlying collection, first obtaining + * a lock on the mutex. + * + * @param c1 the collection to test for. + * @return true if for every element o in c, contains(o) + * would return true. + * @throws ClassCastException if the type of any element in cl is not a valid + * type for this collection. + * @throws NullPointerException if some element of cl is null and this + * collection does not support null values. + * @throws NullPointerException if cl itself is null. + */ + public boolean containsAll(Collection c1) + { + synchronized (mutex) + { + return c.containsAll(c1); + } + } + + /** + * Returns true if there are no objects in the underlying + * collection. A lock on the mutex is obtained before the + * check is performed. + * + * @return true if this collection contains no elements. + */ + public boolean isEmpty() + { + synchronized (mutex) + { + return c.isEmpty(); + } + } + + /** + * Returns a synchronized iterator wrapper around the underlying + * collection's iterator. A lock on the mutex is obtained before + * retrieving the collection's iterator. + * + * @return An iterator over the elements in the underlying collection, + * which returns each element in any order. + */ + public Iterator iterator() + { + synchronized (mutex) + { + return new SynchronizedIterator(mutex, c.iterator()); + } + } + + /** + * Removes the specified object from the underlying collection, + * first obtaining a lock on the mutex. + * + * @param o The object to remove. + * @return true if the collection changed as a result of this call, that is, + * if the collection contained at least one occurrence of o. + * @throws UnsupportedOperationException if this collection does not + * support the remove operation. + * @throws ClassCastException if the type of o is not a valid type + * for this collection. + * @throws NullPointerException if o is null and the collection doesn't + * support null values. + */ + public boolean remove(Object o) + { + synchronized (mutex) + { + return c.remove(o); + } + } + + /** + * Removes all elements, e, of the underlying + * collection for which col.contains(e) + * returns true. A lock on the mutex is obtained + * before the operation proceeds. + * + * @param col The collection of objects to be removed. + * @return true if this collection was modified as a result of this call. + * @throws UnsupportedOperationException if this collection does not + * support the removeAll operation. + * @throws ClassCastException if the type of any element in c is not a valid + * type for this collection. + * @throws NullPointerException if some element of c is null and this + * collection does not support removing null values. + * @throws NullPointerException if c itself is null. + */ + public boolean removeAll(Collection col) + { + synchronized (mutex) + { + return c.removeAll(col); + } + } + + /** + * Retains all elements, e, of the underlying + * collection for which col.contains(e) + * returns true. That is, every element that doesn't + * exist in col is removed. A lock on the mutex is obtained + * before the operation proceeds. + * + * @param col The collection of objects to be removed. + * @return true if this collection was modified as a result of this call. + * @throws UnsupportedOperationException if this collection does not + * support the removeAll operation. + * @throws ClassCastException if the type of any element in c is not a valid + * type for this collection. + * @throws NullPointerException if some element of c is null and this + * collection does not support removing null values. + * @throws NullPointerException if c itself is null. + */ + public boolean retainAll(Collection col) + { + synchronized (mutex) + { + return c.retainAll(col); + } + } + + /** + * Retrieves the size of the underlying collection. + * A lock on the mutex is obtained before the collection + * is accessed. + * + * @return The size of the collection. + */ + public int size() + { + synchronized (mutex) + { + return c.size(); + } + } + + /** + * Returns an array containing each object within the underlying + * collection. A lock is obtained on the mutex before the collection + * is accessed. + * + * @return An array of objects, matching the collection in size. The + * elements occur in any order. + */ + public Object[] toArray() + { + synchronized (mutex) + { + return c.toArray(); + } + } + + /** + * Copies the elements in the underlying collection to the supplied + * array. If a.length < size(), a new array of the + * same run-time type is created, with a size equal to that of + * the collection. If a.length > size(), then the + * elements from 0 to size() - 1 contain the elements + * from this collection. The following element is set to null + * to indicate the end of the collection objects. However, this + * only makes a difference if null is not a permitted value within + * the collection. + * Before the copying takes place, a lock is obtained on the mutex. + * + * @param a An array to copy elements to. + * @return An array containing the elements of the underlying collection. + * @throws ArrayStoreException if the type of any element of the + * collection is not a subtype of the element type of a. + */ + public Object[] toArray(Object[] a) + { + synchronized (mutex) + { + return c.toArray(a); + } + } + + /** + * Returns a string representation of the underlying collection. + * A lock is obtained on the mutex before the string is created. + * + * @return A string representation of the collection. + */ + public String toString() + { + synchronized (mutex) + { + return c.toString(); + } + } + } // class SynchronizedCollection + + /** + * The implementation of the various iterator methods in the + * synchronized classes. These iterators must "sync" on the same object + * as the collection they iterate over. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class SynchronizedIterator implements Iterator + { + /** + * The object to synchronize on. Package visible for use by subclass. + */ + final Object mutex; + + /** + * The wrapped iterator. + */ + private final Iterator i; + + /** + * Only trusted code creates a wrapper, with the specified sync. + * @param sync the mutex + * @param i the wrapped iterator + */ + SynchronizedIterator(Object sync, Iterator i) + { + this.i = i; + mutex = sync; + } + + /** + * Retrieves the next object in the underlying collection. + * A lock is obtained on the mutex before the collection is accessed. + * + * @return The next object in the collection. + * @throws NoSuchElementException if there are no more elements + */ + public Object next() + { + synchronized (mutex) + { + return i.next(); + } + } + + /** + * Returns true if objects can still be retrieved from the iterator + * using next(). A lock is obtained on the mutex before + * the collection is accessed. + * + * @return true if at least one element is still to be returned by + * next(). + */ + public boolean hasNext() + { + synchronized (mutex) + { + return i.hasNext(); + } + } + + /** + * Removes the object that was last returned by next() + * from the underlying collection. Only one call to this method is + * allowed per call to the next() method, and it does + * not affect the value that will be returned by next(). + * Thus, if element n was retrieved from the collection by + * next(), it is this element that gets removed. + * Regardless of whether this takes place or not, element n+1 is + * still returned on the subsequent next() call. + * + * @throws IllegalStateException if next has not yet been called or remove + * has already been called since the last call to next. + * @throws UnsupportedOperationException if this Iterator does not support + * the remove operation. + */ + public void remove() + { + synchronized (mutex) + { + i.remove(); + } + } + } // class SynchronizedIterator + + /** + * Returns a synchronized (thread-safe) list wrapper backed by the + * given list. Notice that element access through the iterators + * is thread-safe, but if the list can be structurally modified + * (adding or removing elements) then you should synchronize around the + * iteration to avoid non-deterministic behavior:
    + *

    +   * List l = Collections.synchronizedList(new List(...));
    +   * ...
    +   * synchronized (l)
    +   *   {
    +   *     Iterator i = l.iterator();
    +   *     while (i.hasNext())
    +   *       foo(i.next());
    +   *   }
    +   * 

    + * + * The returned List implements Serializable, but can only be serialized if + * the list it wraps is likewise Serializable. In addition, if the wrapped + * list implements RandomAccess, this does too. + * + * @param l the list to wrap + * @return a synchronized view of the list + * @see Serializable + * @see RandomAccess + */ + public static List synchronizedList(List l) + { + if (l instanceof RandomAccess) + return new SynchronizedRandomAccessList(l); + return new SynchronizedList(l); + } + + /** + * The implementation of {@link #synchronizedList(List)} for sequential + * lists. This class name is required for compatibility with Sun's JDK + * serializability. Package visible, so that lists such as Vector.subList() + * can specify which object to synchronize on. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + static class SynchronizedList extends SynchronizedCollection + implements List + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -7754090372962971524L; + + /** + * The wrapped list; stored both here and in the superclass to avoid + * excessive casting. Package visible for use by subclass. + * @serial the wrapped list + */ + final List list; + + /** + * Wrap a given list. + * @param l the list to wrap + * @throws NullPointerException if l is null + */ + SynchronizedList(List l) + { + super(l); + list = l; + } + + /** + * Called only by trusted code to specify the mutex as well as the list. + * @param sync the mutex + * @param l the list + */ + SynchronizedList(Object sync, List l) + { + super(sync, l); + list = l; + } + + /** + * Insert an element into the underlying list at a given position (optional + * operation). This shifts all existing elements from that position to the + * end one index to the right. This version of add has no return, since it is + * assumed to always succeed if there is no exception. Before the + * addition takes place, a lock is obtained on the mutex. + * + * @param index the location to insert the item + * @param o the object to insert + * @throws UnsupportedOperationException if this list does not support the + * add operation + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + * @throws NullPointerException if o is null and this list doesn't support + * the addition of null values. + */ + public void add(int index, Object o) + { + synchronized (mutex) + { + list.add(index, o); + } + } + + /** + * Add an element to the end of the underlying list (optional operation). + * If the list imposes restraints on what can be inserted, such as no null + * elements, this should be documented. A lock is obtained on the mutex before + * any of the elements are added. + * + * @param o the object to add + * @return true, as defined by Collection for a modified list + * @throws UnsupportedOperationException if this list does not support the + * add operation + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + * @throws NullPointerException if o is null and this list doesn't support + * the addition of null values. + */ + public boolean addAll(int index, Collection c) + { + synchronized (mutex) + { + return list.addAll(index, c); + } + } + + /** + * Tests whether the underlying list is equal to the supplied object. + * The object is deemed to be equal if it is also a List + * of equal size and with the same elements (i.e. each element, e1, + * in list, l1, and each element, e2, in l2, must return true for + * e1 == null ? e2 == null : e1.equals(e2). Before the + * comparison is made, a lock is obtained on the mutex. + * + * @param o The object to test for equality with the underlying list. + * @return true if o is equal to the underlying list under the above + * definition. + */ + public boolean equals(Object o) + { + synchronized (mutex) + { + return list.equals(o); + } + } + + /** + * Retrieves the object at the specified index. A lock + * is obtained on the mutex before the list is accessed. + * + * @param index the index of the element to be returned + * @return the element at index index in this list + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object get(int index) + { + synchronized (mutex) + { + return list.get(index); + } + } + + /** + * Obtains a hashcode for the underlying list, first obtaining + * a lock on the mutex. The calculation of the hashcode is + * detailed in the documentation for the List + * interface. + * + * @return The hashcode of the underlying list. + * @see List#hashCode() + */ + public int hashCode() + { + synchronized (mutex) + { + return list.hashCode(); + } + } + + /** + * Obtain the first index at which a given object is to be found in the + * underlying list. A lock is obtained on the mutex before the list is + * accessed. + * + * @param o the object to search for + * @return the least integer n such that o == null ? get(n) == null : + * o.equals(get(n)), or -1 if there is no such index. + * @throws ClassCastException if the type of o is not a valid + * type for this list. + * @throws NullPointerException if o is null and this + * list does not support null values. + */ + + public int indexOf(Object o) + { + synchronized (mutex) + { + return list.indexOf(o); + } + } + + /** + * Obtain the last index at which a given object is to be found in this + * underlying list. A lock is obtained on the mutex before the list + * is accessed. + * + * @return the greatest integer n such that o == null ? get(n) == null + * : o.equals(get(n)), or -1 if there is no such index. + * @throws ClassCastException if the type of o is not a valid + * type for this list. + * @throws NullPointerException if o is null and this + * list does not support null values. + */ + public int lastIndexOf(Object o) + { + synchronized (mutex) + { + return list.lastIndexOf(o); + } + } + + /** + * Retrieves a synchronized wrapper around the underlying list's + * list iterator. A lock is obtained on the mutex before the + * list iterator is retrieved. + * + * @return A list iterator over the elements in the underlying list. + * The list iterator allows additional list-specific operations + * to be performed, in addition to those supplied by the + * standard iterator. + */ + public ListIterator listIterator() + { + synchronized (mutex) + { + return new SynchronizedListIterator(mutex, list.listIterator()); + } + } + + /** + * Retrieves a synchronized wrapper around the underlying list's + * list iterator. A lock is obtained on the mutex before the + * list iterator is retrieved. The iterator starts at the + * index supplied, leading to the element at that index being + * the first one returned by next(). Calling + * previous() from this initial position returns + * index - 1. + * + * @param index the position, between 0 and size() inclusive, to begin the + * iteration from + * @return A list iterator over the elements in the underlying list. + * The list iterator allows additional list-specific operations + * to be performed, in addition to those supplied by the + * standard iterator. + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + public ListIterator listIterator(int index) + { + synchronized (mutex) + { + return new SynchronizedListIterator(mutex, list.listIterator(index)); + } + } + + /** + * Remove the element at a given position in the underlying list (optional + * operation). All remaining elements are shifted to the left to fill the gap. + * A lock on the mutex is obtained before the element is removed. + * + * @param index the position within the list of the object to remove + * @return the object that was removed + * @throws UnsupportedOperationException if this list does not support the + * remove operation + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object remove(int index) + { + synchronized (mutex) + { + return list.remove(index); + } + } + + /** + * Replace an element of the underlying list with another object (optional + * operation). A lock is obtained on the mutex before the element is + * replaced. + * + * @param index the position within this list of the element to be replaced + * @param o the object to replace it with + * @return the object that was replaced + * @throws UnsupportedOperationException if this list does not support the + * set operation. + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + * @throws NullPointerException if o is null and this + * list does not support null values. + */ + public Object set(int index, Object o) + { + synchronized (mutex) + { + return list.set(index, o); + } + } + + /** + * Obtain a List view of a subsection of the underlying list, from fromIndex + * (inclusive) to toIndex (exclusive). If the two indices are equal, the + * sublist is empty. The returned list should be modifiable if and only + * if this list is modifiable. Changes to the returned list should be + * reflected in this list. If this list is structurally modified in + * any way other than through the returned list, the result of any subsequent + * operations on the returned list is undefined. A lock is obtained + * on the mutex before the creation of the sublist. The returned list + * is also synchronized, using the same mutex. + * + * @param fromIndex the index that the returned list should start from + * (inclusive) + * @param toIndex the index that the returned list should go to (exclusive) + * @return a List backed by a subsection of this list + * @throws IndexOutOfBoundsException if fromIndex < 0 + * || toIndex > size() || fromIndex > toIndex + */ + public List subList(int fromIndex, int toIndex) + { + synchronized (mutex) + { + return new SynchronizedList(mutex, list.subList(fromIndex, toIndex)); + } + } + } // class SynchronizedList + + /** + * The implementation of {@link #synchronizedList(List)} for random-access + * lists. This class name is required for compatibility with Sun's JDK + * serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class SynchronizedRandomAccessList + extends SynchronizedList implements RandomAccess + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 1530674583602358482L; + + /** + * Wrap a given list. + * @param l the list to wrap + * @throws NullPointerException if l is null + */ + SynchronizedRandomAccessList(List l) + { + super(l); + } + + /** + * Called only by trusted code to specify the mutex as well as the + * collection. + * @param sync the mutex + * @param l the list + */ + SynchronizedRandomAccessList(Object sync, List l) + { + super(sync, l); + } + + /** + * Obtain a List view of a subsection of the underlying list, from fromIndex + * (inclusive) to toIndex (exclusive). If the two indices are equal, the + * sublist is empty. The returned list should be modifiable if and only + * if this list is modifiable. Changes to the returned list should be + * reflected in this list. If this list is structurally modified in + * any way other than through the returned list, the result of any subsequent + * operations on the returned list is undefined. A lock is obtained + * on the mutex before the creation of the sublist. The returned list + * is also synchronized, using the same mutex. Random accessibility + * is also extended to the new list. + * + * @param fromIndex the index that the returned list should start from + * (inclusive) + * @param toIndex the index that the returned list should go to (exclusive) + * @return a List backed by a subsection of this list + * @throws IndexOutOfBoundsException if fromIndex < 0 + * || toIndex > size() || fromIndex > toIndex + */ + public List subList(int fromIndex, int toIndex) + { + synchronized (mutex) + { + return new SynchronizedRandomAccessList(mutex, + list.subList(fromIndex, + toIndex)); + } + } + } // class SynchronizedRandomAccessList + + /** + * The implementation of {@link SynchronizedList#listIterator()}. This + * iterator must "sync" on the same object as the list it iterates over. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class SynchronizedListIterator + extends SynchronizedIterator implements ListIterator + { + /** + * The wrapped iterator, stored both here and in the superclass to + * avoid excessive casting. + */ + private final ListIterator li; + + /** + * Only trusted code creates a wrapper, with the specified sync. + * @param sync the mutex + * @param li the wrapped iterator + */ + SynchronizedListIterator(Object sync, ListIterator li) + { + super(sync, li); + this.li = li; + } + + /** + * Insert an element into the underlying list at the current position of + * the iterator (optional operation). The element is inserted in between + * the element that would be returned by previous() and the + * element that would be returned by next(). After the + * insertion, a subsequent call to next is unaffected, but + * a call to previous returns the item that was added. The values returned + * by nextIndex() and previousIndex() are incremented. A lock is obtained + * on the mutex before the addition takes place. + * + * @param o the object to insert into the list + * @throws ClassCastException if the object is of a type which cannot be added + * to this list. + * @throws IllegalArgumentException if some other aspect of the object stops + * it being added to this list. + * @throws UnsupportedOperationException if this ListIterator does not + * support the add operation. + */ + public void add(Object o) + { + synchronized (mutex) + { + li.add(o); + } + } + + /** + * Tests whether there are elements remaining in the underlying list + * in the reverse direction. In other words, previous() + * will not fail with a NoSuchElementException. A lock is obtained + * on the mutex before the check takes place. + * + * @return true if the list continues in the reverse direction + */ + public boolean hasPrevious() + { + synchronized (mutex) + { + return li.hasPrevious(); + } + } + + /** + * Find the index of the element that would be returned by a call to + * next(). If hasNext() returns false, this + * returns the list size. A lock is obtained on the mutex before the + * query takes place. + * + * @return the index of the element that would be returned by next() + */ + public int nextIndex() + { + synchronized (mutex) + { + return li.nextIndex(); + } + } + + /** + * Obtain the previous element from the underlying list. Repeated + * calls to previous may be used to iterate backwards over the entire list, + * or calls to next and previous may be used together to go forwards and + * backwards. Alternating calls to next and previous will return the same + * element. A lock is obtained on the mutex before the object is retrieved. + * + * @return the next element in the list in the reverse direction + * @throws NoSuchElementException if there are no more elements + */ + public Object previous() + { + synchronized (mutex) + { + return li.previous(); + } + } + + /** + * Find the index of the element that would be returned by a call to + * previous. If hasPrevious() returns false, this returns -1. + * A lock is obtained on the mutex before the query takes place. + * + * @return the index of the element that would be returned by previous() + */ + public int previousIndex() + { + synchronized (mutex) + { + return li.previousIndex(); + } + } + + /** + * Replace the element last returned by a call to next() or + * previous() with a given object (optional operation). This + * method may only be called if neither add() nor + * remove() have been called since the last call to + * next() or previous. A lock is obtained + * on the mutex before the list is modified. + * + * @param o the object to replace the element with + * @throws ClassCastException the object is of a type which cannot be added + * to this list + * @throws IllegalArgumentException some other aspect of the object stops + * it being added to this list + * @throws IllegalStateException if neither next or previous have been + * called, or if add or remove has been called since the last call + * to next or previous + * @throws UnsupportedOperationException if this ListIterator does not + * support the set operation + */ + public void set(Object o) + { + synchronized (mutex) + { + li.set(o); + } + } + } // class SynchronizedListIterator + + /** + * Returns a synchronized (thread-safe) map wrapper backed by the given + * map. Notice that element access through the collection views and their + * iterators are thread-safe, but if the map can be structurally modified + * (adding or removing elements) then you should synchronize around the + * iteration to avoid non-deterministic behavior:
    + *

    +   * Map m = Collections.synchronizedMap(new Map(...));
    +   * ...
    +   * Set s = m.keySet(); // safe outside a synchronized block
    +   * synchronized (m) // synch on m, not s
    +   *   {
    +   *     Iterator i = s.iterator();
    +   *     while (i.hasNext())
    +   *       foo(i.next());
    +   *   }
    +   * 

    + * + * The returned Map implements Serializable, but can only be serialized if + * the map it wraps is likewise Serializable. + * + * @param m the map to wrap + * @return a synchronized view of the map + * @see Serializable + */ + public static Map synchronizedMap(Map m) + { + return new SynchronizedMap(m); + } + + /** + * The implementation of {@link #synchronizedMap(Map)}. This + * class name is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class SynchronizedMap implements Map, Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 1978198479659022715L; + + /** + * The wrapped map. + * @serial the real map + */ + private final Map m; + + /** + * The object to synchronize on. When an instance is created via public + * methods, it will be this; but other uses like + * SynchronizedSortedMap.subMap() must specify another mutex. Package + * visible for use by subclass. + * @serial the lock + */ + final Object mutex; + + /** + * Cache the entry set. + */ + private transient Set entries; + + /** + * Cache the key set. + */ + private transient Set keys; + + /** + * Cache the value collection. + */ + private transient Collection values; + + /** + * Wrap a given map. + * @param m the map to wrap + * @throws NullPointerException if m is null + */ + SynchronizedMap(Map m) + { + this.m = m; + mutex = this; + if (m == null) + throw new NullPointerException(); + } + + /** + * Called only by trusted code to specify the mutex as well as the map. + * @param sync the mutex + * @param m the map + */ + SynchronizedMap(Object sync, Map m) + { + this.m = m; + mutex = sync; + } + + /** + * Clears all the entries from the underlying map. A lock is obtained + * on the mutex before the map is cleared. + * + * @throws UnsupportedOperationException if clear is not supported + */ + public void clear() + { + synchronized (mutex) + { + m.clear(); + } + } + + /** + * Returns true if the underlying map contains a entry for the given key. + * A lock is obtained on the mutex before the map is queried. + * + * @param key the key to search for. + * @return true if the underlying map contains the key. + * @throws ClassCastException if the key is of an inappropriate type. + * @throws NullPointerException if key is null but the map + * does not permit null keys. + */ + public boolean containsKey(Object key) + { + synchronized (mutex) + { + return m.containsKey(key); + } + } + + /** + * Returns true if the underlying map contains at least one entry with the + * given value. In other words, returns true if a value v exists where + * (value == null ? v == null : value.equals(v)). This usually + * requires linear time. A lock is obtained on the mutex before the map + * is queried. + * + * @param value the value to search for + * @return true if the map contains the value + * @throws ClassCastException if the type of the value is not a valid type + * for this map. + * @throws NullPointerException if the value is null and the map doesn't + * support null values. + */ + public boolean containsValue(Object value) + { + synchronized (mutex) + { + return m.containsValue(value); + } + } + + // This is one of the ickiest cases of nesting I've ever seen. It just + // means "return a SynchronizedSet, except that the iterator() method + // returns an SynchronizedIterator whose next() method returns a + // synchronized wrapper around its normal return value". + public Set entrySet() + { + // Define this here to spare some nesting. + class SynchronizedMapEntry implements Map.Entry + { + final Map.Entry e; + SynchronizedMapEntry(Object o) + { + e = (Map.Entry) o; + } + + /** + * Returns true if the object, o, implements Map.Entry + * with the same key and value as the underlying entry. A lock is + * obtained on the mutex before the comparison takes place. + * + * @param o The object to compare with this entry. + * @return true if o is equivalent to the underlying map entry. + */ + public boolean equals(Object o) + { + synchronized (mutex) + { + return e.equals(o); + } + } + + /** + * Returns the key used in the underlying map entry. A lock is obtained + * on the mutex before the key is retrieved. + * + * @return The key of the underlying map entry. + */ + public Object getKey() + { + synchronized (mutex) + { + return e.getKey(); + } + } + + /** + * Returns the value used in the underlying map entry. A lock is obtained + * on the mutex before the value is retrieved. + * + * @return The value of the underlying map entry. + */ + public Object getValue() + { + synchronized (mutex) + { + return e.getValue(); + } + } + + /** + * Computes the hash code for the underlying map entry. + * This computation is described in the documentation for the + * Map interface. A lock is obtained on the mutex + * before the underlying map is accessed. + * + * @return The hash code of the underlying map entry. + * @see Map#hashCode() + */ + public int hashCode() + { + synchronized (mutex) + { + return e.hashCode(); + } + } + + /** + * Replaces the value in the underlying map entry with the specified + * object (optional operation). A lock is obtained on the mutex + * before the map is altered. The map entry, in turn, will alter + * the underlying map object. The operation is undefined if the + * remove() method of the iterator has been called + * beforehand. + * + * @param value the new value to store + * @return the old value + * @throws UnsupportedOperationException if the operation is not supported. + * @throws ClassCastException if the value is of the wrong type. + * @throws IllegalArgumentException if something about the value + * prevents it from existing in this map. + * @throws NullPointerException if the map forbids null values. + */ + public Object setValue(Object value) + { + synchronized (mutex) + { + return e.setValue(value); + } + } + + /** + * Returns a textual representation of the underlying map entry. + * A lock is obtained on the mutex before the entry is accessed. + * + * @return The contents of the map entry in String form. + */ + public String toString() + { + synchronized (mutex) + { + return e.toString(); + } + } + } // class SynchronizedMapEntry + + // Now the actual code. + if (entries == null) + synchronized (mutex) + { + entries = new SynchronizedSet(mutex, m.entrySet()) + { + /** + * Returns an iterator over the set. The iterator has no specific order, + * unless further specified. A lock is obtained on the set's mutex + * before the iterator is created. The created iterator is also + * thread-safe. + * + * @return A synchronized set iterator. + */ + public Iterator iterator() + { + synchronized (super.mutex) + { + return new SynchronizedIterator(super.mutex, c.iterator()) + { + /** + * Retrieves the next map entry from the iterator. + * A lock is obtained on the iterator's mutex before + * the entry is created. The new map entry is enclosed in + * a thread-safe wrapper. + * + * @return A synchronized map entry. + */ + public Object next() + { + synchronized (super.mutex) + { + return new SynchronizedMapEntry(super.next()); + } + } + }; + } + } + }; + } + return entries; + } + + /** + * Returns true if the object, o, is also an instance + * of Map and contains an equivalent + * entry set to that of the underlying map. A lock + * is obtained on the mutex before the objects are + * compared. + * + * @param o The object to compare. + * @return true if o and the underlying map are equivalent. + */ + public boolean equals(Object o) + { + synchronized (mutex) + { + return m.equals(o); + } + } + + /** + * Returns the value associated with the given key, or null + * if no such mapping exists. An ambiguity exists with maps + * that accept null values as a return value of null could + * be due to a non-existent mapping or simply a null value + * for that key. To resolve this, containsKey + * should be used. A lock is obtained on the mutex before + * the value is retrieved from the underlying map. + * + * @param key The key of the required mapping. + * @return The value associated with the given key, or + * null if no such mapping exists. + * @throws ClassCastException if the key is an inappropriate type. + * @throws NullPointerException if this map does not accept null keys. + */ + public Object get(Object key) + { + synchronized (mutex) + { + return m.get(key); + } + } + + /** + * Calculates the hash code of the underlying map as the + * sum of the hash codes of all entries. A lock is obtained + * on the mutex before the hash code is computed. + * + * @return The hash code of the underlying map. + */ + public int hashCode() + { + synchronized (mutex) + { + return m.hashCode(); + } + } + + /** + * Returns true if the underlying map contains no entries. + * A lock is obtained on the mutex before the map is examined. + * + * @return true if the map is empty. + */ + public boolean isEmpty() + { + synchronized (mutex) + { + return m.isEmpty(); + } + } + + /** + * Returns a thread-safe set view of the keys in the underlying map. The + * set is backed by the map, so that changes in one show up in the other. + * Modifications made while an iterator is in progress cause undefined + * behavior. If the set supports removal, these methods remove the + * underlying mapping from the map: Iterator.remove, + * Set.remove, removeAll, retainAll, + * and clear. Element addition, via add or + * addAll, is not supported via this set. A lock is obtained + * on the mutex before the set is created. + * + * @return A synchronized set containing the keys of the underlying map. + */ + public Set keySet() + { + if (keys == null) + synchronized (mutex) + { + keys = new SynchronizedSet(mutex, m.keySet()); + } + return keys; + } + + /** + * Associates the given key to the given value (optional operation). If the + * underlying map already contains the key, its value is replaced. Be aware + * that in a map that permits null values, a null return does not + * always imply that the mapping was created. A lock is obtained on the mutex + * before the modification is made. + * + * @param key the key to map. + * @param value the value to be mapped. + * @return the previous value of the key, or null if there was no mapping + * @throws UnsupportedOperationException if the operation is not supported + * @throws ClassCastException if the key or value is of the wrong type + * @throws IllegalArgumentException if something about this key or value + * prevents it from existing in this map + * @throws NullPointerException if either the key or the value is null, + * and the map forbids null keys or values + * @see #containsKey(Object) + */ + public Object put(Object key, Object value) + { + synchronized (mutex) + { + return m.put(key, value); + } + } + + /** + * Copies all entries of the given map to the underlying one (optional + * operation). If the map already contains a key, its value is replaced. + * A lock is obtained on the mutex before the operation proceeds. + * + * @param map the mapping to load into this map + * @throws UnsupportedOperationException if the operation is not supported + * @throws ClassCastException if a key or value is of the wrong type + * @throws IllegalArgumentException if something about a key or value + * prevents it from existing in this map + * @throws NullPointerException if the map forbids null keys or values, or + * if m is null. + * @see #put(Object, Object) + */ + public void putAll(Map map) + { + synchronized (mutex) + { + m.putAll(map); + } + } + + /** + * Removes the mapping for the key, o, if present (optional operation). If + * the key is not present, this returns null. Note that maps which permit + * null values may also return null if the key was removed. A prior + * containsKey() check is required to avoid this ambiguity. + * Before the mapping is removed, a lock is obtained on the mutex. + * + * @param o the key to remove + * @return the value the key mapped to, or null if not present + * @throws UnsupportedOperationException if deletion is unsupported + * @throws NullPointerException if the key is null and this map doesn't + * support null keys. + * @throws ClassCastException if the type of the key is not a valid type + * for this map. + */ + public Object remove(Object o) + { + synchronized (mutex) + { + return m.remove(o); + } + } + + /** + * Retrieves the size of the underlying map. A lock + * is obtained on the mutex before access takes place. + * Maps with a size greater than Integer.MAX_VALUE + * return Integer.MAX_VALUE instead. + * + * @return The size of the underlying map. + */ + public int size() + { + synchronized (mutex) + { + return m.size(); + } + } + + /** + * Returns a textual representation of the underlying + * map. A lock is obtained on the mutex before the map + * is accessed. + * + * @return The map in String form. + */ + public String toString() + { + synchronized (mutex) + { + return m.toString(); + } + } + + /** + * Returns a synchronized collection view of the values in the underlying + * map. The collection is backed by the map, so that changes in one show up in + * the other. Modifications made while an iterator is in progress cause + * undefined behavior. If the collection supports removal, these methods + * remove the underlying mapping from the map: Iterator.remove, + * Collection.remove, removeAll, + * retainAll, and clear. Element addition, via + * add or addAll, is not supported via this + * collection. A lock is obtained on the mutex before the collection + * is created. + * + * @return the collection of all values in the underlying map. + */ + public Collection values() + { + if (values == null) + synchronized (mutex) + { + values = new SynchronizedCollection(mutex, m.values()); + } + return values; + } + } // class SynchronizedMap + + /** + * Returns a synchronized (thread-safe) set wrapper backed by the given + * set. Notice that element access through the iterator is thread-safe, but + * if the set can be structurally modified (adding or removing elements) + * then you should synchronize around the iteration to avoid + * non-deterministic behavior:
    + *

    +   * Set s = Collections.synchronizedSet(new Set(...));
    +   * ...
    +   * synchronized (s)
    +   *   {
    +   *     Iterator i = s.iterator();
    +   *     while (i.hasNext())
    +   *       foo(i.next());
    +   *   }
    +   * 

    + * + * The returned Set implements Serializable, but can only be serialized if + * the set it wraps is likewise Serializable. + * + * @param s the set to wrap + * @return a synchronized view of the set + * @see Serializable + */ + public static Set synchronizedSet(Set s) + { + return new SynchronizedSet(s); + } + + /** + * The implementation of {@link #synchronizedSet(Set)}. This class + * name is required for compatibility with Sun's JDK serializability. + * Package visible, so that sets such as Hashtable.keySet() + * can specify which object to synchronize on. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + static class SynchronizedSet extends SynchronizedCollection + implements Set + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 487447009682186044L; + + /** + * Wrap a given set. + * @param s the set to wrap + * @throws NullPointerException if s is null + */ + SynchronizedSet(Set s) + { + super(s); + } + + /** + * Called only by trusted code to specify the mutex as well as the set. + * @param sync the mutex + * @param s the set + */ + SynchronizedSet(Object sync, Set s) + { + super(sync, s); + } + + /** + * Returns true if the object, o, is a Set + * of the same size as the underlying set, and contains + * each element, e, which occurs in the underlying set. + * A lock is obtained on the mutex before the comparison + * takes place. + * + * @param o The object to compare against. + * @return true if o is an equivalent set. + */ + public boolean equals(Object o) + { + synchronized (mutex) + { + return c.equals(o); + } + } + + /** + * Computes the hash code for the underlying set as the + * sum of the hash code of all elements within the set. + * A lock is obtained on the mutex before the computation + * occurs. + * + * @return The hash code for the underlying set. + */ + public int hashCode() + { + synchronized (mutex) + { + return c.hashCode(); + } + } + } // class SynchronizedSet + + /** + * Returns a synchronized (thread-safe) sorted map wrapper backed by the + * given map. Notice that element access through the collection views, + * subviews, and their iterators are thread-safe, but if the map can be + * structurally modified (adding or removing elements) then you should + * synchronize around the iteration to avoid non-deterministic behavior:
    + *

    +   * SortedMap m = Collections.synchronizedSortedMap(new SortedMap(...));
    +   * ...
    +   * Set s = m.keySet(); // safe outside a synchronized block
    +   * SortedMap m2 = m.headMap(foo); // safe outside a synchronized block
    +   * Set s2 = m2.keySet(); // safe outside a synchronized block
    +   * synchronized (m) // synch on m, not m2, s or s2
    +   *   {
    +   *     Iterator i = s.iterator();
    +   *     while (i.hasNext())
    +   *       foo(i.next());
    +   *     i = s2.iterator();
    +   *     while (i.hasNext())
    +   *       bar(i.next());
    +   *   }
    +   * 

    + * + * The returned SortedMap implements Serializable, but can only be + * serialized if the map it wraps is likewise Serializable. + * + * @param m the sorted map to wrap + * @return a synchronized view of the sorted map + * @see Serializable + */ + public static SortedMap synchronizedSortedMap(SortedMap m) + { + return new SynchronizedSortedMap(m); + } + + /** + * The implementation of {@link #synchronizedSortedMap(SortedMap)}. This + * class name is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class SynchronizedSortedMap extends SynchronizedMap + implements SortedMap + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -8798146769416483793L; + + /** + * The wrapped map; stored both here and in the superclass to avoid + * excessive casting. + * @serial the wrapped map + */ + private final SortedMap sm; + + /** + * Wrap a given map. + * @param sm the map to wrap + * @throws NullPointerException if sm is null + */ + SynchronizedSortedMap(SortedMap sm) + { + super(sm); + this.sm = sm; + } + + /** + * Called only by trusted code to specify the mutex as well as the map. + * @param sync the mutex + * @param sm the map + */ + SynchronizedSortedMap(Object sync, SortedMap sm) + { + super(sync, sm); + this.sm = sm; + } + + /** + * Returns the comparator used in sorting the underlying map, or null if + * it is the keys' natural ordering. A lock is obtained on the mutex + * before the comparator is retrieved. + * + * @return the sorting comparator. + */ + public Comparator comparator() + { + synchronized (mutex) + { + return sm.comparator(); + } + } + + /** + * Returns the first, lowest sorted, key from the underlying map. + * A lock is obtained on the mutex before the map is accessed. + * + * @return the first key. + * @throws NoSuchElementException if this map is empty. + */ + public Object firstKey() + { + synchronized (mutex) + { + return sm.firstKey(); + } + } + + /** + * Returns a submap containing the keys from the first + * key (as returned by firstKey()) to + * the key before that specified. The submap supports all + * operations supported by the underlying map and all actions + * taking place on the submap are also reflected in the underlying + * map. A lock is obtained on the mutex prior to submap creation. + * This operation is equivalent to subMap(firstKey(), toKey). + * The submap retains the thread-safe status of this map. + * + * @param toKey the exclusive upper range of the submap. + * @return a submap from firstKey() to the + * the key preceding toKey. + * @throws ClassCastException if toKey is not comparable to the underlying + * map's contents. + * @throws IllegalArgumentException if toKey is outside the map's range. + * @throws NullPointerException if toKey is null. but the map does not allow + * null keys. + */ + public SortedMap headMap(Object toKey) + { + synchronized (mutex) + { + return new SynchronizedSortedMap(mutex, sm.headMap(toKey)); + } + } + + /** + * Returns the last, highest sorted, key from the underlying map. + * A lock is obtained on the mutex before the map is accessed. + * + * @return the last key. + * @throws NoSuchElementException if this map is empty. + */ + public Object lastKey() + { + synchronized (mutex) + { + return sm.lastKey(); + } + } + + /** + * Returns a submap containing the keys from fromKey to + * the key before toKey. The submap supports all + * operations supported by the underlying map and all actions + * taking place on the submap are also reflected in the underlying + * map. A lock is obtained on the mutex prior to submap creation. + * The submap retains the thread-safe status of this map. + * + * @param fromKey the inclusive lower range of the submap. + * @param toKey the exclusive upper range of the submap. + * @return a submap from fromKey to the key preceding toKey. + * @throws ClassCastException if fromKey or toKey is not comparable + * to the underlying map's contents. + * @throws IllegalArgumentException if fromKey or toKey is outside the map's + * range. + * @throws NullPointerException if fromKey or toKey is null. but the map does + * not allow null keys. + */ + public SortedMap subMap(Object fromKey, Object toKey) + { + synchronized (mutex) + { + return new SynchronizedSortedMap(mutex, sm.subMap(fromKey, toKey)); + } + } + + /** + * Returns a submap containing all the keys from fromKey onwards. + * The submap supports all operations supported by the underlying + * map and all actions taking place on the submap are also reflected + * in the underlying map. A lock is obtained on the mutex prior to + * submap creation. The submap retains the thread-safe status of + * this map. + * + * @param fromKey the inclusive lower range of the submap. + * @return a submap from fromKey to lastKey(). + * @throws ClassCastException if fromKey is not comparable to the underlying + * map's contents. + * @throws IllegalArgumentException if fromKey is outside the map's range. + * @throws NullPointerException if fromKey is null. but the map does not allow + * null keys. + */ + public SortedMap tailMap(Object fromKey) + { + synchronized (mutex) + { + return new SynchronizedSortedMap(mutex, sm.tailMap(fromKey)); + } + } + } // class SynchronizedSortedMap + + /** + * Returns a synchronized (thread-safe) sorted set wrapper backed by the + * given set. Notice that element access through the iterator and through + * subviews are thread-safe, but if the set can be structurally modified + * (adding or removing elements) then you should synchronize around the + * iteration to avoid non-deterministic behavior:
    + *

    +   * SortedSet s = Collections.synchronizedSortedSet(new SortedSet(...));
    +   * ...
    +   * SortedSet s2 = s.headSet(foo); // safe outside a synchronized block
    +   * synchronized (s) // synch on s, not s2
    +   *   {
    +   *     Iterator i = s2.iterator();
    +   *     while (i.hasNext())
    +   *       foo(i.next());
    +   *   }
    +   * 

    + * + * The returned SortedSet implements Serializable, but can only be + * serialized if the set it wraps is likewise Serializable. + * + * @param s the sorted set to wrap + * @return a synchronized view of the sorted set + * @see Serializable + */ + public static SortedSet synchronizedSortedSet(SortedSet s) + { + return new SynchronizedSortedSet(s); + } + + /** + * The implementation of {@link #synchronizedSortedSet(SortedSet)}. This + * class name is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class SynchronizedSortedSet extends SynchronizedSet + implements SortedSet + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 8695801310862127406L; + + /** + * The wrapped set; stored both here and in the superclass to avoid + * excessive casting. + * @serial the wrapped set + */ + private final SortedSet ss; + + /** + * Wrap a given set. + * @param ss the set to wrap + * @throws NullPointerException if ss is null + */ + SynchronizedSortedSet(SortedSet ss) + { + super(ss); + this.ss = ss; + } + + /** + * Called only by trusted code to specify the mutex as well as the set. + * @param sync the mutex + * @param l the list + */ + SynchronizedSortedSet(Object sync, SortedSet ss) + { + super(sync, ss); + this.ss = ss; + } + + /** + * Returns the comparator used in sorting the underlying set, or null if + * it is the elements' natural ordering. A lock is obtained on the mutex + * before the comparator is retrieved. + * + * @return the sorting comparator. + */ + public Comparator comparator() + { + synchronized (mutex) + { + return ss.comparator(); + } + } + + /** + * Returns the first, lowest sorted, element from the underlying set. + * A lock is obtained on the mutex before the set is accessed. + * + * @return the first element. + * @throws NoSuchElementException if this set is empty. + */ + public Object first() + { + synchronized (mutex) + { + return ss.first(); + } + } + + /** + * Returns a subset containing the element from the first + * element (as returned by first()) to + * the element before that specified. The subset supports all + * operations supported by the underlying set and all actions + * taking place on the subset are also reflected in the underlying + * set. A lock is obtained on the mutex prior to subset creation. + * This operation is equivalent to subSet(first(), toElement). + * The subset retains the thread-safe status of this set. + * + * @param toElement the exclusive upper range of the subset. + * @return a subset from first() to the + * the element preceding toElement. + * @throws ClassCastException if toElement is not comparable to the underlying + * set's contents. + * @throws IllegalArgumentException if toElement is outside the set's range. + * @throws NullPointerException if toElement is null. but the set does not allow + * null elements. + */ + public SortedSet headSet(Object toElement) + { + synchronized (mutex) + { + return new SynchronizedSortedSet(mutex, ss.headSet(toElement)); + } + } + + /** + * Returns the last, highest sorted, element from the underlying set. + * A lock is obtained on the mutex before the set is accessed. + * + * @return the last element. + * @throws NoSuchElementException if this set is empty. + */ + public Object last() + { + synchronized (mutex) + { + return ss.last(); + } + } + + /** + * Returns a subset containing the elements from fromElement to + * the element before toElement. The subset supports all + * operations supported by the underlying set and all actions + * taking place on the subset are also reflected in the underlying + * set. A lock is obtained on the mutex prior to subset creation. + * The subset retains the thread-safe status of this set. + * + * @param fromElement the inclusive lower range of the subset. + * @param toElement the exclusive upper range of the subset. + * @return a subset from fromElement to the element preceding toElement. + * @throws ClassCastException if fromElement or toElement is not comparable + * to the underlying set's contents. + * @throws IllegalArgumentException if fromElement or toElement is outside the set's + * range. + * @throws NullPointerException if fromElement or toElement is null. but the set does + * not allow null elements. + */ + public SortedSet subSet(Object fromElement, Object toElement) + { + synchronized (mutex) + { + return new SynchronizedSortedSet(mutex, + ss.subSet(fromElement, toElement)); + } + } + + /** + * Returns a subset containing all the elements from fromElement onwards. + * The subset supports all operations supported by the underlying + * set and all actions taking place on the subset are also reflected + * in the underlying set. A lock is obtained on the mutex prior to + * subset creation. The subset retains the thread-safe status of + * this set. + * + * @param fromElement the inclusive lower range of the subset. + * @return a subset from fromElement to last(). + * @throws ClassCastException if fromElement is not comparable to the underlying + * set's contents. + * @throws IllegalArgumentException if fromElement is outside the set's range. + * @throws NullPointerException if fromElement is null. but the set does not allow + * null elements. + */ + public SortedSet tailSet(Object fromElement) + { + synchronized (mutex) + { + return new SynchronizedSortedSet(mutex, ss.tailSet(fromElement)); + } + } + } // class SynchronizedSortedSet + + + /** + * Returns an unmodifiable view of the given collection. This allows + * "read-only" access, although changes in the backing collection show up + * in this view. Attempts to modify the collection directly or via iterators + * will fail with {@link UnsupportedOperationException}. Although this view + * prevents changes to the structure of the collection and its elements, the values + * referenced by the objects in the collection can still be modified. + *

    + * + * Since the collection might be a List or a Set, and those have incompatible + * equals and hashCode requirements, this relies on Object's implementation + * rather than passing those calls on to the wrapped collection. The returned + * Collection implements Serializable, but can only be serialized if + * the collection it wraps is likewise Serializable. + * + * @param c the collection to wrap + * @return a read-only view of the collection + * @see Serializable + */ + public static Collection unmodifiableCollection(Collection c) + { + return new UnmodifiableCollection(c); + } + + /** + * The implementation of {@link #unmodifiableCollection(Collection)}. This + * class name is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class UnmodifiableCollection + implements Collection, Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 1820017752578914078L; + + /** + * The wrapped collection. Package visible for use by subclasses. + * @serial the real collection + */ + final Collection c; + + /** + * Wrap a given collection. + * @param c the collection to wrap + * @throws NullPointerException if c is null + */ + UnmodifiableCollection(Collection c) + { + this.c = c; + if (c == null) + throw new NullPointerException(); + } + + /** + * Blocks the addition of elements to the underlying collection. + * This method never returns, throwing an exception instead. + * + * @param o the object to add. + * @return true if the collection was modified as a result of this action. + * @throws UnsupportedOperationException as an unmodifiable collection does not + * support the add operation. + */ + public boolean add(Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * Blocks the addition of a collection of elements to the underlying + * collection. This method never returns, throwing an exception instead. + * + * @param c the collection to add. + * @return true if the collection was modified as a result of this action. + * @throws UnsupportedOperationException as an unmodifiable collection does not + * support the addAll operation. + */ + public boolean addAll(Collection c) + { + throw new UnsupportedOperationException(); + } + + /** + * Blocks the clearing of the underlying collection. This method never + * returns, throwing an exception instead. + * + * @throws UnsupportedOperationException as an unmodifiable collection does + * not support the clear() operation. + */ + public void clear() + { + throw new UnsupportedOperationException(); + } + + /** + * Test whether the underlying collection contains a given object as one of its + * elements. + * + * @param o the element to look for. + * @return true if the underlying collection contains at least + * one element e such that + * o == null ? e == null : o.equals(e). + * @throws ClassCastException if the type of o is not a valid type for the + * underlying collection. + * @throws NullPointerException if o is null and the underlying collection + * doesn't support null values. + */ + public boolean contains(Object o) + { + return c.contains(o); + } + + /** + * Test whether the underlying collection contains every element in a given + * collection. + * + * @param c1 the collection to test for. + * @return true if for every element o in c, contains(o) would + * return true. + * @throws ClassCastException if the type of any element in c is not a valid + * type for the underlying collection. + * @throws NullPointerException if some element of c is null and the underlying + * collection does not support null values. + * @throws NullPointerException if c itself is null. + */ + public boolean containsAll(Collection c1) + { + return c.containsAll(c1); + } + + /** + * Tests whether the underlying collection is empty, that is, + * if size() == 0. + * + * @return true if this collection contains no elements. + */ + public boolean isEmpty() + { + return c.isEmpty(); + } + + /** + * Obtain an Iterator over the underlying collection, which maintains + * its unmodifiable nature. + * + * @return an UnmodifiableIterator over the elements of the underlying + * collection, in any order. + */ + public Iterator iterator() + { + return new UnmodifiableIterator(c.iterator()); + } + + /** + * Blocks the removal of an object from the underlying collection. + * This method never returns, throwing an exception instead. + * + * @param o The object to remove. + * @return true if the object was removed (i.e. the underlying + * collection returned 1 or more instances of o). + * @throws UnsupportedOperationException as an unmodifiable collection + * does not support the remove() operation. + */ + public boolean remove(Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * Blocks the removal of a collection of objects from the underlying + * collection. This method never returns, throwing an exception + * instead. + * + * @param c The collection of objects to remove. + * @return true if the collection was modified. + * @throws UnsupportedOperationException as an unmodifiable collection + * does not support the removeAll() operation. + */ + public boolean removeAll(Collection c) + { + throw new UnsupportedOperationException(); + } + + /** + * Blocks the removal of all elements from the underlying collection, + * except those in the supplied collection. This method never returns, + * throwing an exception instead. + * + * @param c The collection of objects to retain. + * @return true if the collection was modified. + * @throws UnsupportedOperationException as an unmodifiable collection + * does not support the retainAll() operation. + */ + public boolean retainAll(Collection c) + { + throw new UnsupportedOperationException(); + } + + /** + * Retrieves the number of elements in the underlying collection. + * + * @return the number of elements in the collection. + */ + public int size() + { + return c.size(); + } + + /** + * Copy the current contents of the underlying collection into an array. + * + * @return an array of type Object[] with a length equal to the size of the + * underlying collection and containing the elements currently in + * the underlying collection, in any order. + */ + public Object[] toArray() + { + return c.toArray(); + } + + /** + * Copy the current contents of the underlying collection into an array. If + * the array passed as an argument has length less than the size of the + * underlying collection, an array of the same run-time type as a, with a length + * equal to the size of the underlying collection, is allocated using reflection. + * Otherwise, a itself is used. The elements of the underlying collection are + * copied into it, and if there is space in the array, the following element is + * set to null. The resultant array is returned. + * Note: The fact that the following element is set to null is only useful + * if it is known that this collection does not contain any null elements. + * + * @param a the array to copy this collection into. + * @return an array containing the elements currently in the underlying + * collection, in any order. + * @throws ArrayStoreException if the type of any element of the + * collection is not a subtype of the element type of a. + */ + public Object[] toArray(Object[] a) + { + return c.toArray(a); + } + + /** + * A textual representation of the unmodifiable collection. + * + * @return The unmodifiable collection in the form of a String. + */ + public String toString() + { + return c.toString(); + } + } // class UnmodifiableCollection + + /** + * The implementation of the various iterator methods in the + * unmodifiable classes. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class UnmodifiableIterator implements Iterator + { + /** + * The wrapped iterator. + */ + private final Iterator i; + + /** + * Only trusted code creates a wrapper. + * @param i the wrapped iterator + */ + UnmodifiableIterator(Iterator i) + { + this.i = i; + } + + /** + * Obtains the next element in the underlying collection. + * + * @return the next element in the collection. + * @throws NoSuchElementException if there are no more elements. + */ + public Object next() + { + return i.next(); + } + /** + * Tests whether there are still elements to be retrieved from the + * underlying collection by next(). When this method + * returns true, an exception will not be thrown on calling + * next(). + * + * @return true if there is at least one more element in the underlying + * collection. + */ + public boolean hasNext() + { + return i.hasNext(); + } + + /** + * Blocks the removal of elements from the underlying collection by the + * iterator. + * + * @throws UnsupportedOperationException as an unmodifiable collection + * does not support the removal of elements by its iterator. + */ + public void remove() + { + throw new UnsupportedOperationException(); + } + } // class UnmodifiableIterator + + /** + * Returns an unmodifiable view of the given list. This allows + * "read-only" access, although changes in the backing list show up + * in this view. Attempts to modify the list directly, via iterators, or + * via sublists, will fail with {@link UnsupportedOperationException}. + * Although this view prevents changes to the structure of the list and + * its elements, the values referenced by the objects in the list can + * still be modified. + *

    + * + * The returned List implements Serializable, but can only be serialized if + * the list it wraps is likewise Serializable. In addition, if the wrapped + * list implements RandomAccess, this does too. + * + * @param l the list to wrap + * @return a read-only view of the list + * @see Serializable + * @see RandomAccess + */ + public static List unmodifiableList(List l) + { + if (l instanceof RandomAccess) + return new UnmodifiableRandomAccessList(l); + return new UnmodifiableList(l); + } + + /** + * The implementation of {@link #unmodifiableList(List)} for sequential + * lists. This class name is required for compatibility with Sun's JDK + * serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class UnmodifiableList extends UnmodifiableCollection + implements List + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -283967356065247728L; + + + /** + * The wrapped list; stored both here and in the superclass to avoid + * excessive casting. Package visible for use by subclass. + * @serial the wrapped list + */ + final List list; + + /** + * Wrap a given list. + * @param l the list to wrap + * @throws NullPointerException if l is null + */ + UnmodifiableList(List l) + { + super(l); + list = l; + } + + /** + * Blocks the addition of an element to the underlying + * list at a specific index. This method never returns, + * throwing an exception instead. + * + * @param index The index at which to place the new element. + * @param o the object to add. + * @throws UnsupportedOperationException as an unmodifiable + * list doesn't support the add() operation. + */ + public void add(int index, Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * Blocks the addition of a collection of elements to the + * underlying list at a specific index. This method never + * returns, throwing an exception instead. + * + * @param index The index at which to place the new element. + * @param c the collections of objects to add. + * @throws UnsupportedOperationException as an unmodifiable + * list doesn't support the addAll() operation. + */ + public boolean addAll(int index, Collection c) + { + throw new UnsupportedOperationException(); + } + + /** + * Returns true if the object, o, is an instance of + * List with the same size and elements + * as the underlying list. + * + * @param o The object to compare. + * @return true if o is equivalent to the underlying list. + */ + public boolean equals(Object o) + { + return list.equals(o); + } + + /** + * Retrieves the element at a given index in the underlying list. + * + * @param index the index of the element to be returned + * @return the element at index index in this list + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object get(int index) + { + return list.get(index); + } + + /** + * Computes the hash code for the underlying list. + * The exact computation is described in the documentation + * of the List interface. + * + * @return The hash code of the underlying list. + * @see List#hashCode() + */ + public int hashCode() + { + return list.hashCode(); + } + + /** + * Obtain the first index at which a given object is to be found in the + * underlying list. + * + * @param o the object to search for + * @return the least integer n such that o == null ? get(n) == null : + * o.equals(get(n)), or -1 if there is no such index. + * @throws ClassCastException if the type of o is not a valid + * type for the underlying list. + * @throws NullPointerException if o is null and the underlying + * list does not support null values. + */ + public int indexOf(Object o) + { + return list.indexOf(o); + } + + /** + * Obtain the last index at which a given object is to be found in the + * underlying list. + * + * @return the greatest integer n such that o == null ? get(n) == null + * : o.equals(get(n)), or -1 if there is no such index. + * @throws ClassCastException if the type of o is not a valid + * type for the underlying list. + * @throws NullPointerException if o is null and the underlying + * list does not support null values. + */ + public int lastIndexOf(Object o) + { + return list.lastIndexOf(o); + } + + /** + * Obtains a list iterator over the underlying list, starting at the beginning + * and maintaining the unmodifiable nature of this list. + * + * @return a UnmodifiableListIterator over the elements of the + * underlying list, in order, starting at the beginning. + */ + public ListIterator listIterator() + { + return new UnmodifiableListIterator(list.listIterator()); + } + + /** + * Obtains a list iterator over the underlying list, starting at the specified + * index and maintaining the unmodifiable nature of this list. An initial call + * to next() will retrieve the element at the specified index, + * and an initial call to previous() will retrieve the element + * at index - 1. + * + * + * @param index the position, between 0 and size() inclusive, to begin the + * iteration from. + * @return a UnmodifiableListIterator over the elements of the + * underlying list, in order, starting at the specified index. + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + public ListIterator listIterator(int index) + { + return new UnmodifiableListIterator(list.listIterator(index)); + } + + /** + * Blocks the removal of the element at the specified index. + * This method never returns, throwing an exception instead. + * + * @param index The index of the element to remove. + * @return the removed element. + * @throws UnsupportedOperationException as an unmodifiable + * list does not support the remove() + * operation. + */ + public Object remove(int index) + { + throw new UnsupportedOperationException(); + } + + /** + * Blocks the replacement of the element at the specified index. + * This method never returns, throwing an exception instead. + * + * @param index The index of the element to replace. + * @param o The new object to place at the specified index. + * @return the replaced element. + * @throws UnsupportedOperationException as an unmodifiable + * list does not support the set() + * operation. + */ + public Object set(int index, Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * Obtain a List view of a subsection of the underlying list, from + * fromIndex (inclusive) to toIndex (exclusive). If the two indices + * are equal, the sublist is empty. The returned list will be + * unmodifiable, like this list. Changes to the elements of the + * returned list will be reflected in the underlying list. No structural + * modifications can take place in either list. + * + * @param fromIndex the index that the returned list should start from + * (inclusive). + * @param toIndex the index that the returned list should go to (exclusive). + * @return a List backed by a subsection of the underlying list. + * @throws IndexOutOfBoundsException if fromIndex < 0 + * || toIndex > size() || fromIndex > toIndex. + */ + public List subList(int fromIndex, int toIndex) + { + return unmodifiableList(list.subList(fromIndex, toIndex)); + } + } // class UnmodifiableList + + /** + * The implementation of {@link #unmodifiableList(List)} for random-access + * lists. This class name is required for compatibility with Sun's JDK + * serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class UnmodifiableRandomAccessList + extends UnmodifiableList implements RandomAccess + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -2542308836966382001L; + + /** + * Wrap a given list. + * @param l the list to wrap + * @throws NullPointerException if l is null + */ + UnmodifiableRandomAccessList(List l) + { + super(l); + } + } // class UnmodifiableRandomAccessList + + /** + * The implementation of {@link UnmodifiableList#listIterator()}. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class UnmodifiableListIterator + extends UnmodifiableIterator implements ListIterator + { + /** + * The wrapped iterator, stored both here and in the superclass to + * avoid excessive casting. + */ + private final ListIterator li; + + /** + * Only trusted code creates a wrapper. + * @param li the wrapped iterator + */ + UnmodifiableListIterator(ListIterator li) + { + super(li); + this.li = li; + } + + /** + * Blocks the addition of an object to the list underlying this iterator. + * This method never returns, throwing an exception instead. + * + * @param o The object to add. + * @throws UnsupportedOperationException as the iterator of an unmodifiable + * list does not support the add() operation. + */ + public void add(Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * Tests whether there are still elements to be retrieved from the + * underlying collection by previous(). When this method + * returns true, an exception will not be thrown on calling + * previous(). + * + * @return true if there is at least one more element prior to the + * current position in the underlying list. + */ + public boolean hasPrevious() + { + return li.hasPrevious(); + } + + /** + * Find the index of the element that would be returned by a call to next. + * If hasNext() returns false, this returns the list size. + * + * @return the index of the element that would be returned by + * next(). + */ + public int nextIndex() + { + return li.nextIndex(); + } + + /** + * Obtains the previous element in the underlying list. + * + * @return the previous element in the list. + * @throws NoSuchElementException if there are no more prior elements. + */ + public Object previous() + { + return li.previous(); + } + + /** + * Find the index of the element that would be returned by a call to + * previous. If hasPrevious() returns false, + * this returns -1. + * + * @return the index of the element that would be returned by + * previous(). + */ + public int previousIndex() + { + return li.previousIndex(); + } + + /** + * Blocks the replacement of an element in the list underlying this + * iterator. This method never returns, throwing an exception instead. + * + * @param o The new object to replace the existing one. + * @throws UnsupportedOperationException as the iterator of an unmodifiable + * list does not support the set() operation. + */ + public void set(Object o) + { + throw new UnsupportedOperationException(); + } + } // class UnmodifiableListIterator + + /** + * Returns an unmodifiable view of the given map. This allows "read-only" + * access, although changes in the backing map show up in this view. + * Attempts to modify the map directly, or via collection views or their + * iterators will fail with {@link UnsupportedOperationException}. + * Although this view prevents changes to the structure of the map and its + * entries, the values referenced by the objects in the map can still be + * modified. + *

    + * + * The returned Map implements Serializable, but can only be serialized if + * the map it wraps is likewise Serializable. + * + * @param m the map to wrap + * @return a read-only view of the map + * @see Serializable + */ + public static Map unmodifiableMap(Map m) + { + return new UnmodifiableMap(m); + } + + /** + * The implementation of {@link #unmodifiableMap(Map)}. This + * class name is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class UnmodifiableMap implements Map, Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -1034234728574286014L; + + /** + * The wrapped map. + * @serial the real map + */ + private final Map m; + + /** + * Cache the entry set. + */ + private transient Set entries; + + /** + * Cache the key set. + */ + private transient Set keys; + + /** + * Cache the value collection. + */ + private transient Collection values; + + /** + * Wrap a given map. + * @param m the map to wrap + * @throws NullPointerException if m is null + */ + UnmodifiableMap(Map m) + { + this.m = m; + if (m == null) + throw new NullPointerException(); + } + + /** + * Blocks the clearing of entries from the underlying map. + * This method never returns, throwing an exception instead. + * + * @throws UnsupportedOperationException as an unmodifiable + * map does not support the clear() operation. + */ + public void clear() + { + throw new UnsupportedOperationException(); + } + + /** + * Returns true if the underlying map contains a mapping for + * the given key. + * + * @param key the key to search for + * @return true if the map contains the key + * @throws ClassCastException if the key is of an inappropriate type + * @throws NullPointerException if key is null but the map + * does not permit null keys + */ + public boolean containsKey(Object key) + { + return m.containsKey(key); + } + + /** + * Returns true if the underlying map contains at least one mapping with + * the given value. In other words, it returns true if a value v exists where + * (value == null ? v == null : value.equals(v)). This usually + * requires linear time. + * + * @param value the value to search for + * @return true if the map contains the value + * @throws ClassCastException if the type of the value is not a valid type + * for this map. + * @throws NullPointerException if the value is null and the map doesn't + * support null values. + */ + public boolean containsValue(Object value) + { + return m.containsValue(value); + } + + /** + * Returns a unmodifiable set view of the entries in the underlying map. + * Each element in the set is a unmodifiable variant of Map.Entry. + * The set is backed by the map, so that changes in one show up in the other. + * Modifications made while an iterator is in progress cause undefined + * behavior. These modifications are again limited to the values of + * the objects. + * + * @return the unmodifiable set view of all mapping entries. + * @see Map.Entry + */ + public Set entrySet() + { + if (entries == null) + entries = new UnmodifiableEntrySet(m.entrySet()); + return entries; + } + + /** + * The implementation of {@link UnmodifiableMap#entrySet()}. This class + * name is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class UnmodifiableEntrySet extends UnmodifiableSet + implements Serializable + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 7854390611657943733L; + + /** + * Wrap a given set. + * @param s the set to wrap + */ + UnmodifiableEntrySet(Set s) + { + super(s); + } + + // The iterator must return unmodifiable map entries. + public Iterator iterator() + { + return new UnmodifiableIterator(c.iterator()) + { + /** + * Obtains the next element from the underlying set of + * map entries. + * + * @return the next element in the collection. + * @throws NoSuchElementException if there are no more elements. + */ + public Object next() + { + final Map.Entry e = (Map.Entry) super.next(); + return new Map.Entry() + { + /** + * Returns true if the object, o, is also a map entry with an + * identical key and value. + * + * @param o the object to compare. + * @return true if o is an equivalent map entry. + */ + public boolean equals(Object o) + { + return e.equals(o); + } + + /** + * Returns the key of this map entry. + * + * @return the key. + */ + public Object getKey() + { + return e.getKey(); + } + + /** + * Returns the value of this map entry. + * + * @return the value. + */ + public Object getValue() + { + return e.getValue(); + } + + /** + * Computes the hash code of this map entry. + * The computation is described in the Map + * interface documentation. + * + * @return the hash code of this entry. + * @see Map#hashCode() + */ + public int hashCode() + { + return e.hashCode(); + } + + /** + * Blocks the alteration of the value of this map entry. + * This method never returns, throwing an exception instead. + * + * @param value The new value. + * @throws UnsupportedOperationException as an unmodifiable + * map entry does not support the setValue() + * operation. + */ + public Object setValue(Object value) + { + throw new UnsupportedOperationException(); + } + + /** + * Returns a textual representation of the map entry. + * + * @return The map entry as a String. + */ + public String toString() + { + return e.toString(); + } + }; + } + }; + } + } // class UnmodifiableEntrySet + + /** + * Returns true if the object, o, is also an instance + * of Map with an equal set of map entries. + * + * @param o The object to compare. + * @return true if o is an equivalent map. + */ + public boolean equals(Object o) + { + return m.equals(o); + } + + /** + * Returns the value associated with the supplied key or + * null if no such mapping exists. An ambiguity can occur + * if null values are accepted by the underlying map. + * In this case, containsKey() can be used + * to separate the two possible cases of a null result. + * + * @param key The key to look up. + * @return the value associated with the key, or null if key not in map. + * @throws ClassCastException if the key is an inappropriate type. + * @throws NullPointerException if this map does not accept null keys. + * @see #containsKey(Object) + */ + public Object get(Object key) + { + return m.get(key); + } + + /** + * Blocks the addition of a new entry to the underlying map. + * This method never returns, throwing an exception instead. + * + * @param key The new key. + * @param value The new value. + * @return the previous value of the key, or null if there was no mapping. + * @throws UnsupportedOperationException as an unmodifiable + * map does not support the put() operation. + */ + public Object put(Object key, Object value) + { + throw new UnsupportedOperationException(); + } + + /** + * Computes the hash code for the underlying map, as the sum + * of the hash codes of all entries. + * + * @return The hash code of the underlying map. + * @see Map.Entry#hashCode() + */ + public int hashCode() + { + return m.hashCode(); + } + + /** + * Returns true if the underlying map contains no entries. + * + * @return true if the map is empty. + */ + public boolean isEmpty() + { + return m.isEmpty(); + } + + /** + * Returns a unmodifiable set view of the keys in the underlying map. + * The set is backed by the map, so that changes in one show up in the other. + * Modifications made while an iterator is in progress cause undefined + * behavior. These modifications are again limited to the values of + * the keys. + * + * @return the set view of all keys. + */ + public Set keySet() + { + if (keys == null) + keys = new UnmodifiableSet(m.keySet()); + return keys; + } + + /** + * Blocks the addition of the entries in the supplied map. + * This method never returns, throwing an exception instead. + * + * @param m The map, the entries of which should be added + * to the underlying map. + * @throws UnsupportedOperationException as an unmodifiable + * map does not support the putAll operation. + */ + public void putAll(Map m) + { + throw new UnsupportedOperationException(); + } + + /** + * Blocks the removal of an entry from the map. + * This method never returns, throwing an exception instead. + * + * @param o The key of the entry to remove. + * @return The value the key was associated with, or null + * if no such mapping existed. Null is also returned + * if the removed entry had a null key. + * @throws UnsupportedOperationException as an unmodifiable + * map does not support the remove operation. + */ + public Object remove(Object o) + { + throw new UnsupportedOperationException(); + } + + + /** + * Returns the number of key-value mappings in the underlying map. + * If there are more than Integer.MAX_VALUE mappings, Integer.MAX_VALUE + * is returned. + * + * @return the number of mappings. + */ + public int size() + { + return m.size(); + } + + /** + * Returns a textual representation of the map. + * + * @return The map in the form of a String. + */ + public String toString() + { + return m.toString(); + } + + /** + * Returns a unmodifiable collection view of the values in the underlying map. + * The collection is backed by the map, so that changes in one show up in the other. + * Modifications made while an iterator is in progress cause undefined + * behavior. These modifications are again limited to the values of + * the keys. + * + * @return the collection view of all values. + */ + public Collection values() + { + if (values == null) + values = new UnmodifiableCollection(m.values()); + return values; + } + } // class UnmodifiableMap + + /** + * Returns an unmodifiable view of the given set. This allows + * "read-only" access, although changes in the backing set show up + * in this view. Attempts to modify the set directly or via iterators + * will fail with {@link UnsupportedOperationException}. + * Although this view prevents changes to the structure of the set and its + * entries, the values referenced by the objects in the set can still be + * modified. + *

    + * + * The returned Set implements Serializable, but can only be serialized if + * the set it wraps is likewise Serializable. + * + * @param s the set to wrap + * @return a read-only view of the set + * @see Serializable + */ + public static Set unmodifiableSet(Set s) + { + return new UnmodifiableSet(s); + } + + /** + * The implementation of {@link #unmodifiableSet(Set)}. This class + * name is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class UnmodifiableSet extends UnmodifiableCollection + implements Set + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -9215047833775013803L; + + /** + * Wrap a given set. + * @param s the set to wrap + * @throws NullPointerException if s is null + */ + UnmodifiableSet(Set s) + { + super(s); + } + + /** + * Returns true if the object, o, is also an instance of + * Set of the same size and with the same entries. + * + * @return true if o is an equivalent set. + */ + public boolean equals(Object o) + { + return c.equals(o); + } + + /** + * Computes the hash code of this set, as the sum of the + * hash codes of all elements within the set. + * + * @return the hash code of the set. + */ + public int hashCode() + { + return c.hashCode(); + } + } // class UnmodifiableSet + + /** + * Returns an unmodifiable view of the given sorted map. This allows + * "read-only" access, although changes in the backing map show up in this + * view. Attempts to modify the map directly, via subviews, via collection + * views, or iterators, will fail with {@link UnsupportedOperationException}. + * Although this view prevents changes to the structure of the map and its + * entries, the values referenced by the objects in the map can still be + * modified. + *

    + * + * The returned SortedMap implements Serializable, but can only be + * serialized if the map it wraps is likewise Serializable. + * + * @param m the map to wrap + * @return a read-only view of the map + * @see Serializable + */ + public static SortedMap unmodifiableSortedMap(SortedMap m) + { + return new UnmodifiableSortedMap(m); + } + + /** + * The implementation of {@link #unmodifiableSortedMap(SortedMap)}. This + * class name is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class UnmodifiableSortedMap extends UnmodifiableMap + implements SortedMap + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -8806743815996713206L; + + /** + * The wrapped map; stored both here and in the superclass to avoid + * excessive casting. + * @serial the wrapped map + */ + private final SortedMap sm; + + /** + * Wrap a given map. + * @param sm the map to wrap + * @throws NullPointerException if sm is null + */ + UnmodifiableSortedMap(SortedMap sm) + { + super(sm); + this.sm = sm; + } + + /** + * Returns the comparator used in sorting the underlying map, + * or null if it is the keys' natural ordering. + * + * @return the sorting comparator. + */ + public Comparator comparator() + { + return sm.comparator(); + } + + /** + * Returns the first (lowest sorted) key in the map. + * + * @return the first key. + * @throws NoSuchElementException if this map is empty. + */ + public Object firstKey() + { + return sm.firstKey(); + } + + /** + * Returns a unmodifiable view of the portion of the map strictly less + * than toKey. The view is backed by the underlying map, so changes in + * one show up in the other. The submap supports all optional operations + * of the original. This operation is equivalent to + * subMap(firstKey(), toKey). + *

    + * + * The returned map throws an IllegalArgumentException any time a key is + * used which is out of the range of toKey. Note that the endpoint, toKey, + * is not included; if you want this value to be included, pass its successor + * object in to toKey. For example, for Integers, you could request + * headMap(new Integer(limit.intValue() + 1)). + * + * @param toKey the exclusive upper range of the submap. + * @return the submap. + * @throws ClassCastException if toKey is not comparable to the map contents. + * @throws IllegalArgumentException if this is a subMap, and toKey is out + * of range. + * @throws NullPointerException if toKey is null but the map does not allow + * null keys. + */ + public SortedMap headMap(Object toKey) + { + return new UnmodifiableSortedMap(sm.headMap(toKey)); + } + + /** + * Returns the last (highest sorted) key in the map. + * + * @return the last key. + * @throws NoSuchElementException if this map is empty. + */ + public Object lastKey() + { + return sm.lastKey(); + } + + /** + * Returns a unmodifiable view of the portion of the map greater than or + * equal to fromKey, and strictly less than toKey. The view is backed by + * the underlying map, so changes in one show up in the other. The submap + * supports all optional operations of the original. + *

    + * + * The returned map throws an IllegalArgumentException any time a key is + * used which is out of the range of fromKey and toKey. Note that the + * lower endpoint is included, but the upper is not; if you want to + * change the inclusion or exclusion of an endpoint, pass its successor + * object in instead. For example, for Integers, you could request + * subMap(new Integer(lowlimit.intValue() + 1), + * new Integer(highlimit.intValue() + 1)) to reverse + * the inclusiveness of both endpoints. + * + * @param fromKey the inclusive lower range of the submap. + * @param toKey the exclusive upper range of the submap. + * @return the submap. + * @throws ClassCastException if fromKey or toKey is not comparable to + * the map contents. + * @throws IllegalArgumentException if this is a subMap, and fromKey or + * toKey is out of range. + * @throws NullPointerException if fromKey or toKey is null but the map + * does not allow null keys. + */ + public SortedMap subMap(Object fromKey, Object toKey) + { + return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey)); + } + + /** + * Returns a unmodifiable view of the portion of the map greater than or + * equal to fromKey. The view is backed by the underlying map, so changes + * in one show up in the other. The submap supports all optional operations + * of the original. + *

    + * + * The returned map throws an IllegalArgumentException any time a key is + * used which is out of the range of fromKey. Note that the endpoint, fromKey, is + * included; if you do not want this value to be included, pass its successor object in + * to fromKey. For example, for Integers, you could request + * tailMap(new Integer(limit.intValue() + 1)). + * + * @param fromKey the inclusive lower range of the submap + * @return the submap + * @throws ClassCastException if fromKey is not comparable to the map + * contents + * @throws IllegalArgumentException if this is a subMap, and fromKey is out + * of range + * @throws NullPointerException if fromKey is null but the map does not allow + * null keys + */ + public SortedMap tailMap(Object fromKey) + { + return new UnmodifiableSortedMap(sm.tailMap(fromKey)); + } + } // class UnmodifiableSortedMap + + /** + * Returns an unmodifiable view of the given sorted set. This allows + * "read-only" access, although changes in the backing set show up + * in this view. Attempts to modify the set directly, via subsets, or via + * iterators, will fail with {@link UnsupportedOperationException}. + * Although this view prevents changes to the structure of the set and its + * entries, the values referenced by the objects in the set can still be + * modified. + *

    + * + * The returns SortedSet implements Serializable, but can only be + * serialized if the set it wraps is likewise Serializable. + * + * @param s the set to wrap + * @return a read-only view of the set + * @see Serializable + */ + public static SortedSet unmodifiableSortedSet(SortedSet s) + { + return new UnmodifiableSortedSet(s); + } + + /** + * The implementation of {@link #synchronizedSortedMap(SortedMap)}. This + * class name is required for compatibility with Sun's JDK serializability. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static class UnmodifiableSortedSet extends UnmodifiableSet + implements SortedSet + { + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -4929149591599911165L; + + /** + * The wrapped set; stored both here and in the superclass to avoid + * excessive casting. + * @serial the wrapped set + */ + private SortedSet ss; + + /** + * Wrap a given set. + * @param ss the set to wrap + * @throws NullPointerException if ss is null + */ + UnmodifiableSortedSet(SortedSet ss) + { + super(ss); + this.ss = ss; + } + + /** + * Returns the comparator used in sorting the underlying set, + * or null if it is the elements' natural ordering. + * + * @return the sorting comparator + */ + public Comparator comparator() + { + return ss.comparator(); + } + + /** + * Returns the first (lowest sorted) element in the underlying + * set. + * + * @return the first element. + * @throws NoSuchElementException if the set is empty. + */ + public Object first() + { + return ss.first(); + } + + /** + * Returns a unmodifiable view of the portion of the set strictly + * less than toElement. The view is backed by the underlying set, + * so changes in one show up in the other. The subset supports + * all optional operations of the original. This operation + * is equivalent to subSet(first(), toElement). + *

    + * + * The returned set throws an IllegalArgumentException any time an element is + * used which is out of the range of toElement. Note that the endpoint, toElement, + * is not included; if you want this value included, pass its successor object in to + * toElement. For example, for Integers, you could request + * headSet(new Integer(limit.intValue() + 1)). + * + * @param toElement the exclusive upper range of the subset + * @return the subset. + * @throws ClassCastException if toElement is not comparable to the set + * contents. + * @throws IllegalArgumentException if this is a subSet, and toElement is out + * of range. + * @throws NullPointerException if toElement is null but the set does not + * allow null elements. + */ + public SortedSet headSet(Object toElement) + { + return new UnmodifiableSortedSet(ss.headSet(toElement)); + } + + /** + * Returns the last (highest sorted) element in the underlying + * set. + * + * @return the last element. + * @throws NoSuchElementException if the set is empty. + */ + public Object last() + { + return ss.last(); + } + + /** + * Returns a unmodifiable view of the portion of the set greater than or + * equal to fromElement, and strictly less than toElement. The view is backed by + * the underlying set, so changes in one show up in the other. The subset + * supports all optional operations of the original. + *

    + * + * The returned set throws an IllegalArgumentException any time an element is + * used which is out of the range of fromElement and toElement. Note that the + * lower endpoint is included, but the upper is not; if you want to + * change the inclusion or exclusion of an endpoint, pass its successor + * object in instead. For example, for Integers, you can request + * subSet(new Integer(lowlimit.intValue() + 1), + * new Integer(highlimit.intValue() + 1)) to reverse + * the inclusiveness of both endpoints. + * + * @param fromElement the inclusive lower range of the subset. + * @param toElement the exclusive upper range of the subset. + * @return the subset. + * @throws ClassCastException if fromElement or toElement is not comparable + * to the set contents. + * @throws IllegalArgumentException if this is a subSet, and fromElement or + * toElement is out of range. + * @throws NullPointerException if fromElement or toElement is null but the + * set does not allow null elements. + */ + public SortedSet subSet(Object fromElement, Object toElement) + { + return new UnmodifiableSortedSet(ss.subSet(fromElement, toElement)); + } + + /** + * Returns a unmodifiable view of the portion of the set greater than or equal to + * fromElement. The view is backed by the underlying set, so changes in one show up + * in the other. The subset supports all optional operations of the original. + *

    + * + * The returned set throws an IllegalArgumentException any time an element is + * used which is out of the range of fromElement. Note that the endpoint, + * fromElement, is included; if you do not want this value to be included, pass its + * successor object in to fromElement. For example, for Integers, you could request + * tailSet(new Integer(limit.intValue() + 1)). + * + * @param fromElement the inclusive lower range of the subset + * @return the subset. + * @throws ClassCastException if fromElement is not comparable to the set + * contents. + * @throws IllegalArgumentException if this is a subSet, and fromElement is + * out of range. + * @throws NullPointerException if fromElement is null but the set does not + * allow null elements. + */ + public SortedSet tailSet(Object fromElement) + { + return new UnmodifiableSortedSet(ss.tailSet(fromElement)); + } + } // class UnmodifiableSortedSet +} // class Collections diff --git a/libjava/classpath/java/util/Comparator.java b/libjava/classpath/java/util/Comparator.java new file mode 100644 index 0000000..386bdc1 --- /dev/null +++ b/libjava/classpath/java/util/Comparator.java @@ -0,0 +1,119 @@ +/* Comparator.java -- Interface for objects that specify an ordering + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * Interface for objects that specify an ordering between objects. The ordering + * should be total, such that any two objects of the correct type + * can be compared, and the comparison is reflexive, anti-symmetric, and + * transitive. It is also recommended that the comparator be consistent + * with equals, although this is not a strict requirement. A relation + * is consistent with equals if these two statements always have the same + * results (if no exceptions occur):
    + * compare((Object) e1, (Object) e2) == 0 and + * e1.equals((Object) e2)
    + * Comparators that violate consistency with equals may cause strange behavior + * in sorted lists and sets. For example, a case-sensitive dictionary order + * comparison of Strings is consistent with equals, but if it is + * case-insensitive it is not, because "abc" and "ABC" compare as equal even + * though "abc".equals("ABC") returns false. + *

    + * In general, Comparators should be Serializable, because when they are passed + * to Serializable data structures such as SortedMap or SortedSet, the entire + * data structure will only serialize correctly if the comparator is + * Serializable. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Comparable + * @see TreeMap + * @see TreeSet + * @see SortedMap + * @see SortedSet + * @see Arrays#sort(Object[], Comparator) + * @see java.io.Serializable + * @since 1.2 + * @status updated to 1.4 + */ +public interface Comparator +{ + /** + * Return an integer that is negative, zero or positive depending on whether + * the first argument is less than, equal to or greater than the second + * according to this ordering. This method should obey the following + * contract: + *

      + *
    • if compare(a, b) < 0 then compare(b, a) > 0
    • + *
    • if compare(a, b) throws an exception, so does compare(b, a)
    • + *
    • if compare(a, b) < 0 and compare(b, c) < 0 then compare(a, c) + * < 0
    • + *
    • if compare(a, b) == 0 then compare(a, c) and compare(b, c) must + * have the same sign
    • + *
    + * To be consistent with equals, the following additional constraint is + * in place: + *
      + *
    • if a.equals(b) or both a and b are null, then + * compare(a, b) == 0.
    • + *

    + * + * Although it is permissible for a comparator to provide an order + * inconsistent with equals, that should be documented. + * + * @param o1 the first object + * @param o2 the second object + * @return the comparison + * @throws ClassCastException if the elements are not of types that can be + * compared by this ordering. + */ + int compare(Object o1, Object o2); + + /** + * Return true if the object is equal to this object. To be + * considered equal, the argument object must satisfy the constraints + * of Object.equals(), be a Comparator, and impose the + * same ordering as this Comparator. The default implementation + * inherited from Object is usually adequate. + * + * @param obj The object + * @return true if it is a Comparator that imposes the same order + * @see Object#equals(Object) + */ + boolean equals(Object obj); +} diff --git a/libjava/classpath/java/util/ConcurrentModificationException.java b/libjava/classpath/java/util/ConcurrentModificationException.java new file mode 100644 index 0000000..3d7ae10 --- /dev/null +++ b/libjava/classpath/java/util/ConcurrentModificationException.java @@ -0,0 +1,92 @@ +/* ConcurrentModificationException.java -- Data structure concurrently modified + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + */ + +/** + * Exception that is thrown by the collections classes when it is detected that + * a modification has been made to a data structure when this is not allowed, + * such as when a collection is structurally modified while an Iterator is + * operating over it. In cases where this can be detected, a + * ConcurrentModificationException will be thrown. An Iterator that detects + * this condition is referred to as fail-fast. Notice that this can occur + * even in single-threaded designs, if you call methods out of order. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see Iterator + * @see ListIterator + * @see Vector + * @see LinkedList + * @see HashSet + * @see Hashtable + * @see TreeMap + * @see AbstractList + * @since 1.2 + * @status updated to 1.4 + */ +public class ConcurrentModificationException extends RuntimeException +{ + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = -3666751008965953603L; + + /** + * Constructs a ConcurrentModificationException with no detail message. + */ + public ConcurrentModificationException() + { + } + + /** + * Constructs a ConcurrentModificationException with a detail message. + * + * @param detail the detail message for the exception + */ + public ConcurrentModificationException(String detail) + { + super(detail); + } +} diff --git a/libjava/classpath/java/util/Currency.java b/libjava/classpath/java/util/Currency.java new file mode 100644 index 0000000..32ea753 --- /dev/null +++ b/libjava/classpath/java/util/Currency.java @@ -0,0 +1,437 @@ +/* Currency.java -- Representation of a currency + 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 java.util; + +import gnu.java.locale.LocaleHelper; + +import java.io.IOException; +import java.io.ObjectStreamException; +import java.io.Serializable; + +/** + * Representation of a currency for a particular locale. Each currency + * is identified by its ISO 4217 code, and only one instance of this + * class exists per currency. As a result, instances are created + * via the getInstance() methods rather than by using + * a constructor. + * + * @see java.util.Locale + * @author Guilhem Lavaux (guilhem.lavaux@free.fr) + * @author Dalibor Topic (robilad@kaffe.org) + * @author Bryce McKinlay (mckinlay@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.4 + */ +public final class Currency + implements Serializable +{ + /** + * For compatability with Sun's JDK + */ + static final long serialVersionUID = -158308464356906721L; + + /** + * The set of properties which map a currency to + * the currency information such as the ISO 4217 + * currency code and the number of decimal points. + * + * @see #getCurrencyCode() + * @serial ignored. + */ + private static transient Properties properties; + + /** + * The ISO 4217 currency code associated with this + * particular instance. + * + * @see #getCurrencyCode() + * @serial the ISO 4217 currency code + */ + private String currencyCode; + + /** + * The number of fraction digits associated with this + * particular instance. + * + * @see #getDefaultFractionDigits() + * @serial the number of fraction digits + */ + private transient int fractionDigits; + + /** + * A cached map of country codes + * instances to international currency code + * Strings. Seperating this + * from the Currency instances + * ensures we have a common lookup between + * the two getInstance() methods. + * + * @see #getInstance(java.util.Locale) + * @serial ignored. + */ + private static transient Map countryMap; + + /** + * A cache of Currency instances to + * ensure the singleton nature of this class. The key + * is the international currency code. + * + * @see #getInstance(java.util.Locale) + * @see #getInstance(java.lang.String) + * @see #readResolve() + * @serial ignored. + */ + private static transient Map cache; + + /** + * Instantiates the cache and reads in the properties. + */ + static + { + /* Create a hash map for the locale mappings */ + countryMap = new HashMap(); + /* Create a hash map for the cache */ + cache = new HashMap(); + /* Create the properties object */ + properties = new Properties(); + /* Try and load the properties from our iso4217.properties resource */ + try + { + properties.load(Currency.class.getResourceAsStream("iso4217.properties")); + } + catch (IOException exception) + { + System.out.println("Failed to load currency resource: " + exception); + } + } + + /** + * Default constructor for deserialization + */ + private Currency() + { + } + + /** + * Constructor to create a Currency object + * for a particular Locale. + * All components of the given locale, other than the + * country code, are ignored. The results of calling this + * method may vary over time, as the currency associated with + * a particular country changes. For countries without + * a given currency (e.g. Antarctica), the result is null. + * + * @param loc the locale for the new currency, or null if + * there is no country code specified or a currency + * for this country. + */ + private Currency(Locale loc) + { + String countryCode; + String currencyKey; + String fractionDigitsKey; + int commaPosition; + + /* Retrieve the country code from the locale */ + countryCode = loc.getCountry(); + /* If there is no country code, return */ + if (countryCode.equals("")) + { + throw new + IllegalArgumentException("Invalid (empty) country code for locale:" + + loc); + } + /* Construct the key for the currency */ + currencyKey = countryCode + ".currency"; + /* Construct the key for the fraction digits */ + fractionDigitsKey = countryCode + ".fractionDigits"; + /* Retrieve the currency */ + currencyCode = properties.getProperty(currencyKey); + /* Return if the currency code is null */ + if (currencyCode == null) + { + return; + } + /* Split off the first currency code (we only use the first for now) */ + commaPosition = currencyCode.indexOf(","); + if (commaPosition != -1) + { + currencyCode = currencyCode.substring(0, commaPosition); + } + /* Retrieve the fraction digits */ + fractionDigits = Integer.parseInt(properties.getProperty(fractionDigitsKey)); + } + + /** + * Constructor for the "XXX" special case. This allows + * a Currency to be constructed from an assumed good + * currency code. + * + * @param code the code to use. + */ + private Currency(String code) + { + currencyCode = code; + fractionDigits = -1; /* Pseudo currency */ + } + + /** + * Returns the ISO4217 currency code of this currency. + * + * @return a String containing currency code. + */ + public String getCurrencyCode() + { + return currencyCode; + } + + /** + * Returns the number of digits which occur after the decimal point + * for this particular currency. For example, currencies such + * as the U.S. dollar, the Euro and the Great British pound have two + * digits following the decimal point to indicate the value which exists + * in the associated lower-valued coinage (cents in the case of the first + * two, pennies in the latter). Some currencies such as the Japanese + * Yen have no digits after the decimal point. In the case of pseudo + * currencies, such as IMF Special Drawing Rights, -1 is returned. + * + * @return the number of digits after the decimal separator for this currency. + */ + public int getDefaultFractionDigits() + { + return fractionDigits; + } + + /** + * Builds a new currency instance for this locale. + * All components of the given locale, other than the + * country code, are ignored. The results of calling this + * method may vary over time, as the currency associated with + * a particular country changes. For countries without + * a given currency (e.g. Antarctica), the result is null. + * + * @param locale a Locale instance. + * @return a new Currency instance. + * @throws NullPointerException if the locale or its + * country code is null. + * @throws IllegalArgumentException if the country of + * the given locale is not a supported ISO3166 code. + */ + public static Currency getInstance(Locale locale) + { + /** + * The new instance must be the only available instance + * for the currency it supports. We ensure this happens, + * while maintaining a suitable performance level, by + * creating the appropriate object on the first call to + * this method, and returning the cached instance on + * later calls. + */ + Currency newCurrency; + + String country = locale.getCountry(); + if (locale == null || country == null) + { + throw new + NullPointerException("The locale or its country is null."); + } + /* Attempt to get the currency from the cache */ + String code = (String) countryMap.get(country); + if (code == null) + { + /* Create the currency for this locale */ + newCurrency = new Currency(locale); + /* + * If the currency code is null, then creation failed + * and we return null. + */ + code = newCurrency.getCurrencyCode(); + if (code == null) + { + return null; + } + else + { + /* Cache it */ + countryMap.put(country, code); + cache.put(code, newCurrency); + } + } + else + { + newCurrency = (Currency) cache.get(code); + } + /* Return the instance */ + return newCurrency; + } + + /** + * Builds the currency corresponding to the specified currency code. + * + * @param currencyCode a string representing a currency code. + * @return a new Currency instance. + * @throws NullPointerException if currencyCode is null. + * @throws IllegalArgumentException if the supplied currency code + * is not a supported ISO 4217 code. + */ + public static Currency getInstance(String currencyCode) + { + Locale[] allLocales; + + /* + * Throw a null pointer exception explicitly if currencyCode is null. + * One is not thrown otherwise. It results in an + * IllegalArgumentException. + */ + if (currencyCode == null) + { + throw new NullPointerException("The supplied currency code is null."); + } + /* Nasty special case to allow an erroneous currency... blame Sun */ + if (currencyCode.equals("XXX")) + return new Currency("XXX"); + Currency newCurrency = (Currency) cache.get(currencyCode); + if (newCurrency == null) + { + /* Get all locales */ + allLocales = Locale.getAvailableLocales(); + /* Loop through each locale, looking for the code */ + for (int i = 0;i < allLocales.length; i++) + { + try + { + Currency testCurrency = getInstance (allLocales[i]); + if (testCurrency != null && + testCurrency.getCurrencyCode().equals(currencyCode)) + { + return testCurrency; + } + } + catch (IllegalArgumentException exception) + { + /* Ignore locales without valid countries */ + } + } + /* + * If we get this far, the code is not supported by any of + * our locales. + */ + throw new IllegalArgumentException("The currency code, " + currencyCode + + ", is not supported."); + } + else + { + return newCurrency; + } + } + + /** + * This method returns the symbol which precedes or follows a + * value in this particular currency in the default locale. + * In cases where there is no such symbol for the currency, + * the ISO 4217 currency code is returned. + * + * @return the currency symbol, or the ISO 4217 currency code if + * one doesn't exist. + */ + public String getSymbol() + { + return getSymbol(Locale.getDefault()); + } + + /** + *

    + * This method returns the symbol which precedes or follows a + * value in this particular currency. The returned value is + * the symbol used to denote the currency in the specified locale. + *

    + *

    + * For example, a supplied locale may specify a different symbol + * for the currency, due to conflicts with its own currency. + * This would be the case with the American currency, the dollar. + * Locales that also use a dollar-based currency (e.g. Canada, Australia) + * need to differentiate the American dollar using 'US$' rather than '$'. + * So, supplying one of these locales to getSymbol() would + * return this value, rather than the standard '$'. + *

    + *

    + * In cases where there is no such symbol for a particular currency, + * the ISO 4217 currency code is returned. + *

    + * + * @param locale the locale to express the symbol in. + * @return the currency symbol, or the ISO 4217 currency code if + * one doesn't exist. + * @throws NullPointerException if the locale is null. + */ + public String getSymbol(Locale locale) + { + return LocaleHelper.getLocalizedString(locale, currencyCode, + "currenciesSymbol", false, true); + } + + /** + * Returns the international ISO4217 currency code of this currency. + * + * @return a String containing the ISO4217 currency code. + */ + public String toString() + { + return getCurrencyCode(); + } + + /** + * Resolves the deserialized object to the singleton instance for its + * particular currency. The currency code of the deserialized instance + * is used to return the correct instance. + * + * @return the singleton instance for the currency specified by the + * currency code of the deserialized object. This replaces + * the deserialized object as the returned object from + * deserialization. + * @throws ObjectStreamException if a problem occurs with deserializing + * the object. + */ + private Object readResolve() + throws ObjectStreamException + { + return getInstance(currencyCode); + } + +} diff --git a/libjava/classpath/java/util/Date.java b/libjava/classpath/java/util/Date.java new file mode 100644 index 0000000..aecca29 --- /dev/null +++ b/libjava/classpath/java/util/Date.java @@ -0,0 +1,1263 @@ +/* java.util.Date + Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +/** + *

    + * This class represents a specific time in milliseconds since the epoch. + * The epoch is 1970, January 1 00:00:00.0000 UTC. + *

    + *

    + * Date is intended to reflect universal time coordinate (UTC), + * but this depends on the underlying host environment. Most operating systems + * don't handle the leap second, which occurs about once every year or + * so. The leap second is added to the last minute of the day on either + * the 30th of June or the 31st of December, creating a minute 61 seconds + * in length. + *

    + *

    + * The representations of the date fields are as follows: + *

      + *
    • + * Years are specified as the difference between the year + * and 1900. Thus, the final year used is equal to + * 1900 + y, where y is the input value. + *
    • + *
    • + * Months are represented using zero-based indexing, + * making 0 January and 11 December. + *
    • + *
    • + * Dates are represented with the usual values of + * 1 through to 31. + *
    • + *
    • + * Hours are represented in the twenty-four hour clock, + * with integer values from 0 to 23. 12am is 0, and + * 12pm is 12. + *
    • + *
    • + * Minutes are again as usual, with values from 0 to 59. + *
    • + *
    • + * Seconds are represented with the values 0 through to 61, + * with 60 and 61 being leap seconds (as per the ISO C standard). + *
    • + *
    + *

    + *

    + * Prior to JDK 1.1, this class was the sole class handling date and time + * related functionality. However, this particular solution was not + * amenable to internationalization. The new Calendar + * class should now be used to handle dates and times, with Date + * being used only for values in milliseconds since the epoch. The + * Calendar class, and its concrete implementations, handle + * the interpretation of these values into minutes, hours, days, months + * and years. The formatting and parsing of dates is left to the + * DateFormat class, which is able to handle the different + * types of date format which occur in different locales. + *

    + * + * @see Calendar + * @see GregorianCalendar + * @see java.text.DateFormat + * @author Jochen Hoenicke + * @author Per Bothner (bothner@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class Date + implements Cloneable, Comparable, Serializable +{ + /** + * This is the serialization UID for this class + * for compatability with Sun's JDK. + */ + private static final long serialVersionUID = 7523967970034938905L; + + /** + * The time in milliseconds since the epoch. + */ + private transient long time; + + /** + * An array of week names used to map names to integer values. + */ + private static final String[] weekNames = { "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" }; + /** + * An array of month names used to map names to integer values. + */ + private static final String[] monthNames = { "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; + /** + * Creates a new Date Object representing the current time. + */ + public Date() + { + time = System.currentTimeMillis(); + } + + /** + * Creates a new Date Object representing the given time. + * + * @param time the time in milliseconds since the epoch. + */ + public Date(long time) + { + this.time = time; + } + + /** + * Creates a new Date Object representing the given time. + * + * @deprecated use new GregorianCalendar(year+1900, month, + * day) instead. + * @param year the difference between the required year and 1900. + * @param month the month as a value between 0 and 11. + * @param day the day as a value between 0 and 31. + */ + public Date(int year, int month, int day) + { + this(year, month, day, 0, 0, 0); + } + + /** + * Creates a new Date Object representing the given time. + * + * @deprecated use new GregorianCalendar(year+1900, month, + * day, hour, min) instead. + * @param year the difference between the required year and 1900. + * @param month the month as a value between 0 and 11. + * @param day the day as a value between 0 and 31. + * @param hour the hour as a value between 0 and 23, in 24-hour + * clock notation. + * @param min the minute as a value between 0 and 59. + */ + public Date(int year, int month, int day, int hour, int min) + { + this(year, month, day, hour, min, 0); + } + + /** + * Creates a new Date Object representing the given time. + * + * @deprecated use new GregorianCalendar(year+1900, month, + * day, hour, min, sec) instead. + * @param year the difference between the required year and 1900. + * @param month the month as a value between 0 and 11. + * @param day the day as a value between 0 and 31. + * @param hour the hour as a value between 0 and 23, in 24-hour + * clock notation. + * @param min the minute as a value between 0 and 59. + * @param sec the second as a value between 0 and 61 (with 60 + * and 61 being leap seconds). + */ + public Date(int year, int month, int day, int hour, int min, int sec) + { + GregorianCalendar cal = + new GregorianCalendar(year + 1900, month, day, hour, min, sec); + time = cal.getTimeInMillis(); + } + + /** + * Creates a new Date from the given string representation. This + * does the same as new Date(Date.parse(s)) + * @see #parse + * @deprecated use java.text.DateFormat.parse(s) instead. + */ + public Date(String s) + { + time = parse(s); + } + + /** + * Returns a copy of this Date object. + * + * @return a copy, or null if the object couldn't be + * cloned. + * @see Object#clone() + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException ex) + { + return null; + } + } + + /** + * Returns the number of milliseconds since the epoch + * specified by the given arguments. The arguments are + * interpreted relative to UTC rather than the local + * time zone. + * + * @deprecated Use Calendar with a UTC + * TimeZone instead. + * @param year the difference between the required year and 1900. + * @param month the month as a value between 0 and 11. + * @param date the day as a value between 0 and 31. + * @param hrs the hour as a value between 0 and 23, in 24-hour + * clock notation. + * @param min the minute as a value between 0 and 59. + * @param sec the second as a value between 0 and 61 (with 60 + * and 61 being leap seconds). + * @return the time in milliseconds since the epoch. + */ + public static long UTC(int year, int month, int date, + int hrs, int min, int sec) + { + GregorianCalendar cal = + new GregorianCalendar(year + 1900, month, date, hrs, min, sec); + cal.set(Calendar.ZONE_OFFSET, 0); + cal.set(Calendar.DST_OFFSET, 0); + return cal.getTimeInMillis(); + } + + /** + * Gets the time represented by this object. + * + * @return the time in milliseconds since the epoch. + */ + public long getTime() + { + return time; + } + + /** + * Returns the number of minutes offset used with UTC to give the time + * represented by this object in the current time zone. The date information + * from this object is also used to determine whether or not daylight savings + * time is in effect. For example, the offset for the UK would be 0 if the + * month of the date object was January, and 1 if the month was August. + * + * @deprecated use + * Calendar.get(Calendar.ZONE_OFFSET)+Calendar.get(Calendar.DST_OFFSET) + * instead. + * @return The time zone offset in minutes of the local time zone + * relative to UTC. The time represented by this object is used to + * determine if we should use daylight savings. + */ + public int getTimezoneOffset() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return - (cal.get(Calendar.ZONE_OFFSET) + + cal.get(Calendar.DST_OFFSET)) / (60 * 1000); + } + + /** + * Sets the time which this object should represent. + * + * @param time the time in milliseconds since the epoch. + */ + public void setTime(long time) + { + this.time = time; + } + + /** + * Tests if this date is after the specified date. + * + * @param when the other date + * @return true, if the date represented by this object is + * strictly later than the time represented by when. + */ + public boolean after(Date when) + { + return time > when.time; + } + + /** + * Tests if this date is before the specified date. + * + * @param when the other date + * @return true, if the date represented by when is strictly later + * than the time represented by this object. + */ + public boolean before(Date when) + { + return time < when.time; + } + + /** + * Compares two dates for equality. + * + * @param obj the object to compare. + * @return true, if obj is a Date object and the time represented + * by obj is exactly the same as the time represented by this + * object. + */ + public boolean equals(Object obj) + { + return (obj instanceof Date && time == ((Date) obj).time); + } + + /** + * Compares two dates. + * + * @param when the other date. + * @return 0, if the date represented + * by obj is exactly the same as the time represented by this + * object, a negative if this Date is before the other Date, and + * a positive value otherwise. + */ + public int compareTo(Date when) + { + return (time < when.time) ? -1 : (time == when.time) ? 0 : 1; + } + + /** + * Compares this Date to another object. This behaves like + * compareTo(Date), but it takes a generic object + * and throws a ClassCastException if obj is + * not a Date. + * + * @param obj the other date. + * @return 0, if the date represented + * by obj is exactly the same as the time represented by this + * object, a negative if this Date is before the other Date, and + * a positive value otherwise. + * @exception ClassCastException if obj is not of type Date. + */ + public int compareTo(Object obj) + { + return compareTo((Date) obj); + } + + /** + * Computes the hash code of this Date as the + * XOR of the most significant and the least significant + * 32 bits of the 64 bit milliseconds value. + * + * @return the hash code. + */ + public int hashCode() + { + return (int) time ^ (int) (time >>> 32); + } + + /** + *

    + * Returns a string representation of this date using + * the following date format: + *

    + *

    + * day mon dd hh:mm:ss zz yyyy + *

    + *

    where the fields used here are: + *

      + *
    • + * day -- the day of the week + * (Sunday through to Saturday). + *
    • + *
    • + * mon -- the month (Jan to Dec). + *
    • + *
    • + * dd -- the day of the month + * as two decimal digits (01 to 31). + *
    • + *
    • + * hh -- the hour of the day + * as two decimal digits in 24-hour clock notation + * (01 to 23). + *
    • + *
    • + * mm -- the minute of the day + * as two decimal digits (01 to 59). + *
    • + *
    • + * ss -- the second of the day + * as two decimal digits (01 to 61). + *
    • + *
    • + * zz -- the time zone information if available. + * The possible time zones used include the abbreviations + * recognised by parse() (e.g. GMT, CET, etc.) + * and may reflect the fact that daylight savings time is in + * effect. The empty string is used if there is no time zone + * information. + *
    • + *
    • + * yyyy -- the year as four decimal digits. + *
    • + *
    + *

    + * The DateFormat class should now be + * preferred over using this method. + *

    + * + * @return A string of the form 'day mon dd hh:mm:ss zz yyyy' + * @see #parse(String) + * @see DateFormat + */ + public String toString() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + String day = "0" + cal.get(Calendar.DATE); + String hour = "0" + cal.get(Calendar.HOUR_OF_DAY); + String min = "0" + cal.get(Calendar.MINUTE); + String sec = "0" + cal.get(Calendar.SECOND); + String year = "000" + cal.get(Calendar.YEAR); + return weekNames[cal.get(Calendar.DAY_OF_WEEK) - 1] + " " + + monthNames[cal.get(Calendar.MONTH)] + " " + + day.substring(day.length() - 2) + " " + + hour.substring(hour.length() - 2) + ":" + + min.substring(min.length() - 2) + ":" + + sec.substring(sec.length() - 2) + " " + + + cal.getTimeZone().getDisplayName(cal.getTimeZone().inDaylightTime(this), + TimeZone.SHORT) + " " + + year.substring(year.length() - 4); + } + + /** + * Returns a locale-dependent string representation of this + * Date object. + * + * @deprecated Use DateFormat.format(Date) + * @return A locale-dependent string representation. + * @see #parse(String) + * @see DateFormat + */ + public String toLocaleString() + { + return java.text.DateFormat.getInstance().format(this); + } + + /** + *

    + * Returns a string representation of this Date + * object using GMT rather than the local timezone. + * The following date format is used: + *

    + *

    + * d mon yyyy hh:mm:ss GMT + *

    + *

    where the fields used here are: + *

      + *
    • + * d -- the day of the month + * as one or two decimal digits (1 to 31). + *
    • + *
    • + * mon -- the month (Jan to Dec). + *
    • + *
    • + * yyyy -- the year as four decimal digits. + *
    • + *
    • + * hh -- the hour of the day + * as two decimal digits in 24-hour clock notation + * (01 to 23). + *
    • + *
    • + * mm -- the minute of the day + * as two decimal digits (01 to 59). + *
    • + *
    • + * ss -- the second of the day + * as two decimal digits (01 to 61). + *
    • + *
    • + * GMT -- the literal string "GMT" + * indicating Greenwich Mean Time as opposed to + * the local timezone. + *
    • + *
    + * + * @deprecated Use DateFormat.format(Date) with a GMT TimeZone. + * @return A string of the form 'd mon yyyy hh:mm:ss GMT' using + * GMT as opposed to the local timezone. + * @see #parse(String) + * @see DateFormat + */ + public String toGMTString() + { + java.text.DateFormat format = java.text.DateFormat.getInstance(); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + return format.format(this); + } + + /** + * Parses the time zone string. + * + * @param tok The token containing the time zone. + * @param sign The sign (+ or -) used by the time zone. + * @return An integer representing the number of minutes offset + * from GMT for the time zone. + */ + private static int parseTz(String tok, char sign) + throws IllegalArgumentException + { + int num; + + try + { + // parseInt doesn't handle '+' so strip off sign. + num = Integer.parseInt(tok.substring(1)); + } + catch (NumberFormatException ex) + { + throw new IllegalArgumentException(tok); + } + + // Convert hours to minutes. + if (num < 24) + num *= 60; + else + num = (num / 100) * 60 + num % 100; + + return sign == '-' ? -num : num; + } + + /** + * Parses the month string. + * + * @param tok the token containing the month. + * @return An integer between 0 and 11, representing + * a month from January (0) to December (11), + * or -1 if parsing failed. + */ + private static int parseMonth(String tok) + { + // Initialize strings for month names. + // We could possibly use the fields of DateFormatSymbols but that is + // localized and thus might not match the English words specified. + String months[] = { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", + "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", + "NOVEMBER", "DECEMBER" }; + + int i; + for (i = 0; i < 12; i++) + if (months[i].startsWith(tok)) + return i; + + // Return -1 if not found. + return -1; + } + + /** + * Parses the day of the week string. + * + * @param tok the token containing the day of the week. + * @return true if the token was parsed successfully. + */ + private static boolean parseDayOfWeek(String tok) + { + // Initialize strings for days of the week names. + // We could possibly use the fields of DateFormatSymbols but that is + // localized and thus might not match the English words specified. + String daysOfWeek[] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", + "THURSDAY", "FRIDAY", "SATURDAY" }; + + int i; + for (i = 0; i < 7; i++) + if (daysOfWeek[i].startsWith(tok)) + return true; + + return false; + } + + /** + *

    + * Parses a String and returns the time, in milliseconds since the + * epoch, it represents. Most syntaxes are handled, including + * the IETF date standard "day, dd mon yyyy hh:mm:ss zz" (see + * toString() for definitions of these fields). + * Standard U.S. time zone abbreviations are recognised, in + * addition to time zone offsets in positive or negative minutes. + * If a time zone is specified, the specified time is assumed to + * be in UTC and the appropriate conversion is applied, following + * parsing, to convert this to the local time zone. If no zone + * is specified, the time is assumed to already be in the local + * time zone. + *

    + *

    + * The method parses the string progressively from left to right. + * At the end of the parsing process, either a time is returned + * or an IllegalArgumentException is thrown to signify + * failure. The ASCII characters A-Z, a-z, 0-9, and ',', '+', '-', + * ':' and '/' are the only characters permitted within the string, + * besides whitespace and characters enclosed within parantheses + * '(' and ')'. + *

    + *

    + * A sequence of consecutive digits are recognised as a number, + * and interpreted as follows: + *

      + *
    • + * A number preceded by a sign (+ or -) is taken to be a time zone + * offset. The time zone offset can be specified in either hours + * or minutes. The former is assumed if the number is less than 24. + * Otherwise, the offset is assumed to be in minutes. A - indicates + * a time zone west of GMT, while a + represents a time zone to the + * east of GMT. The time zones are always assumed to be relative + * to GMT, and a (redundant) specification of this can be included + * with the time zone. For example, '-9', 'utc-9' and 'GMT-9' all + * represent a time zone nine hours west of GMT. Similarly, + * '+4', 'ut+4' and 'UTC+4' all give 4 hours east of GMT. + *
    • + *
    • + * A number equal to or greater than 70 is regarded as a year specification. + * Values lower than 70 are only assumed to indicate a year if both the + * day of the month and the month itself have already been recognised. + * Year values less than 100 are interpreted as being relative to the current + * century when the Date class is initialised.. Given a century, + * x, the year is assumed to be within the range x - 80 to x + 19. The value + * itself is then used as a match against the two last digits of one of these + * years. For example, take x to be 2004. A two-digit year is assumed to fall + * within the range x - 80 (1924) and x + 19 (2023). Thus, any intepreted value + * between 0 and 23 is assumed to be 2000 to 2023 and values between 24 and 99 + * are taken as being 1924 to 1999. This only applies for the case of 2004. + * With a different year, the values will be interpreted differently. 2005 + * will used 0 to 24 as 2000 to 2024 and 25 to 99 as 1925 to 1999, for example. + * This behaviour differs from that of SimpleDateFormat and is + * time-dependent (a two-digit year will be interpreted differently depending + * on the time the code is run). + *
    • + *
    • + * Numbers followed by a colon are interpreted by first an hour, and then + * as a minute, once an hour has been found. + *
    • + *
    • + *
    • + * Numbers followed by a slash are regarded first as a month, and then as + * a day of the month once the month has been found. This follows the + * U.S. date format of mm/dd, rather than the European dd/mm. Months + * are converted to the recognised value - 1 before storage, in order + * to put the number within the range 0 to 11. + *
    • + *
    • + * Numbers followed by commas, whitespace, hyphens or the end of the string + * are interpreted in the following order: hour, minute, second, day of month. + * The first type not already recognised in the current string being parsed is + * assumed. + *
    • + *
    + *

    + *

    + * A sequence of consecutive alphabetic characters is recognised as a word, + * and interpreted as follows, in a case-insentive fashion: + *

      + *
    • + * The characters 'AM' or 'PM' restrict the hour value to a value between 0 + * and 12. In the latter case, 12 is added to the hour value before storage. + *
    • + *
    • + * Any words which match any prefix of one of the days of the week ('Monday', + * 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' and 'Sunday'), + * are simply ignored. + *
    • + *
    • + * Any words which match any prefix of one of the months of the year ('January', + * 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', + * 'October', 'November', 'December') are recognised and interpreted as the + * appropriate value between 0 and 11. The first match made against a + * month is the one used, in the order specified here. For example, 'Ma' is + * intepreted as 'March' (2) and not as 'May' (4). Similarly, 'Ju' is 'June', + * and not 'July'. + *
    • + *
    • + * The words 'GMT', 'UT' and 'UTC' are interpreted as specifying UTC as the + * time zone in use for this date. + *
    • + *
    • + * The word pairs 'EST'/'EDT', 'CST'/'CDT', 'MST'/'MDT' and 'PST'/'PDT' are + * interpreted as the appropriate U.S. time zone abbreviation. Each pair + * is the standard and daylight savings time zone specification, respectively, + * for each zone within the U.S, these being Eastern Standard/Daylight Time + * (-5), Central Standard/Daylight Time (-6), Mountain Standard/Daylight Time + * (-7) and Pacific Standard/Daylight Time (-8). + *
    • + *
    + * + * @param string The String to parse. + * @return The time in milliseconds since the epoch. + * @throws IllegalArgumentException if the string fails to parse. + * @deprecated Use DateFormat.parse(String) + * @see #toString() + * @see SimpleDateFormat + */ + public static long parse(String string) + { + // Initialize date/time fields before parsing begins. + int year = -1; + int month = -1; + int day = -1; + int hour = -1; + int minute = -1; + int second = -1; + int timezone = 0; + boolean localTimezone = true; + + // Trim out any nested stuff in parentheses now to make parsing easier. + StringBuffer buf = new StringBuffer(); + int parenNesting = 0; + int len = string.length(); + for (int i = 0; i < len; i++) + { + char ch = string.charAt(i); + if (ch >= 'a' && ch <= 'z') + ch -= 'a' - 'A'; + if (ch == '(') + parenNesting++; + else if (parenNesting == 0) + buf.append(ch); + else if (ch == ')') + parenNesting--; + } + int tmpMonth; + + // Make all chars upper case to simplify comparisons later. + // Also ignore commas; treat them as delimiters. + StringTokenizer strtok = new StringTokenizer(buf.toString(), " \t\n\r,"); + + while (strtok.hasMoreTokens()) + { + String tok = strtok.nextToken(); + char firstch = tok.charAt(0); + if ((firstch == '+' || firstch == '-') && year >= 0) + { + timezone = parseTz(tok, firstch); + localTimezone = false; + } + else if (firstch >= '0' && firstch <= '9') + { + while (tok != null && tok.length() > 0) + { + int punctOffset = tok.length(); + int num = 0; + int punct; + for (int i = 0; ; i++) + { + if (i >= punctOffset) + { + punct = -1; + break; + } + else + { + punct = tok.charAt(i); + if (punct >= '0' && punct <= '9') + { + if (num > 999999999) // in case of overflow + throw new IllegalArgumentException(tok); + num = 10 * num + (punct - '0'); + } + else + { + punctOffset = i; + break; + } + } + + } + + if (punct == ':') + { + if (hour < 0) + hour = num; + else + minute = num; + } + else if ((num >= 70 + && (punct == ' ' || punct == ',' + || punct == '/' || punct < 0)) + || (num < 70 && day >= 0 && month >= 0 && year < 0)) + { + if (num >= 100) + year = num; + else + { + int curYear = 1900 + new Date().getYear(); + int firstYear = curYear - 80; + year = firstYear / 100 * 100 + num; + if (year < firstYear) + year += 100; + } + } + else if (punct == '/') + { + if (month < 0) + month = num - 1; + else + day = num; + } + else if (hour >= 0 && minute < 0) + minute = num; + else if (minute >= 0 && second < 0) + second = num; + else if (day < 0) + day = num; + else + throw new IllegalArgumentException(tok); + + // Advance string if there's more to process in this token. + if (punct < 0 || punctOffset + 1 >= tok.length()) + tok = null; + else + tok = tok.substring(punctOffset + 1); + } + } + else if (firstch >= 'A' && firstch <= 'Z') + { + if (tok.equals("AM")) + { + if (hour < 1 || hour > 12) + throw new IllegalArgumentException(tok); + if (hour == 12) + hour = 0; + } + else if (tok.equals("PM")) + { + if (hour < 1 || hour > 12) + throw new IllegalArgumentException(tok); + if (hour < 12) + hour += 12; + } + else if (parseDayOfWeek(tok)) + ; // Ignore it; throw the token away. + else if (tok.equals("UT") || tok.equals("UTC") || tok.equals("GMT")) + localTimezone = false; + else if (tok.startsWith("UT") || tok.startsWith("GMT")) + { + int signOffset = 3; + if (tok.charAt(1) == 'T' && tok.charAt(2) != 'C') + signOffset = 2; + + char sign = tok.charAt(signOffset); + if (sign != '+' && sign != '-') + throw new IllegalArgumentException(tok); + + timezone = parseTz(tok.substring(signOffset), sign); + localTimezone = false; + } + else if ((tmpMonth = parseMonth(tok)) >= 0) + month = tmpMonth; + else if (tok.length() == 3 && tok.charAt(2) == 'T') + { + // Convert timezone offset from hours to minutes. + char ch = tok.charAt(0); + if (ch == 'E') + timezone = -5 * 60; + else if (ch == 'C') + timezone = -6 * 60; + else if (ch == 'M') + timezone = -7 * 60; + else if (ch == 'P') + timezone = -8 * 60; + else + throw new IllegalArgumentException(tok); + + // Shift 60 minutes for Daylight Savings Time. + if (tok.charAt(1) == 'D') + timezone += 60; + else if (tok.charAt(1) != 'S') + throw new IllegalArgumentException(tok); + + localTimezone = false; + } + else + throw new IllegalArgumentException(tok); + } + else + throw new IllegalArgumentException(tok); + } + + // Unspecified hours, minutes, or seconds should default to 0. + if (hour < 0) + hour = 0; + if (minute < 0) + minute = 0; + if (second < 0) + second = 0; + + // Throw exception if any other fields have not been recognized and set. + if (year < 0 || month < 0 || day < 0) + throw new IllegalArgumentException("Missing field"); + + // Return the time in either local time or relative to GMT as parsed. + // If no time-zone was specified, get the local one (in minutes) and + // convert to milliseconds before adding to the UTC. + GregorianCalendar cal + = new GregorianCalendar(year, month, day, hour, minute, second); + if (!localTimezone) + { + cal.set(Calendar.ZONE_OFFSET, timezone * 60 * 1000); + cal.set(Calendar.DST_OFFSET, 0); + } + return cal.getTimeInMillis(); + } + + /** + * Returns the difference between the year represented by this + * Date object and 1900. + * + * @return the year minus 1900 represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.YEAR) + * instead. Note the 1900 difference in the year. + * @see Calendar + * @see #setYear(int) + */ + public int getYear() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.YEAR) - 1900; + } + + /** + * Sets the year to the specified year, plus 1900. The other + * fields are only altered as required to match the same date + * and time in the new year. Usually, this will mean that + * the fields are not changed at all, but in the case of + * a leap day or leap second, the fields will change in + * relation to the existence of such an event in the new year. + * For example, if the date specifies February the 29th, 2000, + * then this will become March the 1st if the year is changed + * to 2001, as 2001 is not a leap year. Similarly, a seconds + * value of 60 or 61 may result in the seconds becoming 0 and + * the minute increasing by 1, if the new time does not include + * a leap second. + * + * @param year the year minus 1900. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.YEAR, year) instead. Note about the 1900 + * difference in year. + * @see #getYear() + * @see Calendar + */ + public void setYear(int year) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.YEAR, 1900 + year); + time = cal.getTimeInMillis(); + } + + /** + * Returns the month represented by this Date object, + * as a value between 0 (January) and 11 (December). + * + * @return the month represented by this date object (zero based). + * @deprecated Use Calendar instead of Date, and use get(Calendar.MONTH) + * instead. + * @see #setMonth(int) + * @see Calendar + */ + public int getMonth() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.MONTH); + } + + /** + * Sets the month to the given value. The other + * fields are only altered as necessary to match + * the same date and time in the new month. In most + * cases, the other fields won't change at all. However, + * in the case of a shorter month or a leap second, values + * may be adjusted. For example, if the day of the month + * is currently 31, and the month value is changed from + * January (0) to September (8), the date will become + * October the 1st, as September only has 30 days. Similarly, + * a seconds value of 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1, if the new time does + * not include a leap second. + * + * @param month the month, with a zero-based index + * from January. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.MONTH, month) instead. + * @see #getMonth() + * @see Calendar + */ + public void setMonth(int month) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.MONTH, month); + time = cal.getTimeInMillis(); + } + + /** + * Returns the day of the month of this Date + * object, as a value between 0 and 31. + * + * @return the day of month represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.DATE) + * instead. + * @see Calendar + * @see #setDate(int) + */ + public int getDate() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.DATE); + } + + /** + * Sets the date to the given value. The other + * fields are only altered as necessary to match + * the same date and time on the new day of the month. In most + * cases, the other fields won't change at all. However, + * in the case of a leap second or the day being out of + * the range of the current month, values + * may be adjusted. For example, if the day of the month + * is currently 30 and the month is June, a new day of the + * month value of 31 will cause the month to change to July, + * as June only has 30 days . Similarly, + * a seconds value of 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1, if the new time does + * not include a leap second. + * + * @param date the date. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.DATE, date) instead. + * @see Calendar + * @see #getDate() + */ + public void setDate(int date) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.DATE, date); + time = cal.getTimeInMillis(); + } + + /** + * Returns the day represented by this Date + * object as an integer between 0 (Sunday) and 6 (Saturday). + * + * @return the day represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.DAY_OF_WEEK) + * instead. + * @see Calendar + */ + public int getDay() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + // For Calendar, Sunday is 1. For Date, Sunday is 0. + return cal.get(Calendar.DAY_OF_WEEK) - 1; + } + + /** + * Returns the hours represented by this Date + * object as an integer between 0 and 23. + * + * @return the hours represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.HOUR_OF_DAY) + * instead. + * @see Calendar + * @see #setHours(int) + */ + public int getHours() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.HOUR_OF_DAY); + } + + /** + * Sets the hours to the given value. The other + * fields are only altered as necessary to match + * the same date and time in the new hour. In most + * cases, the other fields won't change at all. However, + * in the case of a leap second, values + * may be adjusted. For example, + * a seconds value of 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1 if the new hour does + * not contain a leap second. + * + * @param hours the hours. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.HOUR_OF_DAY, hours) instead. + * @see Calendar + * @see #getHours() + */ + public void setHours(int hours) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.HOUR_OF_DAY, hours); + time = cal.getTimeInMillis(); + } + + /** + * Returns the number of minutes represented by the Date + * object, as an integer between 0 and 59. + * + * @return the minutes represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.MINUTE) + * instead. + * @see Calendar + * @see #setMinutes(int) + */ + public int getMinutes() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.MINUTE); + } + + /** + * Sets the minutes to the given value. The other + * fields are only altered as necessary to match + * the same date and time in the new minute. In most + * cases, the other fields won't change at all. However, + * in the case of a leap second, values + * may be adjusted. For example, + * a seconds value of 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1 if the new minute does + * not contain a leap second. + * + * @param minutes the minutes. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.MINUTE, minutes) instead. + * @see Calendar + * @see #getMinutes() + */ + public void setMinutes(int minutes) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.MINUTE, minutes); + time = cal.getTimeInMillis(); + } + + /** + * Returns the number of seconds represented by the Date + * object, as an integer between 0 and 61 (60 and 61 being leap seconds). + * + * @return the seconds represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.SECOND) + * instead. + * @see Calendar + * @see #setSeconds(int) + */ + public int getSeconds() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.SECOND); + } + + /** + * Sets the seconds to the given value. The other + * fields are only altered as necessary to match + * the same date and time in the new minute. In most + * cases, the other fields won't change at all. However, + * in the case of a leap second, values + * may be adjusted. For example, setting the + * seconds value to 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1, if the current time does + * not contain a leap second. + * + * @param seconds the seconds. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.SECOND, seconds) instead. + * @see Calendar + * @see #getSeconds() + */ + public void setSeconds(int seconds) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.SECOND, seconds); + time = cal.getTimeInMillis(); + } + + /** + * Deserializes a Date object from an + * input stream, setting the time (in milliseconds + * since the epoch) to the long value read from the + * stream. + * + * @param input the input stream. + * @throws IOException if an I/O error occurs in the stream. + * @throws ClassNotFoundException if the class of the + * serialized object could not be found. + */ + private void readObject(ObjectInputStream input) + throws IOException, ClassNotFoundException + { + input.defaultReadObject(); + time = input.readLong(); + } + + /** + * Serializes a Date object to an output stream, + * storing the time (in milliseconds since the epoch) as a long + * value in the stream. + * + * @serialdata A long value representing the offset from the epoch + * in milliseconds. This is the same value that is returned by the + * method getTime(). + * @param output the output stream. + * @throws IOException if an I/O error occurs in the stream. + */ + private void writeObject(ObjectOutputStream output) + throws IOException + { + output.defaultWriteObject(); + output.writeLong(time); + } + +} diff --git a/libjava/classpath/java/util/Dictionary.java b/libjava/classpath/java/util/Dictionary.java new file mode 100644 index 0000000..0d44ab6 --- /dev/null +++ b/libjava/classpath/java/util/Dictionary.java @@ -0,0 +1,136 @@ +/* Dictionary.java -- an abstract (and essentially worthless) + class which is Hashtable's superclass + Copyright (C) 1998, 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 java.util; + +/** + * A Dictionary maps keys to values; how it does that is + * implementation-specific. + * + * This is an abstract class which has really gone by the wayside. + * People at Javasoft are probably embarrassed by it. At this point, + * it might as well be an interface rather than a class, but it remains + * this poor, laughable skeleton for the sake of backwards compatibility. + * At any rate, this was what came before the {@link Map} interface + * in the Collections framework. + * + * @author Jon Zeppieri + * @author Eric Blake (ebb9@email.byu.edu) + * @see Map + * @see Hashtable + * @since 1.0 + * @status updated to 1.4 + */ +public abstract class Dictionary +{ + // WARNING: Dictionary is a CORE class in the bootstrap cycle. See the + // comments in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * Sole constructor (often called implicitly). + */ + public Dictionary() + { + } + + /** + * Returns an Enumeration of the values in this Dictionary. + * + * @return an Enumeration of the values + * @see #keys() + */ + public abstract Enumeration elements(); + + /** + * Returns the value associated with the supplied key, or null + * if no such value exists. Since Dictionaries are not allowed null keys + * or elements, a null result always means the key is not present. + * + * @param key the key to use to fetch the value + * @return the mapped value + * @throws NullPointerException if key is null + * @see #put(Object, Object) + */ + public abstract Object get(Object key); + + /** + * Returns true when there are no elements in this Dictionary. + * + * @return size() == 0 + */ + public abstract boolean isEmpty(); + + /** + * Returns an Enumeration of the keys in this Dictionary + * + * @return an Enumeration of the keys + * @see #elements() + */ + public abstract Enumeration keys(); + + /** + * Inserts a new value into this Dictionary, located by the + * supplied key. Dictionary does not support null keys or values, so + * a null return can safely be interpreted as adding a new key. + * + * @param key the key which locates the value + * @param value the value to put into the Dictionary + * @return the previous value of the key, or null if there was none + * @throws NullPointerException if key or value is null + * @see #get(Object) + */ + public abstract Object put(Object key, Object value); + + /** + * Removes from the Dictionary the value located by the given key. A null + * return safely means that the key was not mapped in the Dictionary. + * + * @param key the key used to locate the value to be removed + * @return the value associated with the removed key + * @throws NullPointerException if key is null + */ + public abstract Object remove(Object key); + + /** + * Returns the number of values currently in this Dictionary. + * + * @return the number of keys in the Dictionary + */ + public abstract int size(); +} // class Dictionary diff --git a/libjava/classpath/java/util/EmptyStackException.java b/libjava/classpath/java/util/EmptyStackException.java new file mode 100644 index 0000000..e8b4509 --- /dev/null +++ b/libjava/classpath/java/util/EmptyStackException.java @@ -0,0 +1,69 @@ +/* EmptyStackException.java -- Attempt to pop from an empty stack + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + */ + +/** + * This exception is thrown by the Stack class when an attempt is made to pop + * or otherwise access elements from an empty stack. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Stack + * @since 1.0 + * @status updated to 1.4 + */ +public class EmptyStackException extends RuntimeException +{ + /** + * Compatible with JDK 1.0. + */ + private static final long serialVersionUID = 5084686378493302095L; + + /** + * Constructs an EmptyStackException with no detail message. + */ + public EmptyStackException() + { + } +} diff --git a/libjava/classpath/java/util/Enumeration.java b/libjava/classpath/java/util/Enumeration.java new file mode 100644 index 0000000..1365bbb --- /dev/null +++ b/libjava/classpath/java/util/Enumeration.java @@ -0,0 +1,81 @@ +/* Enumeration.java -- Interface for enumerating lists of objects + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1. + * Status: Believed complete and correct + */ + +/** + * Interface for lists of objects that can be returned in sequence. Successive + * objects are obtained by the nextElement method. + *

    + * As of Java 1.2, the Iterator interface provides the same functionality, but + * with shorter method names and a new optional method to remove items from the + * list. If writing for 1.2, consider using Iterator instead. Enumerations over + * the new collections classes, for use with legacy APIs that require them, can + * be obtained by the enumeration method in class Collections. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Iterator + * @see Hashtable + * @see Vector + * @since 1.0 + * @status updated to 1.4 + */ +public interface Enumeration +{ + /** + * Tests whether there are elements remaining in the enumeration. + * + * @return true if there is at least one more element in the enumeration, + * that is, if the next call to nextElement will not throw a + * NoSuchElementException. + */ + boolean hasMoreElements(); + + /** + * Obtain the next element in the enumeration. + * + * @return the next element in the enumeration + * @throws NoSuchElementException if there are no more elements + */ + Object nextElement(); +} diff --git a/libjava/classpath/java/util/EventListener.java b/libjava/classpath/java/util/EventListener.java new file mode 100644 index 0000000..c9a1795 --- /dev/null +++ b/libjava/classpath/java/util/EventListener.java @@ -0,0 +1,54 @@ +/* EventListener.java -- tagging interface for all event listeners + Copyright (C) 1998, 1999, 2001, 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 java.util; + +/** + * Empty interface that is implemented by classes that need to receive + * events. Subinterfaces define methods that can be called to fire an + * event notification. Normally the name of these subinterfaces end in + * Listener and all method described by the subinterface + * take as argument an subclass of EventObject. + * + * @author Tom Tromey (tromey@cygnus.com) + * @see EventObject + * @status updated to 1.4 + */ +public interface EventListener +{ +} diff --git a/libjava/classpath/java/util/EventListenerProxy.java b/libjava/classpath/java/util/EventListenerProxy.java new file mode 100644 index 0000000..245c5ff --- /dev/null +++ b/libjava/classpath/java/util/EventListenerProxy.java @@ -0,0 +1,75 @@ +/* EventListenerProxy.java -- abstract wrapper for event listeners + 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 java.util; + +/** + * An abstract wrapper for event listeners. This allows subclasses to + * attach additional parameters to an existing event listener to create + * a new one. Subclasses are expected to add methods to set and retrieve + * any attached properties. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class EventListenerProxy implements EventListener +{ + /** The listener that this proxy wraps. */ + private final EventListener listener; + + /** + * Construct a proxy event listener, given an existing one to augment. + * + * @param listener the listener to wrap + */ + public EventListenerProxy(EventListener listener) + { + this.listener = listener; + } + + /** + * Return the wrapped event listener. + * + * @return the listener associated with this proxy + */ + public EventListener getListener() + { + return listener; + } +} // class EventListenerProxy diff --git a/libjava/classpath/java/util/EventObject.java b/libjava/classpath/java/util/EventObject.java new file mode 100644 index 0000000..7ced18a --- /dev/null +++ b/libjava/classpath/java/util/EventObject.java @@ -0,0 +1,101 @@ +/* EventObject.java -- represents an event on an object + Copyright (C) 1999, 2000, 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 java.util; + +import java.io.Serializable; + +/** + * Represents Events fired by Objects. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see EventListener + * @since 1.1 + * @status updated to 1.4 + */ +public class EventObject implements Serializable +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5516075349620653480L; + + /** + * The source object; in other words, the object which this event takes + * place on. + */ + protected transient Object source; + + /** + * Constructs an EventObject with the specified source. + * + * @param source the source of the event + * @throws IllegalArgumentException if source is null (This is not + * specified, but matches the behavior of the JDK) + */ + public EventObject(Object source) + { + // This check for null is stupid, if you ask me, since source is + // protected and non-final, so a subclass can set it to null later on. + if (source == null) + throw new IllegalArgumentException(); + this.source = source; + } + + /** + * Returns the source of the event. + * + * @return the event source + */ + public Object getSource() + { + return source; + } + + /** + * Converts the event to a String. The format is not specified, but by + * observation, the JDK uses: + * getClass().getName() + "[source=" + source + "]";. + * + * @return String representation of the Event + */ + public String toString() + { + return getClass().getName() + "[source=" + source + "]"; + } +} // class EventObject diff --git a/libjava/classpath/java/util/GregorianCalendar.java b/libjava/classpath/java/util/GregorianCalendar.java new file mode 100644 index 0000000..b086a7d --- /dev/null +++ b/libjava/classpath/java/util/GregorianCalendar.java @@ -0,0 +1,1343 @@ +/* java.util.GregorianCalendar + Copyright (C) 1998, 1999, 2001, 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 java.util; + + +/** + *

    + * This class represents the Gregorian calendar, that is used in most + * countries all over the world. It does also handle the Julian calendar + * for dates smaller than the date of the change to the Gregorian calendar. + * The Gregorian calendar differs from the Julian calendar by a different + * leap year rule (no leap year every 100 years, except if year is divisible + * by 400). + *

    + *

    + * This change date is different from country to country, and can be changed with + * setGregorianChange. The first countries to adopt the Gregorian + * calendar did so on the 15th of October, 1582. This date followed October + * the 4th, 1582 in the Julian calendar system. The non-existant days that were + * omitted when the change took place are interpreted as Gregorian dates. + *

    + *

    + * Prior to the changeover date, New Year's Day occurred on the 25th of March. + * However, this class always takes New Year's Day as being the 1st of January. + * Client code should manually adapt the year value, if required, for dates + * between January the 1st and March the 24th in years prior to the changeover. + *

    + *

    + * Any date infinitely forwards or backwards in time can be represented by + * this class. A proleptic calendar system is used, which allows + * future dates to be created via the existing rules. This allows meaningful + * and consistent dates to be produced for all years. However, dates are only + * historically accurate following March the 1st, 4AD when the Julian calendar + * system was adopted. Prior to this, leap year rules were applied erraticly. + *

    + *

    + * There are two eras available for the Gregorian calendar, namely BC and AD. + *

    + *

    + * Weeks are defined as a period of seven days, beginning on the first day + * of the week, as returned by getFirstDayOfWeek(), and ending + * on the day prior to this. + *

    + *

    + * The weeks of the year are numbered from 1 to a possible 53. The first week + * of the year is defined as the first week that contains at least the minimum + * number of days of the first week in the new year (retrieved via + * getMinimalDaysInFirstWeek()). All weeks after this are numbered + * from 2 onwards. + *

    + *

    + * For example, take the year 2004. It began on a Thursday. The first week + * of 2004 depends both on where a week begins and how long it must minimally + * last. Let's say that the week begins on a Monday and must have a minimum + * of 5 days. In this case, the first week begins on Monday, the 5th of January. + * The first 4 days (Thursday to Sunday) are not eligible, as they are too few + * to make up the minimum number of days of the first week which must be in + * the new year. If the minimum was lowered to 4 days, then the first week + * would instead begin on Monday, the 29th of December, 2003. This first week + * has 4 of its days in the new year, and is now eligible. + *

    + *

    + * The weeks of the month are numbered from 0 to a possible 6. The first week + * of the month (numbered 1) is a set of days, prior to the first day of the week, + * which number at least the minimum number of days in a week. Unlike the first + * week of the year, the first week of the month only uses days from that particular + * month. As a consequence, it may have a variable number of days (from the minimum + * number required up to a full week of 7) and it need not start on the first day of + * the week. It must, however, be following by the first day of the week, as this + * marks the beginning of week 2. Any days of the month which occur prior to the + * first week (because the first day of the week occurs before the minimum number + * of days is met) are seen as week 0. + *

    + *

    + * Again, we will take the example of the year 2004 to demonstrate this. September + * 2004 begins on a Wednesday. Taking our first day of the week as Monday, and the + * minimum length of the first week as 6, we find that week 1 runs from Monday, + * the 6th of September to Sunday the 12th. Prior to the 6th, there are only + * 5 days (Wednesday through to Sunday). This is too small a number to meet the + * minimum, so these are classed as being days in week 0. Week 2 begins on the + * 13th, and so on. This changes if we reduce the minimum to 5. In this case, + * week 1 is a truncated week from Wednesday the 1st to Sunday the 5th, and week + * 0 doesn't exist. The first seven day week is week 2, starting on the 6th. + *

    + *

    + * On using the clear() method, the Gregorian calendar returns + * to its default value of the 1st of January, 1970 AD 00:00:00 (the epoch). + * The day of the week is set to the correct day for that particular time. + * The day is also the first of the month, and the date is in week 0. + *

    + * + * @see Calendar + * @see TimeZone + * @see Calendar#getFirstDayOfWeek() + * @see Calendar#getMinimalDaysInFirstWeek() + */ +public class GregorianCalendar extends Calendar +{ + /** + * Constant representing the era BC (Before Christ). + */ + public static final int BC = 0; + + /** + * Constant representing the era AD (Anno Domini). + */ + public static final int AD = 1; + + /** + * The point at which the Gregorian calendar rules were used. + * This may be changed by using setGregorianChange; + * The default is midnight (UTC) on October 5, 1582 (Julian), + * or October 15, 1582 (Gregorian). + * + * @serial the changeover point from the Julian calendar + * system to the Gregorian. + */ + private long gregorianCutover = (new Date((24 * 60 * 60 * 1000L) * (((1582 * (365 * 4 + + 1)) / 4 + + (java.util.Calendar.OCTOBER * (31 + + 30 + 31 + 30 + 31) - 9) / 5 + 5) + - ((1970 * (365 * 4 + 1)) / 4 + 1 + - 13)))).getTime(); + + /** + * For compatability with Sun's JDK. + */ + static final long serialVersionUID = -8125100834729963327L; + + /** + * Days in the epoch. Relative Jan 1, year '0' which is not a leap year. + * (although there is no year zero, this does not matter.) + * This is consistent with the formula: + * = (year-1)*365L + ((year-1) >> 2) + * + * Plus the gregorian correction: + * Math.floor((year-1) / 400.) - Math.floor((year-1) / 100.); + * For a correct julian date, the correction is -2 instead. + * + * The gregorian cutover in 1582 was 10 days, so by calculating the + * correction from year zero, we have 15 non-leap days (even centuries) + * minus 3 leap days (year 400,800,1200) = 12. Subtracting two corrects + * this to the correct number 10. + */ + private static final int EPOCH_DAYS = 719162; + + /** + * Constructs a new GregorianCalender representing the current + * time, using the default time zone and the default locale. + */ + public GregorianCalendar() + { + this(TimeZone.getDefault(), Locale.getDefault()); + } + + /** + * Constructs a new GregorianCalender representing the current + * time, using the specified time zone and the default locale. + * + * @param zone a time zone. + */ + public GregorianCalendar(TimeZone zone) + { + this(zone, Locale.getDefault()); + } + + /** + * Constructs a new GregorianCalender representing the current + * time, using the default time zone and the specified locale. + * + * @param locale a locale. + */ + public GregorianCalendar(Locale locale) + { + this(TimeZone.getDefault(), locale); + } + + /** + * Constructs a new GregorianCalender representing the current + * time with the given time zone and the given locale. + * + * @param zone a time zone. + * @param locale a locale. + */ + public GregorianCalendar(TimeZone zone, Locale locale) + { + this(zone, locale, false); + setTimeInMillis(System.currentTimeMillis()); + complete(); + } + + /** + * Common constructor that all constructors should call. + * @param zone a time zone. + * @param locale a locale. + * @param unused unused parameter to make the signature differ from + * the public constructor (TimeZone, Locale). + */ + private GregorianCalendar(TimeZone zone, Locale locale, boolean unused) + { + super(zone, locale); + } + + /** + * Constructs a new GregorianCalendar representing midnight on the + * given date with the default time zone and locale. + * + * @param year corresponds to the YEAR time field. + * @param month corresponds to the MONTH time field. + * @param day corresponds to the DAY time field. + */ + public GregorianCalendar(int year, int month, int day) + { + this(TimeZone.getDefault(), Locale.getDefault(), false); + set(year, month, day); + } + + /** + * Constructs a new GregorianCalendar representing midnight on the + * given date with the default time zone and locale. + * + * @param year corresponds to the YEAR time field. + * @param month corresponds to the MONTH time field. + * @param day corresponds to the DAY time field. + * @param hour corresponds to the HOUR_OF_DAY time field. + * @param minute corresponds to the MINUTE time field. + */ + public GregorianCalendar(int year, int month, int day, int hour, int minute) + { + this(TimeZone.getDefault(), Locale.getDefault(), false); + set(year, month, day, hour, minute); + } + + /** + * Constructs a new GregorianCalendar representing midnight on the + * given date with the default time zone and locale. + * + * @param year corresponds to the YEAR time field. + * @param month corresponds to the MONTH time field. + * @param day corresponds to the DAY time field. + * @param hour corresponds to the HOUR_OF_DAY time field. + * @param minute corresponds to the MINUTE time field. + * @param second corresponds to the SECOND time field. + */ + public GregorianCalendar(int year, int month, int day, int hour, int minute, + int second) + { + this(TimeZone.getDefault(), Locale.getDefault(), false); + set(year, month, day, hour, minute, second); + } + + /** + * Sets the date of the switch from Julian dates to Gregorian dates. + * You can use new Date(Long.MAX_VALUE) to use a pure + * Julian calendar, or Long.MIN_VALUE for a pure Gregorian + * calendar. + * + * @param date the date of the change. + */ + public void setGregorianChange(Date date) + { + gregorianCutover = date.getTime(); + } + + /** + * Gets the date of the switch from Julian dates to Gregorian dates. + * + * @return the date of the change. + */ + public final Date getGregorianChange() + { + return new Date(gregorianCutover); + } + + /** + *

    + * Determines if the given year is a leap year. The result is + * undefined if the Gregorian change took place in 1800, so that + * the end of February is skipped, and that year is specified. + * (well...). + *

    + *

    + * To specify a year in the BC era, use a negative value calculated + * as 1 - y, where y is the required year in BC. So, 1 BC is 0, + * 2 BC is -1, 3 BC is -2, etc. + *

    + * + * @param year a year (use a negative value for BC). + * @return true, if the given year is a leap year, false otherwise. + */ + public boolean isLeapYear(int year) + { + // Only years divisible by 4 can be leap years + if ((year & 3) != 0) + return false; + + // Is the leap-day a Julian date? Then it's a leap year + if (! isGregorian(year, 31 + 29 - 1)) + return true; + + // Apply gregorian rules otherwise + return ((year % 100) != 0 || (year % 400) == 0); + } + + /** + * Retrieves the day of the week corresponding to the specified + * day of the specified year. + * + * @param year the year in which the dayOfYear occurs. + * @param dayOfYear the day of the year (an integer between 0 and + * and 366) + */ + private int getWeekDay(int year, int dayOfYear) + { + boolean greg = isGregorian(year, dayOfYear); + int day = (int) getLinearDay(year, dayOfYear, greg); + + // The epoch was a thursday. + int weekday = (day + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + return weekday; + } + + /** + * Returns the day of the week for the first day of a given month (0..11) + */ + private int getFirstDayOfMonth(int year, int month) + { + int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + if (month > 11) + { + year += (month / 12); + month = month % 12; + } + + if (month < 0) + { + year += (int) month / 12; + month = month % 12; + if (month < 0) + { + month += 12; + year--; + } + } + + int dayOfYear = dayCount[month] + 1; + if (month > 1) + if (isLeapYear(year)) + dayOfYear++; + + boolean greg = isGregorian(year, dayOfYear); + int day = (int) getLinearDay(year, dayOfYear, greg); + + // The epoch was a thursday. + int weekday = (day + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + return weekday; + } + + /** + * Takes a year, and a (zero based) day of year and determines + * if it is gregorian or not. + */ + private boolean isGregorian(int year, int dayOfYear) + { + int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear + - EPOCH_DAYS; // gregorian days from 1 to epoch. + int gregFactor = (int) Math.floor((double) (year - 1) / 400.) + - (int) Math.floor((double) (year - 1) / 100.); + + return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover); + } + + /** + * Check set fields for validity, without leniency. + * + * @throws IllegalArgumentException if a field is invalid + */ + private void nonLeniencyCheck() throws IllegalArgumentException + { + int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + int year = fields[YEAR]; + int month = fields[MONTH]; + int leap = isLeapYear(year) ? 1 : 0; + + if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC) + throw new IllegalArgumentException("Illegal ERA."); + if (isSet[YEAR] && fields[YEAR] < 1) + throw new IllegalArgumentException("Illegal YEAR."); + if (isSet[MONTH] && (month < 0 || month > 11)) + throw new IllegalArgumentException("Illegal MONTH."); + if (isSet[WEEK_OF_YEAR]) + { + int daysInYear = 365 + leap; + daysInYear += (getFirstDayOfMonth(year, 0) - 1); // pad first week + int last = getFirstDayOfMonth(year, 11) + 4; + if (last > 7) + last -= 7; + daysInYear += 7 - last; + int weeks = daysInYear / 7; + if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks) + throw new IllegalArgumentException("Illegal WEEK_OF_YEAR."); + } + + if (isSet[WEEK_OF_MONTH]) + { + int weeks = (month == 1 && leap == 0) ? 4 : 5; + if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks) + throw new IllegalArgumentException("Illegal WEEK_OF_MONTH."); + } + + if (isSet[DAY_OF_MONTH]) + if (fields[DAY_OF_MONTH] < 1 + || fields[DAY_OF_MONTH] > month_days[month] + + ((month == 1) ? leap : 0)) + throw new IllegalArgumentException("Illegal DAY_OF_MONTH."); + + if (isSet[DAY_OF_YEAR] + && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap)) + throw new IllegalArgumentException("Illegal DAY_OF_YEAR."); + + if (isSet[DAY_OF_WEEK] + && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7)) + throw new IllegalArgumentException("Illegal DAY_OF_WEEK."); + + if (isSet[DAY_OF_WEEK_IN_MONTH]) + { + int weeks = (month == 1 && leap == 0) ? 4 : 5; + if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks + || fields[DAY_OF_WEEK_IN_MONTH] > weeks) + throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH."); + } + + if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM) + throw new IllegalArgumentException("Illegal AM_PM."); + if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11)) + throw new IllegalArgumentException("Illegal HOUR."); + if (isSet[HOUR_OF_DAY] + && (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23)) + throw new IllegalArgumentException("Illegal HOUR_OF_DAY."); + if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59)) + throw new IllegalArgumentException("Illegal MINUTE."); + if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59)) + throw new IllegalArgumentException("Illegal SECOND."); + if (isSet[MILLISECOND] + && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999)) + throw new IllegalArgumentException("Illegal MILLISECOND."); + if (isSet[ZONE_OFFSET] + && (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L + || fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L)) + throw new IllegalArgumentException("Illegal ZONE_OFFSET."); + if (isSet[DST_OFFSET] + && (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L + || fields[DST_OFFSET] > 12 * 60 * 60 * 1000L)) + throw new IllegalArgumentException("Illegal DST_OFFSET."); + } + + /** + * Converts the time field values (fields) to + * milliseconds since the epoch UTC (time). + * + * @throws IllegalArgumentException if any calendar fields + * are invalid. + */ + protected synchronized void computeTime() + { + int millisInDay = 0; + int era = fields[ERA]; + int year = fields[YEAR]; + int month = fields[MONTH]; + int day = fields[DAY_OF_MONTH]; + + int minute = fields[MINUTE]; + int second = fields[SECOND]; + int millis = fields[MILLISECOND]; + int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + int hour = 0; + + if (! isLenient()) + nonLeniencyCheck(); + + if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR])) + { + // 5: YEAR + DAY_OF_WEEK + WEEK_OF_YEAR + if (isSet[WEEK_OF_YEAR]) + { + int first = getFirstDayOfMonth(year, 0); + int offs = 1; + int daysInFirstWeek = getFirstDayOfWeek() - first; + if (daysInFirstWeek <= 0) + daysInFirstWeek += 7; + + if (daysInFirstWeek < getMinimalDaysInFirstWeek()) + offs += daysInFirstWeek; + else + offs -= 7 - daysInFirstWeek; + month = 0; + day = offs + 7 * (fields[WEEK_OF_YEAR] - 1); + offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek(); + + if (offs < 0) + offs += 7; + day += offs; + } + else + { + // 4: YEAR + DAY_OF_YEAR + month = 0; + day = fields[DAY_OF_YEAR]; + } + } + else + { + if (isSet[DAY_OF_WEEK]) + { + int first = getFirstDayOfMonth(year, month); + + // 3: YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK + if (isSet[DAY_OF_WEEK_IN_MONTH]) + { + if (fields[DAY_OF_WEEK_IN_MONTH] < 0) + { + month++; + first = getFirstDayOfMonth(year, month); + day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH]); + } + else + day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1); + + int offs = fields[DAY_OF_WEEK] - first; + if (offs < 0) + offs += 7; + day += offs; + } + else + { // 2: YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK + int offs = 1; + int daysInFirstWeek = getFirstDayOfWeek() - first; + if (daysInFirstWeek <= 0) + daysInFirstWeek += 7; + + if (daysInFirstWeek < getMinimalDaysInFirstWeek()) + offs += daysInFirstWeek; + else + offs -= 7 - daysInFirstWeek; + + day = offs + 7 * (fields[WEEK_OF_MONTH] - 1); + offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek(); + if (offs <= 0) + offs += 7; + day += offs; + } + } + + // 1: YEAR + MONTH + DAY_OF_MONTH + } + if (era == BC && year > 0) + year = 1 - year; + + // rest of code assumes day/month/year set + // should negative BC years be AD? + // get the hour (but no check for validity) + if (isSet[HOUR]) + { + hour = fields[HOUR]; + if (fields[AM_PM] == PM) + hour += 12; + } + else + hour = fields[HOUR_OF_DAY]; + + // Read the era,year,month,day fields and convert as appropriate. + // Calculate number of milliseconds into the day + // This takes care of both h, m, s, ms over/underflows. + long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis; + day += allMillis / (24 * 60 * 60 * 1000L); + millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L)); + + if (month < 0) + { + year += (int) month / 12; + month = month % 12; + if (month < 0) + { + month += 12; + year--; + } + } + if (month > 11) + { + year += (month / 12); + month = month % 12; + } + + month_days[1] = isLeapYear(year) ? 29 : 28; + + while (day <= 0) + { + if (month == 0) + { + year--; + month_days[1] = isLeapYear(year) ? 29 : 28; + } + month = (month + 11) % 12; + day += month_days[month]; + } + while (day > month_days[month]) + { + day -= (month_days[month]); + month = (month + 1) % 12; + if (month == 0) + { + year++; + month_days[1] = isLeapYear(year) ? 29 : 28; + } + } + + // ok, by here we have valid day,month,year,era and millisinday + int dayOfYear = dayCount[month] + day - 1; // (day starts on 1) + if (isLeapYear(year) && month > 1) + dayOfYear++; + + int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear + - EPOCH_DAYS; // gregorian days from 1 to epoch. + int gregFactor = (int) Math.floor((double) (year - 1) / 400.) + - (int) Math.floor((double) (year - 1) / 100.); + + if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover) + relativeDay += gregFactor; + else + relativeDay -= 2; + + time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay; + + // the epoch was a Thursday. + int weekday = (int) (relativeDay + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + fields[DAY_OF_WEEK] = weekday; + + // Time zone corrections. + TimeZone zone = getTimeZone(); + int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET] + : zone.getRawOffset(); + + int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET] + : (zone.getOffset((year < 0) ? BC : AD, + (year < 0) ? 1 - year + : year, + month, day, weekday, + millisInDay) + - zone.getRawOffset()); + + time -= rawOffset + dstOffset; + + isTimeSet = true; + } + + /** + * Get the linear day in days since the epoch, using the + * Julian or Gregorian calendar as specified. If you specify a + * nonpositive year it is interpreted as BC as following: 0 is 1 + * BC, -1 is 2 BC and so on. + * + * @param year the year of the date. + * @param dayOfYear the day of year of the date; 1 based. + * @param gregorian true, if we should use the Gregorian rules. + * @return the days since the epoch, may be negative. + */ + private long getLinearDay(int year, int dayOfYear, boolean gregorian) + { + // The 13 is the number of days, that were omitted in the Gregorian + // Calender until the epoch. + // We shift right by 2 instead of dividing by 4, to get correct + // results for negative years (and this is even more efficient). + long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1) + - EPOCH_DAYS; // gregorian days from 1 to epoch. + + if (gregorian) + { + // subtract the days that are missing in gregorian calendar + // with respect to julian calendar. + // + // Okay, here we rely on the fact that the gregorian + // calendar was introduced in the AD era. This doesn't work + // with negative years. + // + // The additional leap year factor accounts for the fact that + // a leap day is not seen on Jan 1 of the leap year. + int gregOffset = (int) Math.floor((double) (year - 1) / 400.) + - (int) Math.floor((double) (year - 1) / 100.); + + return julianDay + gregOffset; + } + else + julianDay -= 2; + return julianDay; + } + + /** + * Converts the given linear day into era, year, month, + * day_of_year, day_of_month, day_of_week, and writes the result + * into the fields array. + * + * @param day the linear day. + * @param gregorian true, if we should use Gregorian rules. + */ + private void calculateDay(int[] fields, long day, boolean gregorian) + { + // the epoch was a Thursday. + int weekday = (int) (day + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + fields[DAY_OF_WEEK] = weekday; + + // get a first approximation of the year. This may be one + // year too big. + int year = 1970 + + (int) (gregorian + ? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L + + 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L)); + if (day >= 0) + year++; + + long firstDayOfYear = getLinearDay(year, 1, gregorian); + + // Now look in which year day really lies. + if (day < firstDayOfYear) + { + year--; + firstDayOfYear = getLinearDay(year, 1, gregorian); + } + + day -= firstDayOfYear - 1; // day of year, one based. + + fields[DAY_OF_YEAR] = (int) day; + if (year <= 0) + { + fields[ERA] = BC; + fields[YEAR] = 1 - year; + } + else + { + fields[ERA] = AD; + fields[YEAR] = year; + } + + int leapday = isLeapYear(year) ? 1 : 0; + if (day <= 31 + 28 + leapday) + { + fields[MONTH] = (int) day / 32; // 31->JANUARY, 32->FEBRUARY + fields[DAY_OF_MONTH] = (int) day - 31 * fields[MONTH]; + } + else + { + // A few more magic formulas + int scaledDay = ((int) day - leapday) * 5 + 8; + fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31); + fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1; + } + } + + /** + * Converts the milliseconds since the epoch UTC + * (time) to time fields + * (fields). + */ + protected synchronized void computeFields() + { + boolean gregorian = (time >= gregorianCutover); + + TimeZone zone = getTimeZone(); + fields[ZONE_OFFSET] = zone.getRawOffset(); + long localTime = time + fields[ZONE_OFFSET]; + + long day = localTime / (24 * 60 * 60 * 1000L); + int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L)); + + if (millisInDay < 0) + { + millisInDay += (24 * 60 * 60 * 1000); + day--; + } + + calculateDay(fields, day, gregorian); + fields[DST_OFFSET] = zone.getOffset(fields[ERA], fields[YEAR], + fields[MONTH], fields[DAY_OF_MONTH], + fields[DAY_OF_WEEK], millisInDay) + - fields[ZONE_OFFSET]; + + millisInDay += fields[DST_OFFSET]; + if (millisInDay >= 24 * 60 * 60 * 1000) + { + millisInDay -= 24 * 60 * 60 * 1000; + calculateDay(fields, ++day, gregorian); + } + + fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7; + + // which day of the week are we (0..6), relative to getFirstDayOfWeek + int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7; + + fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 12) / 7; + + int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7; + + // Do the Correction: getMinimalDaysInFirstWeek() is always in the + // first week. + int minDays = getMinimalDaysInFirstWeek(); + int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays) + - getFirstDayOfWeek()) % 7; + if (minDays - firstWeekday < 1) + weekOfYear++; + fields[WEEK_OF_YEAR] = weekOfYear; + + int hourOfDay = millisInDay / (60 * 60 * 1000); + fields[AM_PM] = (hourOfDay < 12) ? AM : PM; + int hour = hourOfDay % 12; + fields[HOUR] = hour; + fields[HOUR_OF_DAY] = hourOfDay; + millisInDay %= (60 * 60 * 1000); + fields[MINUTE] = millisInDay / (60 * 1000); + millisInDay %= (60 * 1000); + fields[SECOND] = millisInDay / (1000); + fields[MILLISECOND] = millisInDay % 1000; + + areFieldsSet = isSet[ERA] = isSet[YEAR] = isSet[MONTH] = isSet[WEEK_OF_YEAR] = isSet[WEEK_OF_MONTH] = isSet[DAY_OF_MONTH] = isSet[DAY_OF_YEAR] = isSet[DAY_OF_WEEK] = isSet[DAY_OF_WEEK_IN_MONTH] = isSet[AM_PM] = isSet[HOUR] = isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] = isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true; + } + + /** + * Compares the given calendar with this. An object, o, is + * equivalent to this if it is also a GregorianCalendar + * with the same time since the epoch under the same conditions + * (same change date and same time zone). + * + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, that represents + * the same time (but doesn't necessarily have the same fields). + * @throws IllegalArgumentException if one of the fields + * ZONE_OFFSET or DST_OFFSET is + * specified, if an unknown field is specified or if one + * of the calendar fields receives an illegal value when + * leniancy is not enabled. + */ + public boolean equals(Object o) + { + if (! (o instanceof GregorianCalendar)) + return false; + + GregorianCalendar cal = (GregorianCalendar) o; + return (cal.getTimeInMillis() == getTimeInMillis()); + } + + /** + * Adds the specified amount of time to the given time field. The + * amount may be negative to subtract the time. If the field overflows + * it does what you expect: Jan, 25 + 10 Days is Feb, 4. + * @param field one of the time field constants. + * @param amount the amount of time to add. + * @exception IllegalArgumentException if field is + * ZONE_OFFSET, DST_OFFSET, or invalid; or + * if amount contains an out-of-range value and the calendar + * is not in lenient mode. + */ + public void add(int field, int amount) + { + switch (field) + { + case YEAR: + complete(); + fields[YEAR] += amount; + isTimeSet = false; + break; + case MONTH: + complete(); + int months = fields[MONTH] + amount; + fields[YEAR] += months / 12; + fields[MONTH] = months % 12; + if (fields[MONTH] < 0) + { + fields[MONTH] += 12; + fields[YEAR]--; + } + int maxDay = getActualMaximum(DAY_OF_MONTH); + if (fields[DAY_OF_MONTH] > maxDay) + fields[DAY_OF_MONTH] = maxDay; + set(YEAR, fields[YEAR]); + set(MONTH, fields[MONTH]); + break; + case DAY_OF_MONTH: + case DAY_OF_YEAR: + case DAY_OF_WEEK: + if (! isTimeSet) + computeTime(); + time += amount * (24 * 60 * 60 * 1000L); + areFieldsSet = false; + break; + case WEEK_OF_YEAR: + case WEEK_OF_MONTH: + case DAY_OF_WEEK_IN_MONTH: + if (! isTimeSet) + computeTime(); + time += amount * (7 * 24 * 60 * 60 * 1000L); + areFieldsSet = false; + break; + case AM_PM: + if (! isTimeSet) + computeTime(); + time += amount * (12 * 60 * 60 * 1000L); + areFieldsSet = false; + break; + case HOUR: + case HOUR_OF_DAY: + if (! isTimeSet) + computeTime(); + time += amount * (60 * 60 * 1000L); + areFieldsSet = false; + break; + case MINUTE: + if (! isTimeSet) + computeTime(); + time += amount * (60 * 1000L); + areFieldsSet = false; + break; + case SECOND: + if (! isTimeSet) + computeTime(); + time += amount * (1000L); + areFieldsSet = false; + break; + case MILLISECOND: + if (! isTimeSet) + computeTime(); + time += amount; + areFieldsSet = false; + break; + case ZONE_OFFSET: + case DST_OFFSET:default: + throw new IllegalArgumentException("Invalid or unknown field"); + } + } + + /** + * Rolls the specified time field up or down. This means add one + * to the specified field, but don't change the other fields. If + * the maximum for this field is reached, start over with the + * minimum value. + * + * Note: There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically converted to July, 1. + * This requires lenient settings. + * + * @param field the time field. One of the time field constants. + * @param up the direction, true for up, false for down. + * @throws IllegalArgumentException if one of the fields + * ZONE_OFFSET or DST_OFFSET is + * specified, if an unknown field is specified or if one + * of the calendar fields receives an illegal value when + * leniancy is not enabled. + */ + public void roll(int field, boolean up) + { + roll(field, up ? 1 : -1); + } + + /** + * Checks that the fields are still within their legal bounds, + * following use of the roll() method. + * + * @param field the field to check. + * @param delta multipler for alterations to the time. + * @see #roll(int, boolean) + * @see #roll(int, int) + */ + private void cleanUpAfterRoll(int field, int delta) + { + switch (field) + { + case ERA: + case YEAR: + case MONTH: + // check that day of month is still in correct range + if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH)) + fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH); + isTimeSet = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_MONTH: + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (24 * 60 * 60 * 1000L); + break; + case WEEK_OF_MONTH: + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (7 * 24 * 60 * 60 * 1000L); + break; + case DAY_OF_WEEK_IN_MONTH: + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (7 * 24 * 60 * 60 * 1000L); + break; + case DAY_OF_YEAR: + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (24 * 60 * 60 * 1000L); + break; + case WEEK_OF_YEAR: + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + time += delta * (7 * 24 * 60 * 60 * 1000L); + break; + case AM_PM: + isSet[HOUR_OF_DAY] = false; + time += delta * (12 * 60 * 60 * 1000L); + break; + case HOUR: + isSet[HOUR_OF_DAY] = false; + time += delta * (60 * 60 * 1000L); + break; + case HOUR_OF_DAY: + isSet[HOUR] = false; + isSet[AM_PM] = false; + time += delta * (60 * 60 * 1000L); + break; + case MINUTE: + time += delta * (60 * 1000L); + break; + case SECOND: + time += delta * (1000L); + break; + case MILLISECOND: + time += delta; + break; + } + } + + /** + * Rolls the specified time field by the given amount. This means + * add amount to the specified field, but don't change the other + * fields. If the maximum for this field is reached, start over + * with the minimum value and vice versa for negative amounts. + * + * Note: There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically corrected to June, 30. + * + * @param field the time field. One of the time field constants. + * @param amount the amount by which we should roll. + * @throws IllegalArgumentException if one of the fields + * ZONE_OFFSET or DST_OFFSET is + * specified, if an unknown field is specified or if one + * of the calendar fields receives an illegal value when + * leniancy is not enabled. + */ + public void roll(int field, int amount) + { + switch (field) + { + case DAY_OF_WEEK: + // day of week is special: it rolls automatically + add(field, amount); + return; + case ZONE_OFFSET: + case DST_OFFSET: + throw new IllegalArgumentException("Can't roll time zone"); + } + complete(); + int min = getActualMinimum(field); + int range = getActualMaximum(field) - min + 1; + int oldval = fields[field]; + int newval = (oldval - min + range + amount) % range + min; + if (newval < min) + newval += range; + fields[field] = newval; + cleanUpAfterRoll(field, newval - oldval); + } + + /** + * The minimum values for the calendar fields. + */ + private static final int[] minimums = + { + BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1, AM, + 1, 0, 0, 0, 0, -(12 * 60 * 60 * 1000), + 0 + }; + + /** + * The maximum values for the calendar fields. + */ + private static final int[] maximums = + { + AD, 5000000, 11, 53, 5, 31, 366, + SATURDAY, 5, PM, 12, 23, 59, 59, 999, + +(12 * 60 * 60 * 1000), + (12 * 60 * 60 * 1000) + }; + + /** + * Gets the smallest value that is allowed for the specified field. + * + * @param field one of the time field constants. + * @return the smallest value for the specified field. + */ + public int getMinimum(int field) + { + return minimums[field]; + } + + /** + * Gets the biggest value that is allowed for the specified field. + * + * @param field one of the time field constants. + * @return the biggest value. + */ + public int getMaximum(int field) + { + return maximums[field]; + } + + /** + * Gets the greatest minimum value that is allowed for the specified field. + * This is the largest value returned by the getActualMinimum(int) + * method. + * + * @param field the time field. One of the time field constants. + * @return the greatest minimum value. + * @see #getActualMinimum(int) + */ + public int getGreatestMinimum(int field) + { + if (field == WEEK_OF_YEAR) + return 1; + return minimums[field]; + } + + /** + * Gets the smallest maximum value that is allowed for the + * specified field. This is the smallest value returned + * by the getActualMaximum(int). For example, + * this is 28 for DAY_OF_MONTH (as all months have at least + * 28 days). + * + * @param field the time field. One of the time field constants. + * @return the least maximum value. + * @see #getActualMaximum(int) + * @since 1.2 + */ + public int getLeastMaximum(int field) + { + switch (field) + { + case WEEK_OF_YEAR: + return 52; + case DAY_OF_MONTH: + return 28; + case DAY_OF_YEAR: + return 365; + case DAY_OF_WEEK_IN_MONTH: + case WEEK_OF_MONTH: + return 4; + default: + return maximums[field]; + } + } + + /** + * Gets the actual minimum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. Note that + * this calls complete() if not enough fields are set. This + * can have ugly side effects. The value given depends on the current + * time used by this instance. + * + * @param field the time field. One of the time field constants. + * @return the actual minimum value. + * @since 1.2 + */ + public int getActualMinimum(int field) + { + if (field == WEEK_OF_YEAR) + { + int min = getMinimalDaysInFirstWeek(); + if (min == 0) + return 1; + if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR]) + complete(); + + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + int weekday = getWeekDay(year, min); + if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1) + return 1; + return 0; + } + return minimums[field]; + } + + /** + * Gets the actual maximum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. Note that + * this calls complete() if not enough fields are set. This + * can have ugly side effects. The value given depends on the current time + * used by this instance; thus, leap years have a maximum day of month value of + * 29, rather than 28. + * + * @param field the time field. One of the time field constants. + * @return the actual maximum value. + */ + public int getActualMaximum(int field) + { + switch (field) + { + case WEEK_OF_YEAR: + { + if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR]) + complete(); + + // This is wrong for the year that contains the gregorian change. + // I.e it gives the weeks in the julian year or in the gregorian + // year in that case. + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + int lastDay = isLeapYear(year) ? 366 : 365; + int weekday = getWeekDay(year, lastDay); + int week = (lastDay + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7; + + int minimalDays = getMinimalDaysInFirstWeek(); + int firstWeekday = getWeekDay(year, minimalDays); + /* + * Is there a set of days at the beginning of the year, before the + * first day of the week, equal to or greater than the minimum number + * of days required in the first week? + */ + if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1) + return week + 1; /* Add week 1: firstWeekday through to firstDayOfWeek */ + } + case DAY_OF_MONTH: + { + if (! areFieldsSet || ! isSet[MONTH]) + complete(); + int month = fields[MONTH]; + + // If you change this, you should also change + // SimpleTimeZone.getDaysInMonth(); + if (month == FEBRUARY) + { + if (! isSet[YEAR] || ! isSet[ERA]) + complete(); + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + return isLeapYear(year) ? 29 : 28; + } + else if (month < AUGUST) + return 31 - (month & 1); + else + return 30 + (month & 1); + } + case DAY_OF_YEAR: + { + if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR]) + complete(); + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + return isLeapYear(year) ? 366 : 365; + } + case DAY_OF_WEEK_IN_MONTH: + { + // This is wrong for the month that contains the gregorian change. + int daysInMonth = getActualMaximum(DAY_OF_MONTH); + + // That's black magic, I know + return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7; + } + case WEEK_OF_MONTH: + { + int daysInMonth = getActualMaximum(DAY_OF_MONTH); + int weekday = (daysInMonth - fields[DAY_OF_MONTH] + + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY; + return (daysInMonth + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7; + } + default: + return maximums[field]; + } + } +} diff --git a/libjava/classpath/java/util/HashMap.java b/libjava/classpath/java/util/HashMap.java new file mode 100644 index 0000000..5ca9cf6 --- /dev/null +++ b/libjava/classpath/java/util/HashMap.java @@ -0,0 +1,906 @@ +/* HashMap.java -- a class providing a basic hashtable data structure, + mapping Object --> Object + 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 java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +// NOTE: This implementation is very similar to that of Hashtable. If you fix +// a bug in here, chances are you should make a similar change to the Hashtable +// code. + +// NOTE: This implementation has some nasty coding style in order to +// support LinkedHashMap, which extends this. + +/** + * This class provides a hashtable-backed implementation of the + * Map interface. + *

    + * + * It uses a hash-bucket approach; that is, hash collisions are handled + * by linking the new node off of the pre-existing node (or list of + * nodes). In this manner, techniques such as linear probing (which + * can cause primary clustering) and rehashing (which does not fit very + * well with Java's method of precomputing hash codes) are avoided. + *

    + * + * Under ideal circumstances (no collisions), HashMap offers O(1) + * performance on most operations (containsValue() is, + * of course, O(n)). In the worst case (all keys map to the same + * hash code -- very unlikely), most operations are O(n). + *

    + * + * HashMap is part of the JDK1.2 Collections API. It differs from + * Hashtable in that it accepts the null key and null values, and it + * does not support "Enumeration views." Also, it is not synchronized; + * if you plan to use it in multiple threads, consider using:
    + * Map m = Collections.synchronizedMap(new HashMap(...)); + *

    + * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * ConcurrentModificationException rather than exhibit + * non-deterministic behavior. + * + * @author Jon Zeppieri + * @author Jochen Hoenicke + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Object#hashCode() + * @see Collection + * @see Map + * @see TreeMap + * @see LinkedHashMap + * @see IdentityHashMap + * @see Hashtable + * @since 1.2 + * @status updated to 1.4 + */ +public class HashMap extends AbstractMap + implements Map, Cloneable, Serializable +{ + /** + * Default number of buckets. This is the value the JDK 1.3 uses. Some + * early documentation specified this value as 101. That is incorrect. + * Package visible for use by HashSet. + */ + static final int DEFAULT_CAPACITY = 11; + + /** + * The default load factor; this is explicitly specified by the spec. + * Package visible for use by HashSet. + */ + static final float DEFAULT_LOAD_FACTOR = 0.75f; + + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = 362498820763181265L; + + /** + * The rounded product of the capacity and the load factor; when the number + * of elements exceeds the threshold, the HashMap calls + * rehash(). + * @serial the threshold for rehashing + */ + private int threshold; + + /** + * Load factor of this HashMap: used in computing the threshold. + * Package visible for use by HashSet. + * @serial the load factor + */ + final float loadFactor; + + /** + * Array containing the actual key-value mappings. + * Package visible for use by nested and subclasses. + */ + transient HashEntry[] buckets; + + /** + * Counts the number of modifications this HashMap has undergone, used + * by Iterators to know when to throw ConcurrentModificationExceptions. + * Package visible for use by nested and subclasses. + */ + transient int modCount; + + /** + * The size of this HashMap: denotes the number of key-value pairs. + * Package visible for use by nested and subclasses. + */ + transient int size; + + /** + * The cache for {@link #entrySet()}. + */ + private transient Set entries; + + /** + * Class to represent an entry in the hash table. Holds a single key-value + * pair. Package visible for use by subclass. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + static class HashEntry extends AbstractMap.BasicMapEntry + { + /** + * The next entry in the linked list. Package visible for use by subclass. + */ + HashEntry next; + + /** + * Simple constructor. + * @param key the key + * @param value the value + */ + HashEntry(Object key, Object value) + { + super(key, value); + } + + /** + * Called when this entry is accessed via {@link #put(Object, Object)}. + * This version does nothing, but in LinkedHashMap, it must do some + * bookkeeping for access-traversal mode. + */ + void access() + { + } + + /** + * Called when this entry is removed from the map. This version simply + * returns the value, but in LinkedHashMap, it must also do bookkeeping. + * + * @return the value of this key as it is removed + */ + Object cleanup() + { + return value; + } + } + + /** + * Construct a new HashMap with the default capacity (11) and the default + * load factor (0.75). + */ + public HashMap() + { + this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR); + } + + /** + * Construct a new HashMap from the given Map, with initial capacity + * the greater of the size of m or the default of 11. + *

    + * + * Every element in Map m will be put into this new HashMap. + * + * @param m a Map whose key / value pairs will be put into the new HashMap. + * NOTE: key / value pairs are not cloned in this constructor. + * @throws NullPointerException if m is null + */ + public HashMap(Map m) + { + this(Math.max(m.size() * 2, DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR); + putAll(m); + } + + /** + * Construct a new HashMap with a specific inital capacity and + * default load factor of 0.75. + * + * @param initialCapacity the initial capacity of this HashMap (>=0) + * @throws IllegalArgumentException if (initialCapacity < 0) + */ + public HashMap(int initialCapacity) + { + this(initialCapacity, DEFAULT_LOAD_FACTOR); + } + + /** + * Construct a new HashMap with a specific inital capacity and load factor. + * + * @param initialCapacity the initial capacity (>=0) + * @param loadFactor the load factor (> 0, not NaN) + * @throws IllegalArgumentException if (initialCapacity < 0) || + * ! (loadFactor > 0.0) + */ + public HashMap(int initialCapacity, float loadFactor) + { + if (initialCapacity < 0) + throw new IllegalArgumentException("Illegal Capacity: " + + initialCapacity); + if (! (loadFactor > 0)) // check for NaN too + throw new IllegalArgumentException("Illegal Load: " + loadFactor); + + if (initialCapacity == 0) + initialCapacity = 1; + buckets = new HashEntry[initialCapacity]; + this.loadFactor = loadFactor; + threshold = (int) (initialCapacity * loadFactor); + } + + /** + * Returns the number of kay-value mappings currently in this Map. + * + * @return the size + */ + public int size() + { + return size; + } + + /** + * Returns true if there are no key-value mappings currently in this Map. + * + * @return size() == 0 + */ + public boolean isEmpty() + { + return size == 0; + } + + /** + * Return the value in this HashMap associated with the supplied key, + * or null if the key maps to nothing. NOTE: Since the value + * could also be null, you must use containsKey to see if this key + * actually maps to something. + * + * @param key the key for which to fetch an associated value + * @return what the key maps to, if present + * @see #put(Object, Object) + * @see #containsKey(Object) + */ + public Object get(Object key) + { + int idx = hash(key); + HashEntry e = buckets[idx]; + while (e != null) + { + if (equals(key, e.key)) + return e.value; + e = e.next; + } + return null; + } + + /** + * Returns true if the supplied object equals() a key + * in this HashMap. + * + * @param key the key to search for in this HashMap + * @return true if the key is in the table + * @see #containsValue(Object) + */ + public boolean containsKey(Object key) + { + int idx = hash(key); + HashEntry e = buckets[idx]; + while (e != null) + { + if (equals(key, e.key)) + return true; + e = e.next; + } + return false; + } + + /** + * Puts the supplied value into the Map, mapped by the supplied key. + * The value may be retrieved by any object which equals() + * this key. NOTE: Since the prior value could also be null, you must + * first use containsKey if you want to see if you are replacing the + * key's mapping. + * + * @param key the key used to locate the value + * @param value the value to be stored in the HashMap + * @return the prior mapping of the key, or null if there was none + * @see #get(Object) + * @see Object#equals(Object) + */ + public Object put(Object key, Object value) + { + int idx = hash(key); + HashEntry e = buckets[idx]; + + while (e != null) + { + if (equals(key, e.key)) + { + e.access(); // Must call this for bookkeeping in LinkedHashMap. + Object r = e.value; + e.value = value; + return r; + } + else + e = e.next; + } + + // At this point, we know we need to add a new entry. + modCount++; + if (++size > threshold) + { + rehash(); + // Need a new hash value to suit the bigger table. + idx = hash(key); + } + + // LinkedHashMap cannot override put(), hence this call. + addEntry(key, value, idx, true); + return null; + } + + /** + * Copies all elements of the given map into this hashtable. If this table + * already has a mapping for a key, the new mapping replaces the current + * one. + * + * @param m the map to be hashed into this + */ + public void putAll(Map m) + { + Iterator itr = m.entrySet().iterator(); + while (itr.hasNext()) + { + Map.Entry e = (Map.Entry) itr.next(); + // Optimize in case the Entry is one of our own. + if (e instanceof AbstractMap.BasicMapEntry) + { + AbstractMap.BasicMapEntry entry = (AbstractMap.BasicMapEntry) e; + put(entry.key, entry.value); + } + else + put(e.getKey(), e.getValue()); + } + } + + /** + * Removes from the HashMap and returns the value which is mapped by the + * supplied key. If the key maps to nothing, then the HashMap remains + * unchanged, and null is returned. NOTE: Since the value + * could also be null, you must use containsKey to see if you are + * actually removing a mapping. + * + * @param key the key used to locate the value to remove + * @return whatever the key mapped to, if present + */ + public Object remove(Object key) + { + int idx = hash(key); + HashEntry e = buckets[idx]; + HashEntry last = null; + + while (e != null) + { + if (equals(key, e.key)) + { + modCount++; + if (last == null) + buckets[idx] = e.next; + else + last.next = e.next; + size--; + // Method call necessary for LinkedHashMap to work correctly. + return e.cleanup(); + } + last = e; + e = e.next; + } + return null; + } + + /** + * Clears the Map so it has no keys. This is O(1). + */ + public void clear() + { + if (size != 0) + { + modCount++; + Arrays.fill(buckets, null); + size = 0; + } + } + + /** + * Returns true if this HashMap contains a value o, such that + * o.equals(value). + * + * @param value the value to search for in this HashMap + * @return true if at least one key maps to the value + * @see containsKey(Object) + */ + public boolean containsValue(Object value) + { + for (int i = buckets.length - 1; i >= 0; i--) + { + HashEntry e = buckets[i]; + while (e != null) + { + if (equals(value, e.value)) + return true; + e = e.next; + } + } + return false; + } + + /** + * Returns a shallow clone of this HashMap. The Map itself is cloned, + * but its contents are not. This is O(n). + * + * @return the clone + */ + public Object clone() + { + HashMap copy = null; + try + { + copy = (HashMap) super.clone(); + } + catch (CloneNotSupportedException x) + { + // This is impossible. + } + copy.buckets = new HashEntry[buckets.length]; + copy.putAllInternal(this); + // Clear the entry cache. AbstractMap.clone() does the others. + copy.entries = null; + return copy; + } + + /** + * Returns a "set view" of this HashMap's keys. The set is backed by the + * HashMap, so changes in one show up in the other. The set supports + * element removal, but not element addition. + * + * @return a set view of the keys + * @see #values() + * @see #entrySet() + */ + public Set keySet() + { + if (keys == null) + // Create an AbstractSet with custom implementations of those methods + // that can be overridden easily and efficiently. + keys = new AbstractSet() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + // Cannot create the iterator directly, because of LinkedHashMap. + return HashMap.this.iterator(KEYS); + } + + public void clear() + { + HashMap.this.clear(); + } + + public boolean contains(Object o) + { + return containsKey(o); + } + + public boolean remove(Object o) + { + // Test against the size of the HashMap to determine if anything + // really got removed. This is necessary because the return value + // of HashMap.remove() is ambiguous in the null case. + int oldsize = size; + HashMap.this.remove(o); + return oldsize != size; + } + }; + return keys; + } + + /** + * Returns a "collection view" (or "bag view") of this HashMap's values. + * The collection is backed by the HashMap, so changes in one show up + * in the other. The collection supports element removal, but not element + * addition. + * + * @return a bag view of the values + * @see #keySet() + * @see #entrySet() + */ + public Collection values() + { + if (values == null) + // We don't bother overriding many of the optional methods, as doing so + // wouldn't provide any significant performance advantage. + values = new AbstractCollection() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + // Cannot create the iterator directly, because of LinkedHashMap. + return HashMap.this.iterator(VALUES); + } + + public void clear() + { + HashMap.this.clear(); + } + }; + return values; + } + + /** + * Returns a "set view" of this HashMap's entries. The set is backed by + * the HashMap, so changes in one show up in the other. The set supports + * element removal, but not element addition.

    + * + * Note that the iterators for all three views, from keySet(), entrySet(), + * and values(), traverse the HashMap in the same sequence. + * + * @return a set view of the entries + * @see #keySet() + * @see #values() + * @see Map.Entry + */ + public Set entrySet() + { + if (entries == null) + // Create an AbstractSet with custom implementations of those methods + // that can be overridden easily and efficiently. + entries = new AbstractSet() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + // Cannot create the iterator directly, because of LinkedHashMap. + return HashMap.this.iterator(ENTRIES); + } + + public void clear() + { + HashMap.this.clear(); + } + + public boolean contains(Object o) + { + return getEntry(o) != null; + } + + public boolean remove(Object o) + { + HashEntry e = getEntry(o); + if (e != null) + { + HashMap.this.remove(e.key); + return true; + } + return false; + } + }; + return entries; + } + + /** + * Helper method for put, that creates and adds a new Entry. This is + * overridden in LinkedHashMap for bookkeeping purposes. + * + * @param key the key of the new Entry + * @param value the value + * @param idx the index in buckets where the new Entry belongs + * @param callRemove whether to call the removeEldestEntry method + * @see #put(Object, Object) + */ + void addEntry(Object key, Object value, int idx, boolean callRemove) + { + HashEntry e = new HashEntry(key, value); + e.next = buckets[idx]; + buckets[idx] = e; + } + + /** + * Helper method for entrySet(), which matches both key and value + * simultaneously. + * + * @param o the entry to match + * @return the matching entry, if found, or null + * @see #entrySet() + */ + // Package visible, for use in nested classes. + final HashEntry getEntry(Object o) + { + if (! (o instanceof Map.Entry)) + return null; + Map.Entry me = (Map.Entry) o; + Object key = me.getKey(); + int idx = hash(key); + HashEntry e = buckets[idx]; + while (e != null) + { + if (equals(e.key, key)) + return equals(e.value, me.getValue()) ? e : null; + e = e.next; + } + return null; + } + + /** + * Helper method that returns an index in the buckets array for `key' + * based on its hashCode(). Package visible for use by subclasses. + * + * @param key the key + * @return the bucket number + */ + final int hash(Object key) + { + return key == null ? 0 : Math.abs(key.hashCode() % buckets.length); + } + + /** + * Generates a parameterized iterator. Must be overrideable, since + * LinkedHashMap iterates in a different order. + * + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + * @return the appropriate iterator + */ + Iterator iterator(int type) + { + return new HashIterator(type); + } + + /** + * A simplified, more efficient internal implementation of putAll(). clone() + * should not call putAll or put, in order to be compatible with the JDK + * implementation with respect to subclasses. + * + * @param m the map to initialize this from + */ + void putAllInternal(Map m) + { + Iterator itr = m.entrySet().iterator(); + size = 0; + while (itr.hasNext()) + { + size++; + Map.Entry e = (Map.Entry) itr.next(); + Object key = e.getKey(); + int idx = hash(key); + addEntry(key, e.getValue(), idx, false); + } + } + + /** + * Increases the size of the HashMap and rehashes all keys to new + * array indices; this is called when the addition of a new value + * would cause size() > threshold. Note that the existing Entry + * objects are reused in the new hash table. + * + *

    This is not specified, but the new size is twice the current size + * plus one; this number is not always prime, unfortunately. + */ + private void rehash() + { + HashEntry[] oldBuckets = buckets; + + int newcapacity = (buckets.length * 2) + 1; + threshold = (int) (newcapacity * loadFactor); + buckets = new HashEntry[newcapacity]; + + for (int i = oldBuckets.length - 1; i >= 0; i--) + { + HashEntry e = oldBuckets[i]; + while (e != null) + { + int idx = hash(e.key); + HashEntry dest = buckets[idx]; + HashEntry next = e.next; + e.next = buckets[idx]; + buckets[idx] = e; + e = next; + } + } + } + + /** + * Serializes this object to the given stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData the capacity(int) that is the length of the + * bucket array, the size(int) of the hash map + * are emitted first. They are followed by size entries, + * each consisting of a key (Object) and a value (Object). + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + // Write the threshold and loadFactor fields. + s.defaultWriteObject(); + + s.writeInt(buckets.length); + s.writeInt(size); + // Avoid creating a wasted Set by creating the iterator directly. + Iterator it = iterator(ENTRIES); + while (it.hasNext()) + { + HashEntry entry = (HashEntry) it.next(); + s.writeObject(entry.key); + s.writeObject(entry.value); + } + } + + /** + * Deserializes this object from the given stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData the capacity(int) that is the length of the + * bucket array, the size(int) of the hash map + * are emitted first. They are followed by size entries, + * each consisting of a key (Object) and a value (Object). + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + // Read the threshold and loadFactor fields. + s.defaultReadObject(); + + // Read and use capacity, followed by key/value pairs. + buckets = new HashEntry[s.readInt()]; + int len = s.readInt(); + size = len; + while (len-- > 0) + { + Object key = s.readObject(); + addEntry(key, s.readObject(), hash(key), false); + } + } + + /** + * Iterate over HashMap's entries. + * This implementation is parameterized to give a sequential view of + * keys, values, or entries. + * + * @author Jon Zeppieri + */ + private final class HashIterator implements Iterator + { + /** + * The type of this Iterator: {@link #KEYS}, {@link #VALUES}, + * or {@link #ENTRIES}. + */ + private final int type; + /** + * The number of modifications to the backing HashMap that we know about. + */ + private int knownMod = modCount; + /** The number of elements remaining to be returned by next(). */ + private int count = size; + /** Current index in the physical hash table. */ + private int idx = buckets.length; + /** The last Entry returned by a next() call. */ + private HashEntry last; + /** + * The next entry that should be returned by next(). It is set to something + * if we're iterating through a bucket that contains multiple linked + * entries. It is null if next() needs to find a new bucket. + */ + private HashEntry next; + + /** + * Construct a new HashIterator with the supplied type. + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + */ + HashIterator(int type) + { + this.type = type; + } + + /** + * Returns true if the Iterator has more elements. + * @return true if there are more elements + * @throws ConcurrentModificationException if the HashMap was modified + */ + public boolean hasNext() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + return count > 0; + } + + /** + * Returns the next element in the Iterator's sequential view. + * @return the next element + * @throws ConcurrentModificationException if the HashMap was modified + * @throws NoSuchElementException if there is none + */ + public Object next() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (count == 0) + throw new NoSuchElementException(); + count--; + HashEntry e = next; + + while (e == null) + e = buckets[--idx]; + + next = e.next; + last = e; + if (type == VALUES) + return e.value; + if (type == KEYS) + return e.key; + return e; + } + + /** + * Removes from the backing HashMap the last element which was fetched + * with the next() method. + * @throws ConcurrentModificationException if the HashMap was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (last == null) + throw new IllegalStateException(); + + HashMap.this.remove(last.key); + last = null; + knownMod++; + } + } +} diff --git a/libjava/classpath/java/util/HashSet.java b/libjava/classpath/java/util/HashSet.java new file mode 100644 index 0000000..681d5bb --- /dev/null +++ b/libjava/classpath/java/util/HashSet.java @@ -0,0 +1,293 @@ +/* HashSet.java -- a class providing a HashMap-backed Set + Copyright (C) 1998, 1999, 2001, 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 java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * This class provides a HashMap-backed implementation of the Set interface. + *

    + * + * Most operations are O(1), assuming no hash collisions. In the worst + * case (where all hashes collide), operations are O(n). Setting the + * initial capacity too low will force many resizing operations, but + * setting the initial capacity too high (or loadfactor too low) leads + * to wasted memory and slower iteration. + *

    + * + * HashSet accepts the null key and null values. It is not synchronized, + * so if you need multi-threaded access, consider using:
    + * Set s = Collections.synchronizedSet(new HashSet(...)); + *

    + * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * {@link ConcurrentModificationException} rather than exhibit + * non-deterministic behavior. + * + * @author Jon Zeppieri + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see Set + * @see TreeSet + * @see Collections#synchronizedSet(Set) + * @see HashMap + * @see LinkedHashSet + * @since 1.2 + * @status updated to 1.4 + */ +public class HashSet extends AbstractSet + implements Set, Cloneable, Serializable +{ + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = -5024744406713321676L; + + /** + * The HashMap which backs this Set. + */ + private transient HashMap map; + + /** + * Construct a new, empty HashSet whose backing HashMap has the default + * capacity (11) and loadFacor (0.75). + */ + public HashSet() + { + this(HashMap.DEFAULT_CAPACITY, HashMap.DEFAULT_LOAD_FACTOR); + } + + /** + * Construct a new, empty HashSet whose backing HashMap has the supplied + * capacity and the default load factor (0.75). + * + * @param initialCapacity the initial capacity of the backing HashMap + * @throws IllegalArgumentException if the capacity is negative + */ + public HashSet(int initialCapacity) + { + this(initialCapacity, HashMap.DEFAULT_LOAD_FACTOR); + } + + /** + * Construct a new, empty HashSet whose backing HashMap has the supplied + * capacity and load factor. + * + * @param initialCapacity the initial capacity of the backing HashMap + * @param loadFactor the load factor of the backing HashMap + * @throws IllegalArgumentException if either argument is negative, or + * if loadFactor is POSITIVE_INFINITY or NaN + */ + public HashSet(int initialCapacity, float loadFactor) + { + map = init(initialCapacity, loadFactor); + } + + /** + * Construct a new HashSet with the same elements as are in the supplied + * collection (eliminating any duplicates, of course). The backing storage + * has twice the size of the collection, or the default size of 11, + * whichever is greater; and the default load factor (0.75). + * + * @param c a collection of initial set elements + * @throws NullPointerException if c is null + */ + public HashSet(Collection c) + { + this(Math.max(2 * c.size(), HashMap.DEFAULT_CAPACITY)); + addAll(c); + } + + /** + * Adds the given Object to the set if it is not already in the Set. + * This set permits a null element. + * + * @param o the Object to add to this Set + * @return true if the set did not already contain o + */ + public boolean add(Object o) + { + return map.put(o, "") == null; + } + + /** + * Empties this Set of all elements; this takes constant time. + */ + public void clear() + { + map.clear(); + } + + /** + * Returns a shallow copy of this Set. The Set itself is cloned; its + * elements are not. + * + * @return a shallow clone of the set + */ + public Object clone() + { + HashSet copy = null; + try + { + copy = (HashSet) super.clone(); + } + catch (CloneNotSupportedException x) + { + // Impossible to get here. + } + copy.map = (HashMap) map.clone(); + return copy; + } + + /** + * Returns true if the supplied element is in this Set. + * + * @param o the Object to look for + * @return true if it is in the set + */ + public boolean contains(Object o) + { + return map.containsKey(o); + } + + /** + * Returns true if this set has no elements in it. + * + * @return size() == 0. + */ + public boolean isEmpty() + { + return map.size == 0; + } + + /** + * Returns an Iterator over the elements of this Set, which visits the + * elements in no particular order. For this class, the Iterator allows + * removal of elements. The iterator is fail-fast, and will throw a + * ConcurrentModificationException if the set is modified externally. + * + * @return a set iterator + * @see ConcurrentModificationException + */ + public Iterator iterator() + { + // Avoid creating intermediate keySet() object by using non-public API. + return map.iterator(HashMap.KEYS); + } + + /** + * Removes the supplied Object from this Set if it is in the Set. + * + * @param o the object to remove + * @return true if an element was removed + */ + public boolean remove(Object o) + { + return (map.remove(o) != null); + } + + /** + * Returns the number of elements in this Set (its cardinality). + * + * @return the size of the set + */ + public int size() + { + return map.size; + } + + /** + * Helper method which initializes the backing Map. Overridden by + * LinkedHashSet for correct semantics. + * + * @param capacity the initial capacity + * @param load the initial load factor + * @return the backing HashMap + */ + HashMap init(int capacity, float load) + { + return new HashMap(capacity, load); + } + + /** + * Serializes this object to the given stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData the capacity (int) and loadFactor (float) + * of the backing store, followed by the set size (int), + * then a listing of its elements (Object) in no order + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + // Avoid creating intermediate keySet() object by using non-public API. + Iterator it = map.iterator(HashMap.KEYS); + s.writeInt(map.buckets.length); + s.writeFloat(map.loadFactor); + s.writeInt(map.size); + while (it.hasNext()) + s.writeObject(it.next()); + } + + /** + * Deserializes this object from the given stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData the capacity (int) and loadFactor (float) + * of the backing store, followed by the set size (int), + * then a listing of its elements (Object) in no order + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + + map = init(s.readInt(), s.readFloat()); + for (int size = s.readInt(); size > 0; size--) + map.put(s.readObject(), ""); + } +} diff --git a/libjava/classpath/java/util/Hashtable.java b/libjava/classpath/java/util/Hashtable.java new file mode 100644 index 0000000..011cafa --- /dev/null +++ b/libjava/classpath/java/util/Hashtable.java @@ -0,0 +1,1151 @@ +/* Hashtable.java -- a class providing a basic hashtable data structure, + mapping Object --> Object + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +// NOTE: This implementation is very similar to that of HashMap. If you fix +// a bug in here, chances are you should make a similar change to the HashMap +// code. + +/** + * A class which implements a hashtable data structure. + *

    + * + * This implementation of Hashtable uses a hash-bucket approach. That is: + * linear probing and rehashing is avoided; instead, each hashed value maps + * to a simple linked-list which, in the best case, only has one node. + * Assuming a large enough table, low enough load factor, and / or well + * implemented hashCode() methods, Hashtable should provide O(1) + * insertion, deletion, and searching of keys. Hashtable is O(n) in + * the worst case for all of these (if all keys hash to the same bucket). + *

    + * + * This is a JDK-1.2 compliant implementation of Hashtable. As such, it + * belongs, partially, to the Collections framework (in that it implements + * Map). For backwards compatibility, it inherits from the obsolete and + * utterly useless Dictionary class. + *

    + * + * Being a hybrid of old and new, Hashtable has methods which provide redundant + * capability, but with subtle and even crucial differences. + * For example, one can iterate over various aspects of a Hashtable with + * either an Iterator (which is the JDK-1.2 way of doing things) or with an + * Enumeration. The latter can end up in an undefined state if the Hashtable + * changes while the Enumeration is open. + *

    + * + * Unlike HashMap, Hashtable does not accept `null' as a key value. Also, + * all accesses are synchronized: in a single thread environment, this is + * expensive, but in a multi-thread environment, this saves you the effort + * of extra synchronization. However, the old-style enumerators are not + * synchronized, because they can lead to unspecified behavior even if + * they were synchronized. You have been warned. + *

    + * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * ConcurrentModificationException rather than exhibit + * non-deterministic behavior. + * + * @author Jon Zeppieri + * @author Warren Levy + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see HashMap + * @see TreeMap + * @see IdentityHashMap + * @see LinkedHashMap + * @since 1.0 + * @status updated to 1.4 + */ +public class Hashtable extends Dictionary + implements Map, Cloneable, Serializable +{ + // WARNING: Hashtable is a CORE class in the bootstrap cycle. See the + // comments in vm/reference/java/lang/Runtime for implications of this fact. + + /** Default number of buckets. This is the value the JDK 1.3 uses. Some + * early documentation specified this value as 101. That is incorrect. + */ + private static final int DEFAULT_CAPACITY = 11; + + /** An "enum" of iterator types. */ + // Package visible for use by nested classes. + static final int KEYS = 0, + VALUES = 1, + ENTRIES = 2; + + /** + * The default load factor; this is explicitly specified by the spec. + */ + private static final float DEFAULT_LOAD_FACTOR = 0.75f; + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 1421746759512286392L; + + /** + * The rounded product of the capacity and the load factor; when the number + * of elements exceeds the threshold, the Hashtable calls + * rehash(). + * @serial + */ + private int threshold; + + /** + * Load factor of this Hashtable: used in computing the threshold. + * @serial + */ + private final float loadFactor; + + /** + * Array containing the actual key-value mappings. + */ + // Package visible for use by nested classes. + transient HashEntry[] buckets; + + /** + * Counts the number of modifications this Hashtable has undergone, used + * by Iterators to know when to throw ConcurrentModificationExceptions. + */ + // Package visible for use by nested classes. + transient int modCount; + + /** + * The size of this Hashtable: denotes the number of key-value pairs. + */ + // Package visible for use by nested classes. + transient int size; + + /** + * The cache for {@link #keySet()}. + */ + private transient Set keys; + + /** + * The cache for {@link #values()}. + */ + private transient Collection values; + + /** + * The cache for {@link #entrySet()}. + */ + private transient Set entries; + + /** + * Class to represent an entry in the hash table. Holds a single key-value + * pair. A Hashtable Entry is identical to a HashMap Entry, except that + * `null' is not allowed for keys and values. + */ + private static final class HashEntry extends AbstractMap.BasicMapEntry + { + /** The next entry in the linked list. */ + HashEntry next; + + /** + * Simple constructor. + * @param key the key, already guaranteed non-null + * @param value the value, already guaranteed non-null + */ + HashEntry(Object key, Object value) + { + super(key, value); + } + + /** + * Resets the value. + * @param newVal the new value + * @return the prior value + * @throws NullPointerException if newVal is null + */ + public Object setValue(Object newVal) + { + if (newVal == null) + throw new NullPointerException(); + return super.setValue(newVal); + } + } + + /** + * Construct a new Hashtable with the default capacity (11) and the default + * load factor (0.75). + */ + public Hashtable() + { + this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR); + } + + /** + * Construct a new Hashtable from the given Map, with initial capacity + * the greater of the size of m or the default of 11. + *

    + * + * Every element in Map m will be put into this new Hashtable. + * + * @param m a Map whose key / value pairs will be put into + * the new Hashtable. NOTE: key / value pairs + * are not cloned in this constructor. + * @throws NullPointerException if m is null, or if m contains a mapping + * to or from `null'. + * @since 1.2 + */ + public Hashtable(Map m) + { + this(Math.max(m.size() * 2, DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR); + putAll(m); + } + + /** + * Construct a new Hashtable with a specific inital capacity and + * default load factor of 0.75. + * + * @param initialCapacity the initial capacity of this Hashtable (>= 0) + * @throws IllegalArgumentException if (initialCapacity < 0) + */ + public Hashtable(int initialCapacity) + { + this(initialCapacity, DEFAULT_LOAD_FACTOR); + } + + /** + * Construct a new Hashtable with a specific initial capacity and + * load factor. + * + * @param initialCapacity the initial capacity (>= 0) + * @param loadFactor the load factor (> 0, not NaN) + * @throws IllegalArgumentException if (initialCapacity < 0) || + * ! (loadFactor > 0.0) + */ + public Hashtable(int initialCapacity, float loadFactor) + { + if (initialCapacity < 0) + throw new IllegalArgumentException("Illegal Capacity: " + + initialCapacity); + if (! (loadFactor > 0)) // check for NaN too + throw new IllegalArgumentException("Illegal Load: " + loadFactor); + + if (initialCapacity == 0) + initialCapacity = 1; + buckets = new HashEntry[initialCapacity]; + this.loadFactor = loadFactor; + threshold = (int) (initialCapacity * loadFactor); + } + + /** + * Returns the number of key-value mappings currently in this hashtable. + * @return the size + */ + public synchronized int size() + { + return size; + } + + /** + * Returns true if there are no key-value mappings currently in this table. + * @return size() == 0 + */ + public synchronized boolean isEmpty() + { + return size == 0; + } + + /** + * Return an enumeration of the keys of this table. There's no point + * in synchronizing this, as you have already been warned that the + * enumeration is not specified to be thread-safe. + * + * @return the keys + * @see #elements() + * @see #keySet() + */ + public Enumeration keys() + { + return new Enumerator(KEYS); + } + + /** + * Return an enumeration of the values of this table. There's no point + * in synchronizing this, as you have already been warned that the + * enumeration is not specified to be thread-safe. + * + * @return the values + * @see #keys() + * @see #values() + */ + public Enumeration elements() + { + return new Enumerator(VALUES); + } + + /** + * Returns true if this Hashtable contains a value o, + * such that o.equals(value). This is the same as + * containsValue(), and is O(n). + *

    + * + * @param value the value to search for in this Hashtable + * @return true if at least one key maps to the value + * @throws NullPointerException if value is null + * @see #containsValue(Object) + * @see #containsKey(Object) + */ + public synchronized boolean contains(Object value) + { + for (int i = buckets.length - 1; i >= 0; i--) + { + HashEntry e = buckets[i]; + while (e != null) + { + if (value.equals(e.value)) + return true; + e = e.next; + } + } + + // Must throw on null argument even if the table is empty + if (value == null) + throw new NullPointerException(); + + return false; + } + + /** + * Returns true if this Hashtable contains a value o, such that + * o.equals(value). This is the new API for the old + * contains(). + * + * @param value the value to search for in this Hashtable + * @return true if at least one key maps to the value + * @see #contains(Object) + * @see #containsKey(Object) + * @throws NullPointerException if value is null + * @since 1.2 + */ + public boolean containsValue(Object value) + { + // Delegate to older method to make sure code overriding it continues + // to work. + return contains(value); + } + + /** + * Returns true if the supplied object equals() a key + * in this Hashtable. + * + * @param key the key to search for in this Hashtable + * @return true if the key is in the table + * @throws NullPointerException if key is null + * @see #containsValue(Object) + */ + public synchronized boolean containsKey(Object key) + { + int idx = hash(key); + HashEntry e = buckets[idx]; + while (e != null) + { + if (key.equals(e.key)) + return true; + e = e.next; + } + return false; + } + + /** + * Return the value in this Hashtable associated with the supplied key, + * or null if the key maps to nothing. + * + * @param key the key for which to fetch an associated value + * @return what the key maps to, if present + * @throws NullPointerException if key is null + * @see #put(Object, Object) + * @see #containsKey(Object) + */ + public synchronized Object get(Object key) + { + int idx = hash(key); + HashEntry e = buckets[idx]; + while (e != null) + { + if (key.equals(e.key)) + return e.value; + e = e.next; + } + return null; + } + + /** + * Puts the supplied value into the Map, mapped by the supplied key. + * Neither parameter may be null. The value may be retrieved by any + * object which equals() this key. + * + * @param key the key used to locate the value + * @param value the value to be stored in the table + * @return the prior mapping of the key, or null if there was none + * @throws NullPointerException if key or value is null + * @see #get(Object) + * @see Object#equals(Object) + */ + public synchronized Object put(Object key, Object value) + { + int idx = hash(key); + HashEntry e = buckets[idx]; + + // Check if value is null since it is not permitted. + if (value == null) + throw new NullPointerException(); + + while (e != null) + { + if (key.equals(e.key)) + { + // Bypass e.setValue, since we already know value is non-null. + Object r = e.value; + e.value = value; + return r; + } + else + { + e = e.next; + } + } + + // At this point, we know we need to add a new entry. + modCount++; + if (++size > threshold) + { + rehash(); + // Need a new hash value to suit the bigger table. + idx = hash(key); + } + + e = new HashEntry(key, value); + + e.next = buckets[idx]; + buckets[idx] = e; + + return null; + } + + /** + * Removes from the table and returns the value which is mapped by the + * supplied key. If the key maps to nothing, then the table remains + * unchanged, and null is returned. + * + * @param key the key used to locate the value to remove + * @return whatever the key mapped to, if present + */ + public synchronized Object remove(Object key) + { + int idx = hash(key); + HashEntry e = buckets[idx]; + HashEntry last = null; + + while (e != null) + { + if (key.equals(e.key)) + { + modCount++; + if (last == null) + buckets[idx] = e.next; + else + last.next = e.next; + size--; + return e.value; + } + last = e; + e = e.next; + } + return null; + } + + /** + * Copies all elements of the given map into this hashtable. However, no + * mapping can contain null as key or value. If this table already has + * a mapping for a key, the new mapping replaces the current one. + * + * @param m the map to be hashed into this + * @throws NullPointerException if m is null, or contains null keys or values + */ + public synchronized void putAll(Map m) + { + Iterator itr = m.entrySet().iterator(); + + while (itr.hasNext()) + { + Map.Entry e = (Map.Entry) itr.next(); + // Optimize in case the Entry is one of our own. + if (e instanceof AbstractMap.BasicMapEntry) + { + AbstractMap.BasicMapEntry entry = (AbstractMap.BasicMapEntry) e; + put(entry.key, entry.value); + } + else + { + put(e.getKey(), e.getValue()); + } + } + } + + /** + * Clears the hashtable so it has no keys. This is O(1). + */ + public synchronized void clear() + { + if (size > 0) + { + modCount++; + Arrays.fill(buckets, null); + size = 0; + } + } + + /** + * Returns a shallow clone of this Hashtable. The Map itself is cloned, + * but its contents are not. This is O(n). + * + * @return the clone + */ + public synchronized Object clone() + { + Hashtable copy = null; + try + { + copy = (Hashtable) super.clone(); + } + catch (CloneNotSupportedException x) + { + // This is impossible. + } + copy.buckets = new HashEntry[buckets.length]; + copy.putAllInternal(this); + // Clear the caches. + copy.keys = null; + copy.values = null; + copy.entries = null; + return copy; + } + + /** + * Converts this Hashtable to a String, surrounded by braces, and with + * key/value pairs listed with an equals sign between, separated by a + * comma and space. For example, "{a=1, b=2}".

    + * + * NOTE: if the toString() method of any key or value + * throws an exception, this will fail for the same reason. + * + * @return the string representation + */ + public synchronized String toString() + { + // Since we are already synchronized, and entrySet().iterator() + // would repeatedly re-lock/release the monitor, we directly use the + // unsynchronized HashIterator instead. + Iterator entries = new HashIterator(ENTRIES); + StringBuffer r = new StringBuffer("{"); + for (int pos = size; pos > 0; pos--) + { + r.append(entries.next()); + if (pos > 1) + r.append(", "); + } + r.append("}"); + return r.toString(); + } + + /** + * Returns a "set view" of this Hashtable's keys. The set is backed by + * the hashtable, so changes in one show up in the other. The set supports + * element removal, but not element addition. The set is properly + * synchronized on the original hashtable. Sun has not documented the + * proper interaction of null with this set, but has inconsistent behavior + * in the JDK. Therefore, in this implementation, contains, remove, + * containsAll, retainAll, removeAll, and equals just ignore a null key + * rather than throwing a {@link NullPointerException}. + * + * @return a set view of the keys + * @see #values() + * @see #entrySet() + * @since 1.2 + */ + public Set keySet() + { + if (keys == null) + { + // Create a synchronized AbstractSet with custom implementations of + // those methods that can be overridden easily and efficiently. + Set r = new AbstractSet() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + return new HashIterator(KEYS); + } + + public void clear() + { + Hashtable.this.clear(); + } + + public boolean contains(Object o) + { + if (o == null) + return false; + return containsKey(o); + } + + public boolean remove(Object o) + { + return Hashtable.this.remove(o) != null; + } + }; + // We must specify the correct object to synchronize upon, hence the + // use of a non-public API + keys = new Collections.SynchronizedSet(this, r); + } + return keys; + } + + /** + * Returns a "collection view" (or "bag view") of this Hashtable's values. + * The collection is backed by the hashtable, so changes in one show up + * in the other. The collection supports element removal, but not element + * addition. The collection is properly synchronized on the original + * hashtable. Sun has not documented the proper interaction of null with + * this set, but has inconsistent behavior in the JDK. Therefore, in this + * implementation, contains, remove, containsAll, retainAll, removeAll, and + * equals just ignore a null value rather than throwing a + * {@link NullPointerException}. + * + * @return a bag view of the values + * @see #keySet() + * @see #entrySet() + * @since 1.2 + */ + public Collection values() + { + if (values == null) + { + // We don't bother overriding many of the optional methods, as doing so + // wouldn't provide any significant performance advantage. + Collection r = new AbstractCollection() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + return new HashIterator(VALUES); + } + + public void clear() + { + Hashtable.this.clear(); + } + }; + // We must specify the correct object to synchronize upon, hence the + // use of a non-public API + values = new Collections.SynchronizedCollection(this, r); + } + return values; + } + + /** + * Returns a "set view" of this Hashtable's entries. The set is backed by + * the hashtable, so changes in one show up in the other. The set supports + * element removal, but not element addition. The set is properly + * synchronized on the original hashtable. Sun has not documented the + * proper interaction of null with this set, but has inconsistent behavior + * in the JDK. Therefore, in this implementation, contains, remove, + * containsAll, retainAll, removeAll, and equals just ignore a null entry, + * or an entry with a null key or value, rather than throwing a + * {@link NullPointerException}. However, calling entry.setValue(null) + * will fail. + *

    + * + * Note that the iterators for all three views, from keySet(), entrySet(), + * and values(), traverse the hashtable in the same sequence. + * + * @return a set view of the entries + * @see #keySet() + * @see #values() + * @see Map.Entry + * @since 1.2 + */ + public Set entrySet() + { + if (entries == null) + { + // Create an AbstractSet with custom implementations of those methods + // that can be overridden easily and efficiently. + Set r = new AbstractSet() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + return new HashIterator(ENTRIES); + } + + public void clear() + { + Hashtable.this.clear(); + } + + public boolean contains(Object o) + { + return getEntry(o) != null; + } + + public boolean remove(Object o) + { + HashEntry e = getEntry(o); + if (e != null) + { + Hashtable.this.remove(e.key); + return true; + } + return false; + } + }; + // We must specify the correct object to synchronize upon, hence the + // use of a non-public API + entries = new Collections.SynchronizedSet(this, r); + } + return entries; + } + + /** + * Returns true if this Hashtable equals the supplied Object o. + * As specified by Map, this is: + * + * (o instanceof Map) && entrySet().equals(((Map) o).entrySet()); + * + * + * @param o the object to compare to + * @return true if o is an equal map + * @since 1.2 + */ + public boolean equals(Object o) + { + // no need to synchronize, entrySet().equals() does that + if (o == this) + return true; + if (!(o instanceof Map)) + return false; + + return entrySet().equals(((Map) o).entrySet()); + } + + /** + * Returns the hashCode for this Hashtable. As specified by Map, this is + * the sum of the hashCodes of all of its Map.Entry objects + * + * @return the sum of the hashcodes of the entries + * @since 1.2 + */ + public synchronized int hashCode() + { + // Since we are already synchronized, and entrySet().iterator() + // would repeatedly re-lock/release the monitor, we directly use the + // unsynchronized HashIterator instead. + Iterator itr = new HashIterator(ENTRIES); + int hashcode = 0; + for (int pos = size; pos > 0; pos--) + hashcode += itr.next().hashCode(); + + return hashcode; + } + + /** + * Helper method that returns an index in the buckets array for `key' + * based on its hashCode(). + * + * @param key the key + * @return the bucket number + * @throws NullPointerException if key is null + */ + private int hash(Object key) + { + // Note: Inline Math.abs here, for less method overhead, and to avoid + // a bootstrap dependency, since Math relies on native methods. + int hash = key.hashCode() % buckets.length; + return hash < 0 ? -hash : hash; + } + + /** + * Helper method for entrySet(), which matches both key and value + * simultaneously. Ignores null, as mentioned in entrySet(). + * + * @param o the entry to match + * @return the matching entry, if found, or null + * @see #entrySet() + */ + // Package visible, for use in nested classes. + HashEntry getEntry(Object o) + { + if (! (o instanceof Map.Entry)) + return null; + Object key = ((Map.Entry) o).getKey(); + if (key == null) + return null; + + int idx = hash(key); + HashEntry e = buckets[idx]; + while (e != null) + { + if (o.equals(e)) + return e; + e = e.next; + } + return null; + } + + /** + * A simplified, more efficient internal implementation of putAll(). clone() + * should not call putAll or put, in order to be compatible with the JDK + * implementation with respect to subclasses. + * + * @param m the map to initialize this from + */ + void putAllInternal(Map m) + { + Iterator itr = m.entrySet().iterator(); + size = 0; + + while (itr.hasNext()) + { + size++; + Map.Entry e = (Map.Entry) itr.next(); + Object key = e.getKey(); + int idx = hash(key); + HashEntry he = new HashEntry(key, e.getValue()); + he.next = buckets[idx]; + buckets[idx] = he; + } + } + + /** + * Increases the size of the Hashtable and rehashes all keys to new array + * indices; this is called when the addition of a new value would cause + * size() > threshold. Note that the existing Entry objects are reused in + * the new hash table. + *

    + * + * This is not specified, but the new size is twice the current size plus + * one; this number is not always prime, unfortunately. This implementation + * is not synchronized, as it is only invoked from synchronized methods. + */ + protected void rehash() + { + HashEntry[] oldBuckets = buckets; + + int newcapacity = (buckets.length * 2) + 1; + threshold = (int) (newcapacity * loadFactor); + buckets = new HashEntry[newcapacity]; + + for (int i = oldBuckets.length - 1; i >= 0; i--) + { + HashEntry e = oldBuckets[i]; + while (e != null) + { + int idx = hash(e.key); + HashEntry dest = buckets[idx]; + + if (dest != null) + { + while (dest.next != null) + dest = dest.next; + dest.next = e; + } + else + { + buckets[idx] = e; + } + + HashEntry next = e.next; + e.next = null; + e = next; + } + } + } + + /** + * Serializes this object to the given stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData the capacity (int) that is the length of the + * bucket array, the size (int) of the hash map + * are emitted first. They are followed by size entries, + * each consisting of a key (Object) and a value (Object). + */ + private synchronized void writeObject(ObjectOutputStream s) + throws IOException + { + // Write the threshold and loadFactor fields. + s.defaultWriteObject(); + + s.writeInt(buckets.length); + s.writeInt(size); + // Since we are already synchronized, and entrySet().iterator() + // would repeatedly re-lock/release the monitor, we directly use the + // unsynchronized HashIterator instead. + Iterator it = new HashIterator(ENTRIES); + while (it.hasNext()) + { + HashEntry entry = (HashEntry) it.next(); + s.writeObject(entry.key); + s.writeObject(entry.value); + } + } + + /** + * Deserializes this object from the given stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData the capacity (int) that is the length of the + * bucket array, the size (int) of the hash map + * are emitted first. They are followed by size entries, + * each consisting of a key (Object) and a value (Object). + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + // Read the threshold and loadFactor fields. + s.defaultReadObject(); + + // Read and use capacity. + buckets = new HashEntry[s.readInt()]; + int len = s.readInt(); + + // Read and use key/value pairs. + // TODO: should we be defensive programmers, and check for illegal nulls? + while (--len >= 0) + put(s.readObject(), s.readObject()); + } + + /** + * A class which implements the Iterator interface and is used for + * iterating over Hashtables. + * This implementation is parameterized to give a sequential view of + * keys, values, or entries; it also allows the removal of elements, + * as per the Javasoft spec. Note that it is not synchronized; this is + * a performance enhancer since it is never exposed externally and is + * only used within synchronized blocks above. + * + * @author Jon Zeppieri + */ + private final class HashIterator implements Iterator + { + /** + * The type of this Iterator: {@link #KEYS}, {@link #VALUES}, + * or {@link #ENTRIES}. + */ + final int type; + /** + * The number of modifications to the backing Hashtable that we know about. + */ + int knownMod = modCount; + /** The number of elements remaining to be returned by next(). */ + int count = size; + /** Current index in the physical hash table. */ + int idx = buckets.length; + /** The last Entry returned by a next() call. */ + HashEntry last; + /** + * The next entry that should be returned by next(). It is set to something + * if we're iterating through a bucket that contains multiple linked + * entries. It is null if next() needs to find a new bucket. + */ + HashEntry next; + + /** + * Construct a new HashIterator with the supplied type. + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + */ + HashIterator(int type) + { + this.type = type; + } + + /** + * Returns true if the Iterator has more elements. + * @return true if there are more elements + * @throws ConcurrentModificationException if the hashtable was modified + */ + public boolean hasNext() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + return count > 0; + } + + /** + * Returns the next element in the Iterator's sequential view. + * @return the next element + * @throws ConcurrentModificationException if the hashtable was modified + * @throws NoSuchElementException if there is none + */ + public Object next() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (count == 0) + throw new NoSuchElementException(); + count--; + HashEntry e = next; + + while (e == null) + e = buckets[--idx]; + + next = e.next; + last = e; + if (type == VALUES) + return e.value; + if (type == KEYS) + return e.key; + return e; + } + + /** + * Removes from the backing Hashtable the last element which was fetched + * with the next() method. + * @throws ConcurrentModificationException if the hashtable was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (last == null) + throw new IllegalStateException(); + + Hashtable.this.remove(last.key); + last = null; + knownMod++; + } + } // class HashIterator + + + /** + * Enumeration view of this Hashtable, providing sequential access to its + * elements; this implementation is parameterized to provide access either + * to the keys or to the values in the Hashtable. + * + * NOTE: Enumeration is not safe if new elements are put in the table + * as this could cause a rehash and we'd completely lose our place. Even + * without a rehash, it is undetermined if a new element added would + * appear in the enumeration. The spec says nothing about this, but + * the "Java Class Libraries" book infers that modifications to the + * hashtable during enumeration causes indeterminate results. Don't do it! + * + * @author Jon Zeppieri + */ + private final class Enumerator implements Enumeration + { + /** + * The type of this Iterator: {@link #KEYS} or {@link #VALUES}. + */ + final int type; + /** The number of elements remaining to be returned by next(). */ + int count = size; + /** Current index in the physical hash table. */ + int idx = buckets.length; + /** + * Entry which will be returned by the next nextElement() call. It is + * set if we are iterating through a bucket with multiple entries, or null + * if we must look in the next bucket. + */ + HashEntry next; + + /** + * Construct the enumeration. + * @param type either {@link #KEYS} or {@link #VALUES}. + */ + Enumerator(int type) + { + this.type = type; + } + + /** + * Checks whether more elements remain in the enumeration. + * @return true if nextElement() will not fail. + */ + public boolean hasMoreElements() + { + return count > 0; + } + + /** + * Returns the next element. + * @return the next element + * @throws NoSuchElementException if there is none. + */ + public Object nextElement() + { + if (count == 0) + throw new NoSuchElementException("Hashtable Enumerator"); + count--; + HashEntry e = next; + + while (e == null) + e = buckets[--idx]; + + next = e.next; + return type == VALUES ? e.value : e.key; + } + } // class Enumerator +} // class Hashtable diff --git a/libjava/classpath/java/util/IdentityHashMap.java b/libjava/classpath/java/util/IdentityHashMap.java new file mode 100644 index 0000000..6369fac --- /dev/null +++ b/libjava/classpath/java/util/IdentityHashMap.java @@ -0,0 +1,935 @@ +/* IdentityHashMap.java -- a class providing a hashtable data structure, + mapping Object --> Object, which uses object identity for hashing. + Copyright (C) 2001, 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 java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * This class provides a hashtable-backed implementation of the + * Map interface, but uses object identity to do its hashing. In fact, + * it uses object identity for comparing values, as well. It uses a + * linear-probe hash table, which may have faster performance + * than the chaining employed by HashMap. + *

    + * + * WARNING: This is not a general purpose map. Because it uses + * System.identityHashCode and ==, instead of hashCode and equals, for + * comparison, it violated Map's general contract, and may cause + * undefined behavior when compared to other maps which are not + * IdentityHashMaps. This is designed only for the rare cases when + * identity semantics are needed. An example use is + * topology-preserving graph transformations, such as deep cloning, + * or as proxy object mapping such as in debugging. + *

    + * + * This map permits null keys and values, and does not + * guarantee that elements will stay in the same order over time. The + * basic operations (get and put) take + * constant time, provided System.identityHashCode is decent. You can + * tune the behavior by specifying the expected maximum size. As more + * elements are added, the map may need to allocate a larger table, + * which can be expensive. + *

    + * + * This implementation is unsynchronized. If you want multi-thread + * access to be consistent, you must synchronize it, perhaps by using + * Collections.synchronizedMap(new IdentityHashMap(...));. + * The iterators are fail-fast, meaning that a structural modification + * made to the map outside of an iterator's remove method cause the + * iterator, and in the case of the entrySet, the Map.Entry, to + * fail with a {@link ConcurrentModificationException}. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see System#identityHashCode(Object) + * @see Collection + * @see Map + * @see HashMap + * @see TreeMap + * @see LinkedHashMap + * @see WeakHashMap + * @since 1.4 + * @status updated to 1.4 + */ +public class IdentityHashMap extends AbstractMap + implements Map, Serializable, Cloneable +{ + /** The default capacity. */ + private static final int DEFAULT_CAPACITY = 21; + + /** + * This object is used to mark deleted items. Package visible for use by + * nested classes. + */ + static final Object tombstone = new Object(); + + /** + * This object is used to mark empty slots. We need this because + * using null is ambiguous. Package visible for use by nested classes. + */ + static final Object emptyslot = new Object(); + + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 8188218128353913216L; + + /** + * The number of mappings in the table. Package visible for use by nested + * classes. + * @serial + */ + int size; + + /** + * The table itself. Package visible for use by nested classes. + */ + transient Object[] table; + + /** + * The number of structural modifications made so far. Package visible for + * use by nested classes. + */ + transient int modCount; + + /** + * The cache for {@link #entrySet()}. + */ + private transient Set entries; + + /** + * The threshold for rehashing, which is 75% of (table.length / 2). + */ + private transient int threshold; + + /** + * Create a new IdentityHashMap with the default capacity (21 entries). + */ + public IdentityHashMap() + { + this(DEFAULT_CAPACITY); + } + + /** + * Create a new IdentityHashMap with the indicated number of + * entries. If the number of elements added to this hash map + * exceeds this maximum, the map will grow itself; however, that + * incurs a performance penalty. + * + * @param max initial size + * @throws IllegalArgumentException if max is negative + */ + public IdentityHashMap(int max) + { + if (max < 0) + throw new IllegalArgumentException(); + // Need at least two slots, or hash() will break. + if (max < 2) + max = 2; + table = new Object[max << 1]; + Arrays.fill(table, emptyslot); + threshold = (max >> 2) * 3; + } + + /** + * Create a new IdentityHashMap whose contents are taken from the + * given Map. + * + * @param m The map whose elements are to be put in this map + * @throws NullPointerException if m is null + */ + public IdentityHashMap(Map m) + { + this(Math.max(m.size() << 1, DEFAULT_CAPACITY)); + putAll(m); + } + + /** + * Remove all mappings from this map. + */ + public void clear() + { + if (size != 0) + { + modCount++; + Arrays.fill(table, emptyslot); + size = 0; + } + } + + /** + * Creates a shallow copy where keys and values are not cloned. + */ + public Object clone() + { + try + { + IdentityHashMap copy = (IdentityHashMap) super.clone(); + copy.table = (Object[]) table.clone(); + copy.entries = null; // invalidate the cache + return copy; + } + catch (CloneNotSupportedException e) + { + // Can't happen. + return null; + } + } + + /** + * Tests whether the specified key is in this map. Unlike normal Maps, + * this test uses entry == key instead of + * entry == null ? key == null : entry.equals(key). + * + * @param key the key to look for + * @return true if the key is contained in the map + * @see #containsValue(Object) + * @see #get(Object) + */ + public boolean containsKey(Object key) + { + return key == table[hash(key)]; + } + + /** + * Returns true if this HashMap contains the value. Unlike normal maps, + * this test uses entry == value instead of + * entry == null ? value == null : entry.equals(value). + * + * @param value the value to search for in this HashMap + * @return true if at least one key maps to the value + * @see #containsKey(Object) + */ + public boolean containsValue(Object value) + { + for (int i = table.length - 1; i > 0; i -= 2) + if (table[i] == value) + return true; + return false; + } + + /** + * Returns a "set view" of this Map's entries. The set is backed by + * the Map, so changes in one show up in the other. The set supports + * element removal, but not element addition. + *

    + * + * The semantics of this set, and of its contained entries, are + * different from the contract of Set and Map.Entry in order to make + * IdentityHashMap work. This means that while you can compare these + * objects between IdentityHashMaps, comparing them with regular sets + * or entries is likely to have undefined behavior. The entries + * in this set are reference-based, rather than the normal object + * equality. Therefore, e1.equals(e2) returns + * e1.getKey() == e2.getKey() && e1.getValue() == e2.getValue(), + * and e.hashCode() returns + * System.identityHashCode(e.getKey()) ^ + * System.identityHashCode(e.getValue()). + *

    + * + * Note that the iterators for all three views, from keySet(), entrySet(), + * and values(), traverse the Map in the same sequence. + * + * @return a set view of the entries + * @see #keySet() + * @see #values() + * @see Map.Entry + */ + public Set entrySet() + { + if (entries == null) + entries = new AbstractSet() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + return new IdentityIterator(ENTRIES); + } + + public void clear() + { + IdentityHashMap.this.clear(); + } + + public boolean contains(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Map.Entry m = (Map.Entry) o; + return m.getValue() == table[hash(m.getKey()) + 1]; + } + + public int hashCode() + { + return IdentityHashMap.this.hashCode(); + } + + public boolean remove(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Object key = ((Map.Entry) o).getKey(); + int h = hash(key); + if (table[h] == key) + { + size--; + modCount++; + table[h] = tombstone; + table[h + 1] = tombstone; + return true; + } + return false; + } + }; + return entries; + } + + /** + * Compares two maps for equality. This returns true only if both maps + * have the same reference-identity comparisons. While this returns + * this.entrySet().equals(m.entrySet()) as specified by Map, + * this will not work with normal maps, since the entry set compares + * with == instead of .equals. + * + * @param o the object to compare to + * @return true if it is equal + */ + public boolean equals(Object o) + { + // Why did Sun specify this one? The superclass does the right thing. + return super.equals(o); + } + + /** + * Return the value in this Map associated with the supplied key, or + * null if the key maps to nothing. + * + *

    NOTE: Since the value could also be null, you must use + * containsKey to see if this key actually maps to something. + * Unlike normal maps, this tests for the key with entry == + * key instead of entry == null ? key == null : + * entry.equals(key). + * + * @param key the key for which to fetch an associated value + * @return what the key maps to, if present + * @see #put(Object, Object) + * @see #containsKey(Object) + */ + public Object get(Object key) + { + int h = hash(key); + return table[h] == key ? table[h + 1] : null; + } + + /** + * Returns the hashcode of this map. This guarantees that two + * IdentityHashMaps that compare with equals() will have the same hash code, + * but may break with comparison to normal maps since it uses + * System.identityHashCode() instead of hashCode(). + * + * @return the hash code + */ + public int hashCode() + { + int hash = 0; + for (int i = table.length - 2; i >= 0; i -= 2) + { + Object key = table[i]; + if (key == emptyslot || key == tombstone) + continue; + hash += (System.identityHashCode(key) + ^ System.identityHashCode(table[i + 1])); + } + return hash; + } + + /** + * Returns true if there are no key-value mappings currently in this Map + * @return size() == 0 + */ + public boolean isEmpty() + { + return size == 0; + } + + /** + * Returns a "set view" of this Map's keys. The set is backed by the + * Map, so changes in one show up in the other. The set supports + * element removal, but not element addition. + *

    + * + * The semantics of this set are different from the contract of Set + * in order to make IdentityHashMap work. This means that while you can + * compare these objects between IdentityHashMaps, comparing them with + * regular sets is likely to have undefined behavior. The hashCode + * of the set is the sum of the identity hash codes, instead of the + * regular hashCodes, and equality is determined by reference instead + * of by the equals method. + *

    + * + * @return a set view of the keys + * @see #values() + * @see #entrySet() + */ + public Set keySet() + { + if (keys == null) + keys = new AbstractSet() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + return new IdentityIterator(KEYS); + } + + public void clear() + { + IdentityHashMap.this.clear(); + } + + public boolean contains(Object o) + { + return containsKey(o); + } + + public int hashCode() + { + int hash = 0; + for (int i = table.length - 2; i >= 0; i -= 2) + { + Object key = table[i]; + if (key == emptyslot || key == tombstone) + continue; + hash += System.identityHashCode(key); + } + return hash; + + } + + public boolean remove(Object o) + { + int h = hash(o); + if (table[h] == o) + { + size--; + modCount++; + table[h] = tombstone; + table[h + 1] = tombstone; + return true; + } + return false; + } + }; + return keys; + } + + /** + * Puts the supplied value into the Map, mapped by the supplied key. + * The value may be retrieved by any object which equals() + * this key. NOTE: Since the prior value could also be null, you must + * first use containsKey if you want to see if you are replacing the + * key's mapping. Unlike normal maps, this tests for the key + * with entry == key instead of + * entry == null ? key == null : entry.equals(key). + * + * @param key the key used to locate the value + * @param value the value to be stored in the HashMap + * @return the prior mapping of the key, or null if there was none + * @see #get(Object) + */ + public Object put(Object key, Object value) + { + // Rehash if the load factor is too high. + if (size > threshold) + { + Object[] old = table; + // This isn't necessarily prime, but it is an odd number of key/value + // slots, which has a higher probability of fewer collisions. + table = new Object[(old.length * 2) + 2]; + Arrays.fill(table, emptyslot); + size = 0; + threshold = (table.length >>> 3) * 3; + + for (int i = old.length - 2; i >= 0; i -= 2) + { + Object oldkey = old[i]; + if (oldkey != tombstone && oldkey != emptyslot) + // Just use put. This isn't very efficient, but it is ok. + put(oldkey, old[i + 1]); + } + } + + int h = hash(key); + if (table[h] == key) + { + Object r = table[h + 1]; + table[h + 1] = value; + return r; + } + + // At this point, we add a new mapping. + modCount++; + size++; + table[h] = key; + table[h + 1] = value; + return null; + } + + /** + * Copies all of the mappings from the specified map to this. If a key + * is already in this map, its value is replaced. + * + * @param m the map to copy + * @throws NullPointerException if m is null + */ + public void putAll(Map m) + { + // Why did Sun specify this one? The superclass does the right thing. + super.putAll(m); + } + + /** + * Removes from the HashMap and returns the value which is mapped by + * the supplied key. If the key maps to nothing, then the HashMap + * remains unchanged, and null is returned. + * + * NOTE: Since the value could also be null, you must use + * containsKey to see if you are actually removing a mapping. + * Unlike normal maps, this tests for the key with entry == + * key instead of entry == null ? key == null : + * entry.equals(key). + * + * @param key the key used to locate the value to remove + * @return whatever the key mapped to, if present + */ + public Object remove(Object key) + { + int h = hash(key); + if (table[h] == key) + { + modCount++; + size--; + Object r = table[h + 1]; + table[h] = tombstone; + table[h + 1] = tombstone; + return r; + } + return null; + } + + /** + * Returns the number of kay-value mappings currently in this Map + * @return the size + */ + public int size() + { + return size; + } + + /** + * Returns a "collection view" (or "bag view") of this Map's values. + * The collection is backed by the Map, so changes in one show up + * in the other. The collection supports element removal, but not element + * addition. + *

    + * + * The semantics of this set are different from the contract of + * Collection in order to make IdentityHashMap work. This means that + * while you can compare these objects between IdentityHashMaps, comparing + * them with regular sets is likely to have undefined behavior. + * Likewise, contains and remove go by == instead of equals(). + *

    + * + * @return a bag view of the values + * @see #keySet() + * @see #entrySet() + */ + public Collection values() + { + if (values == null) + values = new AbstractCollection() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + return new IdentityIterator(VALUES); + } + + public void clear() + { + IdentityHashMap.this.clear(); + } + + public boolean remove(Object o) + { + for (int i = table.length - 1; i > 0; i -= 2) + if (table[i] == o) + { + modCount++; + table[i - 1] = tombstone; + table[i] = tombstone; + size--; + return true; + } + return false; + } + }; + return values; + } + + /** + * Helper method which computes the hash code, then traverses the table + * until it finds the key, or the spot where the key would go. + * + * @param key the key to check + * @return the index where the key belongs + * @see #IdentityHashMap(int) + * @see #put(Object, Object) + */ + // Package visible for use by nested classes. + int hash(Object key) + { + // Implementation note: it is feasible for the table to have no + // emptyslots, if it is full with entries and tombstones, so we must + // remember where we started. If we encounter the key or an emptyslot, + // we are done. If we encounter a tombstone, the key may still be in + // the array. If we don't encounter the key, we use the first emptyslot + // or tombstone we encountered as the location where the key would go. + // By requiring at least 2 key/value slots, and rehashing at 75% + // capacity, we guarantee that there will always be either an emptyslot + // or a tombstone somewhere in the table. + int h = Math.abs(System.identityHashCode(key) % (table.length >> 1)) << 1; + int del = -1; + int save = h; + + do + { + if (table[h] == key) + return h; + if (table[h] == emptyslot) + break; + if (table[h] == tombstone && del < 0) + del = h; + h -= 2; + if (h < 0) + h = table.length - 2; + } + while (h != save); + + return del < 0 ? h : del; + } + + /** + * This class allows parameterized iteration over IdentityHashMaps. Based + * on its construction, it returns the key or value of a mapping, or + * creates the appropriate Map.Entry object with the correct fail-fast + * semantics and identity comparisons. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Eric Blake (ebb9@email.byu.edu) + */ + private class IdentityIterator implements Iterator + { + /** + * The type of this Iterator: {@link #KEYS}, {@link #VALUES}, + * or {@link #ENTRIES}. + */ + final int type; + /** The number of modifications to the backing Map that we know about. */ + int knownMod = modCount; + /** The number of elements remaining to be returned by next(). */ + int count = size; + /** Location in the table. */ + int loc = table.length; + + /** + * Construct a new Iterator with the supplied type. + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + */ + IdentityIterator(int type) + { + this.type = type; + } + + /** + * Returns true if the Iterator has more elements. + * @return true if there are more elements + * @throws ConcurrentModificationException if the Map was modified + */ + public boolean hasNext() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + return count > 0; + } + + /** + * Returns the next element in the Iterator's sequential view. + * @return the next element + * @throws ConcurrentModificationException if the Map was modified + * @throws NoSuchElementException if there is none + */ + public Object next() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (count == 0) + throw new NoSuchElementException(); + count--; + + Object key; + do + { + loc -= 2; + key = table[loc]; + } + while (key == emptyslot || key == tombstone); + + return type == KEYS ? key : (type == VALUES ? table[loc + 1] + : new IdentityEntry(loc)); + } + + /** + * Removes from the backing Map the last element which was fetched + * with the next() method. + * + * @throws ConcurrentModificationException if the Map was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (loc == table.length || table[loc] == tombstone) + throw new IllegalStateException(); + modCount++; + size--; + table[loc] = tombstone; + table[loc + 1] = tombstone; + knownMod++; + } + } // class IdentityIterator + + /** + * This class provides Map.Entry objects for IdentityHashMaps. The entry + * is fail-fast, and will throw a ConcurrentModificationException if + * the underlying map is modified, or if remove is called on the iterator + * that generated this object. It is identity based, so it violates + * the general contract of Map.Entry, and is probably unsuitable for + * comparison to normal maps; but it works among other IdentityHashMaps. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private final class IdentityEntry implements Map.Entry + { + /** The location of this entry. */ + final int loc; + /** The number of modifications to the backing Map that we know about. */ + final int knownMod = modCount; + + /** + * Constructs the Entry. + * + * @param loc the location of this entry in table + */ + IdentityEntry(int loc) + { + this.loc = loc; + } + + /** + * Compares the specified object with this entry, using identity + * semantics. Note that this can lead to undefined results with + * Entry objects created by normal maps. + * + * @param o the object to compare + * @return true if it is equal + * @throws ConcurrentModificationException if the entry was invalidated + * by modifying the Map or calling Iterator.remove() + */ + public boolean equals(Object o) + { + if (knownMod != modCount || table[loc] == tombstone) + throw new ConcurrentModificationException(); + if (! (o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry) o; + return table[loc] == e.getKey() && table[loc + 1] == e.getValue(); + } + + /** + * Returns the key of this entry. + * + * @return the key + * @throws ConcurrentModificationException if the entry was invalidated + * by modifying the Map or calling Iterator.remove() + */ + public Object getKey() + { + if (knownMod != modCount || table[loc] == tombstone) + throw new ConcurrentModificationException(); + return table[loc]; + } + + /** + * Returns the value of this entry. + * + * @return the value + * @throws ConcurrentModificationException if the entry was invalidated + * by modifying the Map or calling Iterator.remove() + */ + public Object getValue() + { + if (knownMod != modCount || table[loc] == tombstone) + throw new ConcurrentModificationException(); + return table[loc + 1]; + } + + /** + * Returns the hashcode of the entry, using identity semantics. + * Note that this can lead to undefined results with Entry objects + * created by normal maps. + * + * @return the hash code + * @throws ConcurrentModificationException if the entry was invalidated + * by modifying the Map or calling Iterator.remove() + */ + public int hashCode() + { + if (knownMod != modCount || table[loc] == tombstone) + throw new ConcurrentModificationException(); + return (System.identityHashCode(table[loc]) + ^ System.identityHashCode(table[loc + 1])); + } + + /** + * Replaces the value of this mapping, and returns the old value. + * + * @param value the new value + * @return the old value + * @throws ConcurrentModificationException if the entry was invalidated + * by modifying the Map or calling Iterator.remove() + */ + public Object setValue(Object value) + { + if (knownMod != modCount || table[loc] == tombstone) + throw new ConcurrentModificationException(); + Object r = table[loc + 1]; + table[loc + 1] = value; + return r; + } + + /** + * This provides a string representation of the entry. It is of the form + * "key=value", where string concatenation is used on key and value. + * + * @return the string representation + * @throws ConcurrentModificationException if the entry was invalidated + * by modifying the Map or calling Iterator.remove() + */ + public String toString() + { + if (knownMod != modCount || table[loc] == tombstone) + throw new ConcurrentModificationException(); + return table[loc] + "=" + table[loc + 1]; + } + } // class IdentityEntry + + /** + * Reads the object from a serial stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData expects the size (int), followed by that many key (Object) + * and value (Object) pairs, with the pairs in no particular + * order + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + + int num = s.readInt(); + table = new Object[Math.max(num << 1, DEFAULT_CAPACITY) << 1]; + // Read key/value pairs. + while (--num >= 0) + put(s.readObject(), s.readObject()); + } + + /** + * Writes the object to a serial stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData outputs the size (int), followed by that many key (Object) + * and value (Object) pairs, with the pairs in no particular + * order + */ + private void writeObject(ObjectOutputStream s) + throws IOException + { + s.defaultWriteObject(); + s.writeInt(size); + for (int i = table.length - 2; i >= 0; i -= 2) + { + Object key = table[i]; + if (key != tombstone && key != emptyslot) + { + s.writeObject(key); + s.writeObject(table[i + 1]); + } + } + } +} diff --git a/libjava/classpath/java/util/Iterator.java b/libjava/classpath/java/util/Iterator.java new file mode 100644 index 0000000..31ecff8 --- /dev/null +++ b/libjava/classpath/java/util/Iterator.java @@ -0,0 +1,87 @@ +/* Iterator.java -- Interface for iterating over collections + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * An object which iterates over a collection. An Iterator is used to return + * the items once only, in sequence, by successive calls to the next method. + * It is also possible to remove elements from the underlying collection by + * using the optional remove method. Iterator is intended as a replacement + * for the Enumeration interface of previous versions of Java, which did not + * have the remove method and had less conveniently named methods. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see ListIterator + * @see Enumeration + * @since 1.2 + * @status updated to 1.4 + */ +public interface Iterator +{ + /** + * Tests whether there are elements remaining in the collection. In other + * words, calling next() will not throw an exception. + * + * @return true if there is at least one more element in the collection + */ + boolean hasNext(); + + /** + * Obtain the next element in the collection. + * + * @return the next element in the collection + * @throws NoSuchElementException if there are no more elements + */ + Object next(); + + /** + * Remove from the underlying collection the last element returned by next + * (optional operation). This method can be called only once after each + * call to next(). It does not affect what will be returned + * by subsequent calls to next. + * + * @throws IllegalStateException if next has not yet been called or remove + * has already been called since the last call to next. + * @throws UnsupportedOperationException if this Iterator does not support + * the remove operation. + */ + void remove(); +} diff --git a/libjava/classpath/java/util/LinkedHashMap.java b/libjava/classpath/java/util/LinkedHashMap.java new file mode 100644 index 0000000..8e895a9 --- /dev/null +++ b/libjava/classpath/java/util/LinkedHashMap.java @@ -0,0 +1,501 @@ +/* LinkedHashMap.java -- a class providing hashtable data structure, + mapping Object --> Object, with linked list traversal + Copyright (C) 2001, 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 java.util; + +/** + * This class provides a hashtable-backed implementation of the + * Map interface, with predictable traversal order. + *

    + * + * It uses a hash-bucket approach; that is, hash collisions are handled + * by linking the new node off of the pre-existing node (or list of + * nodes). In this manner, techniques such as linear probing (which + * can cause primary clustering) and rehashing (which does not fit very + * well with Java's method of precomputing hash codes) are avoided. In + * addition, this maintains a doubly-linked list which tracks either + * insertion or access order. + *

    + * + * In insertion order, calling put adds the key to the end of + * traversal, unless the key was already in the map; changing traversal order + * requires removing and reinserting a key. On the other hand, in access + * order, all calls to put and get cause the + * accessed key to move to the end of the traversal list. Note that any + * accesses to the map's contents via its collection views and iterators do + * not affect the map's traversal order, since the collection views do not + * call put or get. + *

    + * + * One of the nice features of tracking insertion order is that you can + * copy a hashtable, and regardless of the implementation of the original, + * produce the same results when iterating over the copy. This is possible + * without needing the overhead of TreeMap. + *

    + * + * When using this {@link #LinkedHashMap(int, float, boolean) constructor}, + * you can build an access-order mapping. This can be used to implement LRU + * caches, for example. By overriding {@link #removeEldestEntry(Map.Entry)}, + * you can also control the removal of the oldest entry, and thereby do + * things like keep the map at a fixed size. + *

    + * + * Under ideal circumstances (no collisions), LinkedHashMap offers O(1) + * performance on most operations (containsValue() is, + * of course, O(n)). In the worst case (all keys map to the same + * hash code -- very unlikely), most operations are O(n). Traversal is + * faster than in HashMap (proportional to the map size, and not the space + * allocated for the map), but other operations may be slower because of the + * overhead of the maintaining the traversal order list. + *

    + * + * LinkedHashMap accepts the null key and null values. It is not + * synchronized, so if you need multi-threaded access, consider using:
    + * Map m = Collections.synchronizedMap(new LinkedHashMap(...)); + *

    + * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * {@link ConcurrentModificationException} rather than exhibit + * non-deterministic behavior. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Object#hashCode() + * @see Collection + * @see Map + * @see HashMap + * @see TreeMap + * @see Hashtable + * @since 1.4 + * @status updated to 1.4 + */ +public class LinkedHashMap extends HashMap +{ + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 3801124242820219131L; + + /** + * The oldest Entry to begin iteration at. + */ + transient LinkedHashEntry root; + + /** + * The iteration order of this linked hash map: true for + * access-order, false for insertion-order. + * + * @serial true for access order traversal + */ + final boolean accessOrder; + + /** + * Class to represent an entry in the hash table. Holds a single key-value + * pair and the doubly-linked insertion order list. + */ + class LinkedHashEntry extends HashEntry + { + /** + * The predecessor in the iteration list. If this entry is the root + * (eldest), pred points to the newest entry. + */ + LinkedHashEntry pred; + + /** The successor in the iteration list, null if this is the newest. */ + LinkedHashEntry succ; + + /** + * Simple constructor. + * + * @param key the key + * @param value the value + */ + LinkedHashEntry(Object key, Object value) + { + super(key, value); + if (root == null) + { + root = this; + pred = this; + } + else + { + pred = root.pred; + pred.succ = this; + root.pred = this; + } + } + + /** + * Called when this entry is accessed via put or get. This version does + * the necessary bookkeeping to keep the doubly-linked list in order, + * after moving this element to the newest position in access order. + */ + void access() + { + if (accessOrder && succ != null) + { + modCount++; + if (this == root) + { + root = succ; + pred.succ = this; + succ = null; + } + else + { + pred.succ = succ; + succ.pred = pred; + succ = null; + pred = root.pred; + pred.succ = this; + root.pred = this; + } + } + } + + /** + * Called when this entry is removed from the map. This version does + * the necessary bookkeeping to keep the doubly-linked list in order. + * + * @return the value of this key as it is removed + */ + Object cleanup() + { + if (this == root) + { + root = succ; + if (succ != null) + succ.pred = pred; + } + else if (succ == null) + { + pred.succ = null; + root.pred = pred; + } + else + { + pred.succ = succ; + succ.pred = pred; + } + return value; + } + } // class LinkedHashEntry + + /** + * Construct a new insertion-ordered LinkedHashMap with the default + * capacity (11) and the default load factor (0.75). + */ + public LinkedHashMap() + { + super(); + accessOrder = false; + } + + /** + * Construct a new insertion-ordered LinkedHashMap from the given Map, + * with initial capacity the greater of the size of m or + * the default of 11. + *

    + * + * Every element in Map m will be put into this new HashMap, in the + * order of m's iterator. + * + * @param m a Map whose key / value pairs will be put into + * the new HashMap. NOTE: key / value pairs + * are not cloned in this constructor. + * @throws NullPointerException if m is null + */ + public LinkedHashMap(Map m) + { + super(m); + accessOrder = false; + } + + /** + * Construct a new insertion-ordered LinkedHashMap with a specific + * inital capacity and default load factor of 0.75. + * + * @param initialCapacity the initial capacity of this HashMap (>= 0) + * @throws IllegalArgumentException if (initialCapacity < 0) + */ + public LinkedHashMap(int initialCapacity) + { + super(initialCapacity); + accessOrder = false; + } + + /** + * Construct a new insertion-orderd LinkedHashMap with a specific + * inital capacity and load factor. + * + * @param initialCapacity the initial capacity (>= 0) + * @param loadFactor the load factor (> 0, not NaN) + * @throws IllegalArgumentException if (initialCapacity < 0) || + * ! (loadFactor > 0.0) + */ + public LinkedHashMap(int initialCapacity, float loadFactor) + { + super(initialCapacity, loadFactor); + accessOrder = false; + } + + /** + * Construct a new LinkedHashMap with a specific inital capacity, load + * factor, and ordering mode. + * + * @param initialCapacity the initial capacity (>=0) + * @param loadFactor the load factor (>0, not NaN) + * @param accessOrder true for access-order, false for insertion-order + * @throws IllegalArgumentException if (initialCapacity < 0) || + * ! (loadFactor > 0.0) + */ + public LinkedHashMap(int initialCapacity, float loadFactor, + boolean accessOrder) + { + super(initialCapacity, loadFactor); + this.accessOrder = accessOrder; + } + + /** + * Clears the Map so it has no keys. This is O(1). + */ + public void clear() + { + super.clear(); + root = null; + } + + /** + * Returns true if this HashMap contains a value + * o, such that o.equals(value). + * + * @param value the value to search for in this HashMap + * @return true if at least one key maps to the value + */ + public boolean containsValue(Object value) + { + LinkedHashEntry e = root; + while (e != null) + { + if (equals(value, e.value)) + return true; + e = e.succ; + } + return false; + } + + /** + * Return the value in this Map associated with the supplied key, + * or null if the key maps to nothing. If this is an + * access-ordered Map and the key is found, this performs structural + * modification, moving the key to the newest end of the list. NOTE: + * Since the value could also be null, you must use containsKey to + * see if this key actually maps to something. + * + * @param key the key for which to fetch an associated value + * @return what the key maps to, if present + * @see #put(Object, Object) + * @see #containsKey(Object) + */ + public Object get(Object key) + { + int idx = hash(key); + HashEntry e = buckets[idx]; + while (e != null) + { + if (equals(key, e.key)) + { + e.access(); + return e.value; + } + e = e.next; + } + return null; + } + + /** + * Returns true if this map should remove the eldest entry. + * This method is invoked by all calls to put and + * putAll which place a new entry in the map, providing + * the implementer an opportunity to remove the eldest entry any time + * a new one is added. This can be used to save memory usage of the + * hashtable, as well as emulating a cache, by deleting stale entries. + *

    + * + * For example, to keep the Map limited to 100 entries, override as follows: + *

    +   * private static final int MAX_ENTRIES = 100;
    +   * protected boolean removeEldestEntry(Map.Entry eldest)
    +   * {
    +   *   return size() > MAX_ENTRIES;
    +   * }
    +   * 

    + * + * Typically, this method does not modify the map, but just uses the + * return value as an indication to put whether to proceed. + * However, if you override it to modify the map, you must return false + * (indicating that put should leave the modified map alone), + * or you face unspecified behavior. Remember that in access-order mode, + * even calling get is a structural modification, but using + * the collections views (such as keySet) is not. + *

    + * + * This method is called after the eldest entry has been inserted, so + * if put was called on a previously empty map, the eldest + * entry is the one you just put in! The default implementation just + * returns false, so that this map always behaves like + * a normal one with unbounded growth. + * + * @param eldest the eldest element which would be removed if this + * returns true. For an access-order map, this is the least + * recently accessed; for an insertion-order map, this is the + * earliest element inserted. + * @return true if eldest should be removed + */ + protected boolean removeEldestEntry(Map.Entry eldest) + { + return false; + } + + /** + * Helper method called by put, which creates and adds a + * new Entry, followed by performing bookkeeping (like removeEldestEntry). + * + * @param key the key of the new Entry + * @param value the value + * @param idx the index in buckets where the new Entry belongs + * @param callRemove whether to call the removeEldestEntry method + * @see #put(Object, Object) + * @see #removeEldestEntry(Map.Entry) + * @see LinkedHashEntry#LinkedHashEntry(Object, Object) + */ + void addEntry(Object key, Object value, int idx, boolean callRemove) + { + LinkedHashEntry e = new LinkedHashEntry(key, value); + e.next = buckets[idx]; + buckets[idx] = e; + if (callRemove && removeEldestEntry(root)) + remove(root.key); + } + + /** + * Helper method, called by clone() to reset the doubly-linked list. + * + * @param m the map to add entries from + * @see #clone() + */ + void putAllInternal(Map m) + { + root = null; + super.putAllInternal(m); + } + + /** + * Generates a parameterized iterator. This allows traversal to follow + * the doubly-linked list instead of the random bin order of HashMap. + * + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + * @return the appropriate iterator + */ + Iterator iterator(final int type) + { + return new Iterator() + { + /** The current Entry. */ + LinkedHashEntry current = root; + + /** The previous Entry returned by next(). */ + LinkedHashEntry last; + + /** The number of known modifications to the backing Map. */ + int knownMod = modCount; + + /** + * Returns true if the Iterator has more elements. + * + * @return true if there are more elements + * @throws ConcurrentModificationException if the HashMap was modified + */ + public boolean hasNext() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + return current != null; + } + + /** + * Returns the next element in the Iterator's sequential view. + * + * @return the next element + * @throws ConcurrentModificationException if the HashMap was modified + * @throws NoSuchElementException if there is none + */ + public Object next() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (current == null) + throw new NoSuchElementException(); + last = current; + current = current.succ; + return type == VALUES ? last.value : type == KEYS ? last.key : last; + } + + /** + * Removes from the backing HashMap the last element which was fetched + * with the next() method. + * + * @throws ConcurrentModificationException if the HashMap was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (last == null) + throw new IllegalStateException(); + LinkedHashMap.this.remove(last.key); + last = null; + knownMod++; + } + }; + } +} // class LinkedHashMap diff --git a/libjava/classpath/java/util/LinkedHashSet.java b/libjava/classpath/java/util/LinkedHashSet.java new file mode 100644 index 0000000..6c68195 --- /dev/null +++ b/libjava/classpath/java/util/LinkedHashSet.java @@ -0,0 +1,160 @@ +/* LinkedHashSet.java -- a set backed by a LinkedHashMap, for linked + list traversal. + Copyright (C) 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +import java.io.Serializable; + +/** + * This class provides a hashtable-backed implementation of the + * Set interface, with predictable traversal order. + *

    + * + * It uses a hash-bucket approach; that is, hash collisions are handled + * by linking the new node off of the pre-existing node (or list of + * nodes). In this manner, techniques such as linear probing (which + * can cause primary clustering) and rehashing (which does not fit very + * well with Java's method of precomputing hash codes) are avoided. In + * addition, this maintains a doubly-linked list which tracks insertion + * order. Note that the insertion order is not modified if an + * add simply reinserts an element in the set. + *

    + * + * One of the nice features of tracking insertion order is that you can + * copy a set, and regardless of the implementation of the original, + * produce the same results when iterating over the copy. This is possible + * without needing the overhead of TreeSet. + *

    + * + * Under ideal circumstances (no collisions), LinkedHashSet offers O(1) + * performance on most operations. In the worst case (all elements map + * to the same hash code -- very unlikely), most operations are O(n). + *

    + * + * LinkedHashSet accepts the null entry. It is not synchronized, so if + * you need multi-threaded access, consider using:
    + * Set s = Collections.synchronizedSet(new LinkedHashSet(...)); + *

    + * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * {@link ConcurrentModificationException} rather than exhibit + * non-deterministic behavior. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Object#hashCode() + * @see Collection + * @see Set + * @see HashSet + * @see TreeSet + * @see Collections#synchronizedSet(Set) + * @since 1.4 + * @status updated to 1.4 + */ +public class LinkedHashSet extends HashSet + implements Set, Cloneable, Serializable +{ + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = -2851667679971038690L; + + /** + * Construct a new, empty HashSet whose backing HashMap has the default + * capacity (11) and loadFacor (0.75). + */ + public LinkedHashSet() + { + super(); + } + + /** + * Construct a new, empty HashSet whose backing HashMap has the supplied + * capacity and the default load factor (0.75). + * + * @param initialCapacity the initial capacity of the backing HashMap + * @throws IllegalArgumentException if the capacity is negative + */ + public LinkedHashSet(int initialCapacity) + { + super(initialCapacity); + } + + /** + * Construct a new, empty HashSet whose backing HashMap has the supplied + * capacity and load factor. + * + * @param initialCapacity the initial capacity of the backing HashMap + * @param loadFactor the load factor of the backing HashMap + * @throws IllegalArgumentException if either argument is negative, or + * if loadFactor is POSITIVE_INFINITY or NaN + */ + public LinkedHashSet(int initialCapacity, float loadFactor) + { + super(initialCapacity, loadFactor); + } + + /** + * Construct a new HashSet with the same elements as are in the supplied + * collection (eliminating any duplicates, of course). The backing storage + * has twice the size of the collection, or the default size of 11, + * whichever is greater; and the default load factor (0.75). + * + * @param c a collection of initial set elements + * @throws NullPointerException if c is null + */ + public LinkedHashSet(Collection c) + { + super(c); + } + + /** + * Helper method which initializes the backing Map. + * + * @param capacity the initial capacity + * @param load the initial load factor + * @return the backing HashMap + */ + HashMap init(int capacity, float load) + { + return new LinkedHashMap(capacity, load); + } + +} diff --git a/libjava/classpath/java/util/LinkedList.java b/libjava/classpath/java/util/LinkedList.java new file mode 100644 index 0000000..2a35425 --- /dev/null +++ b/libjava/classpath/java/util/LinkedList.java @@ -0,0 +1,958 @@ +/* LinkedList.java -- Linked list implementation of the List interface + Copyright (C) 1998, 1999, 2000, 2001, 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 java.util; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; + +/** + * Linked list implementation of the List interface. In addition to the + * methods of the List interface, this class provides access to the first + * and last list elements in O(1) time for easy stack, queue, or double-ended + * queue (deque) creation. The list is doubly-linked, with traversal to a + * given index starting from the end closest to the element.

    + * + * LinkedList is not synchronized, so if you need multi-threaded access, + * consider using:
    + * List l = Collections.synchronizedList(new LinkedList(...)); + *

    + * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * {@link ConcurrentModificationException} rather than exhibit + * non-deterministic behavior. + * + * @author Original author unknown + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see List + * @see ArrayList + * @see Vector + * @see Collections#synchronizedList(List) + * @since 1.2 + * @status missing javadoc, but complete to 1.4 + */ +public class LinkedList extends AbstractSequentialList + implements List, Cloneable, Serializable +{ + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = 876323262645176354L; + + /** + * The first element in the list. + */ + transient Entry first; + + /** + * The last element in the list. + */ + transient Entry last; + + /** + * The current length of the list. + */ + transient int size = 0; + + /** + * Class to represent an entry in the list. Holds a single element. + */ + private static final class Entry + { + /** The element in the list. */ + Object data; + + /** The next list entry, null if this is last. */ + Entry next; + + /** The previous list entry, null if this is first. */ + Entry previous; + + /** + * Construct an entry. + * @param data the list element + */ + Entry(Object data) + { + this.data = data; + } + } // class Entry + + /** + * Obtain the Entry at a given position in a list. This method of course + * takes linear time, but it is intelligent enough to take the shorter of the + * paths to get to the Entry required. This implies that the first or last + * entry in the list is obtained in constant time, which is a very desirable + * property. + * For speed and flexibility, range checking is not done in this method: + * Incorrect values will be returned if (n < 0) or (n >= size). + * + * @param n the number of the entry to get + * @return the entry at position n + */ + // Package visible for use in nested classes. + Entry getEntry(int n) + { + Entry e; + if (n < size / 2) + { + e = first; + // n less than size/2, iterate from start + while (n-- > 0) + e = e.next; + } + else + { + e = last; + // n greater than size/2, iterate from end + while (++n < size) + e = e.previous; + } + return e; + } + + /** + * Remove an entry from the list. This will adjust size and deal with + * `first' and `last' appropriatly. + * + * @param e the entry to remove + */ + // Package visible for use in nested classes. + void removeEntry(Entry e) + { + modCount++; + size--; + if (size == 0) + first = last = null; + else + { + if (e == first) + { + first = e.next; + e.next.previous = null; + } + else if (e == last) + { + last = e.previous; + e.previous.next = null; + } + else + { + e.next.previous = e.previous; + e.previous.next = e.next; + } + } + } + + /** + * Checks that the index is in the range of possible elements (inclusive). + * + * @param index the index to check + * @throws IndexOutOfBoundsException if index < 0 || index > size + */ + private void checkBoundsInclusive(int index) + { + if (index < 0 || index > size) + throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + + size); + } + + /** + * Checks that the index is in the range of existing elements (exclusive). + * + * @param index the index to check + * @throws IndexOutOfBoundsException if index < 0 || index >= size + */ + private void checkBoundsExclusive(int index) + { + if (index < 0 || index >= size) + throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + + size); + } + + /** + * Create an empty linked list. + */ + public LinkedList() + { + } + + /** + * Create a linked list containing the elements, in order, of a given + * collection. + * + * @param c the collection to populate this list from + * @throws NullPointerException if c is null + */ + public LinkedList(Collection c) + { + addAll(c); + } + + /** + * Returns the first element in the list. + * + * @return the first list element + * @throws NoSuchElementException if the list is empty + */ + public Object getFirst() + { + if (size == 0) + throw new NoSuchElementException(); + return first.data; + } + + /** + * Returns the last element in the list. + * + * @return the last list element + * @throws NoSuchElementException if the list is empty + */ + public Object getLast() + { + if (size == 0) + throw new NoSuchElementException(); + return last.data; + } + + /** + * Remove and return the first element in the list. + * + * @return the former first element in the list + * @throws NoSuchElementException if the list is empty + */ + public Object removeFirst() + { + if (size == 0) + throw new NoSuchElementException(); + modCount++; + size--; + Object r = first.data; + + if (first.next != null) + first.next.previous = null; + else + last = null; + + first = first.next; + + return r; + } + + /** + * Remove and return the last element in the list. + * + * @return the former last element in the list + * @throws NoSuchElementException if the list is empty + */ + public Object removeLast() + { + if (size == 0) + throw new NoSuchElementException(); + modCount++; + size--; + Object r = last.data; + + if (last.previous != null) + last.previous.next = null; + else + first = null; + + last = last.previous; + + return r; + } + + /** + * Insert an element at the first of the list. + * + * @param o the element to insert + */ + public void addFirst(Object o) + { + Entry e = new Entry(o); + + modCount++; + if (size == 0) + first = last = e; + else + { + e.next = first; + first.previous = e; + first = e; + } + size++; + } + + /** + * Insert an element at the last of the list. + * + * @param o the element to insert + */ + public void addLast(Object o) + { + addLastEntry(new Entry(o)); + } + + /** + * Inserts an element at the end of the list. + * + * @param e the entry to add + */ + private void addLastEntry(Entry e) + { + modCount++; + if (size == 0) + first = last = e; + else + { + e.previous = last; + last.next = e; + last = e; + } + size++; + } + + /** + * Returns true if the list contains the given object. Comparison is done by + * o == null ? e = null : o.equals(e). + * + * @param o the element to look for + * @return true if it is found + */ + public boolean contains(Object o) + { + Entry e = first; + while (e != null) + { + if (equals(o, e.data)) + return true; + e = e.next; + } + return false; + } + + /** + * Returns the size of the list. + * + * @return the list size + */ + public int size() + { + return size; + } + + /** + * Adds an element to the end of the list. + * + * @param o the entry to add + * @return true, as it always succeeds + */ + public boolean add(Object o) + { + addLastEntry(new Entry(o)); + return true; + } + + /** + * Removes the entry at the lowest index in the list that matches the given + * object, comparing by o == null ? e = null : o.equals(e). + * + * @param o the object to remove + * @return true if an instance of the object was removed + */ + public boolean remove(Object o) + { + Entry e = first; + while (e != null) + { + if (equals(o, e.data)) + { + removeEntry(e); + return true; + } + e = e.next; + } + return false; + } + + /** + * Append the elements of the collection in iteration order to the end of + * this list. If this list is modified externally (for example, if this + * list is the collection), behavior is unspecified. + * + * @param c the collection to append + * @return true if the list was modified + * @throws NullPointerException if c is null + */ + public boolean addAll(Collection c) + { + return addAll(size, c); + } + + /** + * Insert the elements of the collection in iteration order at the given + * index of this list. If this list is modified externally (for example, + * if this list is the collection), behavior is unspecified. + * + * @param c the collection to append + * @return true if the list was modified + * @throws NullPointerException if c is null + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + public boolean addAll(int index, Collection c) + { + checkBoundsInclusive(index); + int csize = c.size(); + + if (csize == 0) + return false; + + Iterator itr = c.iterator(); + + // Get the entries just before and after index. If index is at the start + // of the list, BEFORE is null. If index is at the end of the list, AFTER + // is null. If the list is empty, both are null. + Entry after = null; + Entry before = null; + if (index != size) + { + after = getEntry(index); + before = after.previous; + } + else + before = last; + + // Create the first new entry. We do not yet set the link from `before' + // to the first entry, in order to deal with the case where (c == this). + // [Actually, we don't have to handle this case to fufill the + // contract for addAll(), but Sun's implementation appears to.] + Entry e = new Entry(itr.next()); + e.previous = before; + Entry prev = e; + Entry firstNew = e; + + // Create and link all the remaining entries. + for (int pos = 1; pos < csize; pos++) + { + e = new Entry(itr.next()); + e.previous = prev; + prev.next = e; + prev = e; + } + + // Link the new chain of entries into the list. + modCount++; + size += csize; + prev.next = after; + if (after != null) + after.previous = e; + else + last = e; + + if (before != null) + before.next = firstNew; + else + first = firstNew; + return true; + } + + /** + * Remove all elements from this list. + */ + public void clear() + { + if (size > 0) + { + modCount++; + first = null; + last = null; + size = 0; + } + } + + /** + * Return the element at index. + * + * @param index the place to look + * @return the element at index + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object get(int index) + { + checkBoundsExclusive(index); + return getEntry(index).data; + } + + /** + * Replace the element at the given location in the list. + * + * @param index which index to change + * @param o the new element + * @return the prior element + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object set(int index, Object o) + { + checkBoundsExclusive(index); + Entry e = getEntry(index); + Object old = e.data; + e.data = o; + return old; + } + + /** + * Inserts an element in the given position in the list. + * + * @param index where to insert the element + * @param o the element to insert + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + public void add(int index, Object o) + { + checkBoundsInclusive(index); + Entry e = new Entry(o); + + if (index < size) + { + modCount++; + Entry after = getEntry(index); + e.next = after; + e.previous = after.previous; + if (after.previous == null) + first = e; + else + after.previous.next = e; + after.previous = e; + size++; + } + else + addLastEntry(e); + } + + /** + * Removes the element at the given position from the list. + * + * @param index the location of the element to remove + * @return the removed element + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + public Object remove(int index) + { + checkBoundsExclusive(index); + Entry e = getEntry(index); + removeEntry(e); + return e.data; + } + + /** + * Returns the first index where the element is located in the list, or -1. + * + * @param o the element to look for + * @return its position, or -1 if not found + */ + public int indexOf(Object o) + { + int index = 0; + Entry e = first; + while (e != null) + { + if (equals(o, e.data)) + return index; + index++; + e = e.next; + } + return -1; + } + + /** + * Returns the last index where the element is located in the list, or -1. + * + * @param o the element to look for + * @return its position, or -1 if not found + */ + public int lastIndexOf(Object o) + { + int index = size - 1; + Entry e = last; + while (e != null) + { + if (equals(o, e.data)) + return index; + index--; + e = e.previous; + } + return -1; + } + + /** + * Obtain a ListIterator over this list, starting at a given index. The + * ListIterator returned by this method supports the add, remove and set + * methods. + * + * @param index the index of the element to be returned by the first call to + * next(), or size() to be initially positioned at the end of the list + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + public ListIterator listIterator(int index) + { + checkBoundsInclusive(index); + return new LinkedListItr(index); + } + + /** + * Create a shallow copy of this LinkedList (the elements are not cloned). + * + * @return an object of the same class as this object, containing the + * same elements in the same order + */ + public Object clone() + { + LinkedList copy = null; + try + { + copy = (LinkedList) super.clone(); + } + catch (CloneNotSupportedException ex) + { + } + copy.clear(); + copy.addAll(this); + return copy; + } + + /** + * Returns an array which contains the elements of the list in order. + * + * @return an array containing the list elements + */ + public Object[] toArray() + { + Object[] array = new Object[size]; + Entry e = first; + for (int i = 0; i < size; i++) + { + array[i] = e.data; + e = e.next; + } + return array; + } + + /** + * Returns an Array whose component type is the runtime component type of + * the passed-in Array. The returned Array is populated with all of the + * elements in this LinkedList. If the passed-in Array is not large enough + * to store all of the elements in this List, a new Array will be created + * and returned; if the passed-in Array is larger than the size + * of this List, then size() index will be set to null. + * + * @param a the passed-in Array + * @return an array representation of this list + * @throws ArrayStoreException if the runtime type of a does not allow + * an element in this list + * @throws NullPointerException if a is null + */ + public Object[] toArray(Object[] a) + { + if (a.length < size) + a = (Object[]) Array.newInstance(a.getClass().getComponentType(), size); + else if (a.length > size) + a[size] = null; + Entry e = first; + for (int i = 0; i < size; i++) + { + a[i] = e.data; + e = e.next; + } + return a; + } + + /** + * Serializes this object to the given stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData the size of the list (int), followed by all the elements + * (Object) in proper order + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + s.writeInt(size); + Entry e = first; + while (e != null) + { + s.writeObject(e.data); + e = e.next; + } + } + + /** + * Deserializes this object from the given stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData the size of the list (int), followed by all the elements + * (Object) in proper order + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + int i = s.readInt(); + while (--i >= 0) + addLastEntry(new Entry(s.readObject())); + } + + /** + * A ListIterator over the list. This class keeps track of its + * position in the list and the two list entries it is between. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + */ + private final class LinkedListItr implements ListIterator + { + /** Number of modifications we know about. */ + private int knownMod = modCount; + + /** Entry that will be returned by next(). */ + private Entry next; + + /** Entry that will be returned by previous(). */ + private Entry previous; + + /** Entry that will be affected by remove() or set(). */ + private Entry lastReturned; + + /** Index of `next'. */ + private int position; + + /** + * Initialize the iterator. + * + * @param index the initial index + */ + LinkedListItr(int index) + { + if (index == size) + { + next = null; + previous = last; + } + else + { + next = getEntry(index); + previous = next.previous; + } + position = index; + } + + /** + * Checks for iterator consistency. + * + * @throws ConcurrentModificationException if the list was modified + */ + private void checkMod() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + } + + /** + * Returns the index of the next element. + * + * @return the next index + * @throws ConcurrentModificationException if the list was modified + */ + public int nextIndex() + { + checkMod(); + return position; + } + + /** + * Returns the index of the previous element. + * + * @return the previous index + * @throws ConcurrentModificationException if the list was modified + */ + public int previousIndex() + { + checkMod(); + return position - 1; + } + + /** + * Returns true if more elements exist via next. + * + * @return true if next will succeed + * @throws ConcurrentModificationException if the list was modified + */ + public boolean hasNext() + { + checkMod(); + return (next != null); + } + + /** + * Returns true if more elements exist via previous. + * + * @return true if previous will succeed + * @throws ConcurrentModificationException if the list was modified + */ + public boolean hasPrevious() + { + checkMod(); + return (previous != null); + } + + /** + * Returns the next element. + * + * @return the next element + * @throws ConcurrentModificationException if the list was modified + * @throws NoSuchElementException if there is no next + */ + public Object next() + { + checkMod(); + if (next == null) + throw new NoSuchElementException(); + position++; + lastReturned = previous = next; + next = lastReturned.next; + return lastReturned.data; + } + + /** + * Returns the previous element. + * + * @return the previous element + * @throws ConcurrentModificationException if the list was modified + * @throws NoSuchElementException if there is no previous + */ + public Object previous() + { + checkMod(); + if (previous == null) + throw new NoSuchElementException(); + position--; + lastReturned = next = previous; + previous = lastReturned.previous; + return lastReturned.data; + } + + /** + * Remove the most recently returned element from the list. + * + * @throws ConcurrentModificationException if the list was modified + * @throws IllegalStateException if there was no last element + */ + public void remove() + { + checkMod(); + if (lastReturned == null) + throw new IllegalStateException(); + + // Adjust the position to before the removed element, if the element + // being removed is behind the cursor. + if (lastReturned == previous) + position--; + + next = lastReturned.next; + previous = lastReturned.previous; + removeEntry(lastReturned); + knownMod++; + + lastReturned = null; + } + + /** + * Adds an element between the previous and next, and advance to the next. + * + * @param o the element to add + * @throws ConcurrentModificationException if the list was modified + */ + public void add(Object o) + { + checkMod(); + modCount++; + knownMod++; + size++; + position++; + Entry e = new Entry(o); + e.previous = previous; + e.next = next; + + if (previous != null) + previous.next = e; + else + first = e; + + if (next != null) + next.previous = e; + else + last = e; + + previous = e; + lastReturned = null; + } + + /** + * Changes the contents of the element most recently returned. + * + * @param o the new element + * @throws ConcurrentModificationException if the list was modified + * @throws IllegalStateException if there was no last element + */ + public void set(Object o) + { + checkMod(); + if (lastReturned == null) + throw new IllegalStateException(); + lastReturned.data = o; + } + } // class LinkedListItr +} diff --git a/libjava/classpath/java/util/List.java b/libjava/classpath/java/util/List.java new file mode 100644 index 0000000..4458112 --- /dev/null +++ b/libjava/classpath/java/util/List.java @@ -0,0 +1,451 @@ +/* List.java -- An ordered collection which allows indexed access + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * An ordered collection (also known as a list). This collection allows + * access to elements by position, as well as control on where elements + * are inserted. Unlike sets, duplicate elements are permitted by this + * general contract (if a subclass forbids duplicates, this should be + * documented). + *

    + * + * List places additional requirements on iterator, + * add, remove, equals, and + * hashCode, in addition to requiring more methods. List + * indexing is 0-based (like arrays), although some implementations may + * require time proportional to the index to obtain an arbitrary element. + * The List interface is incompatible with Set; you cannot implement both + * simultaneously. + *

    + * + * Lists also provide a ListIterator which allows bidirectional + * traversal and other features atop regular iterators. Lists can be + * searched for arbitrary elements, and allow easy insertion and removal + * of multiple elements in one method call. + *

    + * + * Note: While lists may contain themselves as elements, this leads to + * undefined (usually infinite recursive) behavior for some methods like + * hashCode or equals. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see Set + * @see ArrayList + * @see LinkedList + * @see Vector + * @see Arrays#asList(Object[]) + * @see Collections#nCopies(int, Object) + * @see Collections#EMPTY_LIST + * @see AbstractList + * @see AbstractSequentialList + * @since 1.2 + * @status updated to 1.4 + */ +public interface List extends Collection +{ + /** + * Insert an element into the list at a given position (optional operation). + * This shifts all existing elements from that position to the end one + * index to the right. This version of add has no return, since it is + * assumed to always succeed if there is no exception. + * + * @param index the location to insert the item + * @param o the object to insert + * @throws UnsupportedOperationException if this list does not support the + * add operation + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + * @throws NullPointerException if o is null and this list doesn't support + * the addition of null values. + */ + void add(int index, Object o); + + /** + * Add an element to the end of the list (optional operation). If the list + * imposes restraints on what can be inserted, such as no null elements, + * this should be documented. + * + * @param o the object to add + * @return true, as defined by Collection for a modified list + * @throws UnsupportedOperationException if this list does not support the + * add operation + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + * @throws NullPointerException if o is null and this list doesn't support + * the addition of null values. + */ + boolean add(Object o); + + /** + * Insert the contents of a collection into the list at a given position + * (optional operation). Shift all elements at that position to the right + * by the number of elements inserted. This operation is undefined if + * this list is modified during the operation (for example, if you try + * to insert a list into itself). + * + * @param index the location to insert the collection + * @param c the collection to insert + * @return true if the list was modified by this action, that is, if c is + * non-empty + * @throws UnsupportedOperationException if this list does not support the + * addAll operation + * @throws IndexOutOfBoundsException if index < 0 || index > size() + * @throws ClassCastException if some element of c cannot be added to this + * list due to its type + * @throws IllegalArgumentException if some element of c cannot be added + * to this list for some other reason + * @throws NullPointerException if some element of c is null and this list + * doesn't support the addition of null values. + * @throws NullPointerException if the specified collection is null + * @see #add(int, Object) + */ + boolean addAll(int index, Collection c); + + /** + * Add the contents of a collection to the end of the list (optional + * operation). This operation is undefined if this list is modified + * during the operation (for example, if you try to insert a list into + * itself). + * + * @param c the collection to add + * @return true if the list was modified by this action, that is, if c is + * non-empty + * @throws UnsupportedOperationException if this list does not support the + * addAll operation + * @throws ClassCastException if some element of c cannot be added to this + * list due to its type + * @throws IllegalArgumentException if some element of c cannot be added + * to this list for some other reason + * @throws NullPointerException if the specified collection is null + * @throws NullPointerException if some element of c is null and this list + * doesn't support the addition of null values. + * @see #add(Object) + */ + boolean addAll(Collection c); + + /** + * Clear the list, such that a subsequent call to isEmpty() would return + * true (optional operation). + * + * @throws UnsupportedOperationException if this list does not support the + * clear operation + */ + void clear(); + + /** + * Test whether this list contains a given object as one of its elements. + * This is defined as the existence of an element e such that + * o == null ? e == null : o.equals(e). + * + * @param o the element to look for + * @return true if this list contains the element + * @throws ClassCastException if the type of o is not a valid type + * for this list. + * @throws NullPointerException if o is null and the list doesn't + * support null values. + */ + boolean contains(Object o); + + /** + * Test whether this list contains every element in a given collection. + * + * @param c the collection to test for + * @return true if for every element o in c, contains(o) would return true + * @throws NullPointerException if the collection is null + * @throws ClassCastException if the type of any element in c is not a valid + * type for this list. + * @throws NullPointerException if some element of c is null and this + * list does not support null values. + * @see #contains(Object) + */ + boolean containsAll(Collection c); + + /** + * Test whether this list is equal to another object. A List is defined to be + * equal to an object if and only if that object is also a List, and the two + * lists have the same sequence. Two lists l1 and l2 are equal if and only + * if l1.size() == l2.size(), and for every integer n between 0 + * and l1.size() - 1 inclusive, l1.get(n) == null ? + * l2.get(n) == null : l1.get(n).equals(l2.get(n)). + * + * @param o the object to test for equality with this list + * @return true if o is equal to this list + * @see Object#equals(Object) + * @see #hashCode() + */ + boolean equals(Object o); + + /** + * Get the element at a given index in this list. + * + * @param index the index of the element to be returned + * @return the element at index index in this list + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + Object get(int index); + + /** + * Obtains a hash code for this list. In order to obey the general + * contract of the hashCode method of class Object, this value is + * calculated as follows: + * +

    hashCode = 1;
    +Iterator i = list.iterator();
    +while (i.hasNext())
    +{
    +  Object obj = i.next();
    +  hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
    +}
    + * + *

    This ensures that the general contract of Object.hashCode() + * is adhered to. + * + * @return the hash code of this list + * @see Object#hashCode() + * @see #equals(Object) + */ + int hashCode(); + + /** + * Obtain the first index at which a given object is to be found in this + * list. + * + * @param o the object to search for + * @return the least integer n such that o == null ? get(n) == null : + * o.equals(get(n)), or -1 if there is no such index. + * @throws ClassCastException if the type of o is not a valid + * type for this list. + * @throws NullPointerException if o is null and this + * list does not support null values. + */ + int indexOf(Object o); + + /** + * Test whether this list is empty, that is, if size() == 0. + * + * @return true if this list contains no elements + */ + boolean isEmpty(); + + /** + * Obtain an Iterator over this list, whose sequence is the list order. + * + * @return an Iterator over the elements of this list, in order + */ + Iterator iterator(); + + /** + * Obtain the last index at which a given object is to be found in this + * list. + * + * @return the greatest integer n such that o == null ? get(n) == null + * : o.equals(get(n)), or -1 if there is no such index. + * @throws ClassCastException if the type of o is not a valid + * type for this list. + * @throws NullPointerException if o is null and this + * list does not support null values. + */ + int lastIndexOf(Object o); + + /** + * Obtain a ListIterator over this list, starting at the beginning. + * + * @return a ListIterator over the elements of this list, in order, starting + * at the beginning + */ + ListIterator listIterator(); + + /** + * Obtain a ListIterator over this list, starting at a given position. + * A first call to next() would return the same as get(index), and a + * first call to previous() would return the same as get(index - 1). + * + * @param index the position, between 0 and size() inclusive, to begin the + * iteration from + * @return a ListIterator over the elements of this list, in order, starting + * at index + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + ListIterator listIterator(int index); + + /** + * Remove the element at a given position in this list (optional operation). + * Shifts all remaining elements to the left to fill the gap. + * + * @param index the position within the list of the object to remove + * @return the object that was removed + * @throws UnsupportedOperationException if this list does not support the + * remove operation + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + Object remove(int index); + + /** + * Remove the first occurence of an object from this list (optional + * operation). That is, remove the first element e such that + * o == null ? e == null : o.equals(e). + * + * @param o the object to remove + * @return true if the list changed as a result of this call, that is, if + * the list contained at least one occurrence of o + * @throws UnsupportedOperationException if this list does not support the + * remove operation + * @throws ClassCastException if the type of o is not a valid + * type for this list. + * @throws NullPointerException if o is null and this + * list does not support removing null values. + */ + boolean remove(Object o); + + /** + * Remove all elements of a given collection from this list (optional + * operation). That is, remove every element e such that c.contains(e). + * + * @param c the collection to filter out + * @return true if this list was modified as a result of this call + * @throws UnsupportedOperationException if this list does not support the + * removeAll operation + * @throws NullPointerException if the collection is null + * @throws ClassCastException if the type of any element in c is not a valid + * type for this list. + * @throws NullPointerException if some element of c is null and this + * list does not support removing null values. + * @see #remove(Object) + * @see #contains(Object) + */ + boolean removeAll(Collection c); + + /** + * Remove all elements of this list that are not contained in a given + * collection (optional operation). That is, remove every element e such + * that !c.contains(e). + * + * @param c the collection to retain + * @return true if this list was modified as a result of this call + * @throws UnsupportedOperationException if this list does not support the + * retainAll operation + * @throws NullPointerException if the collection is null + * @throws ClassCastException if the type of any element in c is not a valid + * type for this list. + * @throws NullPointerException if some element of c is null and this + * list does not support retaining null values. + * @see #remove(Object) + * @see #contains(Object) + */ + boolean retainAll(Collection c); + + /** + * Replace an element of this list with another object (optional operation). + * + * @param index the position within this list of the element to be replaced + * @param o the object to replace it with + * @return the object that was replaced + * @throws UnsupportedOperationException if this list does not support the + * set operation + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + * @throws ClassCastException if o cannot be added to this list due to its + * type + * @throws IllegalArgumentException if o cannot be added to this list for + * some other reason + * @throws NullPointerException if o is null and this + * list does not support null values. + */ + Object set(int index, Object o); + + /** + * Get the number of elements in this list. If the list contains more + * than Integer.MAX_VALUE elements, return Integer.MAX_VALUE. + * + * @return the number of elements in the list + */ + int size(); + + /** + * Obtain a List view of a subsection of this list, from fromIndex + * (inclusive) to toIndex (exclusive). If the two indices are equal, the + * sublist is empty. The returned list should be modifiable if and only + * if this list is modifiable. Changes to the returned list should be + * reflected in this list. If this list is structurally modified in + * any way other than through the returned list, the result of any subsequent + * operations on the returned list is undefined. + * + * @param fromIndex the index that the returned list should start from + * (inclusive) + * @param toIndex the index that the returned list should go to (exclusive) + * @return a List backed by a subsection of this list + * @throws IndexOutOfBoundsException if fromIndex < 0 + * || toIndex > size() || fromIndex > toIndex + */ + List subList(int fromIndex, int toIndex); + + /** + * Copy the current contents of this list into an array. + * + * @return an array of type Object[] and length equal to the length of this + * list, containing the elements currently in this list, in order + */ + Object[] toArray(); + + /** + * Copy the current contents of this list into an array. If the array passed + * as an argument has length less than that of this list, an array of the + * same run-time type as a, and length equal to the length of this list, is + * allocated using Reflection. Otherwise, a itself is used. The elements of + * this list are copied into it, and if there is space in the array, the + * following element is set to null. The resultant array is returned. + * Note: The fact that the following element is set to null is only useful + * if it is known that this list does not contain any null elements. + * + * @param a the array to copy this list into + * @return an array containing the elements currently in this list, in + * order + * @throws ArrayStoreException if the type of any element of the + * collection is not a subtype of the element type of a + * @throws NullPointerException if the specified array is null + */ + Object[] toArray(Object[] a); +} diff --git a/libjava/classpath/java/util/ListIterator.java b/libjava/classpath/java/util/ListIterator.java new file mode 100644 index 0000000..5e17108 --- /dev/null +++ b/libjava/classpath/java/util/ListIterator.java @@ -0,0 +1,170 @@ +/* ListIterator.java -- Extended Iterator for iterating over ordered lists + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * An extended version of Iterator to support the extra features of Lists. The + * elements may be accessed in forward or reverse order, elements may be + * replaced as well as removed, and new elements may be inserted, during the + * traversal of the list. + *

    + * + * A list with n elements provides n+1 iterator positions (the front, the end, + * or between two elements). Note that remove and set + * operate on the last element returned, whether it was by next + * or previous. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see List + * @see Iterator + * @see Enumeration + * @since 1.2 + * @status updated to 1.4 + */ +public interface ListIterator extends Iterator +{ + /** + * Tests whether there are elements remaining in the list in the forward + * direction. In other words, next() will not fail with a + * NoSuchElementException. + * + * @return true if the list continues in the forward direction + */ + boolean hasNext(); + + /** + * Tests whether there are elements remaining in the list in the reverse + * direction. In other words, previous() will not fail with a + * NoSuchElementException. + * + * @return true if the list continues in the reverse direction + */ + boolean hasPrevious(); + + /** + * Obtain the next element in the list in the forward direction. Repeated + * calls to next may be used to iterate over the entire list, or calls to + * next and previous may be used together to go forwards and backwards. + * Alternating calls to next and previous will return the same element. + * + * @return the next element in the list in the forward direction + * @throws NoSuchElementException if there are no more elements + */ + Object next(); + + /** + * Obtain the next element in the list in the reverse direction. Repeated + * calls to previous may be used to iterate backwards over the entire list, + * or calls to next and previous may be used together to go forwards and + * backwards. Alternating calls to next and previous will return the same + * element. + * + * @return the next element in the list in the reverse direction + * @throws NoSuchElementException if there are no more elements + */ + Object previous(); + + /** + * Find the index of the element that would be returned by a call to next. + * If hasNext() returns false, this returns the list size. + * + * @return the index of the element that would be returned by next() + */ + int nextIndex(); + + /** + * Find the index of the element that would be returned by a call to + * previous. If hasPrevious() returns false, this returns -1. + * + * @return the index of the element that would be returned by previous() + */ + int previousIndex(); + + /** + * Insert an element into the list at the current position of the iterator + * (optional operation). The element is inserted in between the element that + * would be returned by previous and the element that would be returned by + * next. After the insertion, a subsequent call to next is unaffected, but + * a call to previous returns the item that was added. The values returned + * by nextIndex() and previousIndex() are incremented. + * + * @param o the object to insert into the list + * @throws ClassCastException if the object is of a type which cannot be added + * to this list. + * @throws IllegalArgumentException if some other aspect of the object stops + * it being added to this list. + * @throws UnsupportedOperationException if this ListIterator does not + * support the add operation. + */ + void add(Object o); + + /** + * Remove from the list the element last returned by a call to next or + * previous (optional operation). This method may only be called if neither + * add nor remove have been called since the last call to next or previous. + * + * @throws IllegalStateException if neither next or previous have been + * called, or if add or remove has been called since the last call + * to next or previous + * @throws UnsupportedOperationException if this ListIterator does not + * support the remove operation + */ + void remove(); + + /** + * Replace the element last returned by a call to next or previous with a + * given object (optional operation). This method may only be called if + * neither add nor remove have been called since the last call to next or + * previous. + * + * @param o the object to replace the element with + * @throws ClassCastException the object is of a type which cannot be added + * to this list + * @throws IllegalArgumentException some other aspect of the object stops + * it being added to this list + * @throws IllegalStateException if neither next or previous have been + * called, or if add or remove has been called since the last call + * to next or previous + * @throws UnsupportedOperationException if this ListIterator does not + * support the set operation + */ + void set(Object o); +} diff --git a/libjava/classpath/java/util/ListResourceBundle.java b/libjava/classpath/java/util/ListResourceBundle.java new file mode 100644 index 0000000..2bc51c3 --- /dev/null +++ b/libjava/classpath/java/util/ListResourceBundle.java @@ -0,0 +1,140 @@ +/* ListResourceBundle -- a resource bundle build around a list + Copyright (C) 1998, 1999, 2001, 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 java.util; + +/** + * A ListResouceBundle provides an easy way, to create your own + * resource bundle. It is an abstract class that you can subclass. You should + * then overwrite the getContents method, that provides a key/value list. + * + *

    The key/value list is a two dimensional list of Object. The first + * dimension ranges over the resources. The second dimension ranges from + * zero (key) to one (value). The keys must be of type String, and they are + * case-sensitive. For example: + * +

    public class MyResources
    +  extends ListResourceBundle
    +{
    +  public Object[][] getContents()
    +  {
    +    return contents;
    +  }
    +
    +  static final Object[][] contents =
    +  {
    +    // LOCALIZED STRINGS
    +    {"s1", "The disk \"{1}\" contains {0}."},  // MessageFormat pattern
    +    {"s2", "1"},                       // location of {0} in pattern
    +    {"s3", "My Disk"},                 // sample disk name
    +    {"s4", "no files"},                // first ChoiceFormat choice
    +    {"s5", "one file"},                // second ChoiceFormat choice
    +    {"s6", "{0,number} files"}         // third ChoiceFormat choice
    +    {"s7", "3 Mar 96"},                // sample date
    +    {"s8", new Dimension(1,5)}         // real object, not just string
    +    // END OF LOCALIZED MATERIAL
    +  };
    +}
    + * + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @see Locale + * @see PropertyResourceBundle + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class ListResourceBundle extends ResourceBundle +{ + /** + * The constructor. It does nothing special. + */ + public ListResourceBundle() + { + } + + /** + * Gets a resource for a given key. This is called by getObject. + * + * @param key the key of the resource + * @return the resource for the key, or null if it doesn't exist + */ + public final Object handleGetObject(String key) + { + Object[][] contents = getContents(); + int i = contents.length; + while (--i >= 0) + if (key.equals(contents[i][0])) + return contents[i][1]; + return null; + } + + /** + * This method should return all keys for which a resource exists. + * + * @return an enumeration of the keys + */ + public Enumeration getKeys() + { + // We make a new Set that holds all the keys, then return an enumeration + // for that. This prevents modifications from ruining the enumeration, + // as well as ignoring duplicates. + final Object[][] contents = getContents(); + Set s = new HashSet(); + int i = contents.length; + while (--i >= 0) + s.add(contents[i][0]); + ResourceBundle bundle = parent; + // Eliminate tail recursion. + while (bundle != null) + { + Enumeration e = bundle.getKeys(); + while (e.hasMoreElements()) + s.add(e.nextElement()); + bundle = bundle.parent; + } + return Collections.enumeration(s); + } + + /** + * Gets the key/value list. You must override this method, and should not + * provide duplicate keys or null entries. + * + * @return a two dimensional list of String key / Object resouce pairs + */ + protected abstract Object[][] getContents(); +} // class ListResourceBundle diff --git a/libjava/classpath/java/util/Locale.java b/libjava/classpath/java/util/Locale.java new file mode 100644 index 0000000..6d3f846 --- /dev/null +++ b/libjava/classpath/java/util/Locale.java @@ -0,0 +1,952 @@ +/* Locale.java -- i18n locales + Copyright (C) 1998, 1999, 2001, 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 java.util; + +import gnu.classpath.SystemProperties; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * Locales represent a specific country and culture. Classes which can be + * passed a Locale object tailor their information for a given locale. For + * instance, currency number formatting is handled differently for the USA + * and France. + * + *

    Locales are made up of a language code, a country code, and an optional + * set of variant strings. Language codes are represented by + * + * ISO 639:1988 w/ additions from ISO 639/RA Newsletter No. 1/1989 + * and a decision of the Advisory Committee of ISO/TC39 on August 8, 1997. + * + *

    Country codes are represented by + * + * ISO 3166. Variant strings are vendor and browser specific. Standard + * variant strings include "POSIX" for POSIX, "WIN" for MS-Windows, and + * "MAC" for Macintosh. When there is more than one variant string, they must + * be separated by an underscore (U+005F). + * + *

    The default locale is determined by the values of the system properties + * user.language, user.region, and user.variant, defaulting to "en". Note that + * the locale does NOT contain the conversion and formatting capabilities (for + * that, use ResourceBundle and java.text). Rather, it is an immutable tag + * object for identifying a given locale, which is referenced by these other + * classes when they must make locale-dependent decisions. + * + * @see ResourceBundle + * @see java.text.Format + * @see java.text.NumberFormat + * @see java.text.Collator + * @author Jochen Hoenicke + * @author Paul Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.1 + * @status updated to 1.4 + */ +public final class Locale implements Serializable, Cloneable +{ + /** Locale which represents the English language. */ + public static final Locale ENGLISH = getLocale("en"); + + /** Locale which represents the French language. */ + public static final Locale FRENCH = getLocale("fr"); + + /** Locale which represents the German language. */ + public static final Locale GERMAN = getLocale("de"); + + /** Locale which represents the Italian language. */ + public static final Locale ITALIAN = getLocale("it"); + + /** Locale which represents the Japanese language. */ + public static final Locale JAPANESE = getLocale("ja"); + + /** Locale which represents the Korean language. */ + public static final Locale KOREAN = getLocale("ko"); + + /** Locale which represents the Chinese language. */ + public static final Locale CHINESE = getLocale("zh"); + + /** Locale which represents the Chinese language as used in China. */ + public static final Locale SIMPLIFIED_CHINESE = getLocale("zh", "CN"); + + /** + * Locale which represents the Chinese language as used in Taiwan. + * Same as TAIWAN Locale. + */ + public static final Locale TRADITIONAL_CHINESE = getLocale("zh", "TW"); + + /** Locale which represents France. */ + public static final Locale FRANCE = getLocale("fr", "FR"); + + /** Locale which represents Germany. */ + public static final Locale GERMANY = getLocale("de", "DE"); + + /** Locale which represents Italy. */ + public static final Locale ITALY = getLocale("it", "IT"); + + /** Locale which represents Japan. */ + public static final Locale JAPAN = getLocale("ja", "JP"); + + /** Locale which represents Korea. */ + public static final Locale KOREA = getLocale("ko", "KR"); + + /** + * Locale which represents China. + * Same as SIMPLIFIED_CHINESE Locale. + */ + public static final Locale CHINA = SIMPLIFIED_CHINESE; + + /** + * Locale which represents the People's Republic of China. + * Same as CHINA Locale. + */ + public static final Locale PRC = CHINA; + + /** + * Locale which represents Taiwan. + * Same as TRADITIONAL_CHINESE Locale. + */ + public static final Locale TAIWAN = TRADITIONAL_CHINESE; + + /** Locale which represents the United Kingdom. */ + public static final Locale UK = getLocale("en", "GB"); + + /** Locale which represents the United States. */ + public static final Locale US = getLocale("en", "US"); + + /** Locale which represents the English speaking portion of Canada. */ + public static final Locale CANADA = getLocale("en", "CA"); + + /** Locale which represents the French speaking portion of Canada. */ + public static final Locale CANADA_FRENCH = getLocale("fr", "CA"); + + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 9149081749638150636L; + + /** + * The language code, as returned by getLanguage(). + * + * @serial the languange, possibly "" + */ + private String language; + + /** + * The country code, as returned by getCountry(). + * + * @serial the country, possibly "" + */ + private String country; + + /** + * The variant code, as returned by getVariant(). + * + * @serial the variant, possibly "" + */ + private String variant; + + /** + * This is the cached hashcode. When writing to stream, we write -1. + * + * @serial should be -1 in serial streams + */ + private transient int hashcode; + + /** + * Array storing all available locales. + */ + private static transient Locale[] availableLocales; + + /** + * Locale cache. Only created locale objects are stored. + * Contains all supported locales when getAvailableLocales() + * got called. + */ + private static transient HashMap localeMap; + + /** + * The default locale. Except for during bootstrapping, this should never be + * null. Note the logic in the main constructor, to detect when + * bootstrapping has completed. + */ + private static Locale defaultLocale = + getLocale(SystemProperties.getProperty("user.language", "en"), + SystemProperties.getProperty("user.region", ""), + SystemProperties.getProperty("user.variant", "")); + + /** + * Array storing all the available two-letter ISO639 languages. + */ + private static transient String[] languageCache; + + /** + * Array storing all the available two-letter ISO3166 country codes. + */ + private static transient String[] countryCache; + + /** + * Retrieves the locale with the specified language from the cache. + * + * @param language the language of the locale to retrieve. + * @return the locale. + */ + private static Locale getLocale(String language) + { + return getLocale(language, "", ""); + } + + /** + * Retrieves the locale with the specified language and region + * from the cache. + * + * @param language the language of the locale to retrieve. + * @param region the region of the locale to retrieve. + * @return the locale. + */ + private static Locale getLocale(String language, String region) + { + return getLocale(language, region, ""); + } + + /** + * Retrieves the locale with the specified language, region + * and variant from the cache. + * + * @param language the language of the locale to retrieve. + * @param region the region of the locale to retrieve. + * @param variant the variant of the locale to retrieve. + * @return the locale. + */ + private static Locale getLocale(String language, String region, String variant) + { + if (localeMap == null) + localeMap = new HashMap(256); + + String name = language + "_" + region + "_" + variant; + Locale locale = (Locale) localeMap.get(name); + + if (locale == null) + { + locale = new Locale(language, region, variant); + localeMap.put(name, locale); + } + + return locale; + } + + /** + * Convert new iso639 codes to the old ones. + * + * @param language the language to check + * @return the appropriate code + */ + private String convertLanguage(String language) + { + if (language.equals("")) + return language; + language = language.toLowerCase(); + int index = "he,id,yi".indexOf(language); + if (index != -1) + return "iw,in,ji".substring(index, index + 2); + return language; + } + + /** + * Creates a new locale for the given language and country. + * + * @param language lowercase two-letter ISO-639 A2 language code + * @param country uppercase two-letter ISO-3166 A2 contry code + * @param variant vendor and browser specific + * @throws NullPointerException if any argument is null + */ + public Locale(String language, String country, String variant) + { + // During bootstrap, we already know the strings being passed in are + // the correct capitalization, and not null. We can't call + // String.toUpperCase during this time, since that depends on the + // default locale. + if (defaultLocale != null) + { + language = convertLanguage(language).intern(); + country = country.toUpperCase().intern(); + variant = variant.intern(); + } + this.language = language; + this.country = country; + this.variant = variant; + hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); + } + + /** + * Creates a new locale for the given language and country. + * + * @param language lowercase two-letter ISO-639 A2 language code + * @param country uppercase two-letter ISO-3166 A2 country code + * @throws NullPointerException if either argument is null + */ + public Locale(String language, String country) + { + this(language, country, ""); + } + + /** + * Creates a new locale for a language. + * + * @param language lowercase two-letter ISO-639 A2 language code + * @throws NullPointerException if either argument is null + * @since 1.4 + */ + public Locale(String language) + { + this(language, "", ""); + } + + /** + * Returns the default Locale. The default locale is generally once set + * on start up and then never changed. Normally you should use this locale + * for everywhere you need a locale. The initial setting matches the + * default locale, the user has chosen. + * + * @return the default locale for this virtual machine + */ + public static Locale getDefault() + { + return defaultLocale; + } + + /** + * Changes the default locale. Normally only called on program start up. + * Note that this doesn't change the locale for other programs. This has + * a security check, + * PropertyPermission("user.language", "write"), because of + * its potential impact to running code. + * + * @param newLocale the new default locale + * @throws NullPointerException if newLocale is null + * @throws SecurityException if permission is denied + */ + public static void setDefault(Locale newLocale) + { + if (newLocale == null) + throw new NullPointerException(); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission("user.language", "write")); + defaultLocale = newLocale; + } + + /** + * Returns the list of available locales. + * + * @return the installed locales + */ + public static synchronized Locale[] getAvailableLocales() + { + if (availableLocales == null) + { + String[] localeNames = LocaleData.localeNames; + availableLocales = new Locale[localeNames.length]; + + for (int i = 0; i < localeNames.length; i++) + { + String language; + String region = ""; + String variant = ""; + String name = localeNames[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); + } + + availableLocales[i] = getLocale(language, region, variant); + } + } + + return availableLocales; + } + + /** + * Returns a list of all 2-letter uppercase country codes as defined + * in ISO 3166. + * + * @return a list of acceptable country codes + */ + public static String[] getISOCountries() + { + if (countryCache == null) + { + countryCache = getISOStrings("territories"); + } + + return countryCache; + } + + /** + * Returns a list of all 2-letter lowercase language codes as defined + * in ISO 639 (both old and new variant). + * + * @return a list of acceptable language codes + */ + public static String[] getISOLanguages() + { + if (languageCache == null) + { + languageCache = getISOStrings("languages"); + } + return languageCache; + } + + /** + * Returns the set of keys from the specified resource hashtable, filtered + * so that only two letter strings are returned. + * + * @param tableName the name of the table from which to retrieve the keys. + * @return an array of two-letter strings. + */ + private static String[] getISOStrings(String tableName) + { + int count = 0; + ResourceBundle bundle = + ResourceBundle.getBundle("gnu.java.locale.LocaleInformation"); + Enumeration e = bundle.getKeys(); + ArrayList tempList = new ArrayList(); + + while (e.hasMoreElements()) + { + String key = (String) e.nextElement(); + + if (key.startsWith(tableName + ".")) + { + String str = key.substring(tableName.length() + 1); + + if (str.length() == 2 + && Character.isLetter(str.charAt(0)) + && Character.isLetter(str.charAt(1))) + { + tempList.add(str); + ++count; + } + } + } + + String[] strings = new String[count]; + + for (int a = 0; a < count; ++a) + strings[a] = (String) tempList.get(a); + + return strings; + } + + /** + * Returns the language code of this locale. Some language codes have changed + * as ISO 639 has evolved; this returns the old name, even if you built + * the locale with the new one. + * + * @return language code portion of this locale, or an empty String + */ + public String getLanguage() + { + return language; + } + + /** + * Returns the country code of this locale. + * + * @return country code portion of this locale, or an empty String + */ + public String getCountry() + { + return country; + } + + /** + * Returns the variant code of this locale. + * + * @return the variant code portion of this locale, or an empty String + */ + public String getVariant() + { + return variant; + } + + /** + * Gets the string representation of the current locale. This consists of + * the language, the country, and the variant, separated by an underscore. + * The variant is listed only if there is a language or country. Examples: + * "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr__MAC". + * + * @return the string representation of this Locale + * @see #getDisplayName() + */ + public String toString() + { + if (language.length() == 0 && country.length() == 0) + return ""; + else if (country.length() == 0 && variant.length() == 0) + return language; + StringBuffer result = new StringBuffer(language); + result.append('_').append(country); + if (variant.length() != 0) + result.append('_').append(variant); + return result.toString(); + } + + /** + * Returns the three-letter ISO language abbrevation of this locale. + * + * @throws MissingResourceException if the three-letter code is not known + */ + public String getISO3Language() + { + // We know all strings are interned so we can use '==' for better performance. + if (language == "") + return ""; + int index + = ("aa,ab,af,am,ar,as,ay,az,ba,be,bg,bh,bi,bn,bo,br,ca,co,cs,cy,da," + + "de,dz,el,en,eo,es,et,eu,fa,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu,ha,iw," + + "hi,hr,hu,hy,ia,in,ie,ik,in,is,it,iu,iw,ja,ji,jw,ka,kk,kl,km,kn," + + "ko,ks,ku,ky,la,ln,lo,lt,lv,mg,mi,mk,ml,mn,mo,mr,ms,mt,my,na,ne," + + "nl,no,oc,om,or,pa,pl,ps,pt,qu,rm,rn,ro,ru,rw,sa,sd,sg,sh,si,sk," + + "sl,sm,sn,so,sq,sr,ss,st,su,sv,sw,ta,te,tg,th,ti,tk,tl,tn,to,tr," + + "ts,tt,tw,ug,uk,ur,uz,vi,vo,wo,xh,ji,yo,za,zh,zu") + .indexOf(language); + + if (index % 3 != 0 || language.length() != 2) + throw new MissingResourceException + ("Can't find ISO3 language for " + language, + "java.util.Locale", language); + + // Don't read this aloud. These are the three letter language codes. + return + ("aarabkaframharaasmaymazebakbelbulbihbisbenbodbrecatcoscescymdandeu" + + "dzoellengepospaesteusfasfinfijfaofrafrygaigdhglggrngujhauhebhinhrv" + + "hunhyeinaindileipkindislitaikuhebjpnyidjawkatkazkalkhmkankorkaskur" + + "kirlatlinlaolitlavmlgmrimkdmalmonmolmarmsamltmyanaunepnldnorociorm" + + "oripanpolpusporquerohrunronruskinsansndsagsrpsinslkslvsmosnasomsqi" + + "srpsswsotsunsweswatamteltgkthatirtuktgltsntonturtsotattwiuigukrurd" + + "uzbvievolwolxhoyidyorzhazhozul") + .substring(index, index + 3); + } + + /** + * Returns the three-letter ISO country abbrevation of the locale. + * + * @throws MissingResourceException if the three-letter code is not known + */ + public String getISO3Country() + { + // We know all strings are interned so we can use '==' for better performance. + if (country == "") + return ""; + int index + = ("AD,AE,AF,AG,AI,AL,AM,AN,AO,AQ,AR,AS,AT,AU,AW,AZ,BA,BB,BD,BE,BF," + + "BG,BH,BI,BJ,BM,BN,BO,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CF,CG,CH,CI,CK," + + "CL,CM,CN,CO,CR,CU,CV,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER," + + "ES,ET,FI,FJ,FK,FM,FO,FR,FX,GA,GB,GD,GE,GF,GH,GI,GL,GM,GN,GP,GQ," + + "GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IN,IO,IQ,IR,IS,IT," + + "JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS," + + "LT,LU,LV,LY,MA,MC,MD,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV," + + "MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG," + + "PH,PK,PL,PM,PN,PR,PT,PW,PY,QA,RE,RO,RU,RW,SA,SB,SC,SD,SE,SG,SH," + + "SI,SJ,SK,SL,SM,SN,SO,SR,ST,SV,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TM,TN," + + "TO,TP,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF," + + "WS,YE,YT,YU,ZA,ZM,ZR,ZW") + .indexOf(country); + + if (index % 3 != 0 || country.length() != 2) + throw new MissingResourceException + ("Can't find ISO3 country for " + country, + "java.util.Locale", country); + + // Don't read this aloud. These are the three letter country codes. + return + ("ANDAREAFGATGAIAALBARMANTAGOATAARGASMAUTAUSABWAZEBIHBRBBGDBELBFABGR" + + "BHRBDIBENBMUBRNBOLBRABHSBTNBVTBWABLRBLZCANCCKCAFCOGCHECIVCOKCHLCMR" + + "CHNCOLCRICUBCPVCXRCYPCZEDEUDJIDNKDMADOMDZAECUESTEGYESHERIESPETHFIN" + + "FJIFLKFSMFROFRAFXXGABGBRGRDGEOGUFGHAGIBGRLGMBGINGLPGNQGRCSGSGTMGUM" + + "GNBGUYHKGHMDHNDHRVHTIHUNIDNIRLISRINDIOTIRQIRNISLITAJAMJORJPNKENKGZ" + + "KHMKIRCOMKNAPRKKORKWTCYMKAZLAOLBNLCALIELKALBRLSOLTULUXLVALBYMARMCO" + + "MDAMDGMHLMKDMLIMMRMNGMACMNPMTQMRTMSRMLTMUSMDVMWIMEXMYSMOZNAMNCLNER" + + "NFKNGANICNLDNORNPLNRUNIUNZLOMNPANPERPYFPNGPHLPAKPOLSPMPCNPRIPRTPLW" + + "PRYQATREUROMRUSRWASAUSLBSYCSDNSWESGPSHNSVNSJMSVKSLESMRSENSOMSURSTP" + + "SLVSYRSWZTCATCDATFTGOTHATJKTKLTKMTUNTONTMPTURTTOTUVTWNTZAUKRUGAUMI" + + "USAURYUZBVATVCTVENVGBVIRVNMVUTWLFWSMYEMMYTYUGZAFZMBZARZWE") + .substring(index, index + 3); + } + + /** + * Gets the country name suitable for display to the user, formatted + * for the default locale. This has the same effect as + *

    +   * getDisplayLanguage(Locale.getDefault());
    +   * 
    + * + * @return the language name of this locale localized to the default locale, + * with the ISO code as backup + */ + public String getDisplayLanguage() + { + return getDisplayLanguage(defaultLocale); + } + + /** + *

    + * Gets the name of the language specified by this locale, in a form suitable + * for display to the user. If possible, the display name will be localized + * to the specified locale. For example, if the locale instance is + * Locale.GERMANY, and the specified locale is Locale.UK, + * the result would be 'German'. Using the German locale would instead give + * 'Deutsch'. If the display name can not be localized to the supplied + * locale, it will fall back on other output in the following order: + *

    + *
      + *
    • the display name in the default locale
    • + *
    • the display name in English
    • + *
    • the ISO code
    • + *
    + *

    + * If the language is unspecified by this locale, then the empty string is + * returned. + *

    + * + * @param inLocale the locale to use for formatting the display string. + * @return the language name of this locale localized to the given locale, + * with the default locale, English and the ISO code as backups. + * @throws NullPointerException if the supplied locale is null. + */ + public String getDisplayLanguage(Locale inLocale) + { + try + { + ResourceBundle res = + ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + inLocale, + ClassLoader.getSystemClassLoader()); + + return res.getString("languages." + language); + } + catch (MissingResourceException e) + { + return language; + } + } + + /** + * Returns the country name of this locale localized to the + * default locale. If the localized is not found, the ISO code + * is returned. This has the same effect as + *
    +   * getDisplayCountry(Locale.getDefault());
    +   * 
    + * + * @return the country name of this locale localized to the given locale, + * with the ISO code as backup + */ + public String getDisplayCountry() + { + return getDisplayCountry(defaultLocale); + } + + /** + *

    + * Gets the name of the country specified by this locale, in a form suitable + * for display to the user. If possible, the display name will be localized + * to the specified locale. For example, if the locale instance is + * Locale.GERMANY, and the specified locale is Locale.UK, + * the result would be 'Germany'. Using the German locale would instead give + * 'Deutschland'. If the display name can not be localized to the supplied + * locale, it will fall back on other output in the following order: + *

    + *
      + *
    • the display name in the default locale
    • + *
    • the display name in English
    • + *
    • the ISO code
    • + *
    + *

    + * If the country is unspecified by this locale, then the empty string is + * returned. + *

    + * + * @param inLocale the locale to use for formatting the display string. + * @return the country name of this locale localized to the given locale, + * with the default locale, English and the ISO code as backups. + * @throws NullPointerException if the supplied locale is null. + */ + public String getDisplayCountry(Locale inLocale) + { + try + { + ResourceBundle res = + ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + inLocale, + ClassLoader.getSystemClassLoader()); + + return res.getString("territories." + country); + } + catch (MissingResourceException e) + { + return country; + } + } + + /** + * Returns the variant name of this locale localized to the + * default locale. If the localized is not found, the variant code + * itself is returned. This has the same effect as + *
    +   * getDisplayVariant(Locale.getDefault());
    +   * 
    + * + * @return the variant code of this locale localized to the given locale, + * with the ISO code as backup + */ + public String getDisplayVariant() + { + return getDisplayVariant(defaultLocale); + } + + + /** + *

    + * Gets the name of the variant specified by this locale, in a form suitable + * for display to the user. If possible, the display name will be localized + * to the specified locale. For example, if the locale instance is a revised + * variant, and the specified locale is Locale.UK, the result + * would be 'REVISED'. Using the German locale would instead give + * 'Revidiert'. If the display name can not be localized to the supplied + * locale, it will fall back on other output in the following order: + *

    + *
      + *
    • the display name in the default locale
    • + *
    • the display name in English
    • + *
    • the ISO code
    • + *
    + *

    + * If the variant is unspecified by this locale, then the empty string is + * returned. + *

    + * + * @param inLocale the locale to use for formatting the display string. + * @return the variant name of this locale localized to the given locale, + * with the default locale, English and the ISO code as backups. + * @throws NullPointerException if the supplied locale is null. + */ + public String getDisplayVariant(Locale inLocale) + { + try + { + ResourceBundle res = + ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + inLocale, + ClassLoader.getSystemClassLoader()); + + return res.getString("variants." + variant); + } + catch (MissingResourceException e) + { + return variant; + } + } + + /** + * Gets all local components suitable for display to the user, formatted + * for the default locale. For the language component, getDisplayLanguage + * is called. For the country component, getDisplayCountry is called. + * For the variant set component, getDisplayVariant is called. + * + *

    The returned String will be one of the following forms:
    + *

    +   * language (country, variant)
    +   * language (country)
    +   * language (variant)
    +   * country (variant)
    +   * language
    +   * country
    +   * variant
    +   * 
    + * + * @return String version of this locale, suitable for display to the user + */ + public String getDisplayName() + { + return getDisplayName(defaultLocale); + } + + /** + * Gets all local components suitable for display to the user, formatted + * for a specified locale. For the language component, + * getDisplayLanguage(Locale) is called. For the country component, + * getDisplayCountry(Locale) is called. For the variant set component, + * getDisplayVariant(Locale) is called. + * + *

    The returned String will be one of the following forms:
    + *

    +   * language (country, variant)
    +   * language (country)
    +   * language (variant)
    +   * country (variant)
    +   * language
    +   * country
    +   * variant
    +   * 
    + * + * @param locale locale to use for formatting + * @return String version of this locale, suitable for display to the user + */ + public String getDisplayName(Locale locale) + { + StringBuffer result = new StringBuffer(); + int count = 0; + String[] delimiters = {"", " (", ","}; + if (language.length() != 0) + { + result.append(delimiters[count++]); + result.append(getDisplayLanguage(locale)); + } + if (country.length() != 0) + { + result.append(delimiters[count++]); + result.append(getDisplayCountry(locale)); + } + if (variant.length() != 0) + { + result.append(delimiters[count++]); + result.append(getDisplayVariant(locale)); + } + if (count > 1) + result.append(")"); + return result.toString(); + } + + /** + * Does the same as Object.clone() but does not throw + * a CloneNotSupportedException. Why anyone would + * use this method is a secret to me, since this class is immutable. + * + * @return the clone + */ + public Object clone() + { + // This class is final, so no need to use native super.clone(). + return new Locale(language, country, variant); + } + + /** + * Return the hash code for this locale. The hashcode is the logical + * xor of the hash codes of the language, the country and the variant. + * The hash code is precomputed, since Locales are often + * used in hash tables. + * + * @return the hashcode + */ + public int hashCode() + { + return hashcode; + } + + /** + * Compares two locales. To be equal, obj must be a Locale with the same + * language, country, and variant code. + * + * @param obj the other locale + * @return true if obj is equal to this + */ + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (! (obj instanceof Locale)) + return false; + Locale l = (Locale) obj; + + return (language == l.language + && country == l.country + && variant == l.variant); + } + + /** + * Write the locale to an object stream. + * + * @param output the stream to write to + * @throws IOException if the write fails + * @serialData The first three fields are Strings representing language, + * country, and variant. The fourth field is a placeholder for + * the cached hashcode, but this is always written as -1, and + * recomputed when reading it back. + */ + private void writeObject(ObjectOutputStream s) + throws IOException + { + s.writeObject(language); + s.writeObject(country); + s.writeObject(variant); + // Hashcode field is always written as -1. + s.writeInt(-1); + } + + /** + * Reads a locale from the input stream. + * + * @param input the stream to read from + * @throws IOException if reading fails + * @throws ClassNotFoundException if reading fails + * @serialData the hashCode is always invalid and must be recomputed + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + language = ((String) s.readObject()).intern(); + country = ((String) s.readObject()).intern(); + variant = ((String) s.readObject()).intern(); + // Recompute hashcode. + hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); + } +} // class Locale diff --git a/libjava/classpath/java/util/Map.java b/libjava/classpath/java/util/Map.java new file mode 100644 index 0000000..256e988 --- /dev/null +++ b/libjava/classpath/java/util/Map.java @@ -0,0 +1,338 @@ +/* Map.java: interface Map -- An object that maps keys to values + interface Map.Entry -- an Entry in a Map + Copyright (C) 1998, 2001, 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 java.util; + +/** + * An object that maps keys onto values. Keys cannot be duplicated. This + * interface replaces the obsolete {@link Dictionary} abstract class. + *

    + * + * The map has three collection views, which are backed by the map + * (modifications on one show up on the other): a set of keys, a collection + * of values, and a set of key-value mappings. Some maps have a guaranteed + * order, but not all do. + *

    + * + * Note: Be careful about using mutable keys. Behavior is unspecified if + * a key's comparison behavior is changed after the fact. As a corollary + * to this rule, don't use a Map as one of its own keys or values, as it makes + * hashCode and equals have undefined behavior. + *

    + * + * All maps are recommended to provide a no argument constructor, which builds + * an empty map, and one that accepts a Map parameter and copies the mappings + * (usually by putAll), to create an equivalent map. Unfortunately, Java + * cannot enforce these suggestions. + *

    + * + * The map may be unmodifiable, in which case unsupported operations will + * throw an UnsupportedOperationException. Note that some operations may be + * safe, such as putAll(m) where m is empty, even if the operation would + * normally fail with a non-empty argument. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see HashMap + * @see TreeMap + * @see Hashtable + * @see SortedMap + * @see Collection + * @see Set + * @since 1.2 + * @status updated to 1.4 + */ +public interface Map +{ + /** + * Remove all entries from this Map (optional operation). + * + * @throws UnsupportedOperationException if clear is not supported + */ + void clear(); + + /** + * Returns true if this contains a mapping for the given key. + * + * @param key the key to search for + * @return true if the map contains the key + * @throws ClassCastException if the key is of an inappropriate type + * @throws NullPointerException if key is null but the map + * does not permit null keys + */ + boolean containsKey(Object key); + + /** + * Returns true if this contains at least one mapping with the given value. + * In other words, returns true if a value v exists where + * (value == null ? v == null : value.equals(v)). This usually + * requires linear time. + * + * @param value the value to search for + * @return true if the map contains the value + * @throws ClassCastException if the type of the value is not a valid type + * for this map. + * @throws NullPointerException if the value is null and the map doesn't + * support null values. + */ + boolean containsValue(Object value); + + /** + * Returns a set view of the mappings in this Map. Each element in the + * set is a Map.Entry. The set is backed by the map, so that changes in + * one show up in the other. Modifications made while an iterator is + * in progress cause undefined behavior. If the set supports removal, + * these methods remove the underlying mapping from the map: + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear. + * Element addition, via add or addAll, is + * not supported via this set. + * + * @return the set view of all mapping entries + * @see Map.Entry + */ + Set entrySet(); + + /** + * Compares the specified object with this map for equality. Returns + * true if the other object is a Map with the same mappings, + * that is,
    + * o instanceof Map && entrySet().equals(((Map) o).entrySet(); + * This allows comparison of maps, regardless of implementation. + * + * @param o the object to be compared + * @return true if the object equals this map + * @see Set#equals(Object) + */ + boolean equals(Object o); + + /** + * Returns the value mapped by the given key. Returns null if + * there is no mapping. However, in Maps that accept null values, you + * must rely on containsKey to determine if a mapping exists. + * + * @param key the key to look up + * @return the value associated with the key, or null if key not in map + * @throws ClassCastException if the key is an inappropriate type + * @throws NullPointerException if this map does not accept null keys + * @see #containsKey(Object) + */ + Object get(Object key); + + /** + * Associates the given key to the given value (optional operation). If the + * map already contains the key, its value is replaced. Be aware that in + * a map that permits null values, a null return does not + * always imply that the mapping was created. + * + * @param key the key to map + * @param value the value to be mapped + * @return the previous value of the key, or null if there was no mapping + * @throws UnsupportedOperationException if the operation is not supported + * @throws ClassCastException if the key or value is of the wrong type + * @throws IllegalArgumentException if something about this key or value + * prevents it from existing in this map + * @throws NullPointerException if either the key or the value is null, + * and the map forbids null keys or values + * @see #containsKey(Object) + */ + Object put(Object key, Object value); + + /** + * Returns the hash code for this map. This is the sum of all hashcodes + * for each Map.Entry object in entrySet. This allows comparison of maps, + * regardless of implementation, and satisfies the contract of + * Object.hashCode. + * + * @return the hash code + * @see Map.Entry#hashCode() + */ + int hashCode(); + + /** + * Returns true if the map contains no mappings. + * + * @return true if the map is empty + */ + boolean isEmpty(); + + /** + * Returns a set view of the keys in this Map. The set is backed by the + * map, so that changes in one show up in the other. Modifications made + * while an iterator is in progress cause undefined behavior. If the set + * supports removal, these methods remove the underlying mapping from + * the map: Iterator.remove, Set.remove, + * removeAll, retainAll, and clear. + * Element addition, via add or addAll, is + * not supported via this set. + * + * @return the set view of all keys + */ + Set keySet(); + + /** + * Copies all entries of the given map to this one (optional operation). If + * the map already contains a key, its value is replaced. + * + * @param m the mapping to load into this map + * @throws UnsupportedOperationException if the operation is not supported + * @throws ClassCastException if a key or value is of the wrong type + * @throws IllegalArgumentException if something about a key or value + * prevents it from existing in this map + * @throws NullPointerException if the map forbids null keys or values, or + * if m is null. + * @see #put(Object, Object) + */ + void putAll(Map m); + + /** + * Removes the mapping for this key if present (optional operation). If + * the key is not present, this returns null. Note that maps which permit + * null values may also return null if the key was removed. + * + * @param key the key to remove + * @return the value the key mapped to, or null if not present. + * @throws UnsupportedOperationException if deletion is unsupported + * @throws NullPointerException if the key is null and this map doesn't + * support null keys. + * @throws ClassCastException if the type of the key is not a valid type + * for this map. + */ + Object remove(Object key); + + /** + * Returns the number of key-value mappings in the map. If there are more + * than Integer.MAX_VALUE mappings, return Integer.MAX_VALUE. + * + * @return the number of mappings + */ + int size(); + + /** + * Returns a collection (or bag) view of the values in this Map. The + * collection is backed by the map, so that changes in one show up in + * the other. Modifications made while an iterator is in progress cause + * undefined behavior. If the collection supports removal, these methods + * remove the underlying mapping from the map: Iterator.remove, + * Collection.remove, removeAll, + * retainAll, and clear. Element addition, via + * add or addAll, is not supported via this + * collection. + * + * @return the collection view of all values + */ + Collection values(); + + /** + * A map entry (key-value pair). The Map.entrySet() method returns a set + * view of these objects; there is no other valid way to come across them. + * These objects are only valid for the duration of an iteration; in other + * words, if you mess with one after modifying the map, you are asking + * for undefined behavior. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Map + * @see Map#entrySet() + * @since 1.2 + * @status updated to 1.4 + */ + interface Entry + { + /** + * Get the key corresponding to this entry. + * + * @return the key + */ + Object getKey(); + + /** + * Get the value corresponding to this entry. If you already called + * Iterator.remove(), this is undefined. + * + * @return the value + */ + Object getValue(); + + /** + * Replaces the value with the specified object (optional operation). + * This writes through to the map, and is undefined if you already + * called Iterator.remove(). + * + * @param value the new value to store + * @return the old value + * @throws UnsupportedOperationException if the operation is not supported + * @throws ClassCastException if the value is of the wrong type + * @throws IllegalArgumentException if something about the value + * prevents it from existing in this map + * @throws NullPointerException if the map forbids null values + */ + Object setValue(Object value); + + + /** + * Returns the hash code of the entry. This is defined as the + * exclusive-or of the hashcodes of the key and value (using 0 for + * null). In other words, this must be: + * +

    (getKey() == null ? 0 : getKey().hashCode())
    +^ (getValue() == null ? 0 : getValue().hashCode())
    + * + * @return the hash code + */ + int hashCode(); + + /** + * Compares the specified object with this entry. Returns true only if + * the object is a mapping of identical key and value. In other words, + * this must be: + * +

    (o instanceof Map.Entry)
    +&& (getKey() == null ? ((HashMap) o).getKey() == null
    +                     : getKey().equals(((HashMap) o).getKey()))
    +&& (getValue() == null ? ((HashMap) o).getValue() == null
    +                       : getValue().equals(((HashMap) o).getValue()))
    + * + * @param o the object to compare + * + * @return true if it is equal + */ + boolean equals(Object o); + } +} diff --git a/libjava/classpath/java/util/MissingResourceException.java b/libjava/classpath/java/util/MissingResourceException.java new file mode 100644 index 0000000..26640de --- /dev/null +++ b/libjava/classpath/java/util/MissingResourceException.java @@ -0,0 +1,105 @@ +/* MissingResourceException.java -- thrown for a missing resource + Copyright (C) 1998, 1999, 2001, 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 java.util; + +/** + * This exception is thrown when a resource is missing. + * + * @author Jochen Hoenicke + * @author Warren Levy (warrenl@cygnus.com) + * @see ResourceBundle + * @since 1.1 + * @status updated to 1.4 + */ +public class MissingResourceException extends RuntimeException +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -4876345176062000401L; + + /** + * The name of the resource bundle requested by user. + * + * @serial the class name of the resource bundle + */ + private final String className; + + /** + * The key of the resource in the bundle requested by user. + * + * @serial the name of the resouce + */ + private final String key; + + /** + * Creates a new exception, with the specified parameters. + * + * @param s the detail message + * @param className the name of the resource bundle + * @param key the key of the missing resource + */ + public MissingResourceException(String s, String className, String key) + { + super(s); + this.className = className; + this.key = key; + } + + /** + * Gets the name of the resource bundle, for which a resource is missing. + * + * @return the name of the resource bundle + */ + public String getClassName() + { + return className; + } + + /** + * Gets the key of the resource that is missing bundle, this is an empty + * string if the whole resource bundle is missing. + * + * @return the name of the resource bundle + */ + public String getKey() + { + return key; + } +} diff --git a/libjava/classpath/java/util/NoSuchElementException.java b/libjava/classpath/java/util/NoSuchElementException.java new file mode 100644 index 0000000..5e1a217 --- /dev/null +++ b/libjava/classpath/java/util/NoSuchElementException.java @@ -0,0 +1,88 @@ +/* NoSuchElementException.java -- Attempt to access element that does not exist + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + */ + +/** + * Exception thrown when an attempt is made to access an element that does not + * exist. This exception is thrown by the Enumeration, Iterator and + * ListIterator classes if the nextElement, next or previous method goes + * beyond the end of the list of elements that are being accessed. It is also + * thrown by Vector and Stack when attempting to access the first or last + * element of an empty collection. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Enumeration + * @see Iterator + * @see ListIterator + * @see Enumeration#nextElement() + * @see Iterator#next() + * @see ListIterator#previous() + * @since 1.0 + * @status updated to 1.4 + */ +public class NoSuchElementException extends RuntimeException +{ + /** + * Compatible with JDK 1.0. + */ + private static final long serialVersionUID = 6769829250639411880L; + + /** + * Constructs a NoSuchElementException with no detail message. + */ + public NoSuchElementException() + { + } + + /** + * Constructs a NoSuchElementException with a detail message. + * + * @param detail the detail message for the exception + */ + public NoSuchElementException(String detail) + { + super(detail); + } +} diff --git a/libjava/classpath/java/util/Observable.java b/libjava/classpath/java/util/Observable.java new file mode 100644 index 0000000..4c2cddb --- /dev/null +++ b/libjava/classpath/java/util/Observable.java @@ -0,0 +1,180 @@ +/* Observable.java -- an object to be observed + Copyright (C) 1999, 2000, 2001, 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 java.util; + +/** + * This class represents an object which is observable. Other objects may + * register their intent to be notified when this object changes; and when + * this object does change, it will trigger the update method + * of each observer. + * + * Note that the notifyObservers() method of this class is + * unrelated to the notify() of Object. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Observer + * @status updated to 1.4 + */ +public class Observable +{ + /** Tracks whether this object has changed. */ + private boolean changed; + + /* List of the Observers registered as interested in this Observable. */ + private LinkedHashSet observers; + + /** + * Constructs an Observable with zero Observers. + */ + public Observable() + { + observers = new LinkedHashSet(); + } + + /** + * Adds an Observer. If the observer was already added this method does + * nothing. + * + * @param observer Observer to add + * @throws NullPointerException if observer is null + */ + public synchronized void addObserver(Observer observer) + { + observers.add(observer); + } + + /** + * Reset this Observable's state to unchanged. This is called automatically + * by notifyObservers once all observers have been notified. + * + * @see #notifyObservers() + */ + protected synchronized void clearChanged() + { + changed = false; + } + + /** + * Returns the number of observers for this object. + * + * @return number of Observers for this + */ + public synchronized int countObservers() + { + return observers.size(); + } + + /** + * Deletes an Observer of this Observable. + * + * @param victim Observer to delete + */ + public synchronized void deleteObserver(Observer victim) + { + observers.remove(victim); + } + + /** + * Deletes all Observers of this Observable. + */ + public synchronized void deleteObservers() + { + observers.clear(); + } + + /** + * True if setChanged has been called more recently than + * clearChanged. + * + * @return whether or not this Observable has changed + */ + public synchronized boolean hasChanged() + { + return changed; + } + + /** + * If the Observable has actually changed then tell all Observers about it, + * then reset state to unchanged. + * + * @see #notifyObservers(Object) + * @see Observer#update(Observable, Object) + */ + public void notifyObservers() + { + notifyObservers(null); + } + + /** + * If the Observable has actually changed then tell all Observers about it, + * then reset state to unchanged. Note that though the order of + * notification is unspecified in subclasses, in Observable it is in the + * order of registration. + * + * @param obj argument to Observer's update method + * @see Observer#update(Observable, Object) + */ + public void notifyObservers(Object obj) + { + if (! hasChanged()) + return; + // Create clone inside monitor, as that is relatively fast and still + // important to keep threadsafe, but update observers outside of the + // lock since update() can call arbitrary code. + Set s; + synchronized (this) + { + s = (Set) observers.clone(); + } + int i = s.size(); + Iterator iter = s.iterator(); + while (--i >= 0) + ((Observer) iter.next()).update(this, obj); + clearChanged(); + } + + /** + * Marks this Observable as having changed. + */ + protected synchronized void setChanged() + { + changed = true; + } +} diff --git a/libjava/classpath/java/util/Observer.java b/libjava/classpath/java/util/Observer.java new file mode 100644 index 0000000..c59a0ca --- /dev/null +++ b/libjava/classpath/java/util/Observer.java @@ -0,0 +1,60 @@ +/* Observer.java -- an object that will be informed of changes in an Observable + Copyright (C) 1998, 1999, 2001, 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 java.util; + +/** + * Interface that is implemented when a class wants to be informed of changes + * in Observable objects. + * + * @author Warren Levy (warrenl@cygnus.com) + * @see Observable + * @status updated to 1.4 + */ +public interface Observer +{ + /** + * This method is called whenever the observable object changes, and has + * called notifyObservers. The Observable object can pass + * arbitrary information in the second parameter. + * + * @param observable the Observable object that changed + * @param arg arbitrary information, usually relating to the change + */ + void update(Observable observable, Object arg); +} diff --git a/libjava/classpath/java/util/Properties.java b/libjava/classpath/java/util/Properties.java new file mode 100644 index 0000000..c7c19b3 --- /dev/null +++ b/libjava/classpath/java/util/Properties.java @@ -0,0 +1,574 @@ +/* Properties.java -- a set of persistent properties + 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 java.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * A set of persistent properties, which can be saved or loaded from a stream. + * A property list may also contain defaults, searched if the main list + * does not contain a property for a given key. + * + * An example of a properties file for the german language is given + * here. This extends the example given in ListResourceBundle. + * Create a file MyResource_de.properties with the following contents + * and put it in the CLASSPATH. (The character + * \u00e4 is the german umlaut) + * + * +
    s1=3
    +s2=MeineDisk
    +s3=3. M\u00e4rz 96
    +s4=Die Diskette ''{1}'' enth\u00e4lt {0} in {2}.
    +s5=0
    +s6=keine Dateien
    +s7=1
    +s8=eine Datei
    +s9=2
    +s10={0,number} Dateien
    +s11=Das Formatieren schlug fehl mit folgender Exception: {0}
    +s12=FEHLER
    +s13=Ergebnis
    +s14=Dialog
    +s15=Auswahlkriterium
    +s16=1,3
    + * + *

    Although this is a sub class of a hash table, you should never + * insert anything other than strings to this property, or several + * methods, that need string keys and values, will fail. To ensure + * this, you should use the get/setProperty method instead + * of get/put. + * + * Properties are saved in ISO 8859-1 encoding, using Unicode escapes with + * a single u for any character which cannot be represented. + * + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @see PropertyResourceBundle + * @status updated to 1.4 + */ +public class Properties extends Hashtable +{ + // WARNING: Properties is a CORE class in the bootstrap cycle. See the + // comments in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * The property list that contains default values for any keys not + * in this property list. + * + * @serial the default properties + */ + protected Properties defaults; + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 4112578634029874840L; + + /** + * Creates a new empty property list with no default values. + */ + public Properties() + { + } + + /** + * Create a new empty property list with the specified default values. + * + * @param defaults a Properties object containing the default values + */ + public Properties(Properties defaults) + { + this.defaults = defaults; + } + + /** + * Adds the given key/value pair to this properties. This calls + * the hashtable method put. + * + * @param key the key for this property + * @param value the value for this property + * @return The old value for the given key + * @see #getProperty(String) + * @since 1.2 + */ + public Object setProperty(String key, String value) + { + return put(key, value); + } + + /** + * Reads a property list from an input stream. The stream should + * have the following format:
    + * + * An empty line or a line starting with # or + * ! is ignored. An backslash (\) at the + * end of the line makes the line continueing on the next line + * (but make sure there is no whitespace after the backslash). + * Otherwise, each line describes a key/value pair.
    + * + * The chars up to the first whitespace, = or : are the key. You + * can include this caracters in the key, if you precede them with + * a backslash (\). The key is followed by optional + * whitespaces, optionally one = or :, + * and optionally some more whitespaces. The rest of the line is + * the resource belonging to the key.
    + * + * Escape sequences \t, \n, \r, \\, \", \', \!, \#, \ (a + * space), and unicode characters with the + * \\uxxxx notation are detected, and + * converted to the corresponding single character.
    + * + * +

    # This is a comment
    +key     = value
    +k\:5      \ a string starting with space and ending with newline\n
    +# This is a multiline specification; note that the value contains
    +# no white space.
    +weekdays: Sunday,Monday,Tuesday,Wednesday,\\
    +          Thursday,Friday,Saturday
    +# The safest way to include a space at the end of a value:
    +label   = Name:\\u0020
    + * + * @param inStream the input stream + * @throws IOException if an error occurred when reading the input + * @throws NullPointerException if in is null + */ + public void load(InputStream inStream) throws IOException + { + // The spec says that the file must be encoded using ISO-8859-1. + BufferedReader reader = + new BufferedReader(new InputStreamReader(inStream, "ISO-8859-1")); + String line; + + while ((line = reader.readLine()) != null) + { + char c = 0; + int pos = 0; + // Leading whitespaces must be deleted first. + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; + + // If empty line or begins with a comment character, skip this line. + if ((line.length() - pos) == 0 + || line.charAt(pos) == '#' || line.charAt(pos) == '!') + continue; + + // The characters up to the next Whitespace, ':', or '=' + // describe the key. But look for escape sequences. + StringBuffer key = new StringBuffer(); + while (pos < line.length() + && ! Character.isWhitespace(c = line.charAt(pos++)) + && c != '=' && c != ':') + { + if (c == '\\') + { + if (pos == line.length()) + { + // The line continues on the next line. + line = reader.readLine(); + pos = 0; + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; + } + else + { + c = line.charAt(pos++); + switch (c) + { + case 'n': + key.append('\n'); + break; + case 't': + key.append('\t'); + break; + case 'r': + key.append('\r'); + break; + case 'u': + if (pos + 4 <= line.length()) + { + char uni = (char) Integer.parseInt + (line.substring(pos, pos + 4), 16); + key.append(uni); + pos += 4; + } // else throw exception? + break; + default: + key.append(c); + break; + } + } + } + else + key.append(c); + } + + boolean isDelim = (c == ':' || c == '='); + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; + + if (! isDelim && (c == ':' || c == '=')) + { + pos++; + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; + } + + StringBuffer element = new StringBuffer(line.length() - pos); + while (pos < line.length()) + { + c = line.charAt(pos++); + if (c == '\\') + { + if (pos == line.length()) + { + // The line continues on the next line. + line = reader.readLine(); + + // We might have seen a backslash at the end of + // the file. The JDK ignores the backslash in + // this case, so we follow for compatibility. + if (line == null) + break; + + pos = 0; + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; + element.ensureCapacity(line.length() - pos + + element.length()); + } + else + { + c = line.charAt(pos++); + switch (c) + { + case 'n': + element.append('\n'); + break; + case 't': + element.append('\t'); + break; + case 'r': + element.append('\r'); + break; + case 'u': + if (pos + 4 <= line.length()) + { + char uni = (char) Integer.parseInt + (line.substring(pos, pos + 4), 16); + element.append(uni); + pos += 4; + } // else throw exception? + break; + default: + element.append(c); + break; + } + } + } + else + element.append(c); + } + put(key.toString(), element.toString()); + } + } + + /** + * Calls store(OutputStream out, String header) and + * ignores the IOException that may be thrown. + * + * @param out the stream to write to + * @param header a description of the property list + * @throws ClassCastException if this property contains any key or + * value that are not strings + * @deprecated use {@link #store(OutputStream, String)} instead + */ + public void save(OutputStream out, String header) + { + try + { + store(out, header); + } + catch (IOException ex) + { + } + } + + /** + * Writes the key/value pairs to the given output stream, in a format + * suitable for load.
    + * + * If header is not null, this method writes a comment containing + * the header as first line to the stream. The next line (or first + * line if header is null) contains a comment with the current date. + * Afterwards the key/value pairs are written to the stream in the + * following format.
    + * + * Each line has the form key = value. Newlines, + * Returns and tabs are written as \n,\t,\r resp. + * The characters \, !, #, = and : are + * preceeded by a backslash. Spaces are preceded with a backslash, + * if and only if they are at the beginning of the key. Characters + * that are not in the ascii range 33 to 127 are written in the + * \uxxxx Form.
    + * + * Following the listing, the output stream is flushed but left open. + * + * @param out the output stream + * @param header the header written in the first line, may be null + * @throws ClassCastException if this property contains any key or + * value that isn't a string + * @throws IOException if writing to the stream fails + * @throws NullPointerException if out is null + * @since 1.2 + */ + public void store(OutputStream out, String header) throws IOException + { + // The spec says that the file must be encoded using ISO-8859-1. + PrintWriter writer + = new PrintWriter(new OutputStreamWriter(out, "ISO-8859-1")); + if (header != null) + writer.println("#" + header); + writer.println ("#" + Calendar.getInstance ().getTime ()); + + Iterator iter = entrySet ().iterator (); + int i = size (); + StringBuffer s = new StringBuffer (); // Reuse the same buffer. + while (--i >= 0) + { + Map.Entry entry = (Map.Entry) iter.next (); + formatForOutput ((String) entry.getKey (), s, true); + s.append ('='); + formatForOutput ((String) entry.getValue (), s, false); + writer.println (s); + } + + writer.flush (); + } + + /** + * Gets the property with the specified key in this property list. + * If the key is not found, the default property list is searched. + * If the property is not found in the default, null is returned. + * + * @param key The key for this property + * @return the value for the given key, or null if not found + * @throws ClassCastException if this property contains any key or + * value that isn't a string + * @see #defaults + * @see #setProperty(String, String) + * @see #getProperty(String, String) + */ + public String getProperty(String key) + { + return getProperty(key, null); + } + + /** + * Gets the property with the specified key in this property list. If + * the key is not found, the default property list is searched. If the + * property is not found in the default, the specified defaultValue is + * returned. + * + * @param key The key for this property + * @param defaultValue A default value + * @return The value for the given key + * @throws ClassCastException if this property contains any key or + * value that isn't a string + * @see #defaults + * @see #setProperty(String, String) + */ + public String getProperty(String key, String defaultValue) + { + Properties prop = this; + // Eliminate tail recursion. + do + { + String value = (String) prop.get(key); + if (value != null) + return value; + prop = prop.defaults; + } + while (prop != null); + return defaultValue; + } + + /** + * Returns an enumeration of all keys in this property list, including + * the keys in the default property list. + * + * @return an Enumeration of all defined keys + */ + public Enumeration propertyNames() + { + // We make a new Set that holds all the keys, then return an enumeration + // for that. This prevents modifications from ruining the enumeration, + // as well as ignoring duplicates. + Properties prop = this; + Set s = new HashSet(); + // Eliminate tail recursion. + do + { + s.addAll(prop.keySet()); + prop = prop.defaults; + } + while (prop != null); + return Collections.enumeration(s); + } + + /** + * Prints the key/value pairs to the given print stream. This is + * mainly useful for debugging purposes. + * + * @param out the print stream, where the key/value pairs are written to + * @throws ClassCastException if this property contains a key or a + * value that isn't a string + * @see #list(PrintWriter) + */ + public void list(PrintStream out) + { + PrintWriter writer = new PrintWriter (out); + list (writer); + } + + /** + * Prints the key/value pairs to the given print writer. This is + * mainly useful for debugging purposes. + * + * @param out the print writer where the key/value pairs are written to + * @throws ClassCastException if this property contains a key or a + * value that isn't a string + * @see #list(PrintStream) + * @since 1.1 + */ + public void list(PrintWriter out) + { + out.println ("-- listing properties --"); + + Iterator iter = entrySet ().iterator (); + int i = size (); + while (--i >= 0) + { + Map.Entry entry = (Map.Entry) iter.next (); + out.print ((String) entry.getKey () + "="); + + // JDK 1.3/1.4 restrict the printed value, but not the key, + // to 40 characters, including the truncating ellipsis. + String s = (String ) entry.getValue (); + if (s != null && s.length () > 40) + out.println (s.substring (0, 37) + "..."); + else + out.println (s); + } + out.flush (); + } + + /** + * Formats a key or value for output in a properties file. + * See store for a description of the format. + * + * @param str the string to format + * @param buffer the buffer to add it to + * @param key true if all ' ' must be escaped for the key, false if only + * leading spaces must be escaped for the value + * @see #store(OutputStream, String) + */ + private void formatForOutput(String str, StringBuffer buffer, boolean key) + { + if (key) + { + buffer.setLength(0); + buffer.ensureCapacity(str.length()); + } + else + buffer.ensureCapacity(buffer.length() + str.length()); + boolean head = true; + int size = str.length(); + for (int i = 0; i < size; i++) + { + char c = str.charAt(i); + switch (c) + { + case '\n': + buffer.append("\\n"); + break; + case '\r': + buffer.append("\\r"); + break; + case '\t': + buffer.append("\\t"); + break; + case ' ': + buffer.append(head ? "\\ " : " "); + break; + case '\\': + case '!': + case '#': + case '=': + case ':': + buffer.append('\\').append(c); + break; + default: + if (c < ' ' || c > '~') + { + String hex = Integer.toHexString(c); + buffer.append("\\u0000".substring(0, 6 - hex.length())); + buffer.append(hex); + } + else + buffer.append(c); + } + if (c != ' ') + head = key; + } + } +} // class Properties diff --git a/libjava/classpath/java/util/PropertyPermission.java b/libjava/classpath/java/util/PropertyPermission.java new file mode 100644 index 0000000..d1bdbd1 --- /dev/null +++ b/libjava/classpath/java/util/PropertyPermission.java @@ -0,0 +1,271 @@ +/* PropertyPermission.java -- permission to get and set System properties + Copyright (C) 1999, 2000, 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 java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; +import java.security.BasicPermission; +import java.security.Permission; +import java.security.PermissionCollection; + +/** + * This class represents the permission to access and modify a property.
    + * + * The name is the name of the property, e.g. xxx. You can also + * use an asterisk "*" as described in BasicPermission.
    + * + * The action string is a comma-separated list of keywords. There are + * two possible actions: + *
    + *
    read
    + *
    Allows to read the property via System.getProperty.
    + *
    write
    + *
    Allows to write the property via System.setProperty.
    + *
    + * + * The action string is case insensitive (it is converted to lower case). + * + * @see Permission + * @see BasicPermission + * @see SecurityManager + * @author Jochen Hoenicke + * @since 1.2 + * @status updated to 1.4 + */ +public final class PropertyPermission extends BasicPermission +{ + /** + * PropertyPermission uses a more efficient representation than the + * serialized form; this documents the difference. + * + * @serialField action String the action string + */ + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("action", String.class) + }; + + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 885438825399942851L; + + /** Permission to read. */ + private static final int READ = 1; + /** Permission to write. */ + private static final int WRITE = 2; + + /** The set of actions permitted. */ + // Package visible for use by PropertyPermissionCollection. + transient int actions; + + /** + * The String forms of the actions permitted. + */ + private static final String actionStrings[] = + { + "", "read", "write", "read,write" + }; + + /** + * Constructs a PropertyPermission with the specified property. Possible + * actions are read and write, comma-separated and case-insensitive. + * + * @param name the name of the property + * @param actions the action string + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if name string contains an + * illegal wildcard or actions string contains an illegal action + * (this includes a null actions string) + */ + public PropertyPermission(String name, String actions) + { + super(name); + if (actions == null) + throw new IllegalArgumentException(); + setActions(actions); + } + + /** + * Parse the action string and convert actions from external to internal + * form. This will set the internal actions field. + * + * @param str the action string + * @throws IllegalArgumentException if actions string contains an + * illegal action + */ + private void setActions(String str) + { + // Initialising the class java.util.Locale ... + // tries to initialise the Locale.defaultLocale static + // which calls System.getProperty, + // which calls SecurityManager.checkPropertiesAccess, + // which creates a PropertyPermission with action "read,write", + // which calls setActions("read,write"). + // If we now were to call toLowerCase on 'str', + // this would call Locale.getDefault() which returns null + // because Locale.defaultLocale hasn't been set yet + // then toLowerCase will fail with a null pointer exception. + // + // The solution is to take a punt on 'str' being lower case, and + // test accordingly. If that fails, we convert 'str' to lower case + // and try the tests again. + if ("read".equals(str)) + actions = READ; + else if ("write".equals(str)) + actions = WRITE; + else if ("read,write".equals(str) || "write,read".equals(str)) + actions = READ | WRITE; + else + { + String lstr = str.toLowerCase(); + if ("read".equals(lstr)) + actions = READ; + else if ("write".equals(lstr)) + actions = WRITE; + else if ("read,write".equals(lstr) || "write,read".equals(lstr)) + actions = READ | WRITE; + else + throw new IllegalArgumentException("illegal action " + str); + } + } + + /** + * Reads an object from the stream. This converts the external to the + * internal representation. + * + * @param s the stream to read from + * @throws IOException if the stream fails + * @throws ClassNotFoundException if reserialization fails + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + ObjectInputStream.GetField fields = s.readFields(); + setActions((String) fields.get("actions", null)); + } + + /** + * Writes an object to the stream. This converts the internal to the + * external representation. + * + * @param s the stram to write to + * @throws IOException if the stream fails + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + ObjectOutputStream.PutField fields = s.putFields(); + fields.put("actions", getActions()); + s.writeFields(); + } + + /** + * Check if this permission implies p. This returns true iff all of + * the following conditions are true: + *
      + *
    • p is a PropertyPermission
    • + *
    • this.getName() implies p.getName(), + * e.g. java.* implies java.home
    • + *
    • this.getActions is a subset of p.getActions
    • + *
    + * + * @param p the permission to check + * @return true if this permission implies p + */ + public boolean implies(Permission p) + { + // BasicPermission checks for name and type. + if (super.implies(p)) + { + // We have to check the actions. + PropertyPermission pp = (PropertyPermission) p; + return (pp.actions & ~actions) == 0; + } + return false; + } + + /** + * Check to see whether this object is the same as another + * PropertyPermission object; this is true if it has the same name and + * actions. + * + * @param obj the other object + * @return true if the two are equivalent + */ + public boolean equals(Object obj) + { + return super.equals(obj) && actions == ((PropertyPermission) obj).actions; + } + + /** + * Returns the hash code for this permission. It is equivalent to + * getName().hashCode(). + * + * @return the hash code + */ + public int hashCode() + { + return super.hashCode(); + } + + /** + * Returns the action string. Note that this may differ from the string + * given at the constructor: The actions are converted to lowercase and + * may be reordered. + * + * @return one of "read", "write", or "read,write" + */ + public String getActions() + { + return actionStrings[actions]; + } + + /** + * Returns a permission collection suitable to take + * PropertyPermission objects. + * + * @return a new empty PermissionCollection + */ + public PermissionCollection newPermissionCollection() + { + return new PropertyPermissionCollection(); + } +} diff --git a/libjava/classpath/java/util/PropertyPermissionCollection.java b/libjava/classpath/java/util/PropertyPermissionCollection.java new file mode 100644 index 0000000..c95fa4e --- /dev/null +++ b/libjava/classpath/java/util/PropertyPermissionCollection.java @@ -0,0 +1,166 @@ +/* PropertyPermissionCollection.java -- a collection of PropertyPermissions + 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 java.util; + +import java.security.Permission; +import java.security.PermissionCollection; + +/** + * This class provides the implementation for + * PropertyPermission.newPermissionCollection(). It only accepts + * PropertyPermissions, and correctly implements implies. It + * is synchronized, as specified in the superclass. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @status an undocumented class, but this matches Sun's serialization + */ +class PropertyPermissionCollection extends PermissionCollection +{ + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 7015263904581634791L; + + /** + * The permissions. + * + * @serial the table of permissions in the collection + */ + private final Hashtable permissions = new Hashtable(); + + /** + * A flag to detect if "*" is in the collection. + * + * @serial true if "*" is in the collection + */ + private boolean all_allowed; + + /** + * Adds a PropertyPermission to this collection. + * + * @param permission the permission to add + * @throws IllegalArgumentException if permission is not a PropertyPermission + * @throws SecurityException if collection is read-only + */ + public void add(Permission permission) + { + if (isReadOnly()) + throw new SecurityException("readonly"); + if (! (permission instanceof PropertyPermission)) + throw new IllegalArgumentException(); + PropertyPermission pp = (PropertyPermission) permission; + String name = pp.getName(); + if (name.equals("*")) + all_allowed = true; + PropertyPermission old = (PropertyPermission) permissions.get(name); + if (old != null) + { + if ((pp.actions | old.actions) == old.actions) + pp = old; // Old implies pp. + else if ((pp.actions | old.actions) != pp.actions) + // Here pp doesn't imply old; the only case left is both actions. + pp = new PropertyPermission(name, "read,write"); + } + permissions.put(name, pp); + } + + /** + * Returns true if this collection implies the given permission. This even + * returns true for this case: + * + *
    +   * collection.add(new PropertyPermission("a.*", "read"));
    +   * collection.add(new PropertyPermission("a.b.*", "write"));
    +   * collection.implies(new PropertyPermission("a.b.c", "read,write"));
    +   * 
    + * + * @param permission the permission to check + * @return true if it is implied by this + */ + public boolean implies(Permission permission) + { + if (! (permission instanceof PropertyPermission)) + return false; + PropertyPermission toImply = (PropertyPermission) permission; + int actions = toImply.actions; + + if (all_allowed) + { + int all_actions = ((PropertyPermission) permissions.get("*")).actions; + actions &= ~all_actions; + if (actions == 0) + return true; + } + + String name = toImply.getName(); + if (name.equals("*")) + return false; + + int prefixLength = name.length(); + if (name.endsWith("*")) + prefixLength -= 2; + + while (true) + { + PropertyPermission forName = + (PropertyPermission) permissions.get(name); + if (forName != null) + { + actions &= ~forName.actions; + if (actions == 0) + return true; + } + + prefixLength = name.lastIndexOf('.', prefixLength - 1); + if (prefixLength < 0) + return false; + name = name.substring(0, prefixLength + 1) + '*'; + } + } + + /** + * Enumerate over the collection. + * + * @return an enumeration of the collection contents + */ + public Enumeration elements() + { + return permissions.elements(); + } +} diff --git a/libjava/classpath/java/util/PropertyResourceBundle.java b/libjava/classpath/java/util/PropertyResourceBundle.java new file mode 100644 index 0000000..aaff076 --- /dev/null +++ b/libjava/classpath/java/util/PropertyResourceBundle.java @@ -0,0 +1,152 @@ +/* PropertyResourceBundle -- a resource bundle built from a Property file + Copyright (C) 1998, 1999, 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 java.util; + +import java.io.IOException; +import java.io.InputStream; + +/** + * This class is a concrete ResourceBundle that gets it + * resources from a property file. This implies that the resources are + * strings. For more information about resource bundles see the class + * ResourceBundle. + * + * You should not use this class directly, or subclass it, but you get + * an object of this class automatically when you call + * ResourceBundle.getBundle() and there is a properties + * file. + * + * If there is also a class for this resource and the same locale, the + * class will be chosen. The properties file should have the name of the + * resource bundle, appended with the locale (e.g. _de and the + * extension .properties. The file should have the same format + * as for Properties.load() + * + * An example of a properties file for the german language is given + * here. This extends the example given in ListResourceBundle. + * Create a file MyResource_de.properties with the following contents + * and put it in the CLASSPATH. (The char \u00e4 is the + * german umlaut) + * + * +
    +s1=3
    +s2=MeineDisk
    +s3=3. M\u00e4rz 96
    +s4=Die Diskette ''{1}'' enth\u00e4lt {0} in {2}.
    +s5=0
    +s6=keine Dateien
    +s7=1
    +s8=eine Datei
    +s9=2
    +s10={0,number} Dateien
    +s11=Die Formatierung warf eine Exception: {0}
    +s12=FEHLER
    +s13=Ergebnis
    +s14=Dialog
    +s15=Auswahlkriterium
    +s16=1,3
    +
    + * + * @author Jochen Hoenicke + * @see ResourceBundle + * @see ListResourceBundle + * @see Properties#load(InputStream) + * @since 1.1 + * @status updated to 1.4 + */ +public class PropertyResourceBundle extends ResourceBundle +{ + /** The properties file this bundle is based on. */ + private Properties properties; + + /** + * Creates a new property resource bundle. + * + * @param stream an input stream, where the resources are read from + * @throws NullPointerException if stream is null + * @throws IOException if reading the stream fails + */ + public PropertyResourceBundle(InputStream stream) throws IOException + { + properties = new Properties(); + properties.load(stream); + } + + /** + * Called by getObject when a resource is needed. This + * returns the resource given by the key. + * + * @param key the key of the resource + * @return the resource for the key, or null if it doesn't exist + */ + public Object handleGetObject(String key) + { + return properties.getProperty(key); + } + + /** + * This method should return all keys for which a resource exists. + * + * @return an enumeration of the keys + */ + public Enumeration getKeys() + { + if (parent == null) + return properties.propertyNames(); + // We make a new Set that holds all the keys, then return an enumeration + // for that. This prevents modifications from ruining the enumeration, + // as well as ignoring duplicates. + Set s = new HashSet(); + Enumeration e = properties.propertyNames(); + while (e.hasMoreElements()) + s.add(e.nextElement()); + ResourceBundle bundle = parent; + // Eliminate tail recursion. + do + { + e = bundle.getKeys(); + while (e.hasMoreElements()) + s.add(e.nextElement()); + bundle = bundle.parent; + } + while (bundle != null); + return Collections.enumeration(s); + } +} // class PropertyResourceBundle diff --git a/libjava/classpath/java/util/Random.java b/libjava/classpath/java/util/Random.java new file mode 100644 index 0000000..bc00507 --- /dev/null +++ b/libjava/classpath/java/util/Random.java @@ -0,0 +1,429 @@ +/* Random.java -- a pseudo-random number generator + Copyright (C) 1998, 1999, 2000, 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 java.util; + +import java.io.Serializable; + +/** + * This class generates pseudorandom numbers. It uses the same + * algorithm as the original JDK-class, so that your programs behave + * exactly the same way, if started with the same seed. + * + * The algorithm is described in The Art of Computer Programming, + * Volume 2 by Donald Knuth in Section 3.2.1. It is a 48-bit seed, + * linear congruential formula. + * + * If two instances of this class are created with the same seed and + * the same calls to these classes are made, they behave exactly the + * same way. This should be even true for foreign implementations + * (like this), so every port must use the same algorithm as described + * here. + * + * If you want to implement your own pseudorandom algorithm, you + * should extend this class and overload the next() and + * setSeed(long) method. In that case the above + * paragraph doesn't apply to you. + * + * This class shouldn't be used for security sensitive purposes (like + * generating passwords or encryption keys. See SecureRandom + * in package java.security for this purpose. + * + * For simple random doubles between 0.0 and 1.0, you may consider using + * Math.random instead. + * + * @see java.security.SecureRandom + * @see Math#random() + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class Random implements Serializable +{ + /** + * True if the next nextGaussian is available. This is used by + * nextGaussian, which generates two gaussian numbers by one call, + * and returns the second on the second call. + * + * @serial whether nextNextGaussian is available + * @see #nextGaussian() + * @see #nextNextGaussian + */ + private boolean haveNextNextGaussian; + + /** + * The next nextGaussian, when available. This is used by nextGaussian, + * which generates two gaussian numbers by one call, and returns the + * second on the second call. + * + * @serial the second gaussian of a pair + * @see #nextGaussian() + * @see #haveNextNextGaussian + */ + private double nextNextGaussian; + + /** + * The seed. This is the number set by setSeed and which is used + * in next. + * + * @serial the internal state of this generator + * @see #next() + */ + private long seed; + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3905348978240129619L; + + /** + * Creates a new pseudorandom number generator. The seed is initialized + * to the current time, as if by + * setSeed(System.currentTimeMillis());. + * + * @see System#currentTimeMillis() + */ + public Random() + { + this(System.currentTimeMillis()); + } + + /** + * Creates a new pseudorandom number generator, starting with the + * specified seed, using setSeed(seed);. + * + * @param seed the initial seed + */ + public Random(long seed) + { + setSeed(seed); + } + + /** + * Sets the seed for this pseudorandom number generator. As described + * above, two instances of the same random class, starting with the + * same seed, should produce the same results, if the same methods + * are called. The implementation for java.util.Random is: + * +
    public synchronized void setSeed(long seed)
    +{
    +  this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
    +  haveNextNextGaussian = false;
    +}
    + * + * @param seed the new seed + */ + public synchronized void setSeed(long seed) + { + this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1); + haveNextNextGaussian = false; + } + + /** + * Generates the next pseudorandom number. This returns + * an int value whose bits low order bits are + * independent chosen random bits (0 and 1 are equally likely). + * The implementation for java.util.Random is: + * +
    protected synchronized int next(int bits)
    +{
    +  seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
    +  return (int) (seed >>> (48 - bits));
    +}
    + * + * @param bits the number of random bits to generate, in the range 1..32 + * @return the next pseudorandom value + * @since 1.1 + */ + protected synchronized int next(int bits) + { + seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); + return (int) (seed >>> (48 - bits)); + } + + /** + * Fills an array of bytes with random numbers. All possible values + * are (approximately) equally likely. + * The JDK documentation gives no implementation, but it seems to be: + * +
    public void nextBytes(byte[] bytes)
    +{
    +  for (int i = 0; i < bytes.length; i += 4)
    +  {
    +    int random = next(32);
    +    for (int j = 0; i + j < bytes.length && j < 4; j++)
    +    {
    +      bytes[i+j] = (byte) (random & 0xff)
    +      random >>= 8;
    +    }
    +  }
    +}
    + * + * @param bytes the byte array that should be filled + * @throws NullPointerException if bytes is null + * @since 1.1 + */ + public void nextBytes(byte[] bytes) + { + int random; + // Do a little bit unrolling of the above algorithm. + int max = bytes.length & ~0x3; + for (int i = 0; i < max; i += 4) + { + random = next(32); + bytes[i] = (byte) random; + bytes[i + 1] = (byte) (random >> 8); + bytes[i + 2] = (byte) (random >> 16); + bytes[i + 3] = (byte) (random >> 24); + } + if (max < bytes.length) + { + random = next(32); + for (int j = max; j < bytes.length; j++) + { + bytes[j] = (byte) random; + random >>= 8; + } + } + } + + /** + * Generates the next pseudorandom number. This returns + * an int value whose 32 bits are independent chosen random bits + * (0 and 1 are equally likely). The implementation for + * java.util.Random is: + * +
    public int nextInt()
    +{
    +  return next(32);
    +}
    + * + * @return the next pseudorandom value + */ + public int nextInt() + { + return next(32); + } + + /** + * Generates the next pseudorandom number. This returns + * a value between 0(inclusive) and n(exclusive), and + * each value has the same likelihodd (1/n). + * (0 and 1 are equally likely). The implementation for + * java.util.Random is: + * +
    +public int nextInt(int n)
    +{
    +  if (n <= 0)
    +    throw new IllegalArgumentException("n must be positive");
    +
    +  if ((n & -n) == n)  // i.e., n is a power of 2
    +    return (int)((n * (long) next(31)) >> 31);
    +
    +  int bits, val;
    +  do
    +  {
    +    bits = next(31);
    +    val = bits % n;
    +  }
    +  while(bits - val + (n-1) < 0);
    +
    +  return val;
    +}
    + * + *

    This algorithm would return every value with exactly the same + * probability, if the next()-method would be a perfect random number + * generator. + * + * The loop at the bottom only accepts a value, if the random + * number was between 0 and the highest number less then 1<<31, + * which is divisible by n. The probability for this is high for small + * n, and the worst case is 1/2 (for n=(1<<30)+1). + * + * The special treatment for n = power of 2, selects the high bits of + * the random number (the loop at the bottom would select the low order + * bits). This is done, because the low order bits of linear congruential + * number generators (like the one used in this class) are known to be + * ``less random'' than the high order bits. + * + * @param n the upper bound + * @throws IllegalArgumentException if the given upper bound is negative + * @return the next pseudorandom value + * @since 1.2 + */ + public int nextInt(int n) + { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + if ((n & -n) == n) // i.e., n is a power of 2 + return (int) ((n * (long) next(31)) >> 31); + int bits, val; + do + { + bits = next(31); + val = bits % n; + } + while (bits - val + (n - 1) < 0); + return val; + } + + /** + * Generates the next pseudorandom long number. All bits of this + * long are independently chosen and 0 and 1 have equal likelihood. + * The implementation for java.util.Random is: + * +

    public long nextLong()
    +{
    +  return ((long) next(32) << 32) + next(32);
    +}
    + * + * @return the next pseudorandom value + */ + public long nextLong() + { + return ((long) next(32) << 32) + next(32); + } + + /** + * Generates the next pseudorandom boolean. True and false have + * the same probability. The implementation is: + * +
    public boolean nextBoolean()
    +{
    +  return next(1) != 0;
    +}
    + * + * @return the next pseudorandom boolean + * @since 1.2 + */ + public boolean nextBoolean() + { + return next(1) != 0; + } + + /** + * Generates the next pseudorandom float uniformly distributed + * between 0.0f (inclusive) and 1.0f (exclusive). The + * implementation is as follows. + * +
    public float nextFloat()
    +{
    +  return next(24) / ((float)(1 << 24));
    +}
    + * + * @return the next pseudorandom float + */ + public float nextFloat() + { + return next(24) / (float) (1 << 24); + } + + /** + * Generates the next pseudorandom double uniformly distributed + * between 0.0 (inclusive) and 1.0 (exclusive). The + * implementation is as follows. + * +
    public double nextDouble()
    +{
    +  return (((long) next(26) << 27) + next(27)) / (double)(1L << 53);
    +}
    + * + * @return the next pseudorandom double + */ + public double nextDouble() + { + return (((long) next(26) << 27) + next(27)) / (double) (1L << 53); + } + + /** + * Generates the next pseudorandom, Gaussian (normally) distributed + * double value, with mean 0.0 and standard deviation 1.0. + * The algorithm is as follows. + * +
    public synchronized double nextGaussian()
    +{
    +  if (haveNextNextGaussian)
    +  {
    +    haveNextNextGaussian = false;
    +    return nextNextGaussian;
    +  }
    +  else
    +  {
    +    double v1, v2, s;
    +    do
    +    {
    +      v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0
    +      v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0
    +      s = v1 * v1 + v2 * v2;
    +    }
    +    while (s >= 1);
    +
    +    double norm = Math.sqrt(-2 * Math.log(s) / s);
    +    nextNextGaussian = v2 * norm;
    +    haveNextNextGaussian = true;
    +    return v1 * norm;
    +  }
    +}
    + * + *

    This is described in section 3.4.1 of The Art of Computer + * Programming, Volume 2 by Donald Knuth. + * + * @return the next pseudorandom Gaussian distributed double + */ + public synchronized double nextGaussian() + { + if (haveNextNextGaussian) + { + haveNextNextGaussian = false; + return nextNextGaussian; + } + double v1, v2, s; + do + { + v1 = 2 * nextDouble() - 1; // Between -1.0 and 1.0. + v2 = 2 * nextDouble() - 1; // Between -1.0 and 1.0. + s = v1 * v1 + v2 * v2; + } + while (s >= 1); + double norm = Math.sqrt(-2 * Math.log(s) / s); + nextNextGaussian = v2 * norm; + haveNextNextGaussian = true; + return v1 * norm; + } +} diff --git a/libjava/classpath/java/util/RandomAccess.java b/libjava/classpath/java/util/RandomAccess.java new file mode 100644 index 0000000..054266a --- /dev/null +++ b/libjava/classpath/java/util/RandomAccess.java @@ -0,0 +1,64 @@ +/* RandomAccess.java -- A tagging interface that lists can use to tailor + operations to the correct algorithm + Copyright (C) 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * Marker interface used to inform List implementations that + * they support fast (usually constant time) random access. This allows + * generic list algorithms to tailor their behavior based on the list + * type. + *

    + * + * For example, some sorts are n*log(n) on an array, but decay to quadratic + * time on a linked list. As a rule of thumb, this interface should be + * used is this loop:
    + * for (int i = 0, n = list.size(); i < n; i++) list.get(i); + *
    runs faster than this loop:
    + * for (Iterator i = list.iterator(); i.hasNext(); ) i.next(); + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see List + * @since 1.4 + * @status updated to 1.4 + */ +public interface RandomAccess +{ + // Tagging interface only. +} diff --git a/libjava/classpath/java/util/ResourceBundle.java b/libjava/classpath/java/util/ResourceBundle.java new file mode 100644 index 0000000..91007e9 --- /dev/null +++ b/libjava/classpath/java/util/ResourceBundle.java @@ -0,0 +1,580 @@ +/* ResourceBundle -- aids in loading resource bundles + Copyright (C) 1998, 1999, 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 java.util; + +import gnu.classpath.VMStackWalker; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A resource bundle contains locale-specific data. If you need localized + * data, you can load a resource bundle that matches the locale with + * getBundle. Now you can get your object by calling + * getObject or getString on that bundle. + * + *

    When a bundle is demanded for a specific locale, the ResourceBundle + * is searched in following order (def. language stands for the + * two letter ISO language code of the default locale (see + * Locale.getDefault()). + * +

    baseName_language code_country code_variant
    +baseName_language code_country code
    +baseName_language code
    +baseName_def. language_def. country_def. variant
    +baseName_def. language_def. country
    +baseName_def. language
    +baseName
    + * + *

    A bundle is backed up by less specific bundles (omitting variant, country + * or language). But it is not backed up by the default language locale. + * + *

    If you provide a bundle for a given locale, say + * Bundle_en_UK_POSIX, you must also provide a bundle for + * all sub locales, ie. Bundle_en_UK, Bundle_en, and + * Bundle. + * + *

    When a bundle is searched, we look first for a class with the given + * name, then for a file with .properties extension in the + * classpath. The name must be a fully qualified classname (with dots as + * path separators). + * + *

    (Note: This implementation always backs up the class with a properties + * file if that is existing, but you shouldn't rely on this, if you want to + * be compatible to the standard JDK.) + * + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @see Locale + * @see ListResourceBundle + * @see PropertyResourceBundle + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class ResourceBundle +{ + /** + * The parent bundle. This is consulted when you call getObject and there + * is no such resource in the current bundle. This field may be null. + */ + protected ResourceBundle parent; + + /** + * The locale of this resource bundle. You can read this with + * getLocale and it is automatically set in + * getBundle. + */ + private Locale locale; + + /** + * The resource bundle cache. + */ + private static Map bundleCache; + + /** + * The last default Locale we saw. If this ever changes then we have to + * reset our caches. + */ + private static Locale lastDefaultLocale; + + /** + * The `empty' locale is created once in order to optimize + * tryBundle(). + */ + private static final Locale emptyLocale = new Locale(""); + + /** + * The constructor. It does nothing special. + */ + public ResourceBundle() + { + } + + /** + * Get a String from this resource bundle. Since most localized Objects + * are Strings, this method provides a convenient way to get them without + * casting. + * + * @param key the name of the resource + * @throws MissingResourceException if the resource can't be found + * @throws NullPointerException if key is null + * @throws ClassCastException if resource is not a string + */ + public final String getString(String key) + { + return (String) getObject(key); + } + + /** + * Get an array of Strings from this resource bundle. This method + * provides a convenient way to get it without casting. + * + * @param key the name of the resource + * @throws MissingResourceException if the resource can't be found + * @throws NullPointerException if key is null + * @throws ClassCastException if resource is not a string + */ + public final String[] getStringArray(String key) + { + return (String[]) getObject(key); + } + + /** + * Get an object from this resource bundle. This will call + * handleGetObject for this resource and all of its parents, + * until it finds a non-null resource. + * + * @param key the name of the resource + * @throws MissingResourceException if the resource can't be found + * @throws NullPointerException if key is null + */ + public final Object getObject(String key) + { + for (ResourceBundle bundle = this; bundle != null; bundle = bundle.parent) + { + Object o = bundle.handleGetObject(key); + if (o != null) + return o; + } + + String className = getClass().getName(); + throw new MissingResourceException("Key '" + key + + "'not found in Bundle: " + + className, className, key); + } + + /** + * Return the actual locale of this bundle. You can use it after calling + * getBundle, to know if the bundle for the desired locale was loaded or + * if the fall back was used. + * + * @return the bundle's locale + */ + public Locale getLocale() + { + return locale; + } + + /** + * Set the parent of this bundle. The parent is consulted when you call + * getObject and there is no such resource in the current bundle. + * + * @param parent the parent of this bundle + */ + protected void setParent(ResourceBundle parent) + { + this.parent = parent; + } + + /** + * Get the appropriate ResourceBundle for the default locale. This is like + * calling getBundle(baseName, Locale.getDefault(), + * getClass().getClassLoader(), except that any security check of + * getClassLoader won't fail. + * + * @param baseName the name of the ResourceBundle + * @return the desired resource bundle + * @throws MissingResourceException if the resource bundle can't be found + * @throws NullPointerException if baseName is null + */ + public static ResourceBundle getBundle(String baseName) + { + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + return getBundle(baseName, Locale.getDefault(), cl); + } + + /** + * Get the appropriate ResourceBundle for the given locale. This is like + * calling getBundle(baseName, locale, + * getClass().getClassLoader(), except that any security check of + * getClassLoader won't fail. + * + * @param baseName the name of the ResourceBundle + * @param locale A locale + * @return the desired resource bundle + * @throws MissingResourceException if the resource bundle can't be found + * @throws NullPointerException if baseName or locale is null + */ + public static ResourceBundle getBundle(String baseName, Locale locale) + { + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + return getBundle(baseName, locale, cl); + } + + /** Cache key for the ResourceBundle cache. Resource bundles are keyed + by the combination of bundle name, locale, and class loader. */ + private static class BundleKey + { + String baseName; + Locale locale; + ClassLoader classLoader; + int hashcode; + + BundleKey() {} + + BundleKey(String s, Locale l, ClassLoader cl) + { + set(s, l, cl); + } + + void set(String s, Locale l, ClassLoader cl) + { + baseName = s; + locale = l; + classLoader = cl; + hashcode = baseName.hashCode() ^ locale.hashCode() ^ + classLoader.hashCode(); + } + + public int hashCode() + { + return hashcode; + } + + public boolean equals(Object o) + { + if (! (o instanceof BundleKey)) + return false; + BundleKey key = (BundleKey) o; + return hashcode == key.hashcode && + baseName.equals(key.baseName) && + locale.equals(key.locale) && + classLoader.equals(key.classLoader); + } + } + + /** A cache lookup key. This avoids having to a new one for every + * getBundle() call. */ + private static BundleKey lookupKey = new BundleKey(); + + /** Singleton cache entry to represent previous failed lookups. */ + private static Object nullEntry = new Object(); + + /** + * Get the appropriate ResourceBundle for the given locale. The following + * strategy is used: + * + *

    A sequence of candidate bundle names are generated, and tested in + * this order, where the suffix 1 means the string from the specified + * locale, and the suffix 2 means the string from the default locale:

    + * + *
      + *
    • baseName + "_" + language1 + "_" + country1 + "_" + variant1
    • + *
    • baseName + "_" + language1 + "_" + country1
    • + *
    • baseName + "_" + language1
    • + *
    • baseName + "_" + language2 + "_" + country2 + "_" + variant2
    • + *
    • baseName + "_" + language2 + "_" + country2
    • + *
    • baseName + "_" + language2
    • + *
    • baseName
    • + *
    + * + *

    In the sequence, entries with an empty string are ignored. Next, + * getBundle tries to instantiate the resource bundle:

    + * + *
      + *
    • First, an attempt is made to load a class in the specified classloader + * which is a subclass of ResourceBundle, and which has a public constructor + * with no arguments, via reflection.
    • + *
    • Next, a search is made for a property resource file, by replacing + * '.' with '/' and appending ".properties", and using + * ClassLoader.getResource(). If a file is found, then a + * PropertyResourceBundle is created from the file's contents.
    • + *
    + * If no resource bundle was found, a MissingResourceException is thrown. + * + *

    Next, the parent chain is implemented. The remaining candidate names + * in the above sequence are tested in a similar manner, and if any results + * in a resource bundle, it is assigned as the parent of the first bundle + * using the setParent method (unless the first bundle already + * has a parent).

    + * + *

    For example, suppose the following class and property files are + * provided: MyResources.class, MyResources_fr_CH.properties, + * MyResources_fr_CH.class, MyResources_fr.properties, + * MyResources_en.properties, and MyResources_es_ES.class. The contents of + * all files are valid (that is, public non-abstract subclasses of + * ResourceBundle with public nullary constructors for the ".class" files, + * syntactically correct ".properties" files). The default locale is + * Locale("en", "UK").

    + * + *

    Calling getBundle with the shown locale argument values instantiates + * resource bundles from the following sources:

    + * + *
      + *
    • Locale("fr", "CH"): result MyResources_fr_CH.class, parent + * MyResources_fr.properties, parent MyResources.class
    • + *
    • Locale("fr", "FR"): result MyResources_fr.properties, parent + * MyResources.class
    • + *
    • Locale("de", "DE"): result MyResources_en.properties, parent + * MyResources.class
    • + *
    • Locale("en", "US"): result MyResources_en.properties, parent + * MyResources.class
    • + *
    • Locale("es", "ES"): result MyResources_es_ES.class, parent + * MyResources.class
    • + *
    + * + *

    The file MyResources_fr_CH.properties is never used because it is hidden + * by MyResources_fr_CH.class.

    + * + * @param baseName the name of the ResourceBundle + * @param locale A locale + * @param classLoader a ClassLoader + * @return the desired resource bundle + * @throws MissingResourceException if the resource bundle can't be found + * @throws NullPointerException if any argument is null + * @since 1.2 + */ + // This method is synchronized so that the cache is properly + // handled. + public static synchronized ResourceBundle getBundle + (String baseName, Locale locale, ClassLoader classLoader) + { + // If the default locale changed since the last time we were called, + // all cache entries are invalidated. + Locale defaultLocale = Locale.getDefault(); + if (defaultLocale != lastDefaultLocale) + { + bundleCache = new HashMap(); + lastDefaultLocale = defaultLocale; + } + + // This will throw NullPointerException if any arguments are null. + lookupKey.set(baseName, locale, classLoader); + + Object obj = bundleCache.get(lookupKey); + ResourceBundle rb = null; + + if (obj instanceof ResourceBundle) + { + return (ResourceBundle) obj; + } + else if (obj == nullEntry) + { + // Lookup has failed previously. Fall through. + } + else + { + // First, look for a bundle for the specified locale. We don't want + // the base bundle this time. + boolean wantBase = locale.equals(defaultLocale); + ResourceBundle bundle = tryBundle(baseName, locale, classLoader, + wantBase); + + // Try the default locale if neccessary. + if (bundle == null && !locale.equals(defaultLocale)) + bundle = tryBundle(baseName, defaultLocale, classLoader, true); + + BundleKey key = new BundleKey(baseName, locale, classLoader); + if (bundle == null) + { + // Cache the fact that this lookup has previously failed. + bundleCache.put(key, nullEntry); + } + else + { + // Cache the result and return it. + bundleCache.put(key, bundle); + return bundle; + } + } + + throw new MissingResourceException("Bundle " + baseName + " not found", + baseName, ""); + } + + /** + * Override this method to provide the resource for a keys. This gets + * called by getObject. If you don't have a resource + * for the given key, you should return null instead throwing a + * MissingResourceException. You don't have to ask the parent, getObject() + * already does this; nor should you throw a MissingResourceException. + * + * @param key the key of the resource + * @return the resource for the key, or null if not in bundle + * @throws NullPointerException if key is null + */ + protected abstract Object handleGetObject(String key); + + /** + * This method should return all keys for which a resource exists; you + * should include the enumeration of any parent's keys, after filtering out + * duplicates. + * + * @return an enumeration of the keys + */ + public abstract Enumeration getKeys(); + + /** + * Tries to load a class or a property file with the specified name. + * + * @param localizedName the name + * @param classloader the classloader + * @return the resource bundle if it was loaded, otherwise the backup + */ + private static ResourceBundle tryBundle(String localizedName, + ClassLoader classloader) + { + ResourceBundle bundle = null; + try + { + Class rbClass; + if (classloader == null) + rbClass = Class.forName(localizedName); + else + rbClass = classloader.loadClass(localizedName); + // Note that we do the check up front instead of catching + // ClassCastException. The reason for this is that some crazy + // programs (Eclipse) have classes that do not extend + // ResourceBundle but that have the same name as a property + // bundle; in fact Eclipse relies on ResourceBundle not + // instantiating these classes. + if (ResourceBundle.class.isAssignableFrom(rbClass)) + bundle = (ResourceBundle) rbClass.newInstance(); + } + catch (IllegalAccessException ex) {} + catch (InstantiationException ex) {} + catch (ClassNotFoundException ex) {} + + if (bundle == null) + { + try + { + InputStream is; + String resourceName + = localizedName.replace('.', '/') + ".properties"; + if (classloader == null) + is = ClassLoader.getSystemResourceAsStream(resourceName); + else + is = classloader.getResourceAsStream(resourceName); + if (is != null) + bundle = new PropertyResourceBundle(is); + } + catch (IOException ex) + { + MissingResourceException mre = new MissingResourceException + ("Failed to load bundle: " + localizedName, localizedName, ""); + mre.initCause(ex); + throw mre; + } + } + + return bundle; + } + + /** + * Tries to load a the bundle for a given locale, also loads the backup + * locales with the same language. + * + * @param baseName the raw bundle name, without locale qualifiers + * @param locale the locale + * @param classloader the classloader + * @param bundle the backup (parent) bundle + * @param wantBase whether a resource bundle made only from the base name + * (with no locale information attached) should be returned. + * @return the resource bundle if it was loaded, otherwise the backup + */ + private static ResourceBundle tryBundle(String baseName, Locale locale, + ClassLoader classLoader, + boolean wantBase) + { + String language = locale.getLanguage(); + String country = locale.getCountry(); + String variant = locale.getVariant(); + + int baseLen = baseName.length(); + + // Build up a StringBuffer containing the complete bundle name, fully + // qualified by locale. + StringBuffer sb = new StringBuffer(baseLen + variant.length() + 7); + + sb.append(baseName); + + if (language.length() > 0) + { + sb.append('_'); + sb.append(language); + + if (country.length() > 0) + { + sb.append('_'); + sb.append(country); + + if (variant.length() > 0) + { + sb.append('_'); + sb.append(variant); + } + } + } + + // Now try to load bundles, starting with the most specialized name. + // Build up the parent chain as we go. + String bundleName = sb.toString(); + ResourceBundle first = null; // The most specialized bundle. + ResourceBundle last = null; // The least specialized bundle. + + while (true) + { + ResourceBundle foundBundle = tryBundle(bundleName, classLoader); + if (foundBundle != null) + { + if (first == null) + first = foundBundle; + if (last != null) + last.parent = foundBundle; + foundBundle.locale = locale; + last = foundBundle; + } + int idx = bundleName.lastIndexOf('_'); + // Try the non-localized base name only if we already have a + // localized child bundle, or wantBase is true. + if (idx > baseLen || (idx == baseLen && (first != null || wantBase))) + bundleName = bundleName.substring(0, idx); + else + break; + } + + return first; + } +} diff --git a/libjava/classpath/java/util/Set.java b/libjava/classpath/java/util/Set.java new file mode 100644 index 0000000..839959e --- /dev/null +++ b/libjava/classpath/java/util/Set.java @@ -0,0 +1,264 @@ +/* Set.java -- A collection that prohibits duplicates + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * A collection that contains no duplicates. In other words, for two set + * elements e1 and e2, e1.equals(e2) returns false. There + * are additional stipulations on add, equals + * and hashCode, as well as the requirements that constructors + * do not permit duplicate elements. The Set interface is incompatible with + * List; you cannot implement both simultaneously. + *

    + * + * Note: Be careful about using mutable objects in sets. In particular, + * if a mutable object changes to become equal to another set element, you + * have violated the contract. As a special case of this, a Set is not + * allowed to be an element of itself, without risking undefined behavior. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see List + * @see SortedSet + * @see HashSet + * @see TreeSet + * @see LinkedHashSet + * @see AbstractSet + * @see Collections#singleton(Object) + * @see Collections#EMPTY_SET + * @since 1.2 + * @status updated to 1.4 + */ +public interface Set extends Collection +{ + /** + * Adds the specified element to the set if it is not already present + * (optional operation). In particular, the comparison algorithm is + * o == null ? e == null : o.equals(e). Sets need not permit + * all values, and may document what exceptions will be thrown if + * a value is not permitted. + * + * @param o the object to add + * @return true if the object was not previously in the set + * @throws UnsupportedOperationException if this operation is not allowed + * @throws ClassCastException if the class of o prevents it from being added + * @throws IllegalArgumentException if some aspect of o prevents it from + * being added + * @throws NullPointerException if null is not permitted in this set + */ + boolean add(Object o); + + /** + * Adds all of the elements of the given collection to this set (optional + * operation). If the argument is also a Set, this returns the mathematical + * union of the two. The behavior is unspecified if the set is + * modified while this is taking place. + * + * @param c the collection to add + * @return true if the set changed as a result + * @throws UnsupportedOperationException if this operation is not allowed + * @throws ClassCastException if the class of an element prevents it from + * being added + * @throws IllegalArgumentException if something about an element prevents + * it from being added + * @throws NullPointerException if null is not permitted in this set, or + * if the argument c is null + * @see #add(Object) + */ + boolean addAll(Collection c); + + /** + * Removes all elements from this set (optional operation). This set will + * be empty afterwords, unless an exception occurs. + * + * @throws UnsupportedOperationException if this operation is not allowed + */ + void clear(); + + /** + * Returns true if the set contains the specified element. In other words, + * this looks for o == null ? e == null : o.equals(e). + * + * @param o the object to look for + * @return true if it is found in the set + * @throws ClassCastException if the type of o is not a valid type + * for this set. + * @throws NullPointerException if o is null and this set doesn't + * support null values. + */ + boolean contains(Object o); + + /** + * Returns true if this set contains all elements in the specified + * collection. If the argument is also a set, this is the subset + * relationship. + * + * @param c the collection to check membership in + * @return true if all elements in this set are in c + * @throws NullPointerException if c is null + * @throws ClassCastException if the type of any element in c is not + * a valid type for this set. + * @throws NullPointerException if some element of c is null and this + * set doesn't support null values. + * @see #contains(Object) + */ + boolean containsAll(Collection c); + + /** + * Compares the specified object to this for equality. For sets, the object + * must be a set, the two must have the same size, and every element in + * one must be in the other. + * + * @param o the object to compare to + * @return true if it is an equal set + */ + boolean equals(Object o); + + /** + * Returns the hash code for this set. In order to satisfy the contract of + * equals, this is the sum of the hashcode of all elements in the set. + * + * @return the sum of the hashcodes of all set elements + * @see #equals(Object) + */ + int hashCode(); + + /** + * Returns true if the set contains no elements. + * + * @return true if the set is empty + */ + boolean isEmpty(); + + /** + * Returns an iterator over the set. The iterator has no specific order, + * unless further specified. + * + * @return a set iterator + */ + Iterator iterator(); + + /** + * Removes the specified element from this set (optional operation). If + * an element e exists, o == null ? e == null : o.equals(e), + * it is removed from the set. + * + * @param o the object to remove + * @return true if the set changed (an object was removed) + * @throws UnsupportedOperationException if this operation is not allowed + * @throws ClassCastException if the type of o is not a valid type + * for this set. + * @throws NullPointerException if o is null and this set doesn't allow + * the removal of a null value. + */ + boolean remove(Object o); + + /** + * Removes from this set all elements contained in the specified collection + * (optional operation). If the argument is a set, this returns the + * asymmetric set difference of the two sets. + * + * @param c the collection to remove from this set + * @return true if this set changed as a result + * @throws UnsupportedOperationException if this operation is not allowed + * @throws NullPointerException if c is null + * @throws ClassCastException if the type of any element in c is not + * a valid type for this set. + * @throws NullPointerException if some element of c is null and this + * set doesn't support removing null values. + * @see #remove(Object) + */ + boolean removeAll(Collection c); + + /** + * Retains only the elements in this set that are also in the specified + * collection (optional operation). If the argument is also a set, this + * performs the intersection of the two sets. + * + * @param c the collection to keep + * @return true if this set was modified + * @throws UnsupportedOperationException if this operation is not allowed + * @throws NullPointerException if c is null + * @throws ClassCastException if the type of any element in c is not + * a valid type for this set. + * @throws NullPointerException if some element of c is null and this + * set doesn't support retaining null values. + * @see #remove(Object) + */ + boolean retainAll(Collection c); + + /** + * Returns the number of elements in the set. If there are more + * than Integer.MAX_VALUE mappings, return Integer.MAX_VALUE. This is + * the cardinality of the set. + * + * @return the number of elements + */ + int size(); + + /** + * Returns an array containing the elements of this set. If the set + * makes a guarantee about iteration order, the array has the same + * order. The array is distinct from the set; modifying one does not + * affect the other. + * + * @return an array of this set's elements + * @see #toArray(Object[]) + */ + Object[] toArray(); + + /** + * Returns an array containing the elements of this set, of the same runtime + * type of the argument. If the given set is large enough, it is reused, + * and null is inserted in the first unused slot. Otherwise, reflection + * is used to build a new array. If the set makes a guarantee about iteration + * order, the array has the same order. The array is distinct from the set; + * modifying one does not affect the other. + * + * @param a the array to determine the return type; if it is big enough + * it is used and returned + * @return an array holding the elements of the set + * @throws ArrayStoreException if the runtime type of a is not a supertype + * of all elements in the set + * @throws NullPointerException if a is null + * @see #toArray() + */ + Object[] toArray(Object[] a); +} diff --git a/libjava/classpath/java/util/SimpleTimeZone.java b/libjava/classpath/java/util/SimpleTimeZone.java new file mode 100644 index 0000000..995ccea --- /dev/null +++ b/libjava/classpath/java/util/SimpleTimeZone.java @@ -0,0 +1,1077 @@ +/* java.util.SimpleTimeZone + Copyright (C) 1998, 1999, 2000, 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 java.util; + + +/** + * This class represents a simple time zone offset and handles + * daylight savings. It can only handle one daylight savings rule, so + * it can't represent historical changes. + * + * 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. It can only handle daylight savings for years + * lying in the AD era. + * + * @see Calendar + * @see GregorianCalendar + * @author Jochen Hoenicke + */ +public class SimpleTimeZone extends TimeZone +{ + /** + * The raw time zone offset in milliseconds to GMT, ignoring + * daylight savings. + * @serial + */ + private int rawOffset; + + /** + * True, if this timezone uses daylight savings, false otherwise. + * @serial + */ + private boolean useDaylight; + + /** + * 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 hour. + * @serial + * @since JDK1.1.4 + */ + private int dstSavings = 60 * 60 * 1000; + + /** + * The first year, in which daylight savings rules applies. + * @serial + */ + private int startYear; + private static final int DOM_MODE = 1; + private static final int DOW_IN_MONTH_MODE = 2; + private static final int DOW_GE_DOM_MODE = 3; + private static final int DOW_LE_DOM_MODE = 4; + + /** + * The mode of the start rule. This takes one of the following values: + *

    + *
    DOM_MODE (1)
    + *
    startDay contains the day in month of the start date, + * startDayOfWeek is unused.
    + *
    DOW_IN_MONTH_MODE (2)
    + *
    The startDay gives the day of week in month, and + * startDayOfWeek the day of week. For example startDay=2 and + * startDayOfWeek=Calender.SUNDAY specifies that the change is on + * the second sunday in that month. You must make sure, that this + * day always exists (ie. don't specify the 5th sunday). + *
    + *
    DOW_GE_DOM_MODE (3)
    + *
    The start is on the first startDayOfWeek on or after + * startDay. For example startDay=13 and + * startDayOfWeek=Calendar.FRIDAY specifies that the daylight + * savings start on the first FRIDAY on or after the 13th of that + * Month. Make sure that the change is always in the given month, or + * the result is undefined. + *
    + *
    DOW_LE_DOM_MONTH (4)
    + *
    The start is on the first startDayOfWeek on or before the + * startDay. Make sure that the change is always in the given + * month, or the result is undefined. +
    + *
    + * @serial */ + private int startMode; + + /** + * The month in which daylight savings start. This is one of the + * constants Calendar.JANUARY, ..., Calendar.DECEMBER. + * @serial + */ + private int startMonth; + + /** + * This variable can have different meanings. See startMode for details + * @see #startMode + * @serial + */ + private int startDay; + + /** + * This variable specifies the day of week the change takes place. If + * startMode == DOM_MODE, this is undefined. + * @serial + * @see #startMode + */ + private int startDayOfWeek; + + /** + * This variable specifies the time of change to daylight savings. + * This time is given in milliseconds after midnight local + * standard time. + * @serial + */ + private int startTime; + + /** + * This variable specifies the mode that startTime is specified in. By + * default it is WALL_TIME, but can also be STANDARD_TIME or UTC_TIME. For + * startTime, STANDARD_TIME and WALL_TIME are equivalent. + * @serial + */ + private int startTimeMode = WALL_TIME; + + /** + * The month in which daylight savings ends. This is one of the + * constants Calendar.JANUARY, ..., Calendar.DECEMBER. + * @serial + */ + private int endMonth; + + /** + * This variable gives the mode for the end of daylight savings rule. + * It can take the same values as startMode. + * @serial + * @see #startMode + */ + private int endMode; + + /** + * This variable can have different meanings. See startMode for details + * @serial + * @see #startMode + */ + private int endDay; + + /** + * This variable specifies the day of week the change takes place. If + * endMode == DOM_MODE, this is undefined. + * @serial + * @see #startMode + */ + private int endDayOfWeek; + + /** + * This variable specifies the time of change back to standard time. + * This time is given in milliseconds after midnight local + * standard time. + * @serial + */ + private int endTime; + + /** + * This variable specifies the mode that endTime is specified in. By + * default it is WALL_TIME, but can also be STANDARD_TIME or UTC_TIME. + * @serial + */ + private int endTimeMode = WALL_TIME; + + /** + * This variable points to a deprecated array from JDK 1.1. It is + * ignored in JDK 1.2 but streamed out for compatibility with JDK 1.1. + * The array contains the lengths of the months in the year and is + * assigned from a private static final field to avoid allocating + * the array for every instance of the object. + * Note that static final fields are not serialized. + * @serial + */ + private byte[] monthLength = monthArr; + private static final byte[] monthArr = + { + 31, 28, 31, 30, 31, 30, 31, 31, 30, + 31, 30, 31 + }; + + /** + * The version of the serialized data on the stream. + *
    + *
    0 or not present on stream
    + *
    JDK 1.1.3 or earlier, only provides this fields: + * rawOffset, startDay, startDayOfWeek, startMonth, startTime, + * startYear, endDay, endDayOfWeek, endMonth, endTime + *
    + *
    JDK 1.1.4 or later. This includes three new fields, namely + * startMode, endMode and dstSavings. And there is a optional section + * as described in writeObject. + *
    + *
    + * + * XXX - JDK 1.2 Beta 4 docu states 1.1.4, but my 1.1.5 has the old + * version. + * + * When streaming out this class it is always written in the latest + * version. + * @serial + * @since JDK1.1.4 + */ + private int serialVersionOnStream = 2; + private static final long serialVersionUID = -403250971215465050L; + + /** + * Constant to indicate that start and end times are specified in standard + * time, without adjusting for daylight savings. + */ + public static final int STANDARD_TIME = 1; + + /** + * Constant to indicate that start and end times are specified in wall + * time, adjusting for daylight savings. This is the default. + */ + public static final int WALL_TIME = 0; + + /** + * Constant to indicate that start and end times are specified in UTC. + */ + public static final int UTC_TIME = 2; + + /** + * Create a SimpleTimeZone with the given time offset + * from GMT and without daylight savings. + * @param rawOffset the time offset from GMT in milliseconds. + * @param id The identifier of this time zone. + */ + public SimpleTimeZone(int rawOffset, String id) + { + this.rawOffset = rawOffset; + setID(id); + useDaylight = false; + startYear = 0; + } + + /** + * Create a SimpleTimeZone with the given time offset + * from GMT and with daylight savings. The start/end parameters + * can have different meaning (replace WEEKDAY with a real day of + * week). Only the first two meanings were supported by earlier + * versions of jdk. + * + *
    + *
    day > 0, dayOfWeek = Calendar.WEEKDAY
    + *
    The start/end of daylight savings is on the day-th + * WEEKDAY in the given month.
    + *
    day < 0, dayOfWeek = Calendar.WEEKDAY
    + *
    The start/end of daylight savings is on the -day-th + * WEEKDAY counted from the end of the month.
    + *
    day > 0, dayOfWeek = 0
    + *
    The start/end of daylight is on the day-th day of + * the month.
    + *
    day > 0, dayOfWeek = -Calendar.WEEKDAY
    + *
    The start/end of daylight is on the first WEEKDAY on or after + * the day-th day of the month. You must make sure that + * this day lies in the same month.
    + *
    day < 0, dayOfWeek = -Calendar.WEEKDAY
    + *
    The start/end of daylight is on the first WEEKDAY on or + * before the -day-th day of the month. You + * must make sure that this day lies in the same month.
    + *
    + * + * If you give a non existing month, a day that is zero, or too big, + * or a dayOfWeek that is too big, the result is undefined. + * + * The start rule must have a different month than the end rule. + * This restriction shouldn't hurt for all possible time zones. + * + * @param rawOffset The time offset from GMT in milliseconds. + * @param id The identifier of this time zone. + * @param startMonth The start month of daylight savings; use the + * constants in Calendar. + * @param startDayOfWeekInMonth A day in month or a day of week number, as + * described above. + * @param startDayOfWeek The start rule day of week; see above. + * @param startTime A time in millis in standard time. + * @param endMonth The end month of daylight savings; use the + * constants in Calendar. + * @param endDayOfWeekInMonth A day in month or a day of week number, as + * described above. + * @param endDayOfWeek The end rule day of week; see above. + * @param endTime A time in millis in standard time. + * @throws IllegalArgumentException if parameters are invalid or out of + * range. + */ + public SimpleTimeZone(int rawOffset, String id, int startMonth, + int startDayOfWeekInMonth, int startDayOfWeek, + int startTime, int endMonth, int endDayOfWeekInMonth, + int endDayOfWeek, int endTime) + { + this.rawOffset = rawOffset; + setID(id); + useDaylight = true; + + setStartRule(startMonth, startDayOfWeekInMonth, startDayOfWeek, startTime); + setEndRule(endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime); + if (startMonth == endMonth) + throw new IllegalArgumentException("startMonth and endMonth must be different"); + this.startYear = 0; + } + + /** + * This constructs a new SimpleTimeZone that supports a daylight savings + * rule. The parameter are the same as for the constructor above, except + * there is the additional dstSavaings parameter. + * + * @param dstSavings the amount of savings for daylight savings + * time in milliseconds. This must be positive. + * @since 1.2 + */ + public SimpleTimeZone(int rawOffset, String id, int startMonth, + int startDayOfWeekInMonth, int startDayOfWeek, + int startTime, int endMonth, int endDayOfWeekInMonth, + int endDayOfWeek, int endTime, int dstSavings) + { + this(rawOffset, id, startMonth, startDayOfWeekInMonth, startDayOfWeek, + startTime, endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime); + + this.dstSavings = dstSavings; + } + + /** + * This constructs a new SimpleTimeZone that supports a daylight savings + * rule. The parameter are the same as for the constructor above, except + * there are the additional startTimeMode, endTimeMode, and dstSavings + * parameters. + * + * @param startTimeMode the mode that start times are specified in. One of + * WALL_TIME, STANDARD_TIME, or UTC_TIME. + * @param endTimeMode the mode that end times are specified in. One of + * WALL_TIME, STANDARD_TIME, or UTC_TIME. + * @param dstSavings the amount of savings for daylight savings + * time in milliseconds. This must be positive. + * @throws IllegalArgumentException if parameters are invalid or out of + * range. + * @since 1.4 + */ + public SimpleTimeZone(int rawOffset, String id, int startMonth, + int startDayOfWeekInMonth, int startDayOfWeek, + int startTime, int startTimeMode, int endMonth, + int endDayOfWeekInMonth, int endDayOfWeek, + int endTime, int endTimeMode, int dstSavings) + { + this.rawOffset = rawOffset; + setID(id); + useDaylight = true; + + if (startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) + throw new IllegalArgumentException("startTimeMode must be one of WALL_TIME, STANDARD_TIME, or UTC_TIME"); + if (endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) + throw new IllegalArgumentException("endTimeMode must be one of WALL_TIME, STANDARD_TIME, or UTC_TIME"); + this.startTimeMode = startTimeMode; + this.endTimeMode = endTimeMode; + + setStartRule(startMonth, startDayOfWeekInMonth, startDayOfWeek, startTime); + setEndRule(endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime); + if (startMonth == endMonth) + throw new IllegalArgumentException("startMonth and endMonth must be different"); + this.startYear = 0; + + this.dstSavings = dstSavings; + } + + /** + * Sets the first year, where daylight savings applies. The daylight + * savings rule never apply for years in the BC era. Note that this + * is gregorian calendar specific. + * @param year the start year. + */ + public void setStartYear(int year) + { + startYear = year; + useDaylight = true; + } + + /** + * Checks if the month, day, dayOfWeek arguments are in range and + * returns the mode of the rule. + * @param month the month parameter as in the constructor + * @param day the day parameter as in the constructor + * @param dayOfWeek the day of week parameter as in the constructor + * @return the mode of this rule see startMode. + * @exception IllegalArgumentException if parameters are out of range. + * @see #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int) + * @see #startMode + */ + private int checkRule(int month, int day, int dayOfWeek) + { + if (month < 0 || month > 11) + throw new IllegalArgumentException("month out of range"); + + int daysInMonth = getDaysInMonth(month, 1); + if (dayOfWeek == 0) + { + if (day <= 0 || day > daysInMonth) + throw new IllegalArgumentException("day out of range"); + return DOM_MODE; + } + else if (dayOfWeek > 0) + { + if (Math.abs(day) > (daysInMonth + 6) / 7) + throw new IllegalArgumentException("dayOfWeekInMonth out of range"); + if (dayOfWeek > Calendar.SATURDAY) + throw new IllegalArgumentException("dayOfWeek out of range"); + return DOW_IN_MONTH_MODE; + } + else + { + if (day == 0 || Math.abs(day) > daysInMonth) + throw new IllegalArgumentException("day out of range"); + if (dayOfWeek < -Calendar.SATURDAY) + throw new IllegalArgumentException("dayOfWeek out of range"); + if (day < 0) + return DOW_LE_DOM_MODE; + else + return DOW_GE_DOM_MODE; + } + } + + /** + * Sets the daylight savings start rule. You must also set the + * end rule with setEndRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * @param month The month where daylight savings start, zero + * based. You should use the constants in Calendar. + * @param day A day of month or day of week in month. + * @param dayOfWeek The day of week where daylight savings start. + * @param time The time in milliseconds standard time where daylight + * savings start. + * @see SimpleTimeZone + */ + public void setStartRule(int month, int day, int dayOfWeek, int time) + { + this.startMode = checkRule(month, day, dayOfWeek); + this.startMonth = month; + this.startDay = day; + this.startDayOfWeek = Math.abs(dayOfWeek); + if (this.startTimeMode == WALL_TIME || this.startTimeMode == STANDARD_TIME) + this.startTime = time; + else + // Convert from UTC to STANDARD + this.startTime = time + this.rawOffset; + useDaylight = true; + } + + /** + * Sets the daylight savings start rule. You must also set the + * end rule with setEndRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * Note that this API isn't incredibly well specified. It appears that the + * after flag must override the parameters, since normally, the day and + * dayofweek can select this. I.e., if day < 0 and dayOfWeek < 0, on or + * before mode is chosen. But if after == true, this implementation + * overrides the signs of the other arguments. And if dayOfWeek == 0, it + * falls back to the behavior in the other APIs. I guess this should be + * checked against Sun's implementation. + * + * @param month The month where daylight savings start, zero + * based. You should use the constants in Calendar. + * @param day A day of month or day of week in month. + * @param dayOfWeek The day of week where daylight savings start. + * @param time The time in milliseconds standard time where daylight + * savings start. + * @param after If true, day and dayOfWeek specify first day of week on or + * after day, else first day of week on or before. + * @since 1.2 + * @see SimpleTimeZone + */ + public void setStartRule(int month, int day, int dayOfWeek, int time, + boolean after) + { + // FIXME: XXX: Validate that checkRule and offset processing work with on + // or before mode. + this.startDay = after ? Math.abs(day) : -Math.abs(day); + this.startDayOfWeek = after ? Math.abs(dayOfWeek) : -Math.abs(dayOfWeek); + this.startMode = (dayOfWeek != 0) + ? (after ? DOW_GE_DOM_MODE : DOW_LE_DOM_MODE) + : checkRule(month, day, dayOfWeek); + this.startDay = Math.abs(this.startDay); + this.startDayOfWeek = Math.abs(this.startDayOfWeek); + + this.startMonth = month; + + if (this.startTimeMode == WALL_TIME || this.startTimeMode == STANDARD_TIME) + this.startTime = time; + else + // Convert from UTC to STANDARD + this.startTime = time + this.rawOffset; + useDaylight = true; + } + + /** + * Sets the daylight savings start rule. You must also set the + * end rule with setEndRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * @param month The month where daylight savings start, zero + * based. You should use the constants in Calendar. + * @param day A day of month or day of week in month. + * @param time The time in milliseconds standard time where daylight + * savings start. + * @see SimpleTimeZone + * @since 1.2 + */ + public void setStartRule(int month, int day, int time) + { + setStartRule(month, day, 0, time); + } + + /** + * Sets the daylight savings end rule. You must also set the + * start rule with setStartRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * @param month The end month of daylight savings. + * @param day A day in month, or a day of week in month. + * @param dayOfWeek A day of week, when daylight savings ends. + * @param time A time in millis in standard time. + * @see #setStartRule(int, int, int, int) + */ + public void setEndRule(int month, int day, int dayOfWeek, int time) + { + this.endMode = checkRule(month, day, dayOfWeek); + this.endMonth = month; + this.endDay = day; + this.endDayOfWeek = Math.abs(dayOfWeek); + if (this.endTimeMode == WALL_TIME) + this.endTime = time; + else if (this.endTimeMode == STANDARD_TIME) + // Convert from STANDARD to DST + this.endTime = time + this.dstSavings; + else + // Convert from UTC to DST + this.endTime = time + this.rawOffset + this.dstSavings; + useDaylight = true; + } + + /** + * Sets the daylight savings end rule. You must also set the + * start rule with setStartRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * Note that this API isn't incredibly well specified. It appears that the + * after flag must override the parameters, since normally, the day and + * dayofweek can select this. I.e., if day < 0 and dayOfWeek < 0, on or + * before mode is chosen. But if after == true, this implementation + * overrides the signs of the other arguments. And if dayOfWeek == 0, it + * falls back to the behavior in the other APIs. I guess this should be + * checked against Sun's implementation. + * + * @param month The end month of daylight savings. + * @param day A day in month, or a day of week in month. + * @param dayOfWeek A day of week, when daylight savings ends. + * @param time A time in millis in standard time. + * @param after If true, day and dayOfWeek specify first day of week on or + * after day, else first day of week on or before. + * @since 1.2 + * @see #setStartRule(int, int, int, int, boolean) + */ + public void setEndRule(int month, int day, int dayOfWeek, int time, + boolean after) + { + // FIXME: XXX: Validate that checkRule and offset processing work with on + // or before mode. + this.endDay = after ? Math.abs(day) : -Math.abs(day); + this.endDayOfWeek = after ? Math.abs(dayOfWeek) : -Math.abs(dayOfWeek); + this.endMode = (dayOfWeek != 0) + ? (after ? DOW_GE_DOM_MODE : DOW_LE_DOM_MODE) + : checkRule(month, day, dayOfWeek); + this.endDay = Math.abs(this.endDay); + this.endDayOfWeek = Math.abs(endDayOfWeek); + + this.endMonth = month; + + if (this.endTimeMode == WALL_TIME) + this.endTime = time; + else if (this.endTimeMode == STANDARD_TIME) + // Convert from STANDARD to DST + this.endTime = time + this.dstSavings; + else + // Convert from UTC to DST + this.endTime = time + this.rawOffset + this.dstSavings; + useDaylight = true; + } + + /** + * Sets the daylight savings end rule. You must also set the + * start rule with setStartRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * @param month The end month of daylight savings. + * @param day A day in month, or a day of week in month. + * @param time A time in millis in standard time. + * @see #setStartRule(int, int, int) + */ + public void setEndRule(int month, int day, int time) + { + setEndRule(month, day, 0, time); + } + + /** + * 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. + * + * In the standard JDK the results given by this method may result in + * inaccurate results at the end of February or the beginning of March. + * To avoid this, you should use Calendar instead: + * offset = cal.get(Calendar.ZONE_OFFSET) + * + cal.get(Calendar.DST_OFFSET); + * + * This version doesn't suffer this inaccuracy. + * + * The arguments don't follow the approach for setting start and end rules. + * 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) + { + int daysInMonth = getDaysInMonth(month, year); + if (day < 1 || day > daysInMonth) + throw new IllegalArgumentException("day out of range"); + 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); + + // This method is called by Calendar, so we mustn't use that class. + int daylightSavings = 0; + if (useDaylight && era == GregorianCalendar.AD && year >= startYear) + { + // This does only work for Gregorian calendars :-( + // This is mainly because setStartYear doesn't take an era. + boolean afterStart = ! isBefore(year, month, day, dayOfWeek, millis, + startMode, startMonth, startDay, + startDayOfWeek, startTime); + boolean beforeEnd = isBefore(year, month, day, dayOfWeek, + millis + dstSavings, + endMode, endMonth, endDay, endDayOfWeek, + endTime); + + if (startMonth < endMonth) + // use daylight savings, if the date is after the start of + // savings, and before the end of savings. + daylightSavings = afterStart && beforeEnd ? dstSavings : 0; + else + // use daylight savings, if the date is before the end of + // savings, or after the start of savings. + daylightSavings = beforeEnd || afterStart ? dstSavings : 0; + } + return rawOffset + daylightSavings; + } + + /** + * 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; + } + + /** + * 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. + * + * @since 1.2 + */ + public int getDSTSavings() + { + return dstSavings; + } + + /** + * Sets the daylight savings offset. This is a positive offset in + * milliseconds with respect to standard time. + * + * @param dstSavings the daylight savings offset in milliseconds. + * + * @since 1.2 + */ + public void setDSTSavings(int dstSavings) + { + if (dstSavings <= 0) + throw new IllegalArgumentException("illegal value for dstSavings"); + + this.dstSavings = 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; + } + + /** + * Returns the number of days in the given month. + * Uses gregorian rules prior to 1582 (The default and earliest cutover) + * @param month The month, zero based; use one of the Calendar constants. + * @param year The year. + */ + private int getDaysInMonth(int month, int year) + { + if (month == Calendar.FEBRUARY) + { + if ((year & 3) != 0) + return 28; + + // Assume default Gregorian cutover, + // all years prior to this must be Julian + if (year < 1582) + return 29; + + // Gregorian rules + return ((year % 100) != 0 || (year % 400) == 0) ? 29 : 28; + } + else + return monthArr[month]; + } + + /** + * Checks if the date given in calXXXX, is before the change between + * dst and standard time. + * @param calYear the year of the date to check (for leap day checking). + * @param calMonth the month of the date to check. + * @param calDay the day of month of the date to check. + * @param calDayOfWeek the day of week of the date to check. + * @param calMillis the millis of day of the date to check (standard time). + * @param mode the change mode; same semantic as startMode. + * @param month the change month; same semantic as startMonth. + * @param day the change day; same semantic as startDay. + * @param dayOfWeek the change day of week; + * @param millis the change time in millis since midnight standard time. + * same semantic as startDayOfWeek. + * @return true, if cal is before the change, false if cal is on + * or after the change. + */ + private boolean isBefore(int calYear, int calMonth, int calDayOfMonth, + int calDayOfWeek, int calMillis, int mode, + int month, int day, int dayOfWeek, int millis) + { + // This method is called by Calendar, so we mustn't use that class. + // We have to do all calculations by hand. + // check the months: + // XXX - this is not correct: + // for the DOW_GE_DOM and DOW_LE_DOM modes the change date may + // be in a different month. + if (calMonth != month) + return calMonth < month; + + // check the day: + switch (mode) + { + case DOM_MODE: + if (calDayOfMonth != day) + return calDayOfMonth < day; + break; + case DOW_IN_MONTH_MODE: + { + // This computes the day of month of the day of type + // "dayOfWeek" that lies in the same (sunday based) week as cal. + calDayOfMonth += (dayOfWeek - calDayOfWeek); + + // Now we convert it to 7 based number (to get a one based offset + // after dividing by 7). If we count from the end of the + // month, we get want a -7 based number counting the days from + // the end: + if (day < 0) + calDayOfMonth -= getDaysInMonth(calMonth, calYear) + 7; + else + calDayOfMonth += 6; + + // day > 0 day < 0 + // S M T W T F S S M T W T F S + // 7 8 9 10 11 12 -36-35-34-33-32-31 + // 13 14 15 16 17 18 19 -30-29-28-27-26-25-24 + // 20 21 22 23 24 25 26 -23-22-21-20-19-18-17 + // 27 28 29 30 31 32 33 -16-15-14-13-12-11-10 + // 34 35 36 -9 -8 -7 + // Now we calculate the day of week in month: + int week = calDayOfMonth / 7; + + // day > 0 day < 0 + // S M T W T F S S M T W T F S + // 1 1 1 1 1 1 -5 -5 -4 -4 -4 -4 + // 1 2 2 2 2 2 2 -4 -4 -4 -3 -3 -3 -3 + // 2 3 3 3 3 3 3 -3 -3 -3 -2 -2 -2 -2 + // 3 4 4 4 4 4 4 -2 -2 -2 -1 -1 -1 -1 + // 4 5 5 -1 -1 -1 + if (week != day) + return week < day; + + if (calDayOfWeek != dayOfWeek) + return calDayOfWeek < dayOfWeek; + + // daylight savings starts/ends on the given day. + break; + } + case DOW_LE_DOM_MODE: + // The greatest sunday before or equal December, 12 + // is the same as smallest sunday after or equal December, 6. + day = Math.abs(day) - 6; + case DOW_GE_DOM_MODE: + // Calculate the day of month of the day of type + // "dayOfWeek" that lies before (or on) the given date. + calDayOfMonth -= (calDayOfWeek < dayOfWeek ? 7 : 0) + calDayOfWeek + - dayOfWeek; + if (calDayOfMonth < day) + return true; + if (calDayOfWeek != dayOfWeek || calDayOfMonth >= day + 7) + return false; + + // now we have the same day + break; + } + + // the millis decides: + return (calMillis < millis); + } + + /** + * 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) + { + Calendar cal = Calendar.getInstance(this); + cal.setTime(date); + return (cal.get(Calendar.DST_OFFSET) != 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() + { + return rawOffset + ^ (useDaylight + ? startMonth ^ startDay ^ startDayOfWeek ^ startTime ^ endMonth + ^ endDay ^ endDayOfWeek ^ endTime : 0); + } + + public synchronized boolean equals(Object o) + { + if (this == o) + return true; + if (! (o instanceof SimpleTimeZone)) + return false; + SimpleTimeZone zone = (SimpleTimeZone) o; + if (zone.hashCode() != hashCode() || ! getID().equals(zone.getID()) + || rawOffset != zone.rawOffset || useDaylight != zone.useDaylight) + return false; + if (! useDaylight) + return true; + return (startYear == zone.startYear && startMonth == zone.startMonth + && startDay == zone.startDay + && startDayOfWeek == zone.startDayOfWeek + && startTime == zone.startTime + && startTimeMode == zone.startTimeMode && endMonth == zone.endMonth + && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek + && endTime == zone.endTime && endTimeMode == zone.endTimeMode); + } + + /** + * 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 SimpleTimeZone, + * 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 other) + { + if (this == other) + return true; + if (! (other instanceof SimpleTimeZone)) + return false; + SimpleTimeZone zone = (SimpleTimeZone) other; + if (zone.hashCode() != hashCode() || rawOffset != zone.rawOffset + || useDaylight != zone.useDaylight) + return false; + if (! useDaylight) + return true; + return (startYear == zone.startYear && startMonth == zone.startMonth + && startDay == zone.startDay + && startDayOfWeek == zone.startDayOfWeek + && startTime == zone.startTime + && startTimeMode == zone.startTimeMode && endMonth == zone.endMonth + && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek + && endTime == zone.endTime && endTimeMode == zone.endTimeMode); + } + + /** + * Returns a string representation of this SimpleTimeZone object. + * @return a string representation of this SimpleTimeZone object. + */ + public String toString() + { + // the test for useDaylight is an incompatibility to jdk1.2, but + // I think this shouldn't hurt. + return getClass().getName() + "[" + "id=" + getID() + ",offset=" + + rawOffset + ",dstSavings=" + dstSavings + ",useDaylight=" + + useDaylight + + (useDaylight + ? ",startYear=" + startYear + ",startMode=" + startMode + + ",startMonth=" + startMonth + ",startDay=" + startDay + + ",startDayOfWeek=" + startDayOfWeek + ",startTime=" + + startTime + ",startTimeMode=" + startTimeMode + ",endMode=" + + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay + + ",endDayOfWeek=" + endDayOfWeek + ",endTime=" + endTime + + ",endTimeMode=" + endTimeMode : "") + "]"; + } + + /** + * Reads a serialized simple time zone from stream. + * @see #writeObject + */ + private void readObject(java.io.ObjectInputStream input) + throws java.io.IOException, ClassNotFoundException + { + input.defaultReadObject(); + if (serialVersionOnStream == 0) + { + // initialize the new fields to default values. + dstSavings = 60 * 60 * 1000; + endMode = DOW_IN_MONTH_MODE; + startMode = DOW_IN_MONTH_MODE; + startTimeMode = WALL_TIME; + endTimeMode = WALL_TIME; + serialVersionOnStream = 2; + } + else + { + int length = input.readInt(); + byte[] byteArray = new byte[length]; + input.read(byteArray, 0, length); + if (length >= 4) + { + // Lets hope that Sun does extensions to the serialized + // form in a sane manner. + startDay = byteArray[0]; + startDayOfWeek = byteArray[1]; + endDay = byteArray[2]; + endDayOfWeek = byteArray[3]; + } + } + } + + /** + * Serializes this object to a stream. @serialdata The object is + * first written in the old JDK 1.1 format, so that it can be read + * by by the old classes. This means, that the + * start/endDay(OfWeek)-Fields are written in the + * DOW_IN_MONTH_MODE rule, since this was the only supported rule + * in 1.1. + * + * In the optional section, we write first the length of an byte + * array as int and afterwards the byte array itself. The byte + * array contains in this release four elements, namely the real + * startDay, startDayOfWeek endDay, endDayOfWeek in that Order. + * These fields are needed, because for compatibility reasons only + * approximative values are written to the required section, as + * described above. + */ + private void writeObject(java.io.ObjectOutputStream output) + throws java.io.IOException + { + byte[] byteArray = new byte[] + { + (byte) startDay, (byte) startDayOfWeek, (byte) endDay, + (byte) endDayOfWeek + }; + + /* calculate the approximation for JDK 1.1 */ + switch (startMode) + { + case DOM_MODE: + startDayOfWeek = Calendar.SUNDAY; // random day of week + + // fall through + case DOW_GE_DOM_MODE: + case DOW_LE_DOM_MODE: + startDay = (startDay + 6) / 7; + } + switch (endMode) + { + case DOM_MODE: + endDayOfWeek = Calendar.SUNDAY; + + // fall through + case DOW_GE_DOM_MODE: + case DOW_LE_DOM_MODE: + endDay = (endDay + 6) / 7; + } + + // the required part: + output.defaultWriteObject(); + // the optional part: + output.writeInt(byteArray.length); + output.write(byteArray, 0, byteArray.length); + } +} diff --git a/libjava/classpath/java/util/SortedMap.java b/libjava/classpath/java/util/SortedMap.java new file mode 100644 index 0000000..acfbd0d --- /dev/null +++ b/libjava/classpath/java/util/SortedMap.java @@ -0,0 +1,173 @@ +/* SortedMap.java -- A map that makes guarantees about the order of its keys + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * A map which guarantees its key's iteration order. The entries in the + * map are related by the natural ordering of the keys if they + * are Comparable, or by the provided Comparator. Additional operations + * take advantage of the sorted nature of the map. + *

    + * + * All keys entered in the map must be mutually comparable; in other words, + * k1.compareTo(k2) or comparator.compare(k1, k2) + * must not throw a ClassCastException. The ordering must be consistent + * with equals (see {@link Comparator} for this definition), if the + * map is to obey the general contract of the Map interface. If not, + * the results are well-defined, but probably not what you wanted. + *

    + * + * It is recommended that all implementing classes provide four constructors: + * 1) one that takes no arguments and builds an empty map sorted by natural + * order of the keys; 2) one that takes a Comparator for the sorting order; + * 3) one that takes a Map and sorts according to the natural order of its + * keys; and 4) one that takes a SortedMap and sorts by the same comparator. + * Unfortunately, the Java language does not provide a way to enforce this. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Map + * @see TreeMap + * @see SortedSet + * @see Comparable + * @see Comparator + * @see Collection + * @see ClassCastException + * @since 1.2 + * @status updated to 1.4 + */ +public interface SortedMap extends Map +{ + /** + * Returns the comparator used in sorting this map, or null if it is + * the keys' natural ordering. + * + * @return the sorting comparator + */ + Comparator comparator(); + + /** + * Returns the first (lowest sorted) key in the map. + * + * @return the first key + * @throws NoSuchElementException if this map is empty. + */ + Object firstKey(); + + /** + * Returns a view of the portion of the map strictly less than toKey. The + * view is backed by this map, so changes in one show up in the other. + * The submap supports all optional operations of the original. + *

    + * + * The returned map throws an IllegalArgumentException any time a key is + * used which is out of the range of toKey. Note that the endpoint, toKey, + * is not included; if you want this value to be included, pass its successor + * object in to toKey. For example, for Integers, you could request + * headMap(new Integer(limit.intValue() + 1)). + * + * @param toKey the exclusive upper range of the submap + * @return the submap + * @throws ClassCastException if toKey is not comparable to the map contents + * @throws IllegalArgumentException if this is a subMap, and toKey is out + * of range + * @throws NullPointerException if toKey is null but the map does not allow + * null keys + */ + SortedMap headMap(Object toKey); + + /** + * Returns the last (highest sorted) key in the map. + * + * @return the last key + * @throws NoSuchElementException if this map is empty. + */ + Object lastKey(); + + /** + * Returns a view of the portion of the map greater than or equal to + * fromKey, and strictly less than toKey. The view is backed by this map, + * so changes in one show up in the other. The submap supports all + * optional operations of the original. + *

    + * + * The returned map throws an IllegalArgumentException any time a key is + * used which is out of the range of fromKey and toKey. Note that the + * lower endpoint is included, but the upper is not; if you want to + * change the inclusion or exclusion of an endpoint, pass its successor + * object in instead. For example, for Integers, you could request + * subMap(new Integer(lowlimit.intValue() + 1), + * new Integer(highlimit.intValue() + 1)) to reverse + * the inclusiveness of both endpoints. + * + * @param fromKey the inclusive lower range of the submap + * @param toKey the exclusive upper range of the submap + * @return the submap + * @throws ClassCastException if fromKey or toKey is not comparable to + * the map contents + * @throws IllegalArgumentException if this is a subMap, and fromKey or + * toKey is out of range + * @throws NullPointerException if fromKey or toKey is null but the map + * does not allow null keys + */ + SortedMap subMap(Object fromKey, Object toKey); + + /** + * Returns a view of the portion of the map greater than or equal to + * fromKey. The view is backed by this map, so changes in one show up + * in the other. The submap supports all optional operations of the original. + *

    + * + * The returned map throws an IllegalArgumentException any time a key is + * used which is out of the range of fromKey. Note that the endpoint, fromKey, is + * included; if you do not want this value to be included, pass its successor object in + * to fromKey. For example, for Integers, you could request + * tailMap(new Integer(limit.intValue() + 1)). + * + * @param fromKey the inclusive lower range of the submap + * @return the submap + * @throws ClassCastException if fromKey is not comparable to the map + * contents + * @throws IllegalArgumentException if this is a subMap, and fromKey is out + * of range + * @throws NullPointerException if fromKey is null but the map does not allow + * null keys + */ + SortedMap tailMap(Object fromKey); +} diff --git a/libjava/classpath/java/util/SortedSet.java b/libjava/classpath/java/util/SortedSet.java new file mode 100644 index 0000000..48a24a8 --- /dev/null +++ b/libjava/classpath/java/util/SortedSet.java @@ -0,0 +1,176 @@ +/* SortedSet.java -- A set that makes guarantees about the order of its + elements + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/** + * A set which guarantees its iteration order. The elements in the set + * are related by the natural ordering if they are Comparable, or + * by the provided Comparator. Additional operations take advantage of + * the sorted nature of the set. + *

    + * + * All elements entered in the set must be mutually comparable; in other words, + * k1.compareTo(k2) or comparator.compare(k1, k2) + * must not throw a ClassCastException. The ordering must be consistent + * with equals (see {@link Comparator} for this definition), if the + * set is to obey the general contract of the Set interface. If not, + * the results are well-defined, but probably not what you wanted. + *

    + * + * It is recommended that all implementing classes provide four constructors: + * 1) one that takes no arguments and builds an empty set sorted by natural + * order of the elements; 2) one that takes a Comparator for the sorting order; + * 3) one that takes a Set and sorts according to the natural order of its + * elements; and 4) one that takes a SortedSet and sorts by the same + * comparator. Unfortunately, the Java language does not provide a way to + * enforce this. + * + * @author Original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @see Set + * @see TreeSet + * @see SortedMap + * @see Collection + * @see Comparable + * @see Comparator + * @see ClassCastException + * @since 1.2 + * @status updated to 1.4 + */ +public interface SortedSet extends Set +{ + /** + * Returns the comparator used in sorting this set, or null if it is + * the elements' natural ordering. + * + * @return the sorting comparator + */ + Comparator comparator(); + + /** + * Returns the first (lowest sorted) element in the set. + * + * @return the first element + * @throws NoSuchElementException if the set is empty. + */ + Object first(); + + /** + * Returns a view of the portion of the set strictly less than toElement. The + * view is backed by this set, so changes in one show up in the other. + * The subset supports all optional operations of the original. + *

    + * + * The returned set throws an IllegalArgumentException any time an element is + * used which is out of the range of toElement. Note that the endpoint, toElement, + * is not included; if you want this value included, pass its successor object in to + * toElement. For example, for Integers, you could request + * headSet(new Integer(limit.intValue() + 1)). + * + * @param toElement the exclusive upper range of the subset + * @return the subset + * @throws ClassCastException if toElement is not comparable to the set + * contents + * @throws IllegalArgumentException if this is a subSet, and toElement is out + * of range + * @throws NullPointerException if toElement is null but the set does not + * allow null elements + */ + SortedSet headSet(Object toElement); + + /** + * Returns the last (highest sorted) element in the set. + * + * @return the last element + * @throws NoSuchElementException if the set is empty. + */ + Object last(); + + /** + * Returns a view of the portion of the set greater than or equal to + * fromElement, and strictly less than toElement. The view is backed by + * this set, so changes in one show up in the other. The subset supports all + * optional operations of the original. + *

    + * + * The returned set throws an IllegalArgumentException any time an element is + * used which is out of the range of fromElement and toElement. Note that the + * lower endpoint is included, but the upper is not; if you want to + * change the inclusion or exclusion of an endpoint, pass its successor + * object in instead. For example, for Integers, you can request + * subSet(new Integer(lowlimit.intValue() + 1), + * new Integer(highlimit.intValue() + 1)) to reverse + * the inclusiveness of both endpoints. + * + * @param fromElement the inclusive lower range of the subset + * @param toElement the exclusive upper range of the subset + * @return the subset + * @throws ClassCastException if fromElement or toElement is not comparable + * to the set contents + * @throws IllegalArgumentException if this is a subSet, and fromElement or + * toElement is out of range + * @throws NullPointerException if fromElement or toElement is null but the + * set does not allow null elements + */ + SortedSet subSet(Object fromElement, Object toElement); + + /** + * Returns a view of the portion of the set greater than or equal to + * fromElement. The view is backed by this set, so changes in one show up + * in the other. The subset supports all optional operations of the original. + *

    + * + * The returned set throws an IllegalArgumentException any time an element is + * used which is out of the range of fromElement. Note that the endpoint, + * fromElement, is included; if you do not want this value to be included, pass its + * successor object in to fromElement. For example, for Integers, you could request + * tailSet(new Integer(limit.intValue() + 1)). + * + * @param fromElement the inclusive lower range of the subset + * @return the subset + * @throws ClassCastException if fromElement is not comparable to the set + * contents + * @throws IllegalArgumentException if this is a subSet, and fromElement is + * out of range + * @throws NullPointerException if fromElement is null but the set does not + * allow null elements + */ + SortedSet tailSet(Object fromElement); +} diff --git a/libjava/classpath/java/util/Stack.java b/libjava/classpath/java/util/Stack.java new file mode 100644 index 0000000..730ce17 --- /dev/null +++ b/libjava/classpath/java/util/Stack.java @@ -0,0 +1,158 @@ +/* Stack.java - Class that provides a Last In First Out (LIFO) + datatype, known more commonly as a Stack + Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct + +/** + * Stack provides a Last In First Out (LIFO) data type, commonly known + * as a Stack. Stack itself extends Vector and provides the additional + * methods for stack manipulation (push, pop, peek). You can also seek for + * the 1-based position of an element on the stack. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see List + * @see AbstractList + * @see LinkedList + * @since 1.0 + * @status updated to 1.4 + */ +public class Stack extends Vector +{ + // We could use Vector methods internally for the following methods, + // but have used Vector fields directly for efficiency (i.e. this + // often reduces out duplicate bounds checking). + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 1224463164541339165L; + + /** + * This constructor creates a new Stack, initially empty + */ + public Stack() + { + } + + /** + * Pushes an Object onto the top of the stack. This method is effectively + * the same as addElement(item). + * + * @param item the Object to push onto the stack + * @return the Object pushed onto the stack + * @see Vector#addElement(Object) + */ + public Object push(Object item) + { + // When growing the Stack, use the Vector routines in case more + // memory is needed. + // Note: spec indicates that this method *always* returns obj passed in! + + addElement(item); + return item; + } + + /** + * Pops an item from the stack and returns it. The item popped is + * removed from the Stack. + * + * @return the Object popped from the stack + * @throws EmptyStackException if the stack is empty + */ + public synchronized Object pop() + { + if (elementCount == 0) + throw new EmptyStackException(); + + modCount++; + Object obj = elementData[--elementCount]; + + // Set topmost element to null to assist the gc in cleanup. + elementData[elementCount] = null; + return obj; + } + + /** + * Returns the top Object on the stack without removing it. + * + * @return the top Object on the stack + * @throws EmptyStackException if the stack is empty + */ + public synchronized Object peek() + { + if (elementCount == 0) + throw new EmptyStackException(); + + return elementData[elementCount - 1]; + } + + /** + * Tests if the stack is empty. + * + * @return true if the stack contains no items, false otherwise + */ + public synchronized boolean empty() + { + return elementCount == 0; + } + + /** + * Returns the position of an Object on the stack, with the top + * most Object being at position 1, and each Object deeper in the + * stack at depth + 1. + * + * @param o The object to search for + * @return The 1 based depth of the Object, or -1 if the Object + * is not on the stack + */ + public synchronized int search(Object o) + { + int i = elementCount; + while (--i >= 0) + if (equals(o, elementData[i])) + return elementCount - i; + return -1; + } +} diff --git a/libjava/classpath/java/util/StringTokenizer.java b/libjava/classpath/java/util/StringTokenizer.java new file mode 100644 index 0000000..dcc192c --- /dev/null +++ b/libjava/classpath/java/util/StringTokenizer.java @@ -0,0 +1,268 @@ +/* StringTokenizer -- breaks a String into tokens + Copyright (C) 1998, 1999, 2001, 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 java.util; + +/** + * This class splits a string into tokens. The caller can set on which + * delimiters the string should be split and if the delimiters should be + * returned. This is much simpler than {@link java.io.StreamTokenizer}. + * + *

    You may change the delimiter set on the fly by calling + * nextToken(String). But the semantic is quite difficult; it even + * depends on calling hasMoreTokens(). You should call + * hasMoreTokens() before, otherwise the old delimiters + * after the last token are candidates for being returned. + * + *

    If you want to get the delimiters, you have to use the three argument + * constructor. The delimiters are returned as token consisting of a + * single character. + * + * @author Jochen Hoenicke + * @author Warren Levy (warrenl@cygnus.com) + * @see java.io.StreamTokenizer + * @status updated to 1.4 + */ +public class StringTokenizer implements Enumeration +{ + // WARNING: StringTokenizer is a CORE class in the bootstrap cycle. See the + // comments in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * The position in the str, where we currently are. + */ + private int pos; + + /** + * The string that should be split into tokens. + */ + private final String str; + + /** + * The length of the string. + */ + private final int len; + + /** + * The string containing the delimiter characters. + */ + private String delim; + + /** + * Tells, if we should return the delimiters. + */ + private final boolean retDelims; + + /** + * Creates a new StringTokenizer for the string str, + * that should split on the default delimiter set (space, tab, + * newline, return and formfeed), and which doesn't return the + * delimiters. + * + * @param str The string to split + * @throws NullPointerException if str is null + */ + public StringTokenizer(String str) + { + this(str, " \t\n\r\f", false); + } + + /** + * Create a new StringTokenizer, that splits the given string on + * the given delimiter characters. It doesn't return the delimiter + * characters. + * + * @param str the string to split + * @param delim a string containing all delimiter characters + * @throws NullPointerException if either argument is null + */ + public StringTokenizer(String str, String delim) + { + this(str, delim, false); + } + + /** + * Create a new StringTokenizer, that splits the given string on + * the given delimiter characters. If you set + * returnDelims to true, the delimiter + * characters are returned as tokens of their own. The delimiter + * tokens always consist of a single character. + * + * @param str the string to split + * @param delim a string containing all delimiter characters + * @param returnDelims tells, if you want to get the delimiters + * @throws NullPointerException if str or delim is null + */ + public StringTokenizer(String str, String delim, boolean returnDelims) + { + len = str.length(); + this.str = str; + // The toString() hack causes the NullPointerException. + this.delim = delim.toString(); + this.retDelims = returnDelims; + this.pos = 0; + } + + /** + * Tells if there are more tokens. + * + * @return true if the next call of nextToken() will succeed + */ + public boolean hasMoreTokens() + { + if (! retDelims) + { + while (pos < len && delim.indexOf(str.charAt(pos)) >= 0) + pos++; + } + return pos < len; + } + + /** + * Returns the nextToken, changing the delimiter set to the given + * delim. The change of the delimiter set is + * permanent, ie. the next call of nextToken(), uses the same + * delimiter set. + * + * @param delim a string containing the new delimiter characters + * @return the next token with respect to the new delimiter characters + * @throws NoSuchElementException if there are no more tokens + * @throws NullPointerException if delim is null + */ + public String nextToken(String delim) throws NoSuchElementException + { + this.delim = delim; + return nextToken(); + } + + /** + * Returns the nextToken of the string. + * + * @return the next token with respect to the current delimiter characters + * @throws NoSuchElementException if there are no more tokens + */ + public String nextToken() throws NoSuchElementException + { + if (pos < len && delim.indexOf(str.charAt(pos)) >= 0) + { + if (retDelims) + return str.substring(pos, ++pos); + while (++pos < len && delim.indexOf(str.charAt(pos)) >= 0); + } + if (pos < len) + { + int start = pos; + while (++pos < len && delim.indexOf(str.charAt(pos)) < 0); + + return str.substring(start, pos); + } + throw new NoSuchElementException(); + } + + /** + * This does the same as hasMoreTokens. This is the + * Enumeration interface method. + * + * @return true, if the next call of nextElement() will succeed + * @see #hasMoreTokens() + */ + public boolean hasMoreElements() + { + return hasMoreTokens(); + } + + /** + * This does the same as nextTokens. This is the + * Enumeration interface method. + * + * @return the next token with respect to the current delimiter characters + * @throws NoSuchElementException if there are no more tokens + * @see #nextToken() + */ + public Object nextElement() throws NoSuchElementException + { + return nextToken(); + } + + /** + * This counts the number of remaining tokens in the string, with + * respect to the current delimiter set. + * + * @return the number of times nextTokens() will succeed + * @see #nextToken() + */ + public int countTokens() + { + int count = 0; + int delimiterCount = 0; + boolean tokenFound = false; // Set when a non-delimiter is found + int tmpPos = pos; + + // Note for efficiency, we count up the delimiters rather than check + // retDelims every time we encounter one. That way, we can + // just do the conditional once at the end of the method + while (tmpPos < len) + { + if (delim.indexOf(str.charAt(tmpPos++)) >= 0) + { + if (tokenFound) + { + // Got to the end of a token + count++; + tokenFound = false; + } + delimiterCount++; // Increment for this delimiter + } + else + { + tokenFound = true; + // Get to the end of the token + while (tmpPos < len + && delim.indexOf(str.charAt(tmpPos)) < 0) + ++tmpPos; + } + } + + // Make sure to count the last token + if (tokenFound) + count++; + + // if counting delmiters add them into the token count + return retDelims ? count + delimiterCount : count; + } +} // class StringTokenizer diff --git a/libjava/classpath/java/util/TimeZone.java b/libjava/classpath/java/util/TimeZone.java new file mode 100644 index 0000000..99df11d --- /dev/null +++ b/libjava/classpath/java/util/TimeZone.java @@ -0,0 +1,1523 @@ +/* java.util.TimeZone + 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 java.util; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.DateFormatSymbols; + +/** + * This class represents a time zone offset and handles daylight savings. + * + * You can get the default time zone with getDefault. + * This represents the time zone where program is running. + * + * Another way to create a time zone is getTimeZone, where + * you can give an identifier as parameter. For instance, the identifier + * of the Central European Time zone is "CET". + * + * With the getAvailableIDs method, you can get all the + * supported time zone identifiers. + * + * @see Calendar + * @see SimpleTimeZone + * @author Jochen Hoenicke + */ +public abstract class TimeZone implements java.io.Serializable, Cloneable +{ + + /** + * Constant used to indicate that a short timezone abbreviation should + * be returned, such as "EST" + */ + public static final int SHORT = 0; + + /** + * Constant used to indicate that a long timezone name should be + * returned, such as "Eastern Standard Time". + */ + public static final int LONG = 1; + + /** + * The time zone identifier, e.g. PST. + */ + private String ID; + + /** + * The default time zone, as returned by getDefault. + */ + private static TimeZone defaultZone0; + + /** + * Tries to get the default TimeZone for this system if not already + * set. It will call getDefaultTimeZone(String) with + * the result of System.getProperty("user.timezone"). + * If that fails it calls VMTimeZone.getDefaultTimeZoneId(). + * If that also fails GMT is returned. + */ + private static synchronized TimeZone defaultZone() + { + /* Look up default timezone */ + if (defaultZone0 == null) + { + defaultZone0 = (TimeZone) AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + TimeZone zone = null; + + // Prefer System property user.timezone. + String tzid = System.getProperty("user.timezone"); + if (tzid != null && !tzid.equals("")) + zone = getDefaultTimeZone(tzid); + + // Try platfom specific way. + if (zone == null) + zone = VMTimeZone.getDefaultTimeZoneId(); + + // Fall back on GMT. + if (zone == null) + zone = (TimeZone) timezones().get("GMT"); + + return zone; + } + }); + } + + return defaultZone0; + } + + private static final long serialVersionUID = 3581463369166924961L; + + /** + * HashMap for timezones by ID. + */ + private static HashMap timezones0; + /* initialize this static field lazily to overhead if + * it is not needed: + */ + // Package-private to avoid a trampoline. + static synchronized HashMap timezones() + { + if (timezones0 == null) + { + HashMap timezones = new HashMap(); + timezones0 = timezones; + + TimeZone tz; + // Automatically generated by scripts/timezones.pl + // XXX - Should we read this data from a file? + tz = new SimpleTimeZone(-11000 * 3600, "MIT"); + timezones0.put("MIT", tz); + timezones0.put("Pacific/Apia", tz); + timezones0.put("Pacific/Midway", tz); + timezones0.put("Pacific/Niue", tz); + timezones0.put("Pacific/Pago_Pago", tz); + tz = new SimpleTimeZone + (-10000 * 3600, "America/Adak", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Adak", tz); + tz = new SimpleTimeZone(-10000 * 3600, "HST"); + timezones0.put("HST", tz); + timezones0.put("Pacific/Fakaofo", tz); + timezones0.put("Pacific/Honolulu", tz); + timezones0.put("Pacific/Johnston", tz); + timezones0.put("Pacific/Rarotonga", tz); + timezones0.put("Pacific/Tahiti", tz); + tz = new SimpleTimeZone(-9500 * 3600, "Pacific/Marquesas"); + timezones0.put("Pacific/Marquesas", tz); + tz = new SimpleTimeZone + (-9000 * 3600, "AST", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("AST", tz); + timezones0.put("America/Anchorage", tz); + timezones0.put("America/Juneau", tz); + timezones0.put("America/Nome", tz); + timezones0.put("America/Yakutat", tz); + tz = new SimpleTimeZone(-9000 * 3600, "Pacific/Gambier"); + timezones0.put("Pacific/Gambier", tz); + tz = new SimpleTimeZone + (-8000 * 3600, "PST", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("PST", tz); + timezones0.put("PST8PDT", tz); + timezones0.put("America/Dawson", tz); + timezones0.put("America/Los_Angeles", tz); + timezones0.put("America/Tijuana", tz); + timezones0.put("America/Vancouver", tz); + timezones0.put("America/Whitehorse", tz); + timezones0.put("US/Pacific-New", tz); + tz = new SimpleTimeZone(-8000 * 3600, "Pacific/Pitcairn"); + timezones0.put("Pacific/Pitcairn", tz); + tz = new SimpleTimeZone + (-7000 * 3600, "MST", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("MST", tz); + timezones0.put("MST7MDT", tz); + timezones0.put("America/Boise", tz); + timezones0.put("America/Chihuahua", tz); + timezones0.put("America/Denver", tz); + timezones0.put("America/Edmonton", tz); + timezones0.put("America/Inuvik", tz); + timezones0.put("America/Mazatlan", tz); + timezones0.put("America/Shiprock", tz); + timezones0.put("America/Yellowknife", tz); + tz = new SimpleTimeZone(-7000 * 3600, "MST7"); + timezones0.put("MST7", tz); + timezones0.put("PNT", tz); + timezones0.put("America/Dawson_Creek", tz); + timezones0.put("America/Hermosillo", tz); + timezones0.put("America/Phoenix", tz); + tz = new SimpleTimeZone + (-6000 * 3600, "CST", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("CST", tz); + timezones0.put("CST6CDT", tz); + timezones0.put("America/Cambridge_Bay", tz); + timezones0.put("America/Cancun", tz); + timezones0.put("America/Chicago", tz); + timezones0.put("America/Menominee", tz); + timezones0.put("America/Merida", tz); + timezones0.put("America/Mexico_City", tz); + timezones0.put("America/Monterrey", tz); + timezones0.put("America/Rainy_River", tz); + timezones0.put("America/Winnipeg", tz); + tz = new SimpleTimeZone(-6000 * 3600, "America/Belize"); + timezones0.put("America/Belize", tz); + timezones0.put("America/Costa_Rica", tz); + timezones0.put("America/El_Salvador", tz); + timezones0.put("America/Guatemala", tz); + timezones0.put("America/Managua", tz); + timezones0.put("America/Regina", tz); + timezones0.put("America/Swift_Current", tz); + timezones0.put("America/Tegucigalpa", tz); + timezones0.put("Pacific/Galapagos", tz); + tz = new SimpleTimeZone + (-6000 * 3600, "Pacific/Easter", + Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * 3600, + Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * 3600); + timezones0.put("Pacific/Easter", tz); + tz = new SimpleTimeZone + (-5000 * 3600, "America/Grand_Turk", + Calendar.APRIL, 1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Grand_Turk", tz); + timezones0.put("America/Havana", tz); + tz = new SimpleTimeZone(-5000 * 3600, "EST5"); + timezones0.put("EST5", tz); + timezones0.put("IET", tz); + timezones0.put("America/Bogota", tz); + timezones0.put("America/Cayman", tz); + timezones0.put("America/Eirunepe", tz); + timezones0.put("America/Guayaquil", tz); + timezones0.put("America/Indiana/Indianapolis", tz); + timezones0.put("America/Indiana/Knox", tz); + timezones0.put("America/Indiana/Marengo", tz); + timezones0.put("America/Indiana/Vevay", tz); + timezones0.put("America/Indianapolis", tz); + timezones0.put("America/Iqaluit", tz); + timezones0.put("America/Jamaica", tz); + timezones0.put("America/Lima", tz); + timezones0.put("America/Panama", tz); + timezones0.put("America/Pangnirtung", tz); + timezones0.put("America/Port-au-Prince", tz); + timezones0.put("America/Porto_Acre", tz); + timezones0.put("America/Rankin_Inlet", tz); + tz = new SimpleTimeZone + (-5000 * 3600, "EST", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("EST", tz); + timezones0.put("EST5EDT", tz); + timezones0.put("America/Detroit", tz); + timezones0.put("America/Kentucky/Louisville", tz); + timezones0.put("America/Kentucky/Monticello", tz); + timezones0.put("America/Louisville", tz); + timezones0.put("America/Montreal", tz); + timezones0.put("America/Nassau", tz); + timezones0.put("America/New_York", tz); + timezones0.put("America/Nipigon", tz); + timezones0.put("America/Thunder_Bay", tz); + tz = new SimpleTimeZone(-4000 * 3600, "PRT"); + timezones0.put("PRT", tz); + timezones0.put("America/Anguilla", tz); + timezones0.put("America/Antigua", tz); + timezones0.put("America/Aruba", tz); + timezones0.put("America/Barbados", tz); + timezones0.put("America/Boa_Vista", tz); + timezones0.put("America/Caracas", tz); + timezones0.put("America/Curacao", tz); + timezones0.put("America/Dominica", tz); + timezones0.put("America/Grenada", tz); + timezones0.put("America/Guadeloupe", tz); + timezones0.put("America/Guyana", tz); + timezones0.put("America/La_Paz", tz); + timezones0.put("America/Manaus", tz); + timezones0.put("America/Martinique", tz); + timezones0.put("America/Montserrat", tz); + timezones0.put("America/Port_of_Spain", tz); + timezones0.put("America/Porto_Velho", tz); + timezones0.put("America/Puerto_Rico", tz); + timezones0.put("America/Santo_Domingo", tz); + timezones0.put("America/St_Kitts", tz); + timezones0.put("America/St_Lucia", tz); + timezones0.put("America/St_Thomas", tz); + timezones0.put("America/St_Vincent", tz); + timezones0.put("America/Tortola", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Asuncion", + Calendar.OCTOBER, 1, Calendar.SUNDAY, 0 * 3600, + Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Asuncion", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Cuiaba", + Calendar.OCTOBER, 2, Calendar.SUNDAY, 0 * 3600, + Calendar.FEBRUARY, 3, Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Cuiaba", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Goose_Bay", + Calendar.APRIL, 1, Calendar.SUNDAY, 60000, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 60000); + timezones0.put("America/Goose_Bay", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Glace_Bay", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Glace_Bay", tz); + timezones0.put("America/Halifax", tz); + timezones0.put("America/Thule", tz); + timezones0.put("Atlantic/Bermuda", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Santiago", + Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * 3600, + Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Santiago", tz); + timezones0.put("Antarctica/Palmer", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "Atlantic/Stanley", + Calendar.SEPTEMBER, 2, Calendar.SUNDAY, 0 * 3600, + Calendar.APRIL, 16, -Calendar.SUNDAY, 0 * 3600); + timezones0.put("Atlantic/Stanley", tz); + tz = new SimpleTimeZone + (-3500 * 3600, "CNT", + Calendar.APRIL, 1, Calendar.SUNDAY, 60000, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 60000); + timezones0.put("CNT", tz); + timezones0.put("America/St_Johns", tz); + tz = new SimpleTimeZone + (-3000 * 3600, "America/Araguaina", + Calendar.OCTOBER, 2, Calendar.SUNDAY, 0 * 3600, + Calendar.FEBRUARY, 3, Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Araguaina", tz); + timezones0.put("America/Sao_Paulo", tz); + tz = new SimpleTimeZone(-3000 * 3600, "AGT"); + timezones0.put("AGT", tz); + timezones0.put("America/Belem", tz); + timezones0.put("America/Buenos_Aires", tz); + timezones0.put("America/Catamarca", tz); + timezones0.put("America/Cayenne", tz); + timezones0.put("America/Cordoba", tz); + timezones0.put("America/Fortaleza", tz); + timezones0.put("America/Jujuy", tz); + timezones0.put("America/Maceio", tz); + timezones0.put("America/Mendoza", tz); + timezones0.put("America/Montevideo", tz); + timezones0.put("America/Paramaribo", tz); + timezones0.put("America/Recife", tz); + timezones0.put("America/Rosario", tz); + tz = new SimpleTimeZone + (-3000 * 3600, "America/Godthab", + Calendar.MARCH, 30, -Calendar.SATURDAY, 22000 * 3600, + Calendar.OCTOBER, 30, -Calendar.SATURDAY, 22000 * 3600); + timezones0.put("America/Godthab", tz); + tz = new SimpleTimeZone + (-3000 * 3600, "America/Miquelon", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Miquelon", tz); + tz = new SimpleTimeZone(-2000 * 3600, "America/Noronha"); + timezones0.put("America/Noronha", tz); + timezones0.put("Atlantic/South_Georgia", tz); + tz = new SimpleTimeZone + (-1000 * 3600, "America/Scoresbysund", + Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Scoresbysund", tz); + timezones0.put("Atlantic/Azores", tz); + tz = new SimpleTimeZone(-1000 * 3600, "Atlantic/Cape_Verde"); + timezones0.put("Atlantic/Cape_Verde", tz); + timezones0.put("Atlantic/Jan_Mayen", tz); + tz = new SimpleTimeZone(0 * 3600, "GMT"); + timezones0.put("GMT", tz); + timezones0.put("UTC", tz); + timezones0.put("Africa/Abidjan", tz); + timezones0.put("Africa/Accra", tz); + timezones0.put("Africa/Bamako", tz); + timezones0.put("Africa/Banjul", tz); + timezones0.put("Africa/Bissau", tz); + timezones0.put("Africa/Casablanca", tz); + timezones0.put("Africa/Conakry", tz); + timezones0.put("Africa/Dakar", tz); + timezones0.put("Africa/El_Aaiun", tz); + timezones0.put("Africa/Freetown", tz); + timezones0.put("Africa/Lome", tz); + timezones0.put("Africa/Monrovia", tz); + timezones0.put("Africa/Nouakchott", tz); + timezones0.put("Africa/Ouagadougou", tz); + timezones0.put("Africa/Sao_Tome", tz); + timezones0.put("Africa/Timbuktu", tz); + timezones0.put("Atlantic/Reykjavik", tz); + timezones0.put("Atlantic/St_Helena", tz); + timezones0.put("Europe/Belfast", tz); + timezones0.put("Europe/Dublin", tz); + timezones0.put("Europe/London", tz); + tz = new SimpleTimeZone + (0 * 3600, "WET", + Calendar.MARCH, -1, Calendar.SUNDAY, 1000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600); + timezones0.put("WET", tz); + timezones0.put("Atlantic/Canary", tz); + timezones0.put("Atlantic/Faeroe", tz); + timezones0.put("Atlantic/Madeira", tz); + timezones0.put("Europe/Lisbon", tz); + tz = new SimpleTimeZone(1000 * 3600, "Africa/Algiers"); + timezones0.put("Africa/Algiers", tz); + timezones0.put("Africa/Bangui", tz); + timezones0.put("Africa/Brazzaville", tz); + timezones0.put("Africa/Douala", tz); + timezones0.put("Africa/Kinshasa", tz); + timezones0.put("Africa/Lagos", tz); + timezones0.put("Africa/Libreville", tz); + timezones0.put("Africa/Luanda", tz); + timezones0.put("Africa/Malabo", tz); + timezones0.put("Africa/Ndjamena", tz); + timezones0.put("Africa/Niamey", tz); + timezones0.put("Africa/Porto-Novo", tz); + timezones0.put("Africa/Tunis", tz); + tz = new SimpleTimeZone + (1000 * 3600, "Africa/Windhoek", + Calendar.SEPTEMBER, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Africa/Windhoek", tz); + tz = new SimpleTimeZone + (1000 * 3600, "CET", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("CET", tz); + timezones0.put("CEST", tz); + timezones0.put("ECT", tz); + timezones0.put("MET", tz); + timezones0.put("Africa/Ceuta", tz); + timezones0.put("Arctic/Longyearbyen", tz); + timezones0.put("Europe/Amsterdam", tz); + timezones0.put("Europe/Andorra", tz); + timezones0.put("Europe/Belgrade", tz); + timezones0.put("Europe/Berlin", tz); + timezones0.put("Europe/Bratislava", tz); + timezones0.put("Europe/Brussels", tz); + timezones0.put("Europe/Budapest", tz); + timezones0.put("Europe/Copenhagen", tz); + timezones0.put("Europe/Gibraltar", tz); + timezones0.put("Europe/Ljubljana", tz); + timezones0.put("Europe/Luxembourg", tz); + timezones0.put("Europe/Madrid", tz); + timezones0.put("Europe/Malta", tz); + timezones0.put("Europe/Monaco", tz); + timezones0.put("Europe/Oslo", tz); + timezones0.put("Europe/Paris", tz); + timezones0.put("Europe/Prague", tz); + timezones0.put("Europe/Rome", tz); + timezones0.put("Europe/San_Marino", tz); + timezones0.put("Europe/Sarajevo", tz); + timezones0.put("Europe/Skopje", tz); + timezones0.put("Europe/Stockholm", tz); + timezones0.put("Europe/Tirane", tz); + timezones0.put("Europe/Vaduz", tz); + timezones0.put("Europe/Vatican", tz); + timezones0.put("Europe/Vienna", tz); + timezones0.put("Europe/Warsaw", tz); + timezones0.put("Europe/Zagreb", tz); + timezones0.put("Europe/Zurich", tz); + tz = new SimpleTimeZone + (2000 * 3600, "ART", + Calendar.APRIL, -1, Calendar.FRIDAY, 0 * 3600, + Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 23000 * 3600); + timezones0.put("ART", tz); + timezones0.put("Africa/Cairo", tz); + tz = new SimpleTimeZone(2000 * 3600, "CAT"); + timezones0.put("CAT", tz); + timezones0.put("Africa/Blantyre", tz); + timezones0.put("Africa/Bujumbura", tz); + timezones0.put("Africa/Gaborone", tz); + timezones0.put("Africa/Harare", tz); + timezones0.put("Africa/Johannesburg", tz); + timezones0.put("Africa/Kigali", tz); + timezones0.put("Africa/Lubumbashi", tz); + timezones0.put("Africa/Lusaka", tz); + timezones0.put("Africa/Maputo", tz); + timezones0.put("Africa/Maseru", tz); + timezones0.put("Africa/Mbabane", tz); + timezones0.put("Africa/Tripoli", tz); + timezones0.put("Europe/Riga", tz); + timezones0.put("Europe/Tallinn", tz); + timezones0.put("Europe/Vilnius", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Asia/Amman", + Calendar.MARCH, -1, Calendar.THURSDAY, 0 * 3600, + Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 0 * 3600); + timezones0.put("Asia/Amman", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Asia/Beirut", + Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("Asia/Beirut", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Asia/Damascus", + Calendar.APRIL, 1, 0, 0 * 3600, + Calendar.OCTOBER, 1, 0, 0 * 3600); + timezones0.put("Asia/Damascus", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Asia/Gaza", + Calendar.APRIL, 3, Calendar.FRIDAY, 0 * 3600, + Calendar.OCTOBER, 3, Calendar.FRIDAY, 0 * 3600); + timezones0.put("Asia/Gaza", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Asia/Jerusalem", + Calendar.APRIL, 1, 0, 1000 * 3600, + Calendar.OCTOBER, 1, 0, 1000 * 3600); + timezones0.put("Asia/Jerusalem", tz); + tz = new SimpleTimeZone + (2000 * 3600, "EET", + Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("EET", tz); + timezones0.put("Asia/Istanbul", tz); + timezones0.put("Asia/Nicosia", tz); + timezones0.put("Europe/Athens", tz); + timezones0.put("Europe/Bucharest", tz); + timezones0.put("Europe/Chisinau", tz); + timezones0.put("Europe/Helsinki", tz); + timezones0.put("Europe/Istanbul", tz); + timezones0.put("Europe/Kiev", tz); + timezones0.put("Europe/Nicosia", tz); + timezones0.put("Europe/Simferopol", tz); + timezones0.put("Europe/Sofia", tz); + timezones0.put("Europe/Uzhgorod", tz); + timezones0.put("Europe/Zaporozhye", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Europe/Kaliningrad", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Europe/Kaliningrad", tz); + timezones0.put("Europe/Minsk", tz); + tz = new SimpleTimeZone + (3000 * 3600, "Asia/Baghdad", + Calendar.APRIL, 1, 0, 3000 * 3600, + Calendar.OCTOBER, 1, 0, 3000 * 3600); + timezones0.put("Asia/Baghdad", tz); + tz = new SimpleTimeZone + (3000 * 3600, "Europe/Moscow", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Europe/Moscow", tz); + timezones0.put("Europe/Tiraspol", tz); + tz = new SimpleTimeZone(3000 * 3600, "EAT"); + timezones0.put("EAT", tz); + timezones0.put("Africa/Addis_Ababa", tz); + timezones0.put("Africa/Asmera", tz); + timezones0.put("Africa/Dar_es_Salaam", tz); + timezones0.put("Africa/Djibouti", tz); + timezones0.put("Africa/Kampala", tz); + timezones0.put("Africa/Khartoum", tz); + timezones0.put("Africa/Mogadishu", tz); + timezones0.put("Africa/Nairobi", tz); + timezones0.put("Antarctica/Syowa", tz); + timezones0.put("Asia/Aden", tz); + timezones0.put("Asia/Bahrain", tz); + timezones0.put("Asia/Kuwait", tz); + timezones0.put("Asia/Qatar", tz); + timezones0.put("Asia/Riyadh", tz); + timezones0.put("Indian/Antananarivo", tz); + timezones0.put("Indian/Comoro", tz); + timezones0.put("Indian/Mayotte", tz); + tz = new SimpleTimeZone(3500 * 3600, "Asia/Tehran"); + timezones0.put("Asia/Tehran", tz); + tz = new SimpleTimeZone + (4000 * 3600, "Asia/Baku", + Calendar.MARCH, -1, Calendar.SUNDAY, 1000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600); + timezones0.put("Asia/Baku", tz); + tz = new SimpleTimeZone + (4000 * 3600, "Asia/Aqtau", + Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("Asia/Aqtau", tz); + timezones0.put("Asia/Tbilisi", tz); + tz = new SimpleTimeZone + (4000 * 3600, "Asia/Yerevan", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Asia/Yerevan", tz); + timezones0.put("Europe/Samara", tz); + tz = new SimpleTimeZone(4000 * 3600, "NET"); + timezones0.put("NET", tz); + timezones0.put("Asia/Dubai", tz); + timezones0.put("Asia/Muscat", tz); + timezones0.put("Indian/Mahe", tz); + timezones0.put("Indian/Mauritius", tz); + timezones0.put("Indian/Reunion", tz); + tz = new SimpleTimeZone(4500 * 3600, "Asia/Kabul"); + timezones0.put("Asia/Kabul", tz); + tz = new SimpleTimeZone + (5000 * 3600, "Asia/Aqtobe", + Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("Asia/Aqtobe", tz); + tz = new SimpleTimeZone + (5000 * 3600, "Asia/Bishkek", + Calendar.MARCH, -1, Calendar.SUNDAY, 2500 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2500 * 3600); + timezones0.put("Asia/Bishkek", tz); + tz = new SimpleTimeZone + (5000 * 3600, "Asia/Yekaterinburg", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Asia/Yekaterinburg", tz); + tz = new SimpleTimeZone(5000 * 3600, "PLT"); + timezones0.put("PLT", tz); + timezones0.put("Asia/Ashgabat", tz); + timezones0.put("Asia/Dushanbe", tz); + timezones0.put("Asia/Karachi", tz); + timezones0.put("Asia/Samarkand", tz); + timezones0.put("Asia/Tashkent", tz); + timezones0.put("Indian/Chagos", tz); + timezones0.put("Indian/Kerguelen", tz); + timezones0.put("Indian/Maldives", tz); + tz = new SimpleTimeZone(5500 * 3600, "IST"); + timezones0.put("IST", tz); + timezones0.put("Asia/Calcutta", tz); + tz = new SimpleTimeZone(5750 * 3600, "Asia/Katmandu"); + timezones0.put("Asia/Katmandu", tz); + tz = new SimpleTimeZone(6000 * 3600, "BST"); + timezones0.put("BST", tz); + timezones0.put("Antarctica/Mawson", tz); + timezones0.put("Asia/Colombo", tz); + timezones0.put("Asia/Dhaka", tz); + timezones0.put("Asia/Thimphu", tz); + tz = new SimpleTimeZone + (6000 * 3600, "Asia/Almaty", + Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("Asia/Almaty", tz); + tz = new SimpleTimeZone + (6000 * 3600, "Asia/Novosibirsk", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Asia/Novosibirsk", tz); + timezones0.put("Asia/Omsk", tz); + tz = new SimpleTimeZone(6500 * 3600, "Asia/Rangoon"); + timezones0.put("Asia/Rangoon", tz); + timezones0.put("Indian/Cocos", tz); + tz = new SimpleTimeZone(7000 * 3600, "VST"); + timezones0.put("VST", tz); + timezones0.put("Antarctica/Davis", tz); + timezones0.put("Asia/Bangkok", tz); + timezones0.put("Asia/Hovd", tz); + timezones0.put("Asia/Jakarta", tz); + timezones0.put("Asia/Phnom_Penh", tz); + timezones0.put("Asia/Saigon", tz); + timezones0.put("Asia/Vientiane", tz); + timezones0.put("Indian/Christmas", tz); + tz = new SimpleTimeZone + (7000 * 3600, "Asia/Krasnoyarsk", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Asia/Krasnoyarsk", tz); + tz = new SimpleTimeZone(8000 * 3600, "CTT"); + timezones0.put("CTT", tz); + timezones0.put("Antarctica/Casey", tz); + timezones0.put("Asia/Brunei", tz); + timezones0.put("Asia/Chungking", tz); + timezones0.put("Asia/Harbin", tz); + timezones0.put("Asia/Hong_Kong", tz); + timezones0.put("Asia/Kashgar", tz); + timezones0.put("Asia/Kuala_Lumpur", tz); + timezones0.put("Asia/Kuching", tz); + timezones0.put("Asia/Macao", tz); + timezones0.put("Asia/Manila", tz); + timezones0.put("Asia/Shanghai", tz); + timezones0.put("Asia/Singapore", tz); + timezones0.put("Asia/Taipei", tz); + timezones0.put("Asia/Ujung_Pandang", tz); + timezones0.put("Asia/Ulaanbaatar", tz); + timezones0.put("Asia/Urumqi", tz); + timezones0.put("Australia/Perth", tz); + tz = new SimpleTimeZone + (8000 * 3600, "Asia/Irkutsk", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Asia/Irkutsk", tz); + tz = new SimpleTimeZone(9000 * 3600, "JST"); + timezones0.put("JST", tz); + timezones0.put("Asia/Dili", tz); + timezones0.put("Asia/Jayapura", tz); + timezones0.put("Asia/Pyongyang", tz); + timezones0.put("Asia/Seoul", tz); + timezones0.put("Asia/Tokyo", tz); + timezones0.put("Pacific/Palau", tz); + tz = new SimpleTimeZone + (9000 * 3600, "Asia/Yakutsk", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Asia/Yakutsk", tz); + tz = new SimpleTimeZone + (9500 * 3600, "Australia/Adelaide", + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Australia/Adelaide", tz); + timezones0.put("Australia/Broken_Hill", tz); + tz = new SimpleTimeZone(9500 * 3600, "ACT"); + timezones0.put("ACT", tz); + timezones0.put("Australia/Darwin", tz); + tz = new SimpleTimeZone(10000 * 3600, "Antarctica/DumontDUrville"); + timezones0.put("Antarctica/DumontDUrville", tz); + timezones0.put("Australia/Brisbane", tz); + timezones0.put("Australia/Lindeman", tz); + timezones0.put("Pacific/Guam", tz); + timezones0.put("Pacific/Port_Moresby", tz); + timezones0.put("Pacific/Saipan", tz); + timezones0.put("Pacific/Truk", tz); + timezones0.put("Pacific/Yap", tz); + tz = new SimpleTimeZone + (10000 * 3600, "Asia/Vladivostok", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Asia/Vladivostok", tz); + tz = new SimpleTimeZone + (10000 * 3600, "Australia/Hobart", + Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Australia/Hobart", tz); + tz = new SimpleTimeZone + (10000 * 3600, "AET", + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("AET", tz); + timezones0.put("Australia/Melbourne", tz); + timezones0.put("Australia/Sydney", tz); + tz = new SimpleTimeZone + (10500 * 3600, "Australia/Lord_Howe", + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, 500 * 3600); + timezones0.put("Australia/Lord_Howe", tz); + tz = new SimpleTimeZone + (11000 * 3600, "Asia/Magadan", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Asia/Magadan", tz); + tz = new SimpleTimeZone(11000 * 3600, "SST"); + timezones0.put("SST", tz); + timezones0.put("Pacific/Efate", tz); + timezones0.put("Pacific/Guadalcanal", tz); + timezones0.put("Pacific/Kosrae", tz); + timezones0.put("Pacific/Noumea", tz); + timezones0.put("Pacific/Ponape", tz); + tz = new SimpleTimeZone(11500 * 3600, "Pacific/Norfolk"); + timezones0.put("Pacific/Norfolk", tz); + tz = new SimpleTimeZone + (12000 * 3600, "NST", + Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, 3, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("NST", tz); + timezones0.put("Antarctica/McMurdo", tz); + timezones0.put("Antarctica/South_Pole", tz); + timezones0.put("Pacific/Auckland", tz); + tz = new SimpleTimeZone + (12000 * 3600, "Asia/Anadyr", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Asia/Anadyr", tz); + timezones0.put("Asia/Kamchatka", tz); + tz = new SimpleTimeZone(12000 * 3600, "Pacific/Fiji"); + timezones0.put("Pacific/Fiji", tz); + timezones0.put("Pacific/Funafuti", tz); + timezones0.put("Pacific/Kwajalein", tz); + timezones0.put("Pacific/Majuro", tz); + timezones0.put("Pacific/Nauru", tz); + timezones0.put("Pacific/Tarawa", tz); + timezones0.put("Pacific/Wake", tz); + timezones0.put("Pacific/Wallis", tz); + tz = new SimpleTimeZone + (12750 * 3600, "Pacific/Chatham", + Calendar.OCTOBER, 1, Calendar.SUNDAY, 2750 * 3600, + Calendar.MARCH, 3, Calendar.SUNDAY, 2750 * 3600); + timezones0.put("Pacific/Chatham", tz); + tz = new SimpleTimeZone(13000 * 3600, "Pacific/Enderbury"); + timezones0.put("Pacific/Enderbury", tz); + timezones0.put("Pacific/Tongatapu", tz); + tz = new SimpleTimeZone(14000 * 3600, "Pacific/Kiritimati"); + timezones0.put("Pacific/Kiritimati", tz); + } + return timezones0; + } + + /** + * Maps a time zone name (with optional GMT offset and daylight time + * zone name) to one of the known time zones. This method called + * with the result of System.getProperty("user.timezone") + * or getDefaultTimeZoneId(). Note that giving one of + * the standard tz data names from ftp://elsie.nci.nih.gov/pub/ is + * preferred. + * The time zone name can be given as follows: + * (standard zone name)[(GMT offset)[(DST zone name)[DST offset]]] + * + *

    + * If only a (standard zone name) is given (no numbers in the + * String) then it gets mapped directly to the TimeZone with that + * name, if that fails null is returned. + *

    + * Alternately, a POSIX-style TZ string can be given, defining the time zone: + * std offset dst offset,date/time,date/time + * See the glibc manual, or the man page for tzset for details + * of this format. + *

    + * A GMT offset is the offset to add to the local time to get GMT. + * If a (GMT offset) is included (either in seconds or hours) then + * an attempt is made to find a TimeZone name matching both the name + * and the offset (that doesn't observe daylight time, if the + * timezone observes daylight time then you must include a daylight + * time zone name after the offset), if that fails then a TimeZone + * with the given GMT offset is returned (whether or not the + * TimeZone observes daylight time is ignored), if that also fails + * the GMT TimeZone is returned. + *

    + * If the String ends with (GMT offset)(daylight time zone name) + * then an attempt is made to find a TimeZone with the given name and + * GMT offset that also observes (the daylight time zone name is not + * currently used in any other way), if that fails a TimeZone with + * the given GMT offset that observes daylight time is returned, if + * that also fails the GMT TimeZone is returned. + *

    + * Examples: In Chicago, the time zone id could be "CST6CDT", but + * the preferred name would be "America/Chicago". In Indianapolis + * (which does not have Daylight Savings Time) the string could be + * "EST5", but the preferred name would be "America/Indianapolis". + * The standard time zone name for The Netherlands is "Europe/Amsterdam", + * but can also be given as "CET-1CEST". + */ + static TimeZone getDefaultTimeZone(String sysTimeZoneId) + { + String stdName = null; + String dstName; + int stdOffs; + int dstOffs; + try + { + int idLength = sysTimeZoneId.length(); + + int index = 0; + int prevIndex; + char c; + + // get std + do + c = sysTimeZoneId.charAt(index++); + while (c != '+' && c != '-' && c != ',' && c != ':' + && ! Character.isDigit(c) && c != '\0' && index < idLength); + + if (index >= idLength) + return (TimeZone)timezones().get(sysTimeZoneId); + + stdName = sysTimeZoneId.substring(0, --index); + prevIndex = index; + + // get the std offset + do + c = sysTimeZoneId.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 = sysTimeZoneId.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) + { + // Do we have an existing timezone with that name and offset? + TimeZone tz = (TimeZone) timezones().get(stdName); + if (tz != null) + if (tz.getRawOffset() == stdOffs) + return tz; + + // Custom then. + return new SimpleTimeZone(stdOffs, stdName); + } + + // get dst + do + c = sysTimeZoneId.charAt(index++); + while (c != '+' && c != '-' && c != ',' && c != ':' + && ! Character.isDigit(c) && c != '\0' && index < idLength); + + // Done yet? (Format: std offset dst) + if (index >= idLength) + { + // Do we have an existing timezone with that name and offset + // which has DST? + TimeZone tz = (TimeZone) timezones().get(stdName); + if (tz != null) + if (tz.getRawOffset() == stdOffs && tz.useDaylightTime()) + return tz; + + // Custom then. + return new SimpleTimeZone(stdOffs, stdName); + } + + // get the dst offset + dstName = sysTimeZoneId.substring(prevIndex, --index); + prevIndex = index; + do + c = sysTimeZoneId.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 = sysTimeZoneId.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) + // FIXME: We don't support DST without a rule given. Should we? + if (index >= idLength) + { + // Time Zone existing with same name, dst and offsets? + TimeZone tz = (TimeZone) timezones().get(stdName); + if (tz != null) + if (tz.getRawOffset() == stdOffs && tz.useDaylightTime() + && tz.getDSTSavings() == (dstOffs - stdOffs)) + return tz; + + return new SimpleTimeZone(stdOffs, stdName); + } + + // get the DST rule + if (sysTimeZoneId.charAt(index) == ',' + || sysTimeZoneId.charAt(index) == ';') + { + index++; + int offs = index; + while (sysTimeZoneId.charAt(index) != ',' + && sysTimeZoneId.charAt(index) != ';') + index++; + String startTime = sysTimeZoneId.substring(offs, index); + index++; + String endTime = sysTimeZoneId.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, stdName, start[0], start[1], + start[2], startMillis, end[0], end[1], + end[2], endMillis, (dstOffs - stdOffs)); + } + } + + // FIXME: Produce a warning here? + 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; + + if (date.charAt(0) == 'M' || date.charAt(0) == 'm') + { + int day; + + // Month, week of month, day of week + 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)); + 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. + day = (week - 1) * 7 + 1; + + dayOfWeek++; // Java day of week is one-based, Sunday is first day. + 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++; + if (i >= time.length()) + return millis; + + millis += 60 * 1000 * Integer.parseInt(time.substring(iprev, i)); + millis += 1000 * Integer.parseInt(time.substring(++i)); + return millis; + } + + /** + * 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. + * @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 + * @param milliseconds the millis in the day (in local standard time) + * @return the time zone offset in milliseconds. + */ + public abstract int getOffset(int era, int year, int month, + int day, int dayOfWeek, int milliseconds); + + /** + * 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. + * @since 1.4 + */ + public int getOffset(long date) + { + return (inDaylightTime(new Date(date)) + ? getRawOffset() + getDSTSavings() + : getRawOffset()); + } + + /** + * Gets the time zone offset, ignoring daylight savings. This is + * the offset to add to UTC to get the local time. + * @return the time zone offset in milliseconds. + */ + public abstract int getRawOffset(); + + /** + * Sets the time zone offset, ignoring daylight savings. This is + * the offset to add to UTC to get the local time. + * @param offsetMillis the time zone offset to GMT. + */ + public abstract void setRawOffset(int offsetMillis); + + /** + * Gets the identifier of this time zone. For instance, PST for + * Pacific Standard Time. + * @returns the ID of this time zone. + */ + public String getID() + { + return ID; + } + + /** + * Sets the identifier of this time zone. For instance, PST for + * Pacific Standard Time. + * @param id the new time zone ID. + * @throws NullPointerException if id is null + */ + public void setID(String id) + { + if (id == null) + throw new NullPointerException(); + + this.ID = id; + } + + /** + * This method returns a string name of the time zone suitable + * for displaying to the user. The string returned will be the long + * description of the timezone in the current locale. The name + * displayed will assume daylight savings time is not in effect. + * + * @return The name of the time zone. + */ + public final String getDisplayName() + { + return (getDisplayName(false, LONG, Locale.getDefault())); + } + + /** + * This method returns a string name of the time zone suitable + * for displaying to the user. The string returned will be the long + * description of the timezone in the specified locale. The name + * displayed will assume daylight savings time is not in effect. + * + * @param locale The locale for this timezone name. + * + * @return The name of the time zone. + */ + public final String getDisplayName(Locale locale) + { + return (getDisplayName(false, LONG, locale)); + } + + /** + * This method returns a string name of the time zone suitable + * for displaying to the user. The string returned will be of the + * specified type in the current locale. + * + * @param dst Whether or not daylight savings time is in effect. + * @param style LONG for a long name, SHORT for + * a short abbreviation. + * + * @return The name of the time zone. + */ + public final String getDisplayName(boolean dst, int style) + { + return (getDisplayName(dst, style, Locale.getDefault())); + } + + + /** + * This method returns a string name of the time zone suitable + * for displaying to the user. The string returned will be of the + * specified type in the specified locale. + * + * @param dst Whether or not daylight savings time is in effect. + * @param style LONG for a long name, SHORT for + * a short abbreviation. + * @param locale The locale for this timezone name. + * + * @return The name of the time zone. + */ + public String getDisplayName(boolean dst, int style, Locale locale) + { + DateFormatSymbols dfs; + try + { + dfs = new DateFormatSymbols(locale); + + // The format of the value returned is defined by us. + String[][]zoneinfo = dfs.getZoneStrings(); + for (int i = 0; i < zoneinfo.length; i++) + { + if (zoneinfo[i][0].equals(getID())) + { + if (!dst) + { + if (style == SHORT) + return (zoneinfo[i][2]); + else + return (zoneinfo[i][1]); + } + else + { + if (style == SHORT) + return (zoneinfo[i][4]); + else + return (zoneinfo[i][3]); + } + } + } + } + catch (MissingResourceException e) + { + } + + return getDefaultDisplayName(dst); + } + + private String getDefaultDisplayName(boolean dst) + { + int offset = getRawOffset(); + if (dst && this instanceof SimpleTimeZone) + { + // ugly, but this is a design failure of the API: + // getDisplayName takes a dst parameter even though + // TimeZone knows nothing about daylight saving offsets. + offset += ((SimpleTimeZone) this).getDSTSavings(); + } + + StringBuffer sb = new StringBuffer(9); + sb.append("GMT"); + + offset = offset / (1000 * 60); + int hours = Math.abs(offset) / 60; + int minutes = Math.abs(offset) % 60; + + if (minutes != 0 || hours != 0) + { + sb.append(offset >= 0 ? '+' : '-'); + sb.append((char) ('0' + hours / 10)); + sb.append((char) ('0' + hours % 10)); + sb.append(':'); + sb.append((char) ('0' + minutes / 10)); + sb.append((char) ('0' + minutes % 10)); + } + + return sb.toString(); + } + + /** + * Returns true, if this time zone uses Daylight Savings Time. + */ + public abstract boolean useDaylightTime(); + + /** + * Returns true, if the given date is in Daylight Savings Time in this + * time zone. + * @param date the given Date. + */ + public abstract boolean inDaylightTime(Date date); + + /** + * 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. + *

    The default implementation returns 3600000 milliseconds + * (one hour) if the time zone uses daylight savings time + * (as specified by {@link #useDaylightTime()}), otherwise + * it returns 0. + * @return the daylight savings offset in milliseconds. + * @since 1.4 + */ + public int getDSTSavings () + { + return useDaylightTime () ? 3600000 : 0; + } + + /** + * Gets the TimeZone for the given ID. + * @param ID the time zone identifier. + * @return The time zone for the identifier or GMT, if no such time + * zone exists. + */ + // FIXME: XXX: JCL indicates this and other methods are synchronized. + public static TimeZone getTimeZone(String ID) + { + // First check timezones hash + TimeZone tz = (TimeZone) timezones().get(ID); + if (tz != null) + { + if (tz.getID().equals(ID)) + return tz; + + // We always return a timezone with the requested ID. + // This is the same behaviour as with JDK1.2. + tz = (TimeZone) tz.clone(); + tz.setID(ID); + // We also save the alias, so that we return the same + // object again if getTimeZone is called with the same + // alias. + timezones().put(ID, tz); + return tz; + } + + // See if the ID is really a GMT offset form. + // Note that GMT is in the table so we know it is different. + if (ID.startsWith("GMT")) + { + int pos = 3; + int offset_direction = 1; + + if (ID.charAt(pos) == '-') + { + offset_direction = -1; + pos++; + } + else if (ID.charAt(pos) == '+') + { + pos++; + } + + try + { + int hour, minute; + + String offset_str = ID.substring(pos); + int idx = offset_str.indexOf(":"); + if (idx != -1) + { + hour = Integer.parseInt(offset_str.substring(0, idx)); + minute = Integer.parseInt(offset_str.substring(idx + 1)); + } + else + { + int offset_length = offset_str.length(); + if (offset_length <= 2) + { + // Only hour + hour = Integer.parseInt(offset_str); + minute = 0; + } + else + { + // hour and minute, not separated by colon + hour = Integer.parseInt + (offset_str.substring(0, offset_length - 2)); + minute = Integer.parseInt + (offset_str.substring(offset_length - 2)); + } + } + + return new SimpleTimeZone((hour * (60 * 60 * 1000) + + minute * (60 * 1000)) + * offset_direction, ID); + } + catch (NumberFormatException e) + { + } + } + + // Finally, return GMT per spec + return getTimeZone("GMT"); + } + + /** + * Gets the available IDs according to the given time zone + * offset. + * @param rawOffset the given time zone GMT offset. + * @return An array of IDs, where the time zone has the specified GMT + * offset. For example {"Phoenix", "Denver"}, since both have + * GMT-07:00, but differ in daylight savings behaviour. + */ + public static String[] getAvailableIDs(int rawOffset) + { + int count = 0; + Iterator iter = timezones().entrySet().iterator(); + while (iter.hasNext()) + { + // Don't iterate the values, since we want to count + // doubled values (aliases) + Map.Entry entry = (Map.Entry) iter.next(); + if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset) + count++; + } + + String[] ids = new String[count]; + count = 0; + iter = timezones().entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry entry = (Map.Entry) iter.next(); + if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset) + ids[count++] = (String) entry.getKey(); + } + return ids; + } + + /** + * Gets all available IDs. + * @return An array of all supported IDs. + */ + public static String[] getAvailableIDs() + { + return (String[]) + timezones().keySet().toArray(new String[timezones().size()]); + } + + /** + * Returns the time zone under which the host is running. This + * can be changed with setDefault. + * + * @return A clone of the current default time zone for this host. + * @see #setDefault + */ + public static TimeZone getDefault() + { + return (TimeZone) defaultZone().clone(); + } + + public static void setDefault(TimeZone zone) + { + // Hmmmm. No Security checks? + defaultZone0 = zone; + } + + /** + * 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 raw offsets are identical. Subclasses + * should override this method if they use daylight savings. + * @return true if this zone has the same raw offset + */ + public boolean hasSameRules(TimeZone other) + { + return other.getRawOffset() == getRawOffset(); + } + + /** + * Returns a clone of this object. I can't imagine, why this is + * useful for a time zone. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException ex) + { + return null; + } + } +} diff --git a/libjava/classpath/java/util/Timer.java b/libjava/classpath/java/util/Timer.java new file mode 100644 index 0000000..715f06c --- /dev/null +++ b/libjava/classpath/java/util/Timer.java @@ -0,0 +1,615 @@ +/* Timer.java -- Timer that runs TimerTasks at a later time. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util; + +/** + * Timer that can run TimerTasks at a later time. + * TimerTasks can be scheduled for one time execution at some time in the + * future. They can be scheduled to be rescheduled at a time period after the + * task was last executed. Or they can be scheduled to be executed repeatedly + * at a fixed rate. + *

    + * The normal scheduling will result in a more or less even delay in time + * between successive executions, but the executions could drift in time if + * the task (or other tasks) takes a long time to execute. Fixed delay + * scheduling guarantees more or less that the task will be executed at a + * specific time, but if there is ever a delay in execution then the period + * between successive executions will be shorter. The first method of + * repeated scheduling is preferred for repeated tasks in response to user + * interaction, the second method of repeated scheduling is preferred for tasks + * that act like alarms. + *

    + * The Timer keeps a binary heap as a task priority queue which means that + * scheduling and serving of a task in a queue of n tasks costs O(log n). + * + * @see TimerTask + * @since 1.3 + * @author Mark Wielaard (mark@klomp.org) + */ +public class Timer +{ + /** + * Priority Task Queue. + * TimerTasks are kept in a binary heap. + * The scheduler calls sleep() on the queue when it has nothing to do or + * has to wait. A sleeping scheduler can be notified by calling interrupt() + * which is automatically called by the enqueue(), cancel() and + * timerFinalized() methods. + */ + private static final class TaskQueue + { + /** Default size of this queue */ + private static final int DEFAULT_SIZE = 32; + + /** Whether to return null when there is nothing in the queue */ + private boolean nullOnEmpty; + + /** + * The heap containing all the scheduled TimerTasks + * sorted by the TimerTask.scheduled field. + * Null when the stop() method has been called. + */ + private TimerTask heap[]; + + /** + * The actual number of elements in the heap + * Can be less then heap.length. + * Note that heap[0] is used as a sentinel. + */ + private int elements; + + /** + * Creates a TaskQueue of default size without any elements in it. + */ + public TaskQueue() + { + heap = new TimerTask[DEFAULT_SIZE]; + elements = 0; + nullOnEmpty = false; + } + + /** + * Adds a TimerTask at the end of the heap. + * Grows the heap if necessary by doubling the heap in size. + */ + private void add(TimerTask task) + { + elements++; + if (elements == heap.length) + { + TimerTask new_heap[] = new TimerTask[heap.length * 2]; + System.arraycopy(heap, 0, new_heap, 0, heap.length); + heap = new_heap; + } + heap[elements] = task; + } + + /** + * Removes the last element from the heap. + * Shrinks the heap in half if + * elements+DEFAULT_SIZE/2 <= heap.length/4. + */ + private void remove() + { + // clear the entry first + heap[elements] = null; + elements--; + if (elements + DEFAULT_SIZE / 2 <= (heap.length / 4)) + { + TimerTask new_heap[] = new TimerTask[heap.length / 2]; + System.arraycopy(heap, 0, new_heap, 0, elements + 1); + heap = new_heap; + } + } + + /** + * Adds a task to the queue and puts it at the correct place + * in the heap. + */ + public synchronized void enqueue(TimerTask task) + { + // Check if it is legal to add another element + if (heap == null) + { + throw new IllegalStateException + ("cannot enqueue when stop() has been called on queue"); + } + + heap[0] = task; // sentinel + add(task); // put the new task at the end + // Now push the task up in the heap until it has reached its place + int child = elements; + int parent = child / 2; + while (heap[parent].scheduled > task.scheduled) + { + heap[child] = heap[parent]; + child = parent; + parent = child / 2; + } + // This is the correct place for the new task + heap[child] = task; + heap[0] = null; // clear sentinel + // Maybe sched() is waiting for a new element + this.notify(); + } + + /** + * Returns the top element of the queue. + * Can return null when no task is in the queue. + */ + private TimerTask top() + { + if (elements == 0) + { + return null; + } + else + { + return heap[1]; + } + } + + /** + * Returns the top task in the Queue. + * Removes the element from the heap and reorders the heap first. + * Can return null when there is nothing in the queue. + */ + public synchronized TimerTask serve() + { + // The task to return + TimerTask task = null; + + while (task == null) + { + // Get the next task + task = top(); + + // return null when asked to stop + // or if asked to return null when the queue is empty + if ((heap == null) || (task == null && nullOnEmpty)) + { + return null; + } + + // Do we have a task? + if (task != null) + { + // The time to wait until the task should be served + long time = task.scheduled - System.currentTimeMillis(); + if (time > 0) + { + // This task should not yet be served + // So wait until this task is ready + // or something else happens to the queue + task = null; // set to null to make sure we call top() + try + { + this.wait(time); + } + catch (InterruptedException _) + { + } + } + } + else + { + // wait until a task is added + // or something else happens to the queue + try + { + this.wait(); + } + catch (InterruptedException _) + { + } + } + } + + // reconstruct the heap + TimerTask lastTask = heap[elements]; + remove(); + + // drop lastTask at the beginning and move it down the heap + int parent = 1; + int child = 2; + heap[1] = lastTask; + while (child <= elements) + { + if (child < elements) + { + if (heap[child].scheduled > heap[child + 1].scheduled) + { + child++; + } + } + + if (lastTask.scheduled <= heap[child].scheduled) + break; // found the correct place (the parent) - done + + heap[parent] = heap[child]; + parent = child; + child = parent * 2; + } + + // this is the correct new place for the lastTask + heap[parent] = lastTask; + + // return the task + return task; + } + + /** + * When nullOnEmpty is true the serve() method will return null when + * there are no tasks in the queue, otherwise it will wait until + * a new element is added to the queue. It is used to indicate to + * the scheduler that no new tasks will ever be added to the queue. + */ + public synchronized void setNullOnEmpty(boolean nullOnEmpty) + { + this.nullOnEmpty = nullOnEmpty; + this.notify(); + } + + /** + * When this method is called the current and all future calls to + * serve() will return null. It is used to indicate to the Scheduler + * that it should stop executing since no more tasks will come. + */ + public synchronized void stop() + { + this.heap = null; + this.elements = 0; + this.notify(); + } + + } // TaskQueue + + /** + * The scheduler that executes all the tasks on a particular TaskQueue, + * reschedules any repeating tasks and that waits when no task has to be + * executed immediatly. Stops running when canceled or when the parent + * Timer has been finalized and no more tasks have to be executed. + */ + private static final class Scheduler implements Runnable + { + // The priority queue containing all the TimerTasks. + private TaskQueue queue; + + /** + * Creates a new Scheduler that will schedule the tasks on the + * given TaskQueue. + */ + public Scheduler(TaskQueue queue) + { + this.queue = queue; + } + + public void run() + { + TimerTask task; + while ((task = queue.serve()) != null) + { + // If this task has not been canceled + if (task.scheduled >= 0) + { + + // Mark execution time + task.lastExecutionTime = task.scheduled; + + // Repeatable task? + if (task.period < 0) + { + // Last time this task is executed + task.scheduled = -1; + } + + // Run the task + try + { + task.run(); + } + catch (ThreadDeath death) + { + // If an exception escapes, the Timer becomes invalid. + queue.stop(); + throw death; + } + catch (Throwable t) + { + // If an exception escapes, the Timer becomes invalid. + queue.stop(); + } + } + + // Calculate next time and possibly re-enqueue. + if (task.scheduled >= 0) + { + if (task.fixed) + { + task.scheduled += task.period; + } + else + { + task.scheduled = task.period + System.currentTimeMillis(); + } + + try + { + queue.enqueue(task); + } + catch (IllegalStateException ise) + { + // Ignore. Apparently the Timer queue has been stopped. + } + } + } + } + } // Scheduler + + // Number of Timers created. + // Used for creating nice Thread names. + private static int nr; + + // The queue that all the tasks are put in. + // Given to the scheduler + private TaskQueue queue; + + // The Scheduler that does all the real work + private Scheduler scheduler; + + // Used to run the scheduler. + // Also used to checked if the Thread is still running by calling + // thread.isAlive(). Sometimes a Thread is suddenly killed by the system + // (if it belonged to an Applet). + private Thread thread; + + // When cancelled we don't accept any more TimerTasks. + private boolean canceled; + + /** + * Creates a new Timer with a non daemon Thread as Scheduler, with normal + * priority and a default name. + */ + public Timer() + { + this(false); + } + + /** + * Creates a new Timer with a daemon Thread as scheduler if daemon is true, + * with normal priority and a default name. + */ + public Timer(boolean daemon) + { + this(daemon, Thread.NORM_PRIORITY); + } + + /** + * Creates a new Timer with a daemon Thread as scheduler if daemon is true, + * with the priority given and a default name. + */ + private Timer(boolean daemon, int priority) + { + this(daemon, priority, "Timer-" + (++nr)); + } + + /** + * Creates a new Timer with a daemon Thread as scheduler if daemon is true, + * with the priority and name given.E + */ + private Timer(boolean daemon, int priority, String name) + { + canceled = false; + queue = new TaskQueue(); + scheduler = new Scheduler(queue); + thread = new Thread(scheduler, name); + thread.setDaemon(daemon); + thread.setPriority(priority); + thread.start(); + } + + /** + * Cancels the execution of the scheduler. If a task is executing it will + * normally finish execution, but no other tasks will be executed and no + * more tasks can be scheduled. + */ + public void cancel() + { + canceled = true; + queue.stop(); + } + + /** + * Schedules the task at Time time, repeating every period + * milliseconds if period is positive and at a fixed rate if fixed is true. + * + * @exception IllegalArgumentException if time is negative + * @exception IllegalStateException if the task was already scheduled or + * canceled or this Timer is canceled or the scheduler thread has died + */ + private void schedule(TimerTask task, long time, long period, boolean fixed) + { + if (time < 0) + throw new IllegalArgumentException("negative time"); + + if (task.scheduled == 0 && task.lastExecutionTime == -1) + { + task.scheduled = time; + task.period = period; + task.fixed = fixed; + } + else + { + throw new IllegalStateException + ("task was already scheduled or canceled"); + } + + if (!this.canceled && this.thread != null) + { + queue.enqueue(task); + } + else + { + throw new IllegalStateException + ("timer was canceled or scheduler thread has died"); + } + } + + private static void positiveDelay(long delay) + { + if (delay < 0) + { + throw new IllegalArgumentException("delay is negative"); + } + } + + private static void positivePeriod(long period) + { + if (period < 0) + { + throw new IllegalArgumentException("period is negative"); + } + } + + /** + * Schedules the task at the specified data for one time execution. + * + * @exception IllegalArgumentException if date.getTime() is negative + * @exception IllegalStateException if the task was already scheduled or + * canceled or this Timer is canceled or the scheduler thread has died + */ + public void schedule(TimerTask task, Date date) + { + long time = date.getTime(); + schedule(task, time, -1, false); + } + + /** + * Schedules the task at the specified date and reschedules the task every + * period milliseconds after the last execution of the task finishes until + * this timer or the task is canceled. + * + * @exception IllegalArgumentException if period or date.getTime() is + * negative + * @exception IllegalStateException if the task was already scheduled or + * canceled or this Timer is canceled or the scheduler thread has died + */ + public void schedule(TimerTask task, Date date, long period) + { + positivePeriod(period); + long time = date.getTime(); + schedule(task, time, period, false); + } + + /** + * Schedules the task after the specified delay milliseconds for one time + * execution. + * + * @exception IllegalArgumentException if delay or + * System.currentTimeMillis + delay is negative + * @exception IllegalStateException if the task was already scheduled or + * canceled or this Timer is canceled or the scheduler thread has died + */ + public void schedule(TimerTask task, long delay) + { + positiveDelay(delay); + long time = System.currentTimeMillis() + delay; + schedule(task, time, -1, false); + } + + /** + * Schedules the task after the delay milliseconds and reschedules the + * task every period milliseconds after the last execution of the task + * finishes until this timer or the task is canceled. + * + * @exception IllegalArgumentException if delay or period is negative + * @exception IllegalStateException if the task was already scheduled or + * canceled or this Timer is canceled or the scheduler thread has died + */ + public void schedule(TimerTask task, long delay, long period) + { + positiveDelay(delay); + positivePeriod(period); + long time = System.currentTimeMillis() + delay; + schedule(task, time, period, false); + } + + /** + * Schedules the task at the specified date and reschedules the task at a + * fixed rate every period milliseconds until this timer or the task is + * canceled. + * + * @exception IllegalArgumentException if period or date.getTime() is + * negative + * @exception IllegalStateException if the task was already scheduled or + * canceled or this Timer is canceled or the scheduler thread has died + */ + public void scheduleAtFixedRate(TimerTask task, Date date, long period) + { + positivePeriod(period); + long time = date.getTime(); + schedule(task, time, period, true); + } + + /** + * Schedules the task after the delay milliseconds and reschedules the task + * at a fixed rate every period milliseconds until this timer or the task + * is canceled. + * + * @exception IllegalArgumentException if delay or + * System.currentTimeMillis + delay is negative + * @exception IllegalStateException if the task was already scheduled or + * canceled or this Timer is canceled or the scheduler thread has died + */ + public void scheduleAtFixedRate(TimerTask task, long delay, long period) + { + positiveDelay(delay); + positivePeriod(period); + long time = System.currentTimeMillis() + delay; + schedule(task, time, period, true); + } + + /** + * Tells the scheduler that the Timer task died + * so there will be no more new tasks scheduled. + */ + protected void finalize() throws Throwable + { + queue.setNullOnEmpty(true); + } +} diff --git a/libjava/classpath/java/util/TimerTask.java b/libjava/classpath/java/util/TimerTask.java new file mode 100644 index 0000000..b03118a --- /dev/null +++ b/libjava/classpath/java/util/TimerTask.java @@ -0,0 +1,145 @@ +/* TimerTask.java -- Task that can be run at a later time if given to a Timer. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util; + +/** + * Task that can be run at a later time if given to a Timer. + * The TimerTask must implement a run method that will be called by the + * Timer when the task is scheduled for execution. The task can check when + * it should have been scheduled and cancel itself when no longer needed. + *

    + * Example: + *

    + *  Timer timer = new Timer();
    + *  TimerTask task = new TimerTask() {
    + *      public void run() {
    + *      if (this.scheduledExecutionTime() < System.currentTimeMillis() + 500)
    + *          // Do something
    + *      else
    + *          // Complain: We are more then half a second late!
    + *      if (someStopCondition)
    + *          this.cancel(); // This was our last execution
    + *  };
    + *  timer.scheduleAtFixedRate(task, 1000, 1000); // schedule every second
    + * 
    + *

    + * Note that a TimerTask object is a one shot object and can only given once + * to a Timer. (The Timer will use the TimerTask object for bookkeeping, + * in this implementation). + *

    + * This class also implements Runnable to make it possible to + * give a TimerTask directly as a target to a Thread. + * + * @see Timer + * @since 1.3 + * @author Mark Wielaard (mark@klomp.org) + */ +public abstract class TimerTask implements Runnable +{ + /** + * If positive the next time this task should be run. + * If negative this TimerTask is canceled or executed for the last time. + */ + long scheduled; + + /** + * If positive the last time this task was run. + * If negative this TimerTask has not yet been scheduled. + */ + long lastExecutionTime; + + /** + * If positive the number of milliseconds between runs of this task. + * If -1 this task doesn't have to be run more then once. + */ + long period; + + /** + * If true the next time this task should be run is relative to + * the last scheduled time, otherwise it can drift in time. + */ + boolean fixed; + + /** + * Creates a TimerTask and marks it as not yet scheduled. + */ + protected TimerTask() + { + this.scheduled = 0; + this.lastExecutionTime = -1; + } + + /** + * Marks the task as canceled and prevents any further execution. + * Returns true if the task was scheduled for any execution in the future + * and this cancel operation prevents that execution from happening. + *

    + * A task that has been canceled can never be scheduled again. + *

    + * In this implementation the TimerTask it is possible that the Timer does + * keep a reference to the TimerTask until the first time the TimerTask + * is actually scheduled. But the reference will disappear immediatly when + * cancel is called from within the TimerTask run method. + */ + public boolean cancel() + { + boolean prevented_execution = (this.scheduled >= 0); + this.scheduled = -1; + return prevented_execution; + } + + /** + * Method that is called when this task is scheduled for execution. + */ + public abstract void run(); + + /** + * Returns the last time this task was scheduled or (when called by the + * task from the run method) the time the current execution of the task + * was scheduled. When the task has not yet run the return value is + * undefined. + *

    + * Can be used (when the task is scheduled at fixed rate) to see the + * difference between the requested schedule time and the actual time + * that can be found with System.currentTimeMillis(). + */ + public long scheduledExecutionTime() + { + return lastExecutionTime; + } +} diff --git a/libjava/classpath/java/util/TooManyListenersException.java b/libjava/classpath/java/util/TooManyListenersException.java new file mode 100644 index 0000000..92ad772 --- /dev/null +++ b/libjava/classpath/java/util/TooManyListenersException.java @@ -0,0 +1,78 @@ +/* TooManyListenersException.java -- thrown when a unicast event can't accept + another Listener + Copyright (C) 1998, 1999, 2001, 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 java.util; + +/** + * This exception is part of the java event model. It is thrown if an + * event listener is added via the addXyzEventListener method, but the + * object doesn't support any more listeners, e.g. it only supports a + * single event listener. + * + * @author Jochen Hoenicke + * @author Warren Levy (warrenl@cygnus.com) + * @see EventListener + * @see EventObject + * @since 1.1 + * @status updated to 1.4 + */ +public class TooManyListenersException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5074640544770687831L; + + /** + * Constructs a TooManyListenersException with no detail message. + */ + public TooManyListenersException() + { + } + + /** + * Constructs a TooManyListenersException with a detail message. + * + * @param detail the detail message + */ + public TooManyListenersException(String detail) + { + super(detail); + } +} diff --git a/libjava/classpath/java/util/TreeMap.java b/libjava/classpath/java/util/TreeMap.java new file mode 100644 index 0000000..1e8c805 --- /dev/null +++ b/libjava/classpath/java/util/TreeMap.java @@ -0,0 +1,1781 @@ +/* TreeMap.java -- a class providing a basic Red-Black Tree data structure, + mapping Object --> Object + Copyright (C) 1998, 1999, 2000, 2001, 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 java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * This class provides a red-black tree implementation of the SortedMap + * interface. Elements in the Map will be sorted by either a user-provided + * Comparator object, or by the natural ordering of the keys. + * + * The algorithms are adopted from Corman, Leiserson, and Rivest's + * Introduction to Algorithms. TreeMap guarantees O(log n) + * insertion and deletion of elements. That being said, there is a large + * enough constant coefficient in front of that "log n" (overhead involved + * in keeping the tree balanced), that TreeMap may not be the best choice + * for small collections. If something is already sorted, you may want to + * just use a LinkedHashMap to maintain the order while providing O(1) access. + * + * TreeMap is a part of the JDK1.2 Collections API. Null keys are allowed + * only if a Comparator is used which can deal with them; natural ordering + * cannot cope with null. Null values are always allowed. Note that the + * ordering must be consistent with equals to correctly implement + * the Map interface. If this condition is violated, the map is still + * well-behaved, but you may have suprising results when comparing it to + * other maps.

    + * + * This implementation is not synchronized. If you need to share this between + * multiple threads, do something like:
    + * SortedMap m + * = Collections.synchronizedSortedMap(new TreeMap(...));

    + * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * ConcurrentModificationException rather than exhibit + * non-deterministic behavior. + * + * @author Jon Zeppieri + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Map + * @see HashMap + * @see Hashtable + * @see LinkedHashMap + * @see Comparable + * @see Comparator + * @see Collection + * @see Collections#synchronizedSortedMap(SortedMap) + * @since 1.2 + * @status updated to 1.4 + */ +public class TreeMap extends AbstractMap + implements SortedMap, Cloneable, Serializable +{ + // Implementation note: + // A red-black tree is a binary search tree with the additional properties + // that all paths to a leaf node visit the same number of black nodes, + // and no red node has red children. To avoid some null-pointer checks, + // we use the special node nil which is always black, has no relatives, + // and has key and value of null (but is not equal to a mapping of null). + + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = 919286545866124006L; + + /** + * Color status of a node. Package visible for use by nested classes. + */ + static final int RED = -1, + BLACK = 1; + + /** + * Sentinal node, used to avoid null checks for corner cases and make the + * delete rebalance code simpler. The rebalance code must never assign + * the parent, left, or right of nil, but may safely reassign the color + * to be black. This object must never be used as a key in a TreeMap, or + * it will break bounds checking of a SubMap. + */ + static final Node nil = new Node(null, null, BLACK); + static + { + // Nil is self-referential, so we must initialize it after creation. + nil.parent = nil; + nil.left = nil; + nil.right = nil; + } + + /** + * The root node of this TreeMap. + */ + private transient Node root; + + /** + * The size of this TreeMap. Package visible for use by nested classes. + */ + transient int size; + + /** + * The cache for {@link #entrySet()}. + */ + private transient Set entries; + + /** + * Counts the number of modifications this TreeMap has undergone, used + * by Iterators to know when to throw ConcurrentModificationExceptions. + * Package visible for use by nested classes. + */ + transient int modCount; + + /** + * This TreeMap's comparator, or null for natural ordering. + * Package visible for use by nested classes. + * @serial the comparator ordering this tree, or null + */ + final Comparator comparator; + + /** + * Class to represent an entry in the tree. Holds a single key-value pair, + * plus pointers to parent and child nodes. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class Node extends AbstractMap.BasicMapEntry + { + // All fields package visible for use by nested classes. + /** The color of this node. */ + int color; + + /** The left child node. */ + Node left = nil; + /** The right child node. */ + Node right = nil; + /** The parent node. */ + Node parent = nil; + + /** + * Simple constructor. + * @param key the key + * @param value the value + */ + Node(Object key, Object value, int color) + { + super(key, value); + this.color = color; + } + } + + /** + * Instantiate a new TreeMap with no elements, using the keys' natural + * ordering to sort. All entries in the map must have a key which implements + * Comparable, and which are mutually comparable, otherwise map + * operations may throw a {@link ClassCastException}. Attempts to use + * a null key will throw a {@link NullPointerException}. + * + * @see Comparable + */ + public TreeMap() + { + this((Comparator) null); + } + + /** + * Instantiate a new TreeMap with no elements, using the provided comparator + * to sort. All entries in the map must have keys which are mutually + * comparable by the Comparator, otherwise map operations may throw a + * {@link ClassCastException}. + * + * @param c the sort order for the keys of this map, or null + * for the natural order + */ + public TreeMap(Comparator c) + { + comparator = c; + fabricateTree(0); + } + + /** + * Instantiate a new TreeMap, initializing it with all of the elements in + * the provided Map. The elements will be sorted using the natural + * ordering of the keys. This algorithm runs in n*log(n) time. All entries + * in the map must have keys which implement Comparable and are mutually + * comparable, otherwise map operations may throw a + * {@link ClassCastException}. + * + * @param map a Map, whose entries will be put into this TreeMap + * @throws ClassCastException if the keys in the provided Map are not + * comparable + * @throws NullPointerException if map is null + * @see Comparable + */ + public TreeMap(Map map) + { + this((Comparator) null); + putAll(map); + } + + /** + * Instantiate a new TreeMap, initializing it with all of the elements in + * the provided SortedMap. The elements will be sorted using the same + * comparator as in the provided SortedMap. This runs in linear time. + * + * @param sm a SortedMap, whose entries will be put into this TreeMap + * @throws NullPointerException if sm is null + */ + public TreeMap(SortedMap sm) + { + this(sm.comparator()); + int pos = sm.size(); + Iterator itr = sm.entrySet().iterator(); + + fabricateTree(pos); + Node node = firstNode(); + + while (--pos >= 0) + { + Map.Entry me = (Map.Entry) itr.next(); + node.key = me.getKey(); + node.value = me.getValue(); + node = successor(node); + } + } + + /** + * Clears the Map so it has no keys. This is O(1). + */ + public void clear() + { + if (size > 0) + { + modCount++; + root = nil; + size = 0; + } + } + + /** + * Returns a shallow clone of this TreeMap. The Map itself is cloned, + * but its contents are not. + * + * @return the clone + */ + public Object clone() + { + TreeMap copy = null; + try + { + copy = (TreeMap) super.clone(); + } + catch (CloneNotSupportedException x) + { + } + copy.entries = null; + copy.fabricateTree(size); + + Node node = firstNode(); + Node cnode = copy.firstNode(); + + while (node != nil) + { + cnode.key = node.key; + cnode.value = node.value; + node = successor(node); + cnode = copy.successor(cnode); + } + return copy; + } + + /** + * Return the comparator used to sort this map, or null if it is by + * natural order. + * + * @return the map's comparator + */ + public Comparator comparator() + { + return comparator; + } + + /** + * Returns true if the map contains a mapping for the given key. + * + * @param key the key to look for + * @return true if the key has a mapping + * @throws ClassCastException if key is not comparable to map elements + * @throws NullPointerException if key is null and the comparator is not + * tolerant of nulls + */ + public boolean containsKey(Object key) + { + return getNode(key) != nil; + } + + /** + * Returns true if the map contains at least one mapping to the given value. + * This requires linear time. + * + * @param value the value to look for + * @return true if the value appears in a mapping + */ + public boolean containsValue(Object value) + { + Node node = firstNode(); + while (node != nil) + { + if (equals(value, node.value)) + return true; + node = successor(node); + } + return false; + } + + /** + * Returns a "set view" of this TreeMap's entries. The set is backed by + * the TreeMap, so changes in one show up in the other. The set supports + * element removal, but not element addition.

    + * + * Note that the iterators for all three views, from keySet(), entrySet(), + * and values(), traverse the TreeMap in sorted sequence. + * + * @return a set view of the entries + * @see #keySet() + * @see #values() + * @see Map.Entry + */ + public Set entrySet() + { + if (entries == null) + // Create an AbstractSet with custom implementations of those methods + // that can be overriden easily and efficiently. + entries = new AbstractSet() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + return new TreeIterator(ENTRIES); + } + + public void clear() + { + TreeMap.this.clear(); + } + + public boolean contains(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Map.Entry me = (Map.Entry) o; + Node n = getNode(me.getKey()); + return n != nil && AbstractSet.equals(me.getValue(), n.value); + } + + public boolean remove(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Map.Entry me = (Map.Entry) o; + Node n = getNode(me.getKey()); + if (n != nil && AbstractSet.equals(me.getValue(), n.value)) + { + removeNode(n); + return true; + } + return false; + } + }; + return entries; + } + + /** + * Returns the first (lowest) key in the map. + * + * @return the first key + * @throws NoSuchElementException if the map is empty + */ + public Object firstKey() + { + if (root == nil) + throw new NoSuchElementException(); + return firstNode().key; + } + + /** + * Return the value in this TreeMap associated with the supplied key, + * or null if the key maps to nothing. NOTE: Since the value + * could also be null, you must use containsKey to see if this key + * actually maps to something. + * + * @param key the key for which to fetch an associated value + * @return what the key maps to, if present + * @throws ClassCastException if key is not comparable to elements in the map + * @throws NullPointerException if key is null but the comparator does not + * tolerate nulls + * @see #put(Object, Object) + * @see #containsKey(Object) + */ + public Object get(Object key) + { + // Exploit fact that nil.value == null. + return getNode(key).value; + } + + /** + * Returns a view of this Map including all entries with keys less than + * toKey. The returned map is backed by the original, so changes + * in one appear in the other. The submap will throw an + * {@link IllegalArgumentException} for any attempt to access or add an + * element beyond the specified cutoff. The returned map does not include + * the endpoint; if you want inclusion, pass the successor element. + * + * @param toKey the (exclusive) cutoff point + * @return a view of the map less than the cutoff + * @throws ClassCastException if toKey is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if toKey is null, but the comparator does not + * tolerate null elements + */ + public SortedMap headMap(Object toKey) + { + return new SubMap(nil, toKey); + } + + /** + * Returns a "set view" of this TreeMap's keys. The set is backed by the + * TreeMap, so changes in one show up in the other. The set supports + * element removal, but not element addition. + * + * @return a set view of the keys + * @see #values() + * @see #entrySet() + */ + public Set keySet() + { + if (keys == null) + // Create an AbstractSet with custom implementations of those methods + // that can be overriden easily and efficiently. + keys = new AbstractSet() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + return new TreeIterator(KEYS); + } + + public void clear() + { + TreeMap.this.clear(); + } + + public boolean contains(Object o) + { + return containsKey(o); + } + + public boolean remove(Object key) + { + Node n = getNode(key); + if (n == nil) + return false; + removeNode(n); + return true; + } + }; + return keys; + } + + /** + * Returns the last (highest) key in the map. + * + * @return the last key + * @throws NoSuchElementException if the map is empty + */ + public Object lastKey() + { + if (root == nil) + throw new NoSuchElementException("empty"); + return lastNode().key; + } + + /** + * Puts the supplied value into the Map, mapped by the supplied key. + * The value may be retrieved by any object which equals() + * this key. NOTE: Since the prior value could also be null, you must + * first use containsKey if you want to see if you are replacing the + * key's mapping. + * + * @param key the key used to locate the value + * @param value the value to be stored in the Map + * @return the prior mapping of the key, or null if there was none + * @throws ClassCastException if key is not comparable to current map keys + * @throws NullPointerException if key is null, but the comparator does + * not tolerate nulls + * @see #get(Object) + * @see Object#equals(Object) + */ + public Object put(Object key, Object value) + { + Node current = root; + Node parent = nil; + int comparison = 0; + + // Find new node's parent. + while (current != nil) + { + parent = current; + comparison = compare(key, current.key); + if (comparison > 0) + current = current.right; + else if (comparison < 0) + current = current.left; + else // Key already in tree. + return current.setValue(value); + } + + // Set up new node. + Node n = new Node(key, value, RED); + n.parent = parent; + + // Insert node in tree. + modCount++; + size++; + if (parent == nil) + { + // Special case inserting into an empty tree. + root = n; + return null; + } + if (comparison > 0) + parent.right = n; + else + parent.left = n; + + // Rebalance after insert. + insertFixup(n); + return null; + } + + /** + * Copies all elements of the given map into this TreeMap. If this map + * already has a mapping for a key, the new mapping replaces the current + * one. + * + * @param m the map to be added + * @throws ClassCastException if a key in m is not comparable with keys + * in the map + * @throws NullPointerException if a key in m is null, and the comparator + * does not tolerate nulls + */ + public void putAll(Map m) + { + Iterator itr = m.entrySet().iterator(); + int pos = m.size(); + while (--pos >= 0) + { + Map.Entry e = (Map.Entry) itr.next(); + put(e.getKey(), e.getValue()); + } + } + + /** + * Removes from the TreeMap and returns the value which is mapped by the + * supplied key. If the key maps to nothing, then the TreeMap remains + * unchanged, and null is returned. NOTE: Since the value + * could also be null, you must use containsKey to see if you are + * actually removing a mapping. + * + * @param key the key used to locate the value to remove + * @return whatever the key mapped to, if present + * @throws ClassCastException if key is not comparable to current map keys + * @throws NullPointerException if key is null, but the comparator does + * not tolerate nulls + */ + public Object remove(Object key) + { + Node n = getNode(key); + if (n == nil) + return null; + // Note: removeNode can alter the contents of n, so save value now. + Object result = n.value; + removeNode(n); + return result; + } + + /** + * Returns the number of key-value mappings currently in this Map. + * + * @return the size + */ + public int size() + { + return size; + } + + /** + * Returns a view of this Map including all entries with keys greater or + * equal to fromKey and less than toKey (a + * half-open interval). The returned map is backed by the original, so + * changes in one appear in the other. The submap will throw an + * {@link IllegalArgumentException} for any attempt to access or add an + * element beyond the specified cutoffs. The returned map includes the low + * endpoint but not the high; if you want to reverse this behavior on + * either end, pass in the successor element. + * + * @param fromKey the (inclusive) low cutoff point + * @param toKey the (exclusive) high cutoff point + * @return a view of the map between the cutoffs + * @throws ClassCastException if either cutoff is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if fromKey or toKey is null, but the + * comparator does not tolerate null elements + * @throws IllegalArgumentException if fromKey is greater than toKey + */ + public SortedMap subMap(Object fromKey, Object toKey) + { + return new SubMap(fromKey, toKey); + } + + /** + * Returns a view of this Map including all entries with keys greater or + * equal to fromKey. The returned map is backed by the + * original, so changes in one appear in the other. The submap will throw an + * {@link IllegalArgumentException} for any attempt to access or add an + * element beyond the specified cutoff. The returned map includes the + * endpoint; if you want to exclude it, pass in the successor element. + * + * @param fromKey the (inclusive) low cutoff point + * @return a view of the map above the cutoff + * @throws ClassCastException if fromKey is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if fromKey is null, but the comparator + * does not tolerate null elements + */ + public SortedMap tailMap(Object fromKey) + { + return new SubMap(fromKey, nil); + } + + /** + * Returns a "collection view" (or "bag view") of this TreeMap's values. + * The collection is backed by the TreeMap, so changes in one show up + * in the other. The collection supports element removal, but not element + * addition. + * + * @return a bag view of the values + * @see #keySet() + * @see #entrySet() + */ + public Collection values() + { + if (values == null) + // We don't bother overriding many of the optional methods, as doing so + // wouldn't provide any significant performance advantage. + values = new AbstractCollection() + { + public int size() + { + return size; + } + + public Iterator iterator() + { + return new TreeIterator(VALUES); + } + + public void clear() + { + TreeMap.this.clear(); + } + }; + return values; + } + + /** + * Compares two elements by the set comparator, or by natural ordering. + * Package visible for use by nested classes. + * + * @param o1 the first object + * @param o2 the second object + * @throws ClassCastException if o1 and o2 are not mutually comparable, + * or are not Comparable with natural ordering + * @throws NullPointerException if o1 or o2 is null with natural ordering + */ + final int compare(Object o1, Object o2) + { + return (comparator == null + ? ((Comparable) o1).compareTo(o2) + : comparator.compare(o1, o2)); + } + + /** + * Maintain red-black balance after deleting a node. + * + * @param node the child of the node just deleted, possibly nil + * @param parent the parent of the node just deleted, never nil + */ + private void deleteFixup(Node node, Node parent) + { + // if (parent == nil) + // throw new InternalError(); + // If a black node has been removed, we need to rebalance to avoid + // violating the "same number of black nodes on any path" rule. If + // node is red, we can simply recolor it black and all is well. + while (node != root && node.color == BLACK) + { + if (node == parent.left) + { + // Rebalance left side. + Node sibling = parent.right; + // if (sibling == nil) + // throw new InternalError(); + if (sibling.color == RED) + { + // Case 1: Sibling is red. + // Recolor sibling and parent, and rotate parent left. + sibling.color = BLACK; + parent.color = RED; + rotateLeft(parent); + sibling = parent.right; + } + + if (sibling.left.color == BLACK && sibling.right.color == BLACK) + { + // Case 2: Sibling has no red children. + // Recolor sibling, and move to parent. + sibling.color = RED; + node = parent; + parent = parent.parent; + } + else + { + if (sibling.right.color == BLACK) + { + // Case 3: Sibling has red left child. + // Recolor sibling and left child, rotate sibling right. + sibling.left.color = BLACK; + sibling.color = RED; + rotateRight(sibling); + sibling = parent.right; + } + // Case 4: Sibling has red right child. Recolor sibling, + // right child, and parent, and rotate parent left. + sibling.color = parent.color; + parent.color = BLACK; + sibling.right.color = BLACK; + rotateLeft(parent); + node = root; // Finished. + } + } + else + { + // Symmetric "mirror" of left-side case. + Node sibling = parent.left; + // if (sibling == nil) + // throw new InternalError(); + if (sibling.color == RED) + { + // Case 1: Sibling is red. + // Recolor sibling and parent, and rotate parent right. + sibling.color = BLACK; + parent.color = RED; + rotateRight(parent); + sibling = parent.left; + } + + if (sibling.right.color == BLACK && sibling.left.color == BLACK) + { + // Case 2: Sibling has no red children. + // Recolor sibling, and move to parent. + sibling.color = RED; + node = parent; + parent = parent.parent; + } + else + { + if (sibling.left.color == BLACK) + { + // Case 3: Sibling has red right child. + // Recolor sibling and right child, rotate sibling left. + sibling.right.color = BLACK; + sibling.color = RED; + rotateLeft(sibling); + sibling = parent.left; + } + // Case 4: Sibling has red left child. Recolor sibling, + // left child, and parent, and rotate parent right. + sibling.color = parent.color; + parent.color = BLACK; + sibling.left.color = BLACK; + rotateRight(parent); + node = root; // Finished. + } + } + } + node.color = BLACK; + } + + /** + * Construct a perfectly balanced tree consisting of n "blank" nodes. This + * permits a tree to be generated from pre-sorted input in linear time. + * + * @param count the number of blank nodes, non-negative + */ + private void fabricateTree(final int count) + { + if (count == 0) + { + root = nil; + size = 0; + return; + } + + // We color every row of nodes black, except for the overflow nodes. + // I believe that this is the optimal arrangement. We construct the tree + // in place by temporarily linking each node to the next node in the row, + // then updating those links to the children when working on the next row. + + // Make the root node. + root = new Node(null, null, BLACK); + size = count; + Node row = root; + int rowsize; + + // Fill each row that is completely full of nodes. + for (rowsize = 2; rowsize + rowsize <= count; rowsize <<= 1) + { + Node parent = row; + Node last = null; + for (int i = 0; i < rowsize; i += 2) + { + Node left = new Node(null, null, BLACK); + Node right = new Node(null, null, BLACK); + left.parent = parent; + left.right = right; + right.parent = parent; + parent.left = left; + Node next = parent.right; + parent.right = right; + parent = next; + if (last != null) + last.right = left; + last = right; + } + row = row.left; + } + + // Now do the partial final row in red. + int overflow = count - rowsize; + Node parent = row; + int i; + for (i = 0; i < overflow; i += 2) + { + Node left = new Node(null, null, RED); + Node right = new Node(null, null, RED); + left.parent = parent; + right.parent = parent; + parent.left = left; + Node next = parent.right; + parent.right = right; + parent = next; + } + // Add a lone left node if necessary. + if (i - overflow == 0) + { + Node left = new Node(null, null, RED); + left.parent = parent; + parent.left = left; + parent = parent.right; + left.parent.right = nil; + } + // Unlink the remaining nodes of the previous row. + while (parent != nil) + { + Node next = parent.right; + parent.right = nil; + parent = next; + } + } + + /** + * Returns the first sorted node in the map, or nil if empty. Package + * visible for use by nested classes. + * + * @return the first node + */ + final Node firstNode() + { + // Exploit fact that nil.left == nil. + Node node = root; + while (node.left != nil) + node = node.left; + return node; + } + + /** + * Return the TreeMap.Node associated with key, or the nil node if no such + * node exists in the tree. Package visible for use by nested classes. + * + * @param key the key to search for + * @return the node where the key is found, or nil + */ + final Node getNode(Object key) + { + Node current = root; + while (current != nil) + { + int comparison = compare(key, current.key); + if (comparison > 0) + current = current.right; + else if (comparison < 0) + current = current.left; + else + return current; + } + return current; + } + + /** + * Find the "highest" node which is < key. If key is nil, return last + * node. Package visible for use by nested classes. + * + * @param key the upper bound, exclusive + * @return the previous node + */ + final Node highestLessThan(Object key) + { + if (key == nil) + return lastNode(); + + Node last = nil; + Node current = root; + int comparison = 0; + + while (current != nil) + { + last = current; + comparison = compare(key, current.key); + if (comparison > 0) + current = current.right; + else if (comparison < 0) + current = current.left; + else // Exact match. + return predecessor(last); + } + return comparison <= 0 ? predecessor(last) : last; + } + + /** + * Maintain red-black balance after inserting a new node. + * + * @param n the newly inserted node + */ + private void insertFixup(Node n) + { + // Only need to rebalance when parent is a RED node, and while at least + // 2 levels deep into the tree (ie: node has a grandparent). Remember + // that nil.color == BLACK. + while (n.parent.color == RED && n.parent.parent != nil) + { + if (n.parent == n.parent.parent.left) + { + Node uncle = n.parent.parent.right; + // Uncle may be nil, in which case it is BLACK. + if (uncle.color == RED) + { + // Case 1. Uncle is RED: Change colors of parent, uncle, + // and grandparent, and move n to grandparent. + n.parent.color = BLACK; + uncle.color = BLACK; + uncle.parent.color = RED; + n = uncle.parent; + } + else + { + if (n == n.parent.right) + { + // Case 2. Uncle is BLACK and x is right child. + // Move n to parent, and rotate n left. + n = n.parent; + rotateLeft(n); + } + // Case 3. Uncle is BLACK and x is left child. + // Recolor parent, grandparent, and rotate grandparent right. + n.parent.color = BLACK; + n.parent.parent.color = RED; + rotateRight(n.parent.parent); + } + } + else + { + // Mirror image of above code. + Node uncle = n.parent.parent.left; + // Uncle may be nil, in which case it is BLACK. + if (uncle.color == RED) + { + // Case 1. Uncle is RED: Change colors of parent, uncle, + // and grandparent, and move n to grandparent. + n.parent.color = BLACK; + uncle.color = BLACK; + uncle.parent.color = RED; + n = uncle.parent; + } + else + { + if (n == n.parent.left) + { + // Case 2. Uncle is BLACK and x is left child. + // Move n to parent, and rotate n right. + n = n.parent; + rotateRight(n); + } + // Case 3. Uncle is BLACK and x is right child. + // Recolor parent, grandparent, and rotate grandparent left. + n.parent.color = BLACK; + n.parent.parent.color = RED; + rotateLeft(n.parent.parent); + } + } + } + root.color = BLACK; + } + + /** + * Returns the last sorted node in the map, or nil if empty. + * + * @return the last node + */ + private Node lastNode() + { + // Exploit fact that nil.right == nil. + Node node = root; + while (node.right != nil) + node = node.right; + return node; + } + + /** + * Find the "lowest" node which is >= key. If key is nil, return either + * nil or the first node, depending on the parameter first. + * Package visible for use by nested classes. + * + * @param key the lower bound, inclusive + * @param first true to return the first element instead of nil for nil key + * @return the next node + */ + final Node lowestGreaterThan(Object key, boolean first) + { + if (key == nil) + return first ? firstNode() : nil; + + Node last = nil; + Node current = root; + int comparison = 0; + + while (current != nil) + { + last = current; + comparison = compare(key, current.key); + if (comparison > 0) + current = current.right; + else if (comparison < 0) + current = current.left; + else + return current; + } + return comparison > 0 ? successor(last) : last; + } + + /** + * Return the node preceding the given one, or nil if there isn't one. + * + * @param node the current node, not nil + * @return the prior node in sorted order + */ + private Node predecessor(Node node) + { + if (node.left != nil) + { + node = node.left; + while (node.right != nil) + node = node.right; + return node; + } + + Node parent = node.parent; + // Exploit fact that nil.left == nil and node is non-nil. + while (node == parent.left) + { + node = parent; + parent = node.parent; + } + return parent; + } + + /** + * Construct a tree from sorted keys in linear time. Package visible for + * use by TreeSet. + * + * @param s the stream to read from + * @param count the number of keys to read + * @param readValue true to read values, false to insert "" as the value + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @see #readObject(ObjectInputStream) + * @see TreeSet#readObject(ObjectInputStream) + */ + final void putFromObjStream(ObjectInputStream s, int count, + boolean readValues) + throws IOException, ClassNotFoundException + { + fabricateTree(count); + Node node = firstNode(); + + while (--count >= 0) + { + node.key = s.readObject(); + node.value = readValues ? s.readObject() : ""; + node = successor(node); + } + } + + /** + * Construct a tree from sorted keys in linear time, with values of "". + * Package visible for use by TreeSet. + * + * @param keys the iterator over the sorted keys + * @param count the number of nodes to insert + * @see TreeSet#TreeSet(SortedSet) + */ + final void putKeysLinear(Iterator keys, int count) + { + fabricateTree(count); + Node node = firstNode(); + + while (--count >= 0) + { + node.key = keys.next(); + node.value = ""; + node = successor(node); + } + } + + /** + * Deserializes this object from the given stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData the size (int), followed by key (Object) and value + * (Object) pairs in sorted order + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + int size = s.readInt(); + putFromObjStream(s, size, true); + } + + /** + * Remove node from tree. This will increment modCount and decrement size. + * Node must exist in the tree. Package visible for use by nested classes. + * + * @param node the node to remove + */ + final void removeNode(Node node) + { + Node splice; + Node child; + + modCount++; + size--; + + // Find splice, the node at the position to actually remove from the tree. + if (node.left == nil) + { + // Node to be deleted has 0 or 1 children. + splice = node; + child = node.right; + } + else if (node.right == nil) + { + // Node to be deleted has 1 child. + splice = node; + child = node.left; + } + else + { + // Node has 2 children. Splice is node's predecessor, and we swap + // its contents into node. + splice = node.left; + while (splice.right != nil) + splice = splice.right; + child = splice.left; + node.key = splice.key; + node.value = splice.value; + } + + // Unlink splice from the tree. + Node parent = splice.parent; + if (child != nil) + child.parent = parent; + if (parent == nil) + { + // Special case for 0 or 1 node remaining. + root = child; + return; + } + if (splice == parent.left) + parent.left = child; + else + parent.right = child; + + if (splice.color == BLACK) + deleteFixup(child, parent); + } + + /** + * Rotate node n to the left. + * + * @param node the node to rotate + */ + private void rotateLeft(Node node) + { + Node child = node.right; + // if (node == nil || child == nil) + // throw new InternalError(); + + // Establish node.right link. + node.right = child.left; + if (child.left != nil) + child.left.parent = node; + + // Establish child->parent link. + child.parent = node.parent; + if (node.parent != nil) + { + if (node == node.parent.left) + node.parent.left = child; + else + node.parent.right = child; + } + else + root = child; + + // Link n and child. + child.left = node; + node.parent = child; + } + + /** + * Rotate node n to the right. + * + * @param node the node to rotate + */ + private void rotateRight(Node node) + { + Node child = node.left; + // if (node == nil || child == nil) + // throw new InternalError(); + + // Establish node.left link. + node.left = child.right; + if (child.right != nil) + child.right.parent = node; + + // Establish child->parent link. + child.parent = node.parent; + if (node.parent != nil) + { + if (node == node.parent.right) + node.parent.right = child; + else + node.parent.left = child; + } + else + root = child; + + // Link n and child. + child.right = node; + node.parent = child; + } + + /** + * Return the node following the given one, or nil if there isn't one. + * Package visible for use by nested classes. + * + * @param node the current node, not nil + * @return the next node in sorted order + */ + final Node successor(Node node) + { + if (node.right != nil) + { + node = node.right; + while (node.left != nil) + node = node.left; + return node; + } + + Node parent = node.parent; + // Exploit fact that nil.right == nil and node is non-nil. + while (node == parent.right) + { + node = parent; + parent = parent.parent; + } + return parent; + } + + /** + * Serializes this object to the given stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData the size (int), followed by key (Object) and value + * (Object) pairs in sorted order + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + + Node node = firstNode(); + s.writeInt(size); + while (node != nil) + { + s.writeObject(node.key); + s.writeObject(node.value); + node = successor(node); + } + } + + /** + * Iterate over TreeMap's entries. This implementation is parameterized + * to give a sequential view of keys, values, or entries. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private final class TreeIterator implements Iterator + { + /** + * The type of this Iterator: {@link #KEYS}, {@link #VALUES}, + * or {@link #ENTRIES}. + */ + private final int type; + /** The number of modifications to the backing Map that we know about. */ + private int knownMod = modCount; + /** The last Entry returned by a next() call. */ + private Node last; + /** The next entry that should be returned by next(). */ + private Node next; + /** + * The last node visible to this iterator. This is used when iterating + * on a SubMap. + */ + private final Node max; + + /** + * Construct a new TreeIterator with the supplied type. + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + */ + TreeIterator(int type) + { + // FIXME gcj cannot handle this. Bug java/4695 + // this(type, firstNode(), nil); + this.type = type; + this.next = firstNode(); + this.max = nil; + } + + /** + * Construct a new TreeIterator with the supplied type. Iteration will + * be from "first" (inclusive) to "max" (exclusive). + * + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + * @param first where to start iteration, nil for empty iterator + * @param max the cutoff for iteration, nil for all remaining nodes + */ + TreeIterator(int type, Node first, Node max) + { + this.type = type; + this.next = first; + this.max = max; + } + + /** + * Returns true if the Iterator has more elements. + * @return true if there are more elements + * @throws ConcurrentModificationException if the TreeMap was modified + */ + public boolean hasNext() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + return next != max; + } + + /** + * Returns the next element in the Iterator's sequential view. + * @return the next element + * @throws ConcurrentModificationException if the TreeMap was modified + * @throws NoSuchElementException if there is none + */ + public Object next() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (next == max) + throw new NoSuchElementException(); + last = next; + next = successor(last); + + if (type == VALUES) + return last.value; + else if (type == KEYS) + return last.key; + return last; + } + + /** + * Removes from the backing TreeMap the last element which was fetched + * with the next() method. + * @throws ConcurrentModificationException if the TreeMap was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() + { + if (last == null) + throw new IllegalStateException(); + if (knownMod != modCount) + throw new ConcurrentModificationException(); + + removeNode(last); + last = null; + knownMod++; + } + } // class TreeIterator + + /** + * Implementation of {@link #subMap(Object, Object)} and other map + * ranges. This class provides a view of a portion of the original backing + * map, and throws {@link IllegalArgumentException} for attempts to + * access beyond that range. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private final class SubMap extends AbstractMap implements SortedMap + { + /** + * The lower range of this view, inclusive, or nil for unbounded. + * Package visible for use by nested classes. + */ + final Object minKey; + + /** + * The upper range of this view, exclusive, or nil for unbounded. + * Package visible for use by nested classes. + */ + final Object maxKey; + + /** + * The cache for {@link #entrySet()}. + */ + private Set entries; + + /** + * Create a SubMap representing the elements between minKey (inclusive) + * and maxKey (exclusive). If minKey is nil, SubMap has no lower bound + * (headMap). If maxKey is nil, the SubMap has no upper bound (tailMap). + * + * @param minKey the lower bound + * @param maxKey the upper bound + * @throws IllegalArgumentException if minKey > maxKey + */ + SubMap(Object minKey, Object maxKey) + { + if (minKey != nil && maxKey != nil && compare(minKey, maxKey) > 0) + throw new IllegalArgumentException("fromKey > toKey"); + this.minKey = minKey; + this.maxKey = maxKey; + } + + /** + * Check if "key" is in within the range bounds for this SubMap. The + * lower ("from") SubMap range is inclusive, and the upper ("to") bound + * is exclusive. Package visible for use by nested classes. + * + * @param key the key to check + * @return true if the key is in range + */ + boolean keyInRange(Object key) + { + return ((minKey == nil || compare(key, minKey) >= 0) + && (maxKey == nil || compare(key, maxKey) < 0)); + } + + public void clear() + { + Node next = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + while (next != max) + { + Node current = next; + next = successor(current); + removeNode(current); + } + } + + public Comparator comparator() + { + return comparator; + } + + public boolean containsKey(Object key) + { + return keyInRange(key) && TreeMap.this.containsKey(key); + } + + public boolean containsValue(Object value) + { + Node node = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + while (node != max) + { + if (equals(value, node.getValue())) + return true; + node = successor(node); + } + return false; + } + + public Set entrySet() + { + if (entries == null) + // Create an AbstractSet with custom implementations of those methods + // that can be overriden easily and efficiently. + entries = new AbstractSet() + { + public int size() + { + return SubMap.this.size(); + } + + public Iterator iterator() + { + Node first = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + return new TreeIterator(ENTRIES, first, max); + } + + public void clear() + { + SubMap.this.clear(); + } + + public boolean contains(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Map.Entry me = (Map.Entry) o; + Object key = me.getKey(); + if (! keyInRange(key)) + return false; + Node n = getNode(key); + return n != nil && AbstractSet.equals(me.getValue(), n.value); + } + + public boolean remove(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Map.Entry me = (Map.Entry) o; + Object key = me.getKey(); + if (! keyInRange(key)) + return false; + Node n = getNode(key); + if (n != nil && AbstractSet.equals(me.getValue(), n.value)) + { + removeNode(n); + return true; + } + return false; + } + }; + return entries; + } + + public Object firstKey() + { + Node node = lowestGreaterThan(minKey, true); + if (node == nil || ! keyInRange(node.key)) + throw new NoSuchElementException(); + return node.key; + } + + public Object get(Object key) + { + if (keyInRange(key)) + return TreeMap.this.get(key); + return null; + } + + public SortedMap headMap(Object toKey) + { + if (! keyInRange(toKey)) + throw new IllegalArgumentException("key outside range"); + return new SubMap(minKey, toKey); + } + + public Set keySet() + { + if (this.keys == null) + // Create an AbstractSet with custom implementations of those methods + // that can be overriden easily and efficiently. + this.keys = new AbstractSet() + { + public int size() + { + return SubMap.this.size(); + } + + public Iterator iterator() + { + Node first = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + return new TreeIterator(KEYS, first, max); + } + + public void clear() + { + SubMap.this.clear(); + } + + public boolean contains(Object o) + { + if (! keyInRange(o)) + return false; + return getNode(o) != nil; + } + + public boolean remove(Object o) + { + if (! keyInRange(o)) + return false; + Node n = getNode(o); + if (n != nil) + { + removeNode(n); + return true; + } + return false; + } + }; + return this.keys; + } + + public Object lastKey() + { + Node node = highestLessThan(maxKey); + if (node == nil || ! keyInRange(node.key)) + throw new NoSuchElementException(); + return node.key; + } + + public Object put(Object key, Object value) + { + if (! keyInRange(key)) + throw new IllegalArgumentException("Key outside range"); + return TreeMap.this.put(key, value); + } + + public Object remove(Object key) + { + if (keyInRange(key)) + return TreeMap.this.remove(key); + return null; + } + + public int size() + { + Node node = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + int count = 0; + while (node != max) + { + count++; + node = successor(node); + } + return count; + } + + public SortedMap subMap(Object fromKey, Object toKey) + { + if (! keyInRange(fromKey) || ! keyInRange(toKey)) + throw new IllegalArgumentException("key outside range"); + return new SubMap(fromKey, toKey); + } + + public SortedMap tailMap(Object fromKey) + { + if (! keyInRange(fromKey)) + throw new IllegalArgumentException("key outside range"); + return new SubMap(fromKey, maxKey); + } + + public Collection values() + { + if (this.values == null) + // Create an AbstractCollection with custom implementations of those + // methods that can be overriden easily and efficiently. + this.values = new AbstractCollection() + { + public int size() + { + return SubMap.this.size(); + } + + public Iterator iterator() + { + Node first = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + return new TreeIterator(VALUES, first, max); + } + + public void clear() + { + SubMap.this.clear(); + } + }; + return this.values; + } + } // class SubMap +} // class TreeMap diff --git a/libjava/classpath/java/util/TreeSet.java b/libjava/classpath/java/util/TreeSet.java new file mode 100644 index 0000000..34cb39a --- /dev/null +++ b/libjava/classpath/java/util/TreeSet.java @@ -0,0 +1,416 @@ +/* TreeSet.java -- a class providing a TreeMap-backed SortedSet + Copyright (C) 1999, 2000, 2001, 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 java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * This class provides a TreeMap-backed implementation of the SortedSet + * interface. The elements will be sorted according to their natural + * order, or according to the provided Comparator.

    + * + * Most operations are O(log n), but there is so much overhead that this + * makes small sets expensive. Note that the ordering must be consistent + * with equals to correctly implement the Set interface. If this + * condition is violated, the set is still well-behaved, but you may have + * suprising results when comparing it to other sets.

    + * + * This implementation is not synchronized. If you need to share this between + * multiple threads, do something like:
    + * SortedSet s + * = Collections.synchronizedSortedSet(new TreeSet(...));

    + * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * ConcurrentModificationException rather than exhibit + * non-deterministic behavior. + * + * @author Jon Zeppieri + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see Set + * @see HashSet + * @see LinkedHashSet + * @see Comparable + * @see Comparator + * @see Collections#synchronizedSortedSet(SortedSet) + * @see TreeMap + * @since 1.2 + * @status updated to 1.4 + */ +public class TreeSet extends AbstractSet + implements SortedSet, Cloneable, Serializable +{ + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = -2479143000061671589L; + + /** + * The SortedMap which backs this Set. + */ + // Not final because of readObject. This will always be one of TreeMap or + // TreeMap.SubMap, which both extend AbstractMap. + private transient SortedMap map; + + /** + * Construct a new TreeSet whose backing TreeMap using the "natural" + * ordering of keys. Elements that are not mutually comparable will cause + * ClassCastExceptions down the road. + * + * @see Comparable + */ + public TreeSet() + { + map = new TreeMap(); + } + + /** + * Construct a new TreeSet whose backing TreeMap uses the supplied + * Comparator. Elements that are not mutually comparable will cause + * ClassCastExceptions down the road. + * + * @param comparator the Comparator this Set will use + */ + public TreeSet(Comparator comparator) + { + map = new TreeMap(comparator); + } + + /** + * Construct a new TreeSet whose backing TreeMap uses the "natural" + * orering of the keys and which contains all of the elements in the + * supplied Collection. This runs in n*log(n) time. + * + * @param collection the new Set will be initialized with all + * of the elements in this Collection + * @throws ClassCastException if the elements of the collection are not + * comparable + * @throws NullPointerException if the collection is null + * @see Comparable + */ + public TreeSet(Collection collection) + { + map = new TreeMap(); + addAll(collection); + } + + /** + * Construct a new TreeSet, using the same key ordering as the supplied + * SortedSet and containing all of the elements in the supplied SortedSet. + * This constructor runs in linear time. + * + * @param sortedSet the new TreeSet will use this SortedSet's comparator + * and will initialize itself with all its elements + * @throws NullPointerException if sortedSet is null + */ + public TreeSet(SortedSet sortedSet) + { + map = new TreeMap(sortedSet.comparator()); + Iterator itr = sortedSet.iterator(); + ((TreeMap) map).putKeysLinear(itr, sortedSet.size()); + } + + /** + * This private constructor is used to implement the subSet() calls around + * a backing TreeMap.SubMap. + * + * @param backingMap the submap + */ + private TreeSet(SortedMap backingMap) + { + map = backingMap; + } + + /** + * Adds the spplied Object to the Set if it is not already in the Set; + * returns true if the element is added, false otherwise. + * + * @param obj the Object to be added to this Set + * @throws ClassCastException if the element cannot be compared with objects + * already in the set + */ + public boolean add(Object obj) + { + return map.put(obj, "") == null; + } + + /** + * Adds all of the elements in the supplied Collection to this TreeSet. + * + * @param c The collection to add + * @return true if the Set is altered, false otherwise + * @throws NullPointerException if c is null + * @throws ClassCastException if an element in c cannot be compared with + * objects already in the set + */ + public boolean addAll(Collection c) + { + boolean result = false; + int pos = c.size(); + Iterator itr = c.iterator(); + while (--pos >= 0) + result |= (map.put(itr.next(), "") == null); + return result; + } + + /** + * Removes all elements in this Set. + */ + public void clear() + { + map.clear(); + } + + /** + * Returns a shallow copy of this Set. The elements are not cloned. + * + * @return the cloned set + */ + public Object clone() + { + TreeSet copy = null; + try + { + copy = (TreeSet) super.clone(); + // Map may be either TreeMap or TreeMap.SubMap, hence the ugly casts. + copy.map = (SortedMap) ((AbstractMap) map).clone(); + } + catch (CloneNotSupportedException x) + { + // Impossible result. + } + return copy; + } + + /** + * Returns this Set's comparator. + * + * @return the comparator, or null if the set uses natural ordering + */ + public Comparator comparator() + { + return map.comparator(); + } + + /** + * Returns true if this Set contains the supplied Object, false otherwise. + * + * @param obj the Object to check for + * @return true if it is in the set + * @throws ClassCastException if obj cannot be compared with objects + * already in the set + */ + public boolean contains(Object obj) + { + return map.containsKey(obj); + } + + /** + * Returns the first (by order) element in this Set. + * + * @return the first element + * @throws NoSuchElementException if the set is empty + */ + public Object first() + { + return map.firstKey(); + } + + /** + * Returns a view of this Set including all elements less than + * to. The returned set is backed by the original, so changes + * in one appear in the other. The subset will throw an + * {@link IllegalArgumentException} for any attempt to access or add an + * element beyond the specified cutoff. The returned set does not include + * the endpoint; if you want inclusion, pass the successor element. + * + * @param to the (exclusive) cutoff point + * @return a view of the set less than the cutoff + * @throws ClassCastException if to is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if to is null, but the comparator does not + * tolerate null elements + */ + public SortedSet headSet(Object to) + { + return new TreeSet(map.headMap(to)); + } + + /** + * Returns true if this Set has size 0, false otherwise. + * + * @return true if the set is empty + */ + public boolean isEmpty() + { + return map.isEmpty(); + } + + /** + * Returns in Iterator over the elements in this TreeSet, which traverses + * in ascending order. + * + * @return an iterator + */ + public Iterator iterator() + { + return map.keySet().iterator(); + } + + /** + * Returns the last (by order) element in this Set. + * + * @return the last element + * @throws NoSuchElementException if the set is empty + */ + public Object last() + { + return map.lastKey(); + } + + /** + * If the supplied Object is in this Set, it is removed, and true is + * returned; otherwise, false is returned. + * + * @param obj the Object to remove from this Set + * @return true if the set was modified + * @throws ClassCastException if obj cannot be compared to set elements + */ + public boolean remove(Object obj) + { + return map.remove(obj) != null; + } + + /** + * Returns the number of elements in this Set + * + * @return the set size + */ + public int size() + { + return map.size(); + } + + /** + * Returns a view of this Set including all elements greater or equal to + * from and less than to (a half-open interval). + * The returned set is backed by the original, so changes in one appear in + * the other. The subset will throw an {@link IllegalArgumentException} + * for any attempt to access or add an element beyond the specified cutoffs. + * The returned set includes the low endpoint but not the high; if you want + * to reverse this behavior on either end, pass in the successor element. + * + * @param from the (inclusive) low cutoff point + * @param to the (exclusive) high cutoff point + * @return a view of the set between the cutoffs + * @throws ClassCastException if either cutoff is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if from or to is null, but the comparator + * does not tolerate null elements + * @throws IllegalArgumentException if from is greater than to + */ + public SortedSet subSet(Object from, Object to) + { + return new TreeSet(map.subMap(from, to)); + } + + /** + * Returns a view of this Set including all elements greater or equal to + * from. The returned set is backed by the original, so + * changes in one appear in the other. The subset will throw an + * {@link IllegalArgumentException} for any attempt to access or add an + * element beyond the specified cutoff. The returned set includes the + * endpoint; if you want to exclude it, pass in the successor element. + * + * @param from the (inclusive) low cutoff point + * @return a view of the set above the cutoff + * @throws ClassCastException if from is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if from is null, but the comparator + * does not tolerate null elements + */ + public SortedSet tailSet(Object from) + { + return new TreeSet(map.tailMap(from)); + } + + /** + * Serializes this object to the given stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData the comparator (Object), followed by the set size + * (int), the the elements in sorted order (Object) + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + Iterator itr = map.keySet().iterator(); + int pos = map.size(); + s.writeObject(map.comparator()); + s.writeInt(pos); + while (--pos >= 0) + s.writeObject(itr.next()); + } + + /** + * Deserializes this object from the given stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData the comparator (Object), followed by the set size + * (int), the the elements in sorted order (Object) + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + Comparator comparator = (Comparator) s.readObject(); + int size = s.readInt(); + map = new TreeMap(comparator); + ((TreeMap) map).putFromObjStream(s, size, false); + } +} diff --git a/libjava/classpath/java/util/Vector.java b/libjava/classpath/java/util/Vector.java new file mode 100644 index 0000000..e26d7aa --- /dev/null +++ b/libjava/classpath/java/util/Vector.java @@ -0,0 +1,931 @@ +/* Vector.java -- Class that provides growable arrays. + Copyright (C) 1998, 1999, 2000, 2001, 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 java.util; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; + +/** + * The Vector classes implements growable arrays of Objects. + * You can access elements in a Vector with an index, just as you + * can in a built in array, but Vectors can grow and shrink to accommodate + * more or fewer objects.

    + * + * Vectors try to mantain efficiency in growing by having a + * capacityIncrement that can be specified at instantiation. + * When a Vector can no longer hold a new Object, it grows by the amount + * in capacityIncrement. If this value is 0, the vector doubles in + * size.

    + * + * Vector implements the JDK 1.2 List interface, and is therefore a fully + * compliant Collection object. The iterators are fail-fast - if external + * code structurally modifies the vector, any operation on the iterator will + * then throw a {@link ConcurrentModificationException}. The Vector class is + * fully synchronized, but the iterators are not. So, when iterating over a + * vector, be sure to synchronize on the vector itself. If you don't want the + * expense of synchronization, use ArrayList instead. On the other hand, the + * Enumeration of elements() is not thread-safe, nor is it fail-fast; so it + * can lead to undefined behavior even in a single thread if you modify the + * vector during iteration.

    + * + * Note: Some methods, especially those specified by List, specify throwing + * {@link IndexOutOfBoundsException}, but it is easier to implement by + * throwing the subclass {@link ArrayIndexOutOfBoundsException}. Others + * directly specify this subclass. + * + * @author Scott G. Miller + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see List + * @see ArrayList + * @see LinkedList + * @since 1.0 + * @status updated to 1.4 + */ +public class Vector extends AbstractList + implements List, RandomAccess, Cloneable, Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -2767605614048989439L; + + /** + * The internal array used to hold members of a Vector. The elements are + * in positions 0 through elementCount - 1, and all remaining slots are null. + * @serial the elements + */ + protected Object[] elementData; + + /** + * The number of elements currently in the vector, also returned by + * {@link #size}. + * @serial the size + */ + protected int elementCount; + + /** + * The amount the Vector's internal array should be increased in size when + * a new element is added that exceeds the current size of the array, + * or when {@link #ensureCapacity} is called. If <= 0, the vector just + * doubles in size. + * @serial the amount to grow the vector by + */ + protected int capacityIncrement; + + /** + * Constructs an empty vector with an initial size of 10, and + * a capacity increment of 0 + */ + public Vector() + { + this(10, 0); + } + + /** + * Constructs a vector containing the contents of Collection, in the + * order given by the collection. + * + * @param c collection of elements to add to the new vector + * @throws NullPointerException if c is null + * @since 1.2 + */ + public Vector(Collection c) + { + elementCount = c.size(); + elementData = c.toArray(new Object[elementCount]); + } + + /** + * Constructs a Vector with the initial capacity and capacity + * increment specified. + * + * @param initialCapacity the initial size of the Vector's internal array + * @param capacityIncrement the amount the internal array should be + * increased by when necessary, 0 to double the size + * @throws IllegalArgumentException if initialCapacity < 0 + */ + public Vector(int initialCapacity, int capacityIncrement) + { + if (initialCapacity < 0) + throw new IllegalArgumentException(); + elementData = new Object[initialCapacity]; + this.capacityIncrement = capacityIncrement; + } + + /** + * Constructs a Vector with the initial capacity specified, and a capacity + * increment of 0 (double in size). + * + * @param initialCapacity the initial size of the Vector's internal array + * @throws IllegalArgumentException if initialCapacity < 0 + */ + public Vector(int initialCapacity) + { + this(initialCapacity, 0); + } + + /** + * Copies the contents of a provided array into the Vector. If the + * array is too large to fit in the Vector, an IndexOutOfBoundsException + * is thrown without modifying the array. Old elements in the Vector are + * overwritten by the new elements. + * + * @param a target array for the copy + * @throws IndexOutOfBoundsException the array is not large enough + * @throws NullPointerException the array is null + * @see #toArray(Object[]) + */ + public synchronized void copyInto(Object[] a) + { + System.arraycopy(elementData, 0, a, 0, elementCount); + } + + /** + * Trims the Vector down to size. If the internal data array is larger + * than the number of Objects its holding, a new array is constructed + * that precisely holds the elements. Otherwise this does nothing. + */ + public synchronized void trimToSize() + { + // Don't bother checking for the case where size() == the capacity of the + // vector since that is a much less likely case; it's more efficient to + // not do the check and lose a bit of performance in that infrequent case + + Object[] newArray = new Object[elementCount]; + System.arraycopy(elementData, 0, newArray, 0, elementCount); + elementData = newArray; + } + + /** + * Ensures that minCapacity elements can fit within this Vector. + * If elementData is too small, it is expanded as follows: + * If the elementCount + capacityIncrement is adequate, that + * is the new size. If capacityIncrement is non-zero, the + * candidate size is double the current. If that is not enough, the new + * size is minCapacity. + * + * @param minCapacity the desired minimum capacity, negative values ignored + */ + public synchronized void ensureCapacity(int minCapacity) + { + if (elementData.length >= minCapacity) + return; + + int newCapacity; + if (capacityIncrement <= 0) + newCapacity = elementData.length * 2; + else + newCapacity = elementData.length + capacityIncrement; + + Object[] newArray = new Object[Math.max(newCapacity, minCapacity)]; + + System.arraycopy(elementData, 0, newArray, 0, elementCount); + elementData = newArray; + } + + /** + * Explicitly sets the size of the vector (but not necessarily the size of + * the internal data array). If the new size is smaller than the old one, + * old values that don't fit are lost. If the new size is larger than the + * old one, the vector is padded with null entries. + * + * @param newSize The new size of the internal array + * @throws ArrayIndexOutOfBoundsException if the new size is negative + */ + public synchronized void setSize(int newSize) + { + // Don't bother checking for the case where size() == the capacity of the + // vector since that is a much less likely case; it's more efficient to + // not do the check and lose a bit of performance in that infrequent case + modCount++; + ensureCapacity(newSize); + if (newSize < elementCount) + Arrays.fill(elementData, newSize, elementCount, null); + elementCount = newSize; + } + + /** + * Returns the size of the internal data array (not the amount of elements + * contained in the Vector). + * + * @return capacity of the internal data array + */ + public synchronized int capacity() + { + return elementData.length; + } + + /** + * Returns the number of elements stored in this Vector. + * + * @return the number of elements in this Vector + */ + public synchronized int size() + { + return elementCount; + } + + /** + * Returns true if this Vector is empty, false otherwise + * + * @return true if the Vector is empty, false otherwise + */ + public synchronized boolean isEmpty() + { + return elementCount == 0; + } + + /** + * Returns an Enumeration of the elements of this Vector. The enumeration + * visits the elements in increasing index order, but is NOT thread-safe. + * + * @return an Enumeration + * @see #iterator() + */ + // No need to synchronize as the Enumeration is not thread-safe! + public Enumeration elements() + { + return new Enumeration() + { + private int i = 0; + + public boolean hasMoreElements() + { + return i < elementCount; + } + + public Object nextElement() + { + if (i >= elementCount) + throw new NoSuchElementException(); + return elementData[i++]; + } + }; + } + + /** + * Returns true when elem is contained in this Vector. + * + * @param elem the element to check + * @return true if the object is contained in this Vector, false otherwise + */ + public boolean contains(Object elem) + { + return indexOf(elem, 0) >= 0; + } + + /** + * Returns the first occurrence of elem in the Vector, or -1 if + * elem is not found. + * + * @param elem the object to search for + * @return the index of the first occurrence, or -1 if not found + */ + public int indexOf(Object elem) + { + return indexOf(elem, 0); + } + + /** + * Searches the vector starting at index for object + * elem and returns the index of the first occurrence of this + * Object. If the object is not found, or index is larger than the size + * of the vector, -1 is returned. + * + * @param e the Object to search for + * @param index start searching at this index + * @return the index of the next occurrence, or -1 if it is not found + * @throws IndexOutOfBoundsException if index < 0 + */ + public synchronized int indexOf(Object e, int index) + { + for (int i = index; i < elementCount; i++) + if (equals(e, elementData[i])) + return i; + return -1; + } + + /** + * Returns the last index of elem within this Vector, or -1 + * if the object is not within the Vector. + * + * @param elem the object to search for + * @return the last index of the object, or -1 if not found + */ + public int lastIndexOf(Object elem) + { + return lastIndexOf(elem, elementCount - 1); + } + + /** + * Returns the index of the first occurrence of elem, when + * searching backwards from index. If the object does not + * occur in this Vector, or index is less than 0, -1 is returned. + * + * @param e the object to search for + * @param index the index to start searching in reverse from + * @return the index of the Object if found, -1 otherwise + * @throws IndexOutOfBoundsException if index >= size() + */ + public synchronized int lastIndexOf(Object e, int index) + { + checkBoundExclusive(index); + for (int i = index; i >= 0; i--) + if (equals(e, elementData[i])) + return i; + return -1; + } + + /** + * Returns the Object stored at index. + * + * @param index the index of the Object to retrieve + * @return the object at index + * @throws ArrayIndexOutOfBoundsException index < 0 || index >= size() + * @see #get(int) + */ + public synchronized Object elementAt(int index) + { + checkBoundExclusive(index); + return elementData[index]; + } + + /** + * Returns the first element (index 0) in the Vector. + * + * @return the first Object in the Vector + * @throws NoSuchElementException the Vector is empty + */ + public synchronized Object firstElement() + { + if (elementCount == 0) + throw new NoSuchElementException(); + + return elementData[0]; + } + + /** + * Returns the last element in the Vector. + * + * @return the last Object in the Vector + * @throws NoSuchElementException the Vector is empty + */ + public synchronized Object lastElement() + { + if (elementCount == 0) + throw new NoSuchElementException(); + + return elementData[elementCount - 1]; + } + + /** + * Changes the element at index to be obj + * + * @param obj the object to store + * @param index the position in the Vector to store the object + * @throws ArrayIndexOutOfBoundsException the index is out of range + * @see #set(int, Object) + */ + public void setElementAt(Object obj, int index) + { + set(index, obj); + } + + /** + * Removes the element at index, and shifts all elements at + * positions greater than index to their index - 1. + * + * @param index the index of the element to remove + * @throws ArrayIndexOutOfBoundsException index < 0 || index >= size(); + * @see #remove(int) + */ + public void removeElementAt(int index) + { + remove(index); + } + + /** + * Inserts a new element into the Vector at index. Any elements + * at or greater than index are shifted up one position. + * + * @param obj the object to insert + * @param index the index at which the object is inserted + * @throws ArrayIndexOutOfBoundsException index < 0 || index > size() + * @see #add(int, Object) + */ + public synchronized void insertElementAt(Object obj, int index) + { + checkBoundInclusive(index); + if (elementCount == elementData.length) + ensureCapacity(elementCount + 1); + modCount++; + System.arraycopy(elementData, index, elementData, index + 1, + elementCount - index); + elementCount++; + elementData[index] = obj; + } + + /** + * Adds an element to the Vector at the end of the Vector. The vector + * is increased by ensureCapacity(size() + 1) if needed. + * + * @param obj the object to add to the Vector + */ + public synchronized void addElement(Object obj) + { + if (elementCount == elementData.length) + ensureCapacity(elementCount + 1); + modCount++; + elementData[elementCount++] = obj; + } + + /** + * Removes the first (the lowestindex) occurance of the given object from + * the Vector. If such a remove was performed (the object was found), true + * is returned. If there was no such object, false is returned. + * + * @param obj the object to remove from the Vector + * @return true if the Object was in the Vector, false otherwise + * @see #remove(Object) + */ + public synchronized boolean removeElement(Object obj) + { + int idx = indexOf(obj, 0); + if (idx >= 0) + { + remove(idx); + return true; + } + return false; + } + + /** + * Removes all elements from the Vector. Note that this does not + * resize the internal data array. + * + * @see #clear() + */ + public synchronized void removeAllElements() + { + if (elementCount == 0) + return; + + modCount++; + Arrays.fill(elementData, 0, elementCount, null); + elementCount = 0; + } + + /** + * Creates a new Vector with the same contents as this one. The clone is + * shallow; elements are not cloned. + * + * @return the clone of this vector + */ + public synchronized Object clone() + { + try + { + Vector clone = (Vector) super.clone(); + clone.elementData = (Object[]) elementData.clone(); + return clone; + } + catch (CloneNotSupportedException ex) + { + // Impossible to get here. + throw new InternalError(ex.toString()); + } + } + + /** + * Returns an Object array with the contents of this Vector, in the order + * they are stored within this Vector. Note that the Object array returned + * is not the internal data array, and that it holds only the elements + * within the Vector. This is similar to creating a new Object[] with the + * size of this Vector, then calling Vector.copyInto(yourArray). + * + * @return an Object[] containing the contents of this Vector in order + * @since 1.2 + */ + public synchronized Object[] toArray() + { + Object[] newArray = new Object[elementCount]; + copyInto(newArray); + return newArray; + } + + /** + * Returns an array containing the contents of this Vector. + * If the provided array is large enough, the contents are copied + * into that array, and a null is placed in the position size(). + * In this manner, you can obtain the size of a Vector by the position + * of the null element, if you know the vector does not itself contain + * null entries. If the array is not large enough, reflection is used + * to create a bigger one of the same runtime type. + * + * @param a an array to copy the Vector into if large enough + * @return an array with the contents of this Vector in order + * @throws ArrayStoreException the runtime type of the provided array + * cannot hold the elements of the Vector + * @throws NullPointerException if a is null + * @since 1.2 + */ + public synchronized Object[] toArray(Object[] a) + { + if (a.length < elementCount) + a = (Object[]) Array.newInstance(a.getClass().getComponentType(), + elementCount); + else if (a.length > elementCount) + a[elementCount] = null; + System.arraycopy(elementData, 0, a, 0, elementCount); + return a; + } + + /** + * Returns the element at position index. + * + * @param index the position from which an element will be retrieved + * @return the element at that position + * @throws ArrayIndexOutOfBoundsException index < 0 || index >= size() + * @since 1.2 + */ + public Object get(int index) + { + return elementAt(index); + } + + /** + * Puts element into the Vector at position index + * and returns the Object that previously occupied that position. + * + * @param index the index within the Vector to place the Object + * @param element the Object to store in the Vector + * @return the previous object at the specified index + * @throws ArrayIndexOutOfBoundsException index < 0 || index >= size() + * @since 1.2 + */ + public synchronized Object set(int index, Object element) + { + checkBoundExclusive(index); + Object temp = elementData[index]; + elementData[index] = element; + return temp; + } + + /** + * Adds an object to the Vector. + * + * @param o the element to add to the Vector + * @return true, as specified by List + * @since 1.2 + */ + public boolean add(Object o) + { + addElement(o); + return true; + } + + /** + * Removes the given Object from the Vector. If it exists, true + * is returned, if not, false is returned. + * + * @param o the object to remove from the Vector + * @return true if the Object existed in the Vector, false otherwise + * @since 1.2 + */ + public boolean remove(Object o) + { + return removeElement(o); + } + + /** + * Adds an object at the specified index. Elements at or above + * index are shifted up one position. + * + * @param index the index at which to add the element + * @param element the element to add to the Vector + * @throws ArrayIndexOutOfBoundsException index < 0 || index > size() + * @since 1.2 + */ + public void add(int index, Object element) + { + insertElementAt(element, index); + } + + /** + * Removes the element at the specified index, and returns it. + * + * @param index the position from which to remove the element + * @return the object removed + * @throws ArrayIndexOutOfBoundsException index < 0 || index >= size() + * @since 1.2 + */ + public synchronized Object remove(int index) + { + checkBoundExclusive(index); + Object temp = elementData[index]; + modCount++; + elementCount--; + if (index < elementCount) + System.arraycopy(elementData, index + 1, elementData, index, + elementCount - index); + elementData[elementCount] = null; + return temp; + } + + /** + * Clears all elements in the Vector and sets its size to 0. + */ + public void clear() + { + removeAllElements(); + } + + /** + * Returns true if this Vector contains all the elements in c. + * + * @param c the collection to compare to + * @return true if this vector contains all elements of c + * @throws NullPointerException if c is null + * @since 1.2 + */ + public synchronized boolean containsAll(Collection c) + { + // Here just for the sychronization. + return super.containsAll(c); + } + + /** + * Appends all elements of the given collection to the end of this Vector. + * Behavior is undefined if the collection is modified during this operation + * (for example, if this == c). + * + * @param c the collection to append + * @return true if this vector changed, in other words c was not empty + * @throws NullPointerException if c is null + * @since 1.2 + */ + public synchronized boolean addAll(Collection c) + { + return addAll(elementCount, c); + } + + /** + * Remove from this vector all elements contained in the given collection. + * + * @param c the collection to filter out + * @return true if this vector changed + * @throws NullPointerException if c is null + * @since 1.2 + */ + public synchronized boolean removeAll(Collection c) + { + if (c == null) + throw new NullPointerException(); + + int i; + int j; + for (i = 0; i < elementCount; i++) + if (c.contains(elementData[i])) + break; + if (i == elementCount) + return false; + + modCount++; + for (j = i++; i < elementCount; i++) + if (! c.contains(elementData[i])) + elementData[j++] = elementData[i]; + elementCount -= i - j; + return true; + } + + /** + * Retain in this vector only the elements contained in the given collection. + * + * @param c the collection to filter by + * @return true if this vector changed + * @throws NullPointerException if c is null + * @since 1.2 + */ + public synchronized boolean retainAll(Collection c) + { + if (c == null) + throw new NullPointerException(); + + int i; + int j; + for (i = 0; i < elementCount; i++) + if (! c.contains(elementData[i])) + break; + if (i == elementCount) + return false; + + modCount++; + for (j = i++; i < elementCount; i++) + if (c.contains(elementData[i])) + elementData[j++] = elementData[i]; + elementCount -= i - j; + return true; + } + + /** + * Inserts all elements of the given collection at the given index of + * this Vector. Behavior is undefined if the collection is modified during + * this operation (for example, if this == c). + * + * @param c the collection to append + * @return true if this vector changed, in other words c was not empty + * @throws NullPointerException if c is null + * @throws ArrayIndexOutOfBoundsException index < 0 || index > size() + * @since 1.2 + */ + public synchronized boolean addAll(int index, Collection c) + { + checkBoundInclusive(index); + Iterator itr = c.iterator(); + int csize = c.size(); + + modCount++; + ensureCapacity(elementCount + csize); + int end = index + csize; + if (elementCount > 0 && index != elementCount) + System.arraycopy(elementData, index, + elementData, end, elementCount - index); + elementCount += csize; + for ( ; index < end; index++) + elementData[index] = itr.next(); + return (csize > 0); + } + + /** + * Compares this to the given object. + * + * @param o the object to compare to + * @return true if the two are equal + * @since 1.2 + */ + public synchronized boolean equals(Object o) + { + // Here just for the sychronization. + return super.equals(o); + } + + /** + * Computes the hashcode of this object. + * + * @return the hashcode + * @since 1.2 + */ + public synchronized int hashCode() + { + // Here just for the sychronization. + return super.hashCode(); + } + + /** + * Returns a string representation of this Vector in the form + * "[element0, element1, ... elementN]". + * + * @return the String representation of this Vector + */ + public synchronized String toString() + { + // Here just for the sychronization. + return super.toString(); + } + + /** + * Obtain a List view of a subsection of this list, from fromIndex + * (inclusive) to toIndex (exclusive). If the two indices are equal, the + * sublist is empty. The returned list is modifiable, and changes in one + * reflect in the other. If this list is structurally modified in + * any way other than through the returned list, the result of any subsequent + * operations on the returned list is undefined. + *

    + * + * @param fromIndex the index that the returned list should start from + * (inclusive) + * @param toIndex the index that the returned list should go to (exclusive) + * @return a List backed by a subsection of this vector + * @throws IndexOutOfBoundsException if fromIndex < 0 + * || toIndex > size() + * @throws IllegalArgumentException if fromIndex > toIndex + * @see ConcurrentModificationException + * @since 1.2 + */ + public synchronized List subList(int fromIndex, int toIndex) + { + List sub = super.subList(fromIndex, toIndex); + // We must specify the correct object to synchronize upon, hence the + // use of a non-public API + return new Collections.SynchronizedList(this, sub); + } + + /** + * Removes a range of elements from this list. + * Does nothing when toIndex is equal to fromIndex. + * + * @param fromIndex the index to start deleting from (inclusive) + * @param toIndex the index to delete up to (exclusive) + * @throws IndexOutOfBoundsException if fromIndex > toIndex + */ + // This does not need to be synchronized, because it is only called through + // clear() of a sublist, and clear() had already synchronized. + protected void removeRange(int fromIndex, int toIndex) + { + int change = toIndex - fromIndex; + if (change > 0) + { + modCount++; + System.arraycopy(elementData, toIndex, elementData, fromIndex, + elementCount - toIndex); + int save = elementCount; + elementCount -= change; + Arrays.fill(elementData, elementCount, save, null); + } + else if (change < 0) + throw new IndexOutOfBoundsException(); + } + + /** + * Checks that the index is in the range of possible elements (inclusive). + * + * @param index the index to check + * @throws ArrayIndexOutOfBoundsException if index > size + */ + private void checkBoundInclusive(int index) + { + // Implementation note: we do not check for negative ranges here, since + // use of a negative index will cause an ArrayIndexOutOfBoundsException + // with no effort on our part. + if (index > elementCount) + throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount); + } + + /** + * Checks that the index is in the range of existing elements (exclusive). + * + * @param index the index to check + * @throws ArrayIndexOutOfBoundsException if index >= size + */ + private void checkBoundExclusive(int index) + { + // Implementation note: we do not check for negative ranges here, since + // use of a negative index will cause an ArrayIndexOutOfBoundsException + // with no effort on our part. + if (index >= elementCount) + throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); + } + + /** + * Serializes this object to the given stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData just calls default write function + */ + private synchronized void writeObject(ObjectOutputStream s) + throws IOException + { + s.defaultWriteObject(); + } + +} diff --git a/libjava/classpath/java/util/WeakHashMap.java b/libjava/classpath/java/util/WeakHashMap.java new file mode 100644 index 0000000..7593f7e --- /dev/null +++ b/libjava/classpath/java/util/WeakHashMap.java @@ -0,0 +1,881 @@ +/* WeakHashMap -- a hashtable that keeps only weak references + to its keys, allowing the virtual machine to reclaim them + Copyright (C) 1999, 2000, 2001, 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 java.util; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; + +/** + * 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. + * + *

    A weak hash map makes most sense when the keys doesn't override the + * equals method: If there is no other reference to the + * key nobody can ever look up the key in this table and so the entry + * can be removed. This table also works when the equals + * method is overloaded, such as String keys, but you should be prepared + * to deal with some entries disappearing spontaneously. + * + *

    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) + * + * @see HashMap + * @see WeakReference + * @see LinkedHashMap + * @since 1.2 + * @status updated to 1.4 + */ +public class WeakHashMap extends AbstractMap implements Map +{ + // WARNING: WeakHashMap is a CORE class in the bootstrap cycle. See the + // comments in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * 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() + { + /** + * Sets the hashCode to 0, since that's what null would map to. + * @return the hash code 0 + */ + public int hashCode() + { + return 0; + } + + /** + * Compares this key to the given object. Normally, an object should + * NEVER compare equal to null, but since we don't publicize NULL_VALUE, + * it saves bytecode to do so here. + * @return true iff o is this or null + */ + public boolean equals(Object o) + { + return null == o || this == o; + } + }; + + /** + * 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 WeakHashMap. 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 WeakHashMap. + */ + 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(); + } + + /** + * 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 key.hashCode() ^ WeakHashMap.hashCode(value); + } + + /** + * 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 key.equals(e.getKey()) + && WeakHashMap.equals(value, e.getValue()); + } + return false; + } + + public String toString() + { + return key + "=" + 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 WeakHashMap() + { + 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 WeakHashMap(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 WeakHashMap(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 WeakHashMap with the same mappings as the given map. + * The WeakHashMap has a default load factor of 0.75. + * + * @param m the map to copy + * @throws NullPointerException if m is null + * @since 1.3 + */ + public WeakHashMap(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(key.hashCode() % 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.equals(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; + if (buckets[slot] == bucket) + buckets[slot] = bucket.next; + else + { + WeakBucket prev = buckets[slot]; + /* This may throw a NullPointerException. It shouldn't but if + * a race condition occurred (two threads removing the same + * bucket at the same time) it may happen.
    + * But with race condition many much worse things may happen + * anyway. + */ + while (prev.next != bucket) + prev = prev.next; + 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 WeakHashMap diff --git a/libjava/classpath/java/util/class-dependencies.conf b/libjava/classpath/java/util/class-dependencies.conf new file mode 100644 index 0000000..39f9606 --- /dev/null +++ b/libjava/classpath/java/util/class-dependencies.conf @@ -0,0 +1,78 @@ +# This property file contains dependencies of classes, methods, and +# field on other methods or classes. +# +# Syntax: +# +# : [... ] +# +# means that when is included, (... ) must +# be included as well. +# +# and are of the form +# +# +# +# or just +# +# +# +# Within dependencies, variables can be used. A variable is defined as +# follows: +# +# {variable}: value1 value2 ... value +# +# variables can be used on the right side of dependencies as follows: +# +# : com.bla.blu.{variable}.Class.m()V +# +# The use of the variable will expand to dependencies of the form +# +# : com.bla.blu.value1.Class.m()V +# : com.bla.blu.value2.Class.m()V +# ... +# : com.bla.blu.value.Class.m()V +# +# Variables can be redefined when building a system to select the +# required support for features like encodings, protocols, etc. +# +# Hints: +# +# - For methods and fields, the signature is mandatory. For +# specification, please see the Java Virtual Machine Specification by +# SUN. Unlike in the spec, field signatures (types) are in brackets. +# +# - Package names must be separated by '/' (and not '.'). E.g., +# java/lang/Class (this is necessary, because the '.' is used to +# separate method or field names from classes) +# +# - In case refers to a class, only the class itself will be +# included in the resulting binary, NOT necessarily all its methods +# and fields. If you want to refer to all methods and fields, you can +# write class.* as an abbreviation. +# +# - Abbreviations for packages are also possible: my/package/* means all +# methods and fields of all classes in my/package. +# +# - A line with a trailing '\' continues in the next line. + + +# All calendars supported are loaded via java/util/Calendar.getBundle or +# java/util/GregorianCalendar.getBundle from class +# gnu/java/locale/Calendar_{locale_id} +# +# This introduces a dependency for the localized calendars. To allow an easy +# selection and addition of locales, the library variable {calendar_locales} +# can be set to the set of supported calendar locales. +# + +{calendar_locales}: de en nl + +java/util/Calendar.getBundle(Ljava/util/Locale;)Ljava/util/ResourceBundle;: \ + gnu/java/locale/Calendar.* \ + gnu/java/locale/Calendar_{calendar_locales}.* + +java/util/GregorianCalendar.getBundle(Ljava/util/Locale;)Ljava/util/ResourceBundle;: \ + gnu/java/locale/Calendar.* \ + gnu/java/locale/Calendar_{calendar_locales}.* + +# end of file diff --git a/libjava/classpath/java/util/jar/Attributes.java b/libjava/classpath/java/util/jar/Attributes.java new file mode 100644 index 0000000..4db2c72 --- /dev/null +++ b/libjava/classpath/java/util/jar/Attributes.java @@ -0,0 +1,630 @@ +/* Attributes.java -- Represents attribute name/value pairs from a Manifest + Copyright (C) 2000, 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 java.util.jar; + +import java.util.Collection; +import java.util.Hashtable; +import java.util.Map; +import java.util.Set; + +/** + * Represents attribute name/value pairs from a Manifest as a Map. + * The names of an attribute are represented by the + * Attributes.Name class and should confirm to the restrictions + * described in that class. Note that the Map interface that Attributes + * implements allows you to put names and values into the attribute that don't + * follow these restriction (and are not really Atrribute.Names, but if you do + * that it might cause undefined behaviour later). + *

    + * If you use the constants defined in the inner class Name then you can be + * sure that you always access the right attribute names. This makes + * manipulating the Attributes more or less type safe. + *

    + * Most of the methods are wrappers to implement the Map interface. The really + * useful and often used methods are getValue(Name) and + * getValue(String). If you actually want to set attributes you + * may want to use the putValue(String, String) method + * (sorry there is no public type safe putValue(Name, String) + * method). + * + * @see java.util.jar.Attributes.Name + * @author Mark Wielaard (mark@klomp.org) + */ +public class Attributes implements Cloneable, Map +{ + + // Fields + + /** + * The map that holds all the attribute name/value pairs. In this + * implementation it is actually a Hashtable, but that can be different in + * other implementations. + */ + protected Map map; + + // Inner class + + /** + * Represents a name of a Manifest Attribute. Defines a couple of well + * know names for the general main attributes, stand alone application + * attributes, applet attributes, extension identification attributes, + * package versioning and sealing attributes, file contents attributes, + * bean objects attribute and signing attributes. See the + * + *

    The characters of a Name must obey the following restrictions:

    + * + *
      + *
    • Must contain at least one character
    • + *
    • The first character must be alphanumeric (a-z, A-Z, 0-9)
    • + *
    • All other characters must be alphanumeric, a '-' or a '_'
    • + *
    + * + *

    When comparing Names (with equals) all characters are + * converted to lowercase. But you can get the original case sensitive + * string with the toString() method.

    + * + *

    Most important attributes have a constant defined in this + * class. Some other attributes used in Manifest files are: + *

      + *
    • "Created-By" - General main attribute, tool and version + * that created this Manifest file.
    • + *
    • "Java-Bean" - Bean objects attribute, whether the entry is a Bean. + * Value is either "true" or "false".
    • + *
    • "Magic" - Signing attribute, application specific signing attribute. + * Must be understood by the manifest parser when present to validate the + * jar (entry).
    • + *
    + * + * @since 1.2 + * @author Mark Wielaard (mark@klomp.org) + */ + public static class Name + { + // General Main Attributes + + /** + * General main attribute - + * the version of this Manifest file. + */ + public static final Name MANIFEST_VERSION = new Name("Manifest-Version"); + + /** + * General main attribute - + * the version of the jar file signature. + */ + public static final Name SIGNATURE_VERSION + = new Name("Signature-Version"); + + /** + * General main attribute - + * (relative) file paths of the libraries/classpaths that the Classes in + * this jar file depend on. Paths are separated by spaces. + */ + public static final Name CLASS_PATH = new Name("Class-Path"); + + /** + * Stand alone application attribute - + * the entry (without the .class ending) that is the main + * class of this jar file. + */ + public static final Name MAIN_CLASS = new Name("Main-Class"); + + /** + * Applet attribute - + * a list of extension libraries that the applet in this + * jar file depends on. + * For every named extension there should be some Attributes in the + * Manifest manifest file with the following Names: + *
      + *
    • <extension>-Extension-Name: + * unique name of the extension
    • + *
    • <extension>-Specification-Version: + * minimum specification version
    • + *
    • <extension>-Implementation-Version: + * minimum implementation version
    • + *
    • <extension>-Implementation-Vendor-Id: + * unique id of implementation vendor
    • + *
    • <extension>-Implementation-URL: + * where the latest version of the extension library can be found
    • + *
    + */ + public static final Name EXTENSION_LIST = new Name("Extension-List"); + + /** + * Extension identification attribute - + * the name if the extension library contained in the jar. + */ + public static final Name EXTENSION_NAME = new Name("Extension-Name"); + + /** + * Extension identification attribute - + * synonym for EXTENSTION_NAME. + */ + public static final Name EXTENSION_INSTALLATION = EXTENSION_NAME; + + // Package versioning and sealing attributes + + /** + * Package versioning - + * name of extension library contained in this jar. + */ + public static final Name IMPLEMENTATION_TITLE + = new Name("Implementation-Title"); + + /** + * Package versioning - + * version of the extension library contained in this jar. + */ + public static final Name IMPLEMENTATION_VERSION + = new Name("Implementation-Version"); + + /** + * Package versioning - + * name of extension library creator contained in this jar. + */ + public static final Name IMPLEMENTATION_VENDOR + = new Name("Implementation-Vendor"); + + /** + * Package versioning - + * unique id of extension library creator. + */ + public static final Name IMPLEMENTATION_VENDOR_ID + = new Name("Implementation-Vendor-Id"); + + /** + * Package versioning - + * location where this implementation can be downloaded. + */ + public static final Name IMPLEMENTATION_URL + = new Name("Implementation-URL"); + + /** + * Package versioning - + * title of the specification contained in this jar. + */ + public static final Name SPECIFICATION_TITLE + = new Name("Specification-Title"); + + /** + * Package versioning - + * version of the specification contained in this jar. + */ + public static final Name SPECIFICATION_VERSION + = new Name("Specification-Version"); + + /** + * Package versioning - + * organisation that maintains the specification contains in this + * jar. + */ + public static final Name SPECIFICATION_VENDOR + = new Name("Specification-Vendor"); + + /** + * Package sealing - + * whether (all) package(s) is(/are) sealed. Value is either "true" + * or "false". + */ + public static final Name SEALED = new Name("Sealed"); + + /** + * File contents attribute - + * Mime type and subtype for the jar entry. + */ + public static final Name CONTENT_TYPE = new Name("Content-Type"); + + /** The (lowercase) String representation of this Name */ + private final String name; + + /** The original String given to the constructor */ + private final String origName; + + // Constructor + + /** + * Creates a new Name from the given String. + * Throws an IllegalArgumentException if the given String is empty or + * contains any illegal Name characters. + * + * @param name the name of the new Name + * @exception IllegalArgumentException if name isn't a valid String + * representation of a Name + * @exception NullPointerException if name is null + */ + public Name(String name) throws IllegalArgumentException, + NullPointerException + { + // name must not be null + // this will throw a NullPointerException if it is + char chars[] = name.toCharArray(); + + // there must be at least one character + if (chars.length == 0) + throw new + IllegalArgumentException + ("There must be at least one character in a name"); + + // first character must be alphanum + char c = chars[0]; + if (!((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))) + throw new + IllegalArgumentException("First character must be alphanum"); + + // all other characters must be alphanums, '-' or '_' + for (int i = 1; i < chars.length; i++) + { + c = chars[i]; + if (!((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || (c == '-') || (c == '_'))) + throw new + IllegalArgumentException + ("Characters must be alphanums, '-' or '_'"); + } + + // Still here? Then convert to lower case and be done. + // Store the original name for toString(); + this.origName = name; + this.name = name.toLowerCase(); + } + + /** + * Returns the hash code of the (lowercase) String representation of + * this Name. + */ + public int hashCode() + { + return name.hashCode(); + } + + /** + * Checks if another object is equal to this Name object. + * Another object is equal to this Name object if it is an instance of + * Name and the (lowercase) string representation of the name is equal. + */ + public boolean equals(Object o) + { + // Quick and dirty check + if (name == o) + return true; + + try + { + // Note that the constructor already converts the strings to + // lowercase. + String otherName = ((Name) o).name; + return name.equals(otherName); + } + catch (ClassCastException cce) + { + return false; + } + catch (NullPointerException npe) + { + return false; + } + } + + /** + * Returns the string representation of this Name as given to the + * constructor (not neccesarily the lower case representation). + */ + public String toString() + { + return origName; + } + } + + // Constructors + + /** + * Creates an empty Attributes map. + */ + public Attributes() + { + map = new Hashtable(); + } + + /** + * Creates an empty Attributes map with the given initial size. + * @param size the initial size of the underlying map + */ + public Attributes(int size) + { + map = new Hashtable(size); + } + + /** + * Creates an Attributes map with the initial values taken from another + * Attributes map. + * @param attr Attributes map to take the initial values from + */ + public Attributes(Attributes attr) + { + map = new Hashtable(attr.map); + } + + // Methods + + /** + * Gets the value of an attribute name given as a String. + * + * @param name a String describing the Name to look for + * @return the value gotten from the map of null when not found + */ + public String getValue(String name) + { + return (String) get(new Name(name)); + } + + /** + * Gets the value of the given attribute name. + * + * @param name the Name to look for + * @return the value gotten from the map of null when not found + */ + public String getValue(Name name) + { + return (String) get(name); + } + + /** + * Stores an attribute name (represented by a String) and value in this + * Attributes map. + * When the (case insensitive string) name already exists the value is + * replaced and the old value is returned. + * + * @param name a (case insensitive) String representation of the attribite + * name to add/replace + * @param value the (new) value of the attribute name + * @returns the old value of the attribute name or null if it didn't exist + * yet + */ + public String putValue(String name, String value) + { + return putValue(new Name(name), value); + } + + /** + * Stores an attribute name (represented by a String) and value in this + * Attributes map. + * When the name already exists the value is replaced and the old value + * is returned. + *

    + * I don't know why there is no public method with this signature. I think + * there should be one. + * + * @param name the attribite name to add/replace + * @param value the (new) value of the attribute name + * @returns the old value of the attribute name or null if it didn't exist + * yet + */ + String putValue(Name name, String value) + { + return (String) put(name, value); + } + + // Methods from Cloneable interface + + /** + * Return a clone of this attribute map. + */ + public Object clone() + { + return new Attributes(this); + } + + // Methods from Map interface + + /** + * Removes all attributes. + */ + public void clear() + { + map.clear(); + } + + /** + * Checks to see if there is an attribute with the specified name. + * XXX - what if the object is a String? + * + * @param attrName the name of the attribute to check + * @return true if there is an attribute with the specified name, false + * otherwise + */ + public boolean containsKey(Object attrName) + { + return map.containsKey(attrName); + } + + /** + * Checks to see if there is an attribute name with the specified value. + * + * @param attrValue the value of a attribute to check + * @return true if there is an attribute name with the specified value, + * false otherwise + */ + public boolean containsValue(Object attrValue) + { + return map.containsValue(attrValue); + } + + /** + * Gives a Set of attribute name and values pairs as MapEntries. + * @see java.util.Map.Entry + * @see java.util.Map#entrySet() + * + * @return a set of attribute name value pairs + */ + public Set entrySet() + { + return map.entrySet(); + } + + /** + * Checks to see if two Attributes are equal. The supplied object must be + * a real instance of Attributes and contain the same attribute name/value + * pairs. + * + * @param o another Attribute object which should be checked for equality + * @return true if the object is an instance of Attributes and contains the + * same name/value pairs, false otherwise + */ + public boolean equals(Object o) + { + // quick and dirty check + if (this == o) + return true; + + try + { + return map.equals(((Attributes) o).map); + } + catch (ClassCastException cce) + { + return false; + } + catch (NullPointerException npe) + { + return false; + } + } + + /** + * Gets the value of a specified attribute name. + * XXX - what if the object is a String? + * + * @param attrName the name of the attribute we want the value of + * @return the value of the specified attribute name or null when there is + * no such attribute name + */ + public Object get(Object attrName) + { + return map.get(attrName); + } + + /** + * Returns the hashcode of the attribute name/value map. + */ + public int hashCode() + { + return map.hashCode(); + } + + /** + * Returns true if there are no attributes set, false otherwise. + */ + public boolean isEmpty() + { + return map.isEmpty(); + } + + /** + * Gives a Set of all the values of defined attribute names. + */ + public Set keySet() + { + return map.keySet(); + } + + /** + * Adds or replaces a attribute name/value pair. + * XXX - What if the name is a string? What if the name is neither a Name + * nor a String? What if the value is not a string? + * + * @param name the name of the attribute + * @param value the (new) value of the attribute + * @return the old value of the attribute or null when there was no old + * attribute with this name + */ + public Object put(Object name, Object value) + { + return map.put(name, value); + } + + /** + * Adds or replaces all attribute name/value pairs from another + * Attributes object to this one. The supplied Map must be an instance of + * Attributes. + * + * @param attr the Attributes object to merge with this one + * @exception ClassCastException if the supplied map is not an instance of + * Attributes + */ + public void putAll(Map attr) + { + if (!(attr instanceof Attributes)) + { + throw new + ClassCastException("Supplied Map is not an instance of Attributes"); + } + map.putAll(attr); + } + + /** + * Remove a attribute name/value pair. + * XXX - What if the name is a String? + * + * @param name the name of the attribute name/value pair to remove + * @return the old value of the attribute or null if the attribute didn't + * exist + */ + public Object remove(Object name) + { + return map.remove(name); + } + + /** + * Returns the number of defined attribute name/value pairs. + */ + public int size() + { + return map.size(); + } + + /** + * Returns all the values of the defined attribute name/value pairs as a + * Collection. + */ + public Collection values() + { + return map.values(); + } +} diff --git a/libjava/classpath/java/util/jar/JarEntry.java b/libjava/classpath/java/util/jar/JarEntry.java new file mode 100644 index 0000000..722a283 --- /dev/null +++ b/libjava/classpath/java/util/jar/JarEntry.java @@ -0,0 +1,165 @@ +/* JarEntry.java - Represents an entry in a jar file + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.jar; + +import java.io.IOException; +import java.security.cert.Certificate; +import java.util.zip.ZipEntry; + +/** + * Extension to a ZipEntry that contains manifest attributes and certificates. + * Both the Atrributes and the Certificates can be null when not set. + * Note that the getCertificates() method only returns a + * valid value after all of the data of the entry has been read. + *

    + * There are no public methods to set the attributes or certificate of an + * Entru. Only JarEntries created by the classes in java.util.jar + * will have these properties set. + * + * @since 1.2 + * @author Mark Wielaard (mark@klomp.org) + */ + +public class JarEntry extends ZipEntry +{ + // (Package local) fields + + Attributes attr; + Certificate certs[]; + + // Constructors + + /** + * Creates a new JarEntry with the specified name and no attributes or + * or certificates. Calls super(name) so all other (zip)entry + * fields are null or -1. + * + * @param name the name of the new jar entry + * @exception NullPointerException when the supplied name is null + * @exception IllegalArgumentException when the supplied name is longer + * than 65535 bytes + */ + public JarEntry(String name) throws NullPointerException, + IllegalArgumentException + { + super(name); + attr = null; + certs = null; + } + + /** + * Creates a new JarEntry with the specified ZipEntry as template for + * all properties of the entry. Both attributes and certificates will be + * null. + * + * @param entry the ZipEntry whose fields should be copied + */ + public JarEntry(ZipEntry entry) + { + super(entry); + attr = null; + certs = null; + } + + /** + * Creates a new JarEntry with the specified JarEntry as template for + * all properties of the entry. + * + * @param entry the jarEntry whose fields should be copied + */ + public JarEntry(JarEntry entry) + { + super(entry); + try + { + attr = entry.getAttributes(); + } + catch (IOException _) + { + } + certs = entry.getCertificates(); + } + + // Methods + + /** + * Returns a copy of the Attributes set for this entry. + * When no Attributes are set in the manifest null is returned. + * + * @return a copy of the Attributes set for this entry + * @exception IOException This will never be thrown. It is here for + * binary compatibility. + */ + public Attributes getAttributes() throws IOException + { + if (attr != null) + { + return (Attributes) attr.clone(); + } + else + { + return null; + } + } + + /** + * Returns a copy of the certificates set for this entry. + * When no certificates are set or when not all data of this entry has + * been read null is returned. + *

    + * To make sure that this call returns a valid value you must read all + * data from the JarInputStream for this entry. + * When you don't need the data for an entry but want to know the + * certificates that are set for the entry then you can skip all data by + * calling skip(entry.getSize()) on the JarInputStream for + * the entry. + * + * @return a copy of the certificates set for this entry + */ + public Certificate[] getCertificates() + { + if (certs != null) + { + return (Certificate[])certs.clone(); + } + else + { + return null; + } + } +} diff --git a/libjava/classpath/java/util/jar/JarException.java b/libjava/classpath/java/util/jar/JarException.java new file mode 100644 index 0000000..d6f0634 --- /dev/null +++ b/libjava/classpath/java/util/jar/JarException.java @@ -0,0 +1,77 @@ +/* JarException.java -- thrown to indicate an problem with a jar file + Copyright (C) 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 java.util.jar; + +import java.util.zip.ZipException; + +/** + * This exception is thrown to indicate an problem with a jar file. + * Note that none of the methods in the java.util.jar package actually declare + * to throw this exception, most just declare that they throw an IOException + * which is super class of JarException. + * + * @author Mark Wielaard (mark@klomp.org) + * @since 1.2 + */ +public class JarException extends ZipException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 7159778400963954473L; + + /** + * Create a new JarException without a descriptive error message. + */ + public JarException() + { + } + + /** + * Create a new JarException with a descriptive error message indicating + * what went wrong. This message can later be retrieved by calling the + * getMessage() method. + * + * @param message The descriptive error message + * @see #getMessage() + */ + public JarException(String message) + { + super(message); + } +} diff --git a/libjava/classpath/java/util/jar/JarFile.java b/libjava/classpath/java/util/jar/JarFile.java new file mode 100644 index 0000000..a9ad21e --- /dev/null +++ b/libjava/classpath/java/util/jar/JarFile.java @@ -0,0 +1,1059 @@ +/* JarFile.java - Representation of a jar file + Copyright (C) 2000, 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 java.util.jar; + +import gnu.java.io.Base64InputStream; +import gnu.java.security.OID; +import gnu.java.security.pkcs.PKCS7SignedData; +import gnu.java.security.pkcs.SignerInfo; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +/** + * Representation of a jar file. + *

    + * Note that this class is not a subclass of java.io.File but a subclass of + * java.util.zip.ZipFile and you can only read JarFiles with it (although + * there are constructors that take a File object). + * + * @since 1.2 + * @author Mark Wielaard (mark@klomp.org) + * @author Casey Marshall (csm@gnu.org) wrote the certificate and entry + * verification code. + */ +public class JarFile extends ZipFile +{ + // Fields + + /** The name of the manifest entry: META-INF/MANIFEST.MF */ + public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; + + /** The META-INF directory entry. */ + private static final String META_INF = "META-INF/"; + + /** The suffix for PKCS7 DSA signature entries. */ + private static final String PKCS7_DSA_SUFFIX = ".DSA"; + + /** The suffix for PKCS7 RSA signature entries. */ + private static final String PKCS7_RSA_SUFFIX = ".RSA"; + + /** The suffix for digest attributes. */ + private static final String DIGEST_KEY_SUFFIX = "-Digest"; + + /** The suffix for signature files. */ + private static final String SF_SUFFIX = ".SF"; + + // Signature OIDs. + private static final OID MD2_OID = new OID("1.2.840.113549.2.2"); + private static final OID MD4_OID = new OID("1.2.840.113549.2.4"); + private static final OID MD5_OID = new OID("1.2.840.113549.2.5"); + private static final OID SHA1_OID = new OID("1.3.14.3.2.26"); + private static final OID DSA_ENCRYPTION_OID = new OID("1.2.840.10040.4.1"); + private static final OID RSA_ENCRYPTION_OID = new OID("1.2.840.113549.1.1.1"); + + /** + * The manifest of this file, if any, otherwise null. + * Read when first needed. + */ + private Manifest manifest; + + /** Whether to verify the manifest and all entries. */ + boolean verify; + + /** Whether the has already been loaded. */ + private boolean manifestRead = false; + + /** Whether the signature files have been loaded. */ + boolean signaturesRead = false; + + /** + * A map between entry names and booleans, signaling whether or + * not that entry has been verified. + * Only be accessed with lock on this JarFile*/ + HashMap verified = new HashMap(); + + /** + * A mapping from entry name to certificates, if any. + * Only accessed with lock on this JarFile. + */ + HashMap entryCerts; + + static boolean DEBUG = false; + static void debug(Object msg) + { + System.err.print(JarFile.class.getName()); + System.err.print(" >>> "); + System.err.println(msg); + } + + // Constructors + + /** + * Creates a new JarFile. All jar entries are verified (when a Manifest file + * for this JarFile exists). You need to actually open and read the complete + * jar entry (with getInputStream()) to check its signature. + * + * @param fileName the name of the file to open + * @exception FileNotFoundException if the fileName cannot be found + * @exception IOException if another IO exception occurs while reading + */ + public JarFile(String fileName) throws FileNotFoundException, IOException + { + this(fileName, true); + } + + /** + * Creates a new JarFile. If verify is true then all jar entries are + * verified (when a Manifest file for this JarFile exists). You need to + * actually open and read the complete jar entry + * (with getInputStream()) to check its signature. + * + * @param fileName the name of the file to open + * @param verify checks manifest and entries when true and a manifest + * exists, when false no checks are made + * @exception FileNotFoundException if the fileName cannot be found + * @exception IOException if another IO exception occurs while reading + */ + public JarFile(String fileName, boolean verify) throws + FileNotFoundException, IOException + { + super(fileName); + if (verify) + { + manifest = readManifest(); + verify(); + } + } + + /** + * Creates a new JarFile. All jar entries are verified (when a Manifest file + * for this JarFile exists). You need to actually open and read the complete + * jar entry (with getInputStream()) to check its signature. + * + * @param file the file to open as a jar file + * @exception FileNotFoundException if the file does not exits + * @exception IOException if another IO exception occurs while reading + */ + public JarFile(File file) throws FileNotFoundException, IOException + { + this(file, true); + } + + /** + * Creates a new JarFile. If verify is true then all jar entries are + * verified (when a Manifest file for this JarFile exists). You need to + * actually open and read the complete jar entry + * (with getInputStream()) to check its signature. + * + * @param file the file to open to open as a jar file + * @param verify checks manifest and entries when true and a manifest + * exists, when false no checks are made + * @exception FileNotFoundException if file does not exist + * @exception IOException if another IO exception occurs while reading + */ + public JarFile(File file, boolean verify) throws FileNotFoundException, + IOException + { + super(file); + if (verify) + { + manifest = readManifest(); + verify(); + } + } + + /** + * Creates a new JarFile with the indicated mode. If verify is true then + * all jar entries are verified (when a Manifest file for this JarFile + * exists). You need to actually open and read the complete jar entry + * (with getInputStream()) to check its signature. + * manifest and if the manifest exists and verify is true verfies it. + * + * @param file the file to open to open as a jar file + * @param verify checks manifest and entries when true and a manifest + * exists, when false no checks are made + * @param mode either ZipFile.OPEN_READ or + * (ZipFile.OPEN_READ | ZipFile.OPEN_DELETE) + * @exception FileNotFoundException if the file does not exist + * @exception IOException if another IO exception occurs while reading + * @exception IllegalArgumentException when given an illegal mode + * + * @since 1.3 + */ + public JarFile(File file, boolean verify, int mode) throws + FileNotFoundException, IOException, IllegalArgumentException + { + super(file, mode); + if (verify) + { + manifest = readManifest(); + verify(); + } + } + + // Methods + + /** + * XXX - should verify the manifest file + */ + private void verify() + { + // only check if manifest is not null + if (manifest == null) + { + verify = false; + return; + } + + verify = true; + // XXX - verify manifest + } + + /** + * Parses and returns the manifest if it exists, otherwise returns null. + */ + private Manifest readManifest() + { + try + { + ZipEntry manEntry = super.getEntry(MANIFEST_NAME); + if (manEntry != null) + { + InputStream in = super.getInputStream(manEntry); + manifestRead = true; + return new Manifest(in); + } + else + { + manifestRead = true; + return null; + } + } + catch (IOException ioe) + { + manifestRead = true; + return null; + } + } + + /** + * Returns a enumeration of all the entries in the JarFile. + * Note that also the Jar META-INF entries are returned. + * + * @exception IllegalStateException when the JarFile is already closed + */ + public Enumeration entries() throws IllegalStateException + { + return new JarEnumeration(super.entries(), this); + } + + /** + * Wraps a given Zip Entries Enumeration. For every zip entry a + * JarEntry is created and the corresponding Attributes are looked up. + */ + private static class JarEnumeration implements Enumeration + { + + private final Enumeration entries; + private final JarFile jarfile; + + JarEnumeration(Enumeration e, JarFile f) + { + entries = e; + jarfile = f; + } + + public boolean hasMoreElements() + { + return entries.hasMoreElements(); + } + + public Object nextElement() + { + ZipEntry zip = (ZipEntry) entries.nextElement(); + JarEntry jar = new JarEntry(zip); + Manifest manifest; + try + { + manifest = jarfile.getManifest(); + } + catch (IOException ioe) + { + manifest = null; + } + + if (manifest != null) + { + jar.attr = manifest.getAttributes(jar.getName()); + } + + synchronized(jarfile) + { + if (!jarfile.signaturesRead) + try + { + jarfile.readSignatures(); + } + catch (IOException ioe) + { + if (JarFile.DEBUG) + { + JarFile.debug(ioe); + ioe.printStackTrace(); + } + jarfile.signaturesRead = true; // fudge it. + } + + // Include the certificates only if we have asserted that the + // signatures are valid. This means the certificates will not be + // available if the entry hasn't been read yet. + if (jarfile.entryCerts != null + && jarfile.verified.get(zip.getName()) == Boolean.TRUE) + { + Set certs = (Set) jarfile.entryCerts.get(jar.getName()); + if (certs != null) + jar.certs = (Certificate[]) + certs.toArray(new Certificate[certs.size()]); + } + } + return jar; + } + } + + /** + * XXX + * It actually returns a JarEntry not a zipEntry + * @param name XXX + */ + public synchronized ZipEntry getEntry(String name) + { + ZipEntry entry = super.getEntry(name); + if (entry != null) + { + JarEntry jarEntry = new JarEntry(entry); + Manifest manifest; + try + { + manifest = getManifest(); + } + catch (IOException ioe) + { + manifest = null; + } + + if (manifest != null) + { + jarEntry.attr = manifest.getAttributes(name); + } + + if (!signaturesRead) + try + { + readSignatures(); + } + catch (IOException ioe) + { + if (DEBUG) + { + debug(ioe); + ioe.printStackTrace(); + } + signaturesRead = true; + } + // See the comments in the JarEnumeration for why we do this + // check. + if (DEBUG) + debug("entryCerts=" + entryCerts + " verified " + name + + " ? " + verified.get(name)); + if (entryCerts != null && verified.get(name) == Boolean.TRUE) + { + Set certs = (Set) entryCerts.get(name); + if (certs != null) + jarEntry.certs = (Certificate[]) + certs.toArray(new Certificate[certs.size()]); + } + return jarEntry; + } + return null; + } + + /** + * Returns an input stream for the given entry. If configured to + * verify entries, the input stream returned will verify them while + * the stream is read, but only on the first time. + * + * @param entry The entry to get the input stream for. + * @exception ZipException XXX + * @exception IOException XXX + */ + public synchronized InputStream getInputStream(ZipEntry entry) throws + ZipException, IOException + { + // If we haven't verified the hash, do it now. + if (!verified.containsKey(entry.getName()) && verify) + { + if (DEBUG) + debug("reading and verifying " + entry); + return new EntryInputStream(entry, super.getInputStream(entry), this); + } + else + { + if (DEBUG) + debug("reading already verified entry " + entry); + if (verify && verified.get(entry.getName()) == Boolean.FALSE) + throw new ZipException("digest for " + entry + " is invalid"); + return super.getInputStream(entry); + } + } + + /** + * Returns the JarEntry that belongs to the name if such an entry + * exists in the JarFile. Returns null otherwise + * Convenience method that just casts the result from getEntry + * to a JarEntry. + * + * @param name the jar entry name to look up + * @return the JarEntry if it exists, null otherwise + */ + public JarEntry getJarEntry(String name) + { + return (JarEntry) getEntry(name); + } + + /** + * Returns the manifest for this JarFile or null when the JarFile does not + * contain a manifest file. + */ + public synchronized Manifest getManifest() throws IOException + { + if (!manifestRead) + manifest = readManifest(); + + return manifest; + } + + // Only called with lock on this JarFile. + // Package private for use in inner classes. + void readSignatures() throws IOException + { + Map pkcs7Dsa = new HashMap(); + Map pkcs7Rsa = new HashMap(); + Map sigFiles = new HashMap(); + + // Phase 1: Read all signature files. These contain the user + // certificates as well as the signatures themselves. + for (Enumeration e = super.entries(); e.hasMoreElements(); ) + { + ZipEntry ze = (ZipEntry) e.nextElement(); + String name = ze.getName(); + if (name.startsWith(META_INF)) + { + String alias = name.substring(META_INF.length()); + if (alias.lastIndexOf('.') >= 0) + alias = alias.substring(0, alias.lastIndexOf('.')); + + if (name.endsWith(PKCS7_DSA_SUFFIX) || name.endsWith(PKCS7_RSA_SUFFIX)) + { + if (DEBUG) + debug("reading PKCS7 info from " + name + ", alias=" + alias); + PKCS7SignedData sig = null; + try + { + sig = new PKCS7SignedData(super.getInputStream(ze)); + } + catch (CertificateException ce) + { + IOException ioe = new IOException("certificate parsing error"); + ioe.initCause(ce); + throw ioe; + } + catch (CRLException crle) + { + IOException ioe = new IOException("CRL parsing error"); + ioe.initCause(crle); + throw ioe; + } + if (name.endsWith(PKCS7_DSA_SUFFIX)) + pkcs7Dsa.put(alias, sig); + else if (name.endsWith(PKCS7_RSA_SUFFIX)) + pkcs7Rsa.put(alias, sig); + } + else if (name.endsWith(SF_SUFFIX)) + { + if (DEBUG) + debug("reading signature file for " + alias + ": " + name); + Manifest sf = new Manifest(super.getInputStream(ze)); + sigFiles.put(alias, sf); + if (DEBUG) + debug("result: " + sf); + } + } + } + + // Phase 2: verify the signatures on any signature files. + Set validCerts = new HashSet(); + Map entryCerts = new HashMap(); + for (Iterator it = sigFiles.entrySet().iterator(); it.hasNext(); ) + { + int valid = 0; + Map.Entry e = (Map.Entry) it.next(); + String alias = (String) e.getKey(); + + PKCS7SignedData sig = (PKCS7SignedData) pkcs7Dsa.get(alias); + if (sig != null) + { + Certificate[] certs = sig.getCertificates(); + Set signerInfos = sig.getSignerInfos(); + for (Iterator it2 = signerInfos.iterator(); it2.hasNext(); ) + verify(certs, (SignerInfo) it2.next(), alias, validCerts); + } + + sig = (PKCS7SignedData) pkcs7Rsa.get(alias); + if (sig != null) + { + Certificate[] certs = sig.getCertificates(); + Set signerInfos = sig.getSignerInfos(); + for (Iterator it2 = signerInfos.iterator(); it2.hasNext(); ) + verify(certs, (SignerInfo) it2.next(), alias, validCerts); + } + + // It isn't a signature for anything. Punt it. + if (validCerts.isEmpty()) + { + it.remove(); + continue; + } + + entryCerts.put(e.getValue(), new HashSet(validCerts)); + validCerts.clear(); + } + + // Phase 3: verify the signature file signatures against the manifest, + // mapping the entry name to the target certificates. + this.entryCerts = new HashMap(); + for (Iterator it = entryCerts.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + Manifest sigfile = (Manifest) e.getKey(); + Map entries = sigfile.getEntries(); + Set certificates = (Set) e.getValue(); + + for (Iterator it2 = entries.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e2 = (Map.Entry) it2.next(); + String entryname = String.valueOf(e2.getKey()); + Attributes attr = (Attributes) e2.getValue(); + if (verifyHashes(entryname, attr)) + { + if (DEBUG) + debug("entry " + entryname + " has certificates " + certificates); + Set s = (Set) this.entryCerts.get(entryname); + if (s != null) + s.addAll(certificates); + else + this.entryCerts.put(entryname, new HashSet(certificates)); + } + } + } + + signaturesRead = true; + } + + /** + * Tell if the given signer info is over the given alias's signature file, + * given one of the certificates specified. + */ + private void verify(Certificate[] certs, SignerInfo signerInfo, + String alias, Set validCerts) + { + Signature sig = null; + try + { + OID alg = signerInfo.getDigestEncryptionAlgorithmId(); + if (alg.equals(DSA_ENCRYPTION_OID)) + { + if (!signerInfo.getDigestAlgorithmId().equals(SHA1_OID)) + return; + sig = Signature.getInstance("SHA1withDSA"); + } + else if (alg.equals(RSA_ENCRYPTION_OID)) + { + OID hash = signerInfo.getDigestAlgorithmId(); + if (hash.equals(MD2_OID)) + sig = Signature.getInstance("md2WithRsaEncryption"); + else if (hash.equals(MD4_OID)) + sig = Signature.getInstance("md4WithRsaEncryption"); + else if (hash.equals(MD5_OID)) + sig = Signature.getInstance("md5WithRsaEncryption"); + else if (hash.equals(SHA1_OID)) + sig = Signature.getInstance("sha1WithRsaEncryption"); + else + return; + } + else + { + if (DEBUG) + debug("unsupported signature algorithm: " + alg); + return; + } + } + catch (NoSuchAlgorithmException nsae) + { + if (DEBUG) + { + debug(nsae); + nsae.printStackTrace(); + } + return; + } + ZipEntry sigFileEntry = super.getEntry(META_INF + alias + SF_SUFFIX); + if (sigFileEntry == null) + return; + for (int i = 0; i < certs.length; i++) + { + if (!(certs[i] instanceof X509Certificate)) + continue; + X509Certificate cert = (X509Certificate) certs[i]; + if (!cert.getIssuerX500Principal().equals(signerInfo.getIssuer()) || + !cert.getSerialNumber().equals(signerInfo.getSerialNumber())) + continue; + try + { + sig.initVerify(cert.getPublicKey()); + InputStream in = super.getInputStream(sigFileEntry); + if (in == null) + continue; + byte[] buf = new byte[1024]; + int len = 0; + while ((len = in.read(buf)) != -1) + sig.update(buf, 0, len); + if (sig.verify(signerInfo.getEncryptedDigest())) + { + if (DEBUG) + debug("signature for " + cert.getSubjectDN() + " is good"); + validCerts.add(cert); + } + } + catch (IOException ioe) + { + continue; + } + catch (InvalidKeyException ike) + { + continue; + } + catch (SignatureException se) + { + continue; + } + } + } + + /** + * Verifies that the digest(s) in a signature file were, in fact, made + * over the manifest entry for ENTRY. + * + * @param entry The entry name. + * @param attr The attributes from the signature file to verify. + */ + private boolean verifyHashes(String entry, Attributes attr) + { + int verified = 0; + + // The bytes for ENTRY's manifest entry, which are signed in the + // signature file. + byte[] entryBytes = null; + try + { + ZipEntry e = super.getEntry(entry); + if (e == null) + { + if (DEBUG) + debug("verifyHashes: no entry '" + entry + "'"); + return false; + } + entryBytes = readManifestEntry(e); + } + catch (IOException ioe) + { + if (DEBUG) + { + debug(ioe); + ioe.printStackTrace(); + } + return false; + } + + for (Iterator it = attr.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + String key = String.valueOf(e.getKey()); + if (!key.endsWith(DIGEST_KEY_SUFFIX)) + continue; + String alg = key.substring(0, key.length() - DIGEST_KEY_SUFFIX.length()); + try + { + byte[] hash = Base64InputStream.decode((String) e.getValue()); + MessageDigest md = MessageDigest.getInstance(alg); + md.update(entryBytes); + byte[] hash2 = md.digest(); + if (DEBUG) + debug("verifying SF entry " + entry + " alg: " + md.getAlgorithm() + + " expect=" + new java.math.BigInteger(hash).toString(16) + + " comp=" + new java.math.BigInteger(hash2).toString(16)); + if (!Arrays.equals(hash, hash2)) + return false; + verified++; + } + catch (IOException ioe) + { + if (DEBUG) + { + debug(ioe); + ioe.printStackTrace(); + } + return false; + } + catch (NoSuchAlgorithmException nsae) + { + if (DEBUG) + { + debug(nsae); + nsae.printStackTrace(); + } + return false; + } + } + + // We have to find at least one valid digest. + return verified > 0; + } + + /** + * Read the raw bytes that comprise a manifest entry. We can't use the + * Manifest object itself, because that loses information (such as line + * endings, and order of entries). + */ + private byte[] readManifestEntry(ZipEntry entry) throws IOException + { + InputStream in = super.getInputStream(super.getEntry(MANIFEST_NAME)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] target = ("Name: " + entry.getName()).getBytes(); + int t = 0, c, prev = -1, state = 0, l = -1; + + while ((c = in.read()) != -1) + { +// if (DEBUG) +// debug("read " +// + (c == '\n' ? "\\n" : (c == '\r' ? "\\r" : String.valueOf((char) c))) +// + " state=" + state + " prev=" +// + (prev == '\n' ? "\\n" : (prev == '\r' ? "\\r" : String.valueOf((char) prev))) +// + " t=" + t + (t < target.length ? (" target[t]=" + (char) target[t]) : "") +// + " l=" + l); + switch (state) + { + + // Step 1: read until we find the "target" bytes: the start + // of the entry we need to read. + case 0: + if (((byte) c) != target[t]) + t = 0; + else + { + t++; + if (t == target.length) + { + out.write(target); + state = 1; + } + } + break; + + // Step 2: assert that there is a newline character after + // the "target" bytes. + case 1: + if (c != '\n' && c != '\r') + { + out.reset(); + t = 0; + state = 0; + } + else + { + out.write(c); + state = 2; + } + break; + + // Step 3: read this whole entry, until we reach an empty + // line. + case 2: + if (c == '\n') + { + out.write(c); + // NL always terminates a line. + if (l == 0 || (l == 1 && prev == '\r')) + return out.toByteArray(); + l = 0; + } + else + { + // Here we see a blank line terminated by a CR, + // followed by the next entry. Technically, `c' should + // always be 'N' at this point. + if (l == 1 && prev == '\r') + return out.toByteArray(); + out.write(c); + l++; + } + prev = c; + break; + + default: + throw new RuntimeException("this statement should be unreachable"); + } + } + + // The last entry, with a single CR terminating the line. + if (state == 2 && prev == '\r' && l == 0) + return out.toByteArray(); + + // We should not reach this point, we didn't find the entry (or, possibly, + // it is the last entry and is malformed). + throw new IOException("could not find " + entry + " in manifest"); + } + + /** + * A utility class that verifies jar entries as they are read. + */ + private static class EntryInputStream extends FilterInputStream + { + private final JarFile jarfile; + private final long length; + private long pos; + private final ZipEntry entry; + private final byte[][] hashes; + private final MessageDigest[] md; + private boolean checked; + + EntryInputStream(final ZipEntry entry, + final InputStream in, + final JarFile jar) + throws IOException + { + super(in); + this.entry = entry; + this.jarfile = jar; + + length = entry.getSize(); + pos = 0; + checked = false; + + Attributes attr; + Manifest manifest = jarfile.getManifest(); + if (manifest != null) + attr = manifest.getAttributes(entry.getName()); + else + attr = null; + if (DEBUG) + debug("verifying entry " + entry + " attr=" + attr); + if (attr == null) + { + hashes = new byte[0][]; + md = new MessageDigest[0]; + } + else + { + List hashes = new LinkedList(); + List md = new LinkedList(); + for (Iterator it = attr.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + String key = String.valueOf(e.getKey()); + if (key == null) + continue; + if (!key.endsWith(DIGEST_KEY_SUFFIX)) + continue; + hashes.add(Base64InputStream.decode((String) e.getValue())); + try + { + md.add(MessageDigest.getInstance + (key.substring(0, key.length() - DIGEST_KEY_SUFFIX.length()))); + } + catch (NoSuchAlgorithmException nsae) + { + IOException ioe = new IOException("no such message digest: " + key); + ioe.initCause(nsae); + throw ioe; + } + } + if (DEBUG) + debug("digests=" + md); + this.hashes = (byte[][]) hashes.toArray(new byte[hashes.size()][]); + this.md = (MessageDigest[]) md.toArray(new MessageDigest[md.size()]); + } + } + + public boolean markSupported() + { + return false; + } + + public void mark(int readLimit) + { + } + + public void reset() + { + } + + public int read() throws IOException + { + int b = super.read(); + if (b == -1) + { + eof(); + return -1; + } + for (int i = 0; i < md.length; i++) + md[i].update((byte) b); + pos++; + if (length > 0 && pos >= length) + eof(); + return b; + } + + public int read(byte[] buf, int off, int len) throws IOException + { + int count = super.read(buf, off, (int) Math.min(len, (length != 0 + ? length - pos + : Integer.MAX_VALUE))); + if (count == -1 || (length > 0 && pos >= length)) + { + eof(); + return -1; + } + for (int i = 0; i < md.length; i++) + md[i].update(buf, off, count); + pos += count; + if (length != 0 && pos >= length) + eof(); + return count; + } + + public int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public long skip(long bytes) throws IOException + { + byte[] b = new byte[1024]; + long amount = 0; + while (amount < bytes) + { + int l = read(b, 0, (int) Math.min(b.length, bytes - amount)); + if (l == -1) + break; + amount += l; + } + return amount; + } + + private void eof() throws IOException + { + if (checked) + return; + checked = true; + for (int i = 0; i < md.length; i++) + { + byte[] hash = md[i].digest(); + if (DEBUG) + debug("verifying " + md[i].getAlgorithm() + " expect=" + + new java.math.BigInteger(hashes[i]).toString(16) + + " comp=" + new java.math.BigInteger(hash).toString(16)); + if (!Arrays.equals(hash, hashes[i])) + { + synchronized(jarfile) + { + if (DEBUG) + debug(entry + " could NOT be verified"); + jarfile.verified.put(entry.getName(), Boolean.FALSE); + } + return; + // XXX ??? what do we do here? + // throw new ZipException("message digest mismatch"); + } + } + + synchronized(jarfile) + { + if (DEBUG) + debug(entry + " has been VERIFIED"); + jarfile.verified.put(entry.getName(), Boolean.TRUE); + } + } + } +} diff --git a/libjava/classpath/java/util/jar/JarInputStream.java b/libjava/classpath/java/util/jar/JarInputStream.java new file mode 100644 index 0000000..1788af6 --- /dev/null +++ b/libjava/classpath/java/util/jar/JarInputStream.java @@ -0,0 +1,200 @@ +/* JarInputStream.java - InputStream for reading jar files + Copyright (C) 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 java.util.jar; + +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * InputStream for reading jar files. + * XXX - verification of the signatures in the Manifest file is not yet + * implemented. + * + * @since 1.2 + * @author Mark Wielaard (mark@klomp.org) + */ + +public class JarInputStream extends ZipInputStream +{ + // Fields + + /** The manifest for this file or null when there was no manifest. */ + private Manifest manifest; + + /** The first real JarEntry for this file. Used by readManifest() to store + an entry that isn't the manifest but that should be returned by + getNextEntry next time it is called. Null when no firstEntry was read + while searching for the manifest entry, or when it has already been + returned by getNextEntry(). */ + private JarEntry firstEntry; + + // Constructors + + /** + * Creates a new JarInputStream and tries to read the manifest. + * If such a manifest is present the JarInputStream tries to verify all + * the entry signatures while reading. + * + * @param in InputStream to read the jar from + * @exception IOException when an error occurs when opening or reading + */ + public JarInputStream(InputStream in) throws IOException + { + this(in, true); + } + + /** + * Creates a new JarInputStream and tries to read the manifest. + * If such a manifest is present and verify is true, the JarInputStream + * tries to verify all the entry signatures while reading. + * + * @param in InputStream to read the jar from + * @param verify whether or not to verify the manifest entries + * @exception IOException when an error occurs when opening or reading + */ + public JarInputStream(InputStream in, boolean verify) throws IOException + { + super(in); + readManifest(verify); + } + + // Methods + + /** + * Set the manifest if found. Skips all entries that start with "META-INF/" + * + * @param verify when true (and a Manifest is found) checks the Manifest, + * when false no check is performed + * @exception IOException if an error occurs while reading + */ + private void readManifest(boolean verify) throws IOException + { + firstEntry = (JarEntry) super.getNextEntry(); + while ((firstEntry != null) && + firstEntry.getName().startsWith("META-INF/")) + { + if (firstEntry.getName().equals(JarFile.MANIFEST_NAME)) + { + manifest = new Manifest(this); + } + firstEntry = (JarEntry) super.getNextEntry(); + } + + if (verify) + { + // XXX + } + } + + /** + * Creates a JarEntry for a particular name and consults the manifest + * for the Attributes of the entry. + * Used by ZipEntry.getNextEntry() + * + * @param name the name of the new entry + */ + protected ZipEntry createZipEntry(String name) + { + ZipEntry zipEntry = super.createZipEntry(name); + JarEntry jarEntry = new JarEntry(zipEntry); + if (manifest != null) + { + jarEntry.attr = manifest.getAttributes(name); + } + return jarEntry; + } + + /** + * Returns the Manifest for the jar file or null if there was no Manifest. + */ + public Manifest getManifest() + { + return manifest; + } + + /** + * Returns the next entry or null when there are no more entries. + * Does actually return a JarEntry, if you don't want to cast it yourself + * use getNextJarEntry(). Does not return any entries found + * at the beginning of the ZipFile that are special + * (those that start with "META-INF/"). + * + * @exception IOException if an IO error occurs when reading the entry + */ + public ZipEntry getNextEntry() throws IOException + { + ZipEntry entry; + if (firstEntry != null) + { + entry = firstEntry; + firstEntry = null; + } + else + { + entry = super.getNextEntry(); + } + return entry; + } + + /** + * Returns the next jar entry or null when there are no more entries. + * + * @exception IOException if an IO error occurs when reading the entry + */ + public JarEntry getNextJarEntry() throws IOException + { + return (JarEntry) getNextEntry(); + } + + /** + * XXX + * + * @param buf XXX + * @param off XXX + * @param len XXX + * @return XXX + * @exception IOException XXX + */ + public int read(byte[]buf, int off, int len) throws IOException + { + // XXX if (verify) {} + return super.read(buf, off, len); + } +} diff --git a/libjava/classpath/java/util/jar/JarOutputStream.java b/libjava/classpath/java/util/jar/JarOutputStream.java new file mode 100644 index 0000000..2c8c2f0 --- /dev/null +++ b/libjava/classpath/java/util/jar/JarOutputStream.java @@ -0,0 +1,113 @@ +/* JarOutputStream.java - OutputStream for writing jar files + Copyright (C) 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 java.util.jar; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * OutputStream for writing jar files. + * A special ZipOutputStream that can take JarEntries and can have a optional + * Manifest as first entry. + * + * @author Mark Wielaard (mark@klomp.org) + */ + +public class JarOutputStream extends ZipOutputStream +{ + // Constructors + + /** + * Creates a new JarOutputStream without a manifest entry. + * + * @param out the stream to create the new jar on + * @exception IOException if something unexpected happend + */ + public JarOutputStream(OutputStream out) throws IOException + { + this(out, null); + } + + /** + * Creates a new JarOutputStream with a manifest entry. + * The manifest will be the first entry in the jar. + * + * @param out the stream to create the new jar on + * @param man the manifest that should be put in the jar file or null + * for no manifest entry + * @exception IOException if something unexpected happend + */ + public JarOutputStream(OutputStream out, Manifest man) throws IOException + { + super(out); + if (man != null) + writeManifest(man); + } + + // Methods + + /** + * Writes the manifest to a new JarEntry in this JarOutputStream with as + * name JarFile.MANIFEST_NAME. + * + * @param manifest the non null manifest to be written + * @exception IOException if something unexpected happend + */ + private void writeManifest(Manifest manifest) throws IOException + { + // Create a new Jar Entry for the Manifest + JarEntry entry = new JarEntry(JarFile.MANIFEST_NAME); + putNextEntry(entry); + manifest.write(this); + closeEntry(); + } + + /** + * Prepares the JarOutputStream for writing the next entry. + * This implementation just calls super.putNextEntre(). + * + * @param entry The information for the next entry + * @exception IOException when some unexpected I/O exception occurred + */ + public void putNextEntry(ZipEntry entry) throws IOException + { + super.putNextEntry(entry); // XXX + } +} diff --git a/libjava/classpath/java/util/jar/Manifest.java b/libjava/classpath/java/util/jar/Manifest.java new file mode 100644 index 0000000..fdc76ff --- /dev/null +++ b/libjava/classpath/java/util/jar/Manifest.java @@ -0,0 +1,472 @@ +/* Manifest.java -- Reads, writes and manipulaties jar manifest files + Copyright (C) 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 java.util.jar; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +/** + * Reads, writes and manipulaties jar manifest files. + * XXX + * + * @since 1.2 + * @author Mark Wielaard (mark@klomp.org) + */ +public class Manifest implements Cloneable +{ + // Fields + + /** The main attributes of the manifest (jar file). */ + private final Attributes mainAttr; + + /** A map of atrributes for all entries described in this Manifest. */ + private final Map entries; + + // Constructors + + /** + * Creates a new empty Manifest. + */ + public Manifest() + { + mainAttr = new Attributes(); + entries = new Hashtable(); + } + + /** + * Creates a Manifest from the supplied input stream. + * + * @see read(Inputstream) + * @see write(OutputStream) + * + * @param InputStream the input stream to read the manifest from + * @exception IOException when an i/o exception occurs or the input stream + * does not describe a valid manifest + */ + public Manifest(InputStream in) throws IOException + { + this(); + read(in); + } + + /** + * Creates a Manifest from another Manifest. + * Makes a deep copy of the main attributes, but a shallow copy of + * the other entries. This means that you can freely add, change or remove + * the main attributes or the entries of the new manifest without effecting + * the original manifest, but adding, changing or removing attributes from + * a particular entry also changes the attributes of that entry in the + * original manifest. + * + * @see clone() + * @param man the Manifest to copy from + */ + public Manifest(Manifest man) + { + mainAttr = new Attributes(man.getMainAttributes()); + entries = new Hashtable(man.getEntries()); + } + + // Methods + + /** + * Gets the main attributes of this Manifest. + */ + public Attributes getMainAttributes() + { + return mainAttr; + } + + /** + * Gets a map of entry Strings to Attributes for all the entries described + * in this manifest. Adding, changing or removing from this entries map + * changes the entries of this manifest. + */ + public Map getEntries() + { + return entries; + } + + /** + * Returns the Attributes associated with the Entry. + *

    + * Implemented as: + * return (Attributes)getEntries().get(entryName) + * + * @param entryName the name of the entry to look up + * @return the attributes associated with the entry or null when none + */ + public Attributes getAttributes(String entryName) + { + return (Attributes) getEntries().get(entryName); + } + + /** + * Clears the main attributes and removes all the entries from the + * manifest. + */ + public void clear() + { + mainAttr.clear(); + entries.clear(); + } + + /** + * XXX + */ + public void read(InputStream in) throws IOException + { + BufferedReader br = + new BufferedReader(new InputStreamReader(in, "8859_1")); + read_main_section(getMainAttributes(), br); + read_individual_sections(getEntries(), br); + } + + // Private Static methods for reading the Manifest file from BufferedReader + + private static void read_main_section(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. + if (attr.getValue(Attributes.Name.MANIFEST_VERSION) == null) + attr.putValue(Attributes.Name.MANIFEST_VERSION, "0.0"); + } + + /** + * 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 read_version_info(Attributes attr, + BufferedReader br) throws IOException + { + String version_header = Attributes.Name.MANIFEST_VERSION.toString(); + try + { + String value = expect_header(version_header, br); + attr.putValue(Attributes.Name.MANIFEST_VERSION, value); + } + catch (IOException ioe) + { + throw new JarException("Manifest should start with a " + + version_header + ": " + ioe.getMessage()); + } + } + + private static String expect_header(String header, BufferedReader br) + throws IOException + { + String s = br.readLine(); + if (s == null) + { + throw new JarException("unexpected end of file"); + } + return expect_header(header, br, s); + } + + private static String expect_header(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 read_header_value(value_start, br); + } + } + catch (IndexOutOfBoundsException iobe) + { + } + // If we arrive here, something went wrong + throw new JarException("unexpected '" + s + "'"); + } + + private static String read_header_value(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 void read_attributes(Attributes attr, + BufferedReader br) throws IOException + { + String s = br.readLine(); + while (s != null && (!s.equals(""))) + { + read_attribute(attr, s, br); + s = br.readLine(); + } + } + + private static void read_attribute(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 = read_header_value(value_start, br); + attr.putValue(name, value); + } + catch (IndexOutOfBoundsException iobe) + { + throw new JarException("Manifest contains a bad header: " + s); + } + } + + private static void read_individual_sections(Map entries, + BufferedReader br) throws + IOException + { + String s = br.readLine(); + while (s != null && (!s.equals(""))) + { + Attributes attr = read_section_name(s, br, entries); + read_attributes(attr, br); + s = br.readLine(); + } + } + + private static Attributes read_section_name(String s, BufferedReader br, + Map entries) throws JarException + { + try + { + String name = expect_header("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()); + } + } + + /** + * XXX + */ + public void write(OutputStream out) throws IOException + { + PrintWriter pw = + new PrintWriter(new + BufferedWriter(new OutputStreamWriter(out, "8859_1"))); + write_main_section(getMainAttributes(), pw); + pw.println(); + write_individual_sections(getEntries(), pw); + if (pw.checkError()) + { + throw new JarException("Error while writing manifest"); + } + } + + // Private Static functions for writing the Manifest file to a PrintWriter + + private static void write_main_section(Attributes attr, + PrintWriter pw) throws JarException + { + write_version_info(attr, pw); + write_main_attributes(attr, pw); + } + + private static void write_version_info(Attributes attr, PrintWriter pw) + { + // First check if there is already a version attribute set + String version = attr.getValue(Attributes.Name.MANIFEST_VERSION); + if (version == null) + { + version = "1.0"; + } + write_header(Attributes.Name.MANIFEST_VERSION.toString(), version, pw); + } + + private static void write_header(String name, String value, PrintWriter pw) + { + pw.print(name + ": "); + + int last = 68 - name.length(); + if (last > value.length()) + { + pw.println(value); + } + else + { + pw.println(value.substring(0, last)); + } + while (last < value.length()) + { + pw.print(" "); + int end = (last + 69); + if (end > value.length()) + { + pw.println(value.substring(last)); + } + else + { + pw.println(value.substring(last, end)); + } + last = end; + } + } + + private static void write_main_attributes(Attributes attr, PrintWriter pw) + throws JarException + { + Iterator it = attr.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry entry = (Map.Entry) it.next(); + // Don't print the manifest version again + if (!Attributes.Name.MANIFEST_VERSION.equals(entry.getKey())) + { + write_attribute_entry(entry, pw); + } + } + } + + private static void write_attribute_entry(Map.Entry entry, PrintWriter pw) + throws JarException + { + 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); + } + write_header(name, value, pw); + } + + private static void write_individual_sections(Map entries, PrintWriter pw) + throws JarException + { + + Iterator it = entries.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry entry = (Map.Entry) it.next(); + write_header("Name", entry.getKey().toString(), pw); + write_entry_attributes((Attributes) entry.getValue(), pw); + pw.println(); + } + } + + private static void write_entry_attributes(Attributes attr, PrintWriter pw) + throws JarException + { + Iterator it = attr.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry entry = (Map.Entry) it.next(); + write_attribute_entry(entry, pw); + } + } + + /** + * Makes a deep copy of the main attributes, but a shallow copy of + * the other entries. This means that you can freely add, change or remove + * the main attributes or the entries of the new manifest without effecting + * the original manifest, but adding, changing or removing attributes from + * a particular entry also changes the attributes of that entry in the + * original manifest. Calls new Manifest(this). + */ + public Object clone() + { + return new Manifest(this); + } + + /** + * Checks if another object is equal to this Manifest object. + * Another Object is equal to this Manifest object if it is an instance of + * Manifest and the main attributes and the entries of the other manifest + * are equal to this one. + */ + public boolean equals(Object o) + { + return (o instanceof Manifest) && + (mainAttr.equals(((Manifest) o).mainAttr)) && + (entries.equals(((Manifest) o).entries)); + } + + /** + * Calculates the hash code of the manifest. Implemented by a xor of the + * hash code of the main attributes with the hash code of the entries map. + */ + public int hashCode() + { + return mainAttr.hashCode() ^ entries.hashCode(); + } + +} diff --git a/libjava/classpath/java/util/jar/package.html b/libjava/classpath/java/util/jar/package.html new file mode 100644 index 0000000..7fd8787 --- /dev/null +++ b/libjava/classpath/java/util/jar/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - java.util.jar + + +

    Utility classes for manipulating java archives +(zip files with a manifest file with attributes).

    + + + diff --git a/libjava/classpath/java/util/logging/ConsoleHandler.java b/libjava/classpath/java/util/logging/ConsoleHandler.java new file mode 100644 index 0000000..3cf4bca --- /dev/null +++ b/libjava/classpath/java/util/logging/ConsoleHandler.java @@ -0,0 +1,125 @@ +/* ConsoleHandler.java -- a class for publishing log messages to System.err + 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 java.util.logging; + +/** + * A ConsoleHandler publishes log records to + * System.err. + * + *

    Configuration: Values of the subsequent + * LogManager properties are taken into consideration + * when a ConsoleHandler is initialized. + * If a property is not defined, or if it has an invalid + * value, a default is taken without an exception being thrown. + * + *

      + * + *
    • java.util.logging.ConsoleHandler.level - specifies + * the initial severity level threshold. Default value: + * Level.INFO.
    • + * + *
    • java.util.logging.ConsoleHandler.filter - specifies + * the name of a Filter class. Default value: No Filter.
    • + * + *
    • java.util.logging.ConsoleHandler.formatter - specifies + * the name of a Formatter class. Default value: + * java.util.logging.SimpleFormatter.
    • + * + *
    • java.util.logging.ConsoleHandler.encoding - specifies + * the name of the character encoding. Default value: + * the default platform encoding.
    • + * + *
    + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class ConsoleHandler + extends StreamHandler +{ + /** + * Constructs a StreamHandler that publishes + * log records to System.err. The initial + * configuration is determined by the LogManager + * properties described above. + */ + public ConsoleHandler() + { + super(System.err, "java.util.logging.ConsoleHandler", Level.INFO, + /* formatter */ null, SimpleFormatter.class); + } + + + /** + * Forces any data that may have been buffered to the underlying + * output device, but does not close System.err. + * + *

    In case of an I/O failure, the ErrorManager + * of this ConsoleHandler will be informed, but the caller + * of this method will not receive an exception. + */ + public void close() + { + flush(); + } + + + /** + * Publishes a LogRecord to the console, provided the + * record passes all tests for being loggable. + * + *

    Most applications do not need to call this method directly. + * Instead, they will use use a Logger, which will + * create LogRecords and distribute them to registered handlers. + * + *

    In case of an I/O failure, the ErrorManager + * of this SocketHandler will be informed, but the caller + * of this method will not receive an exception. + * + *

    The GNU implementation of ConsoleHandler.publish + * calls flush() for every request to publish a record, so + * they appear immediately on the console. + * + * @param record the log event to be published. + */ + public void publish(LogRecord record) + { + super.publish(record); + flush(); + } +} diff --git a/libjava/classpath/java/util/logging/ErrorManager.java b/libjava/classpath/java/util/logging/ErrorManager.java new file mode 100644 index 0000000..57c079f --- /dev/null +++ b/libjava/classpath/java/util/logging/ErrorManager.java @@ -0,0 +1,194 @@ +/* ErrorManager.java -- + A class for dealing with errors that a Handler encounters + during logging + 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 java.util.logging; + +/** + * An ErrorManager deals with errors that a Handler + * encounters while logging. + * + * @see Handler#setErrorManager(ErrorManager) + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class ErrorManager +{ + /* The values have been taken from Sun's public J2SE 1.4 API + * documentation. + * See http://java.sun.com/j2se/1.4/docs/api/constant-values.html + */ + + /** + * Indicates that there was a failure that does not readily + * fall into any of the other categories. + */ + public static final int GENERIC_FAILURE = 0; + + + /** + * Indicates that there was a problem upon writing to + * an output stream. + */ + public static final int WRITE_FAILURE = 1; + + + /** + * Indicates that there was a problem upon flushing + * an output stream. + */ + public static final int FLUSH_FAILURE = 2; + + + /** + * Indicates that there was a problem upon closing + * an output stream. + */ + public static final int CLOSE_FAILURE = 3; + + + /** + * Indicates that there was a problem upon opening + * an output stream. + */ + public static final int OPEN_FAILURE = 4; + + + /** + * Indicates that there was a problem upon formatting + * the message of a log record. + */ + public static final int FORMAT_FAILURE = 5; + + + /** + * Indicates whether the {@link #error} method of this ErrorManager + * has ever been used. + * + * Declared volatile in order to correctly support the + * double-checked locking idiom (once the revised Java Memory Model + * gets adopted); see Classpath bug #2944. + */ + private volatile boolean everUsed = false; + + + public ErrorManager() + { + } + + + /** + * Reports an error that occured upon logging. The default implementation + * emits the very first error to System.err, ignoring subsequent errors. + * + * @param message a message describing the error, or null if + * there is no suitable description. + * + * @param ex an exception, or null if the error is not + * related to an exception. + * + * @param errorCode one of the defined error codes, for example + * ErrorManager.CLOSE_FAILURE. + */ + public void error(String message, Exception ex, int errorCode) + { + if (everUsed) + return; + + synchronized (this) + { + /* The double check is intentional. If the first check was + * omitted, the monitor would have to be entered every time + * error() method was called. If the second check was + * omitted, the code below could be executed by multiple + * threads simultaneously. + * + * This is the 'double-checked locking' idiom, which is broken + * with the current version of the Java memory model. However, + * we assume that JVMs will have adopted a revised version of + * the Java Memory Model by the time GNU Classpath gains + * widespread acceptance. See Classpath bug #2944. + */ + if (everUsed) + return; + + everUsed = true; + } + + String codeMsg; + switch (errorCode) + { + case GENERIC_FAILURE: + codeMsg = "GENERIC_FAILURE"; + break; + + case WRITE_FAILURE: + codeMsg = "WRITE_FAILURE"; + break; + + case FLUSH_FAILURE: + codeMsg = "FLUSH_FAILURE"; + break; + + case CLOSE_FAILURE: + codeMsg = "CLOSE_FAILURE"; + break; + + case OPEN_FAILURE: + codeMsg = "OPEN_FAILURE"; + break; + + case FORMAT_FAILURE: + codeMsg = "FORMAT_FAILURE"; + break; + + default: + codeMsg = String.valueOf(errorCode); + break; + } + + System.err.println("Error upon logging: " + codeMsg); + if ((message != null) && (message.length() > 0)) + System.err.println(message); + + if (ex != null) + ex.printStackTrace(); + } +} + diff --git a/libjava/classpath/java/util/logging/FileHandler.java b/libjava/classpath/java/util/logging/FileHandler.java new file mode 100644 index 0000000..3d958b7 --- /dev/null +++ b/libjava/classpath/java/util/logging/FileHandler.java @@ -0,0 +1,646 @@ +/* FileHandler.java -- a class for publishing log messages to log files + 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 java.util.logging; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; + +import java.util.LinkedList; +import java.util.ListIterator; + +/** + * A FileHandler publishes log records to a set of log + * files. A maximum file size can be specified; as soon as a log file + * reaches the size limit, it is closed and the next file in the set + * is taken. + * + *

    Configuration: Values of the subsequent + * LogManager properties are taken into consideration + * when a FileHandler is initialized. If a property is + * not defined, or if it has an invalid value, a default is taken + * without an exception being thrown. + * + *

      + * + *
    • java.util.FileHandler.level - specifies + * the initial severity level threshold. Default value: + * Level.ALL.
    • + * + *
    • java.util.FileHandler.filter - specifies + * the name of a Filter class. Default value: No Filter.
    • + * + *
    • java.util.FileHandler.formatter - specifies + * the name of a Formatter class. Default value: + * java.util.logging.XMLFormatter.
    • + * + *
    • java.util.FileHandler.encoding - specifies + * the name of the character encoding. Default value: + * the default platform encoding.
    • + * + *
    • java.util.FileHandler.limit - specifies the number + * of bytes a log file is approximately allowed to reach before it + * is closed and the handler switches to the next file in the + * rotating set. A value of zero means that files can grow + * without limit. Default value: 0 (unlimited growth).
    • + * + *
    • java.util.FileHandler.count - specifies the number + * of log files through which this handler cycles. Default value: + * 1.
    • + * + *
    • java.util.FileHandler.pattern - specifies a + * pattern for the location and name of the produced log files. + * See the section on file name + * patterns for details. Default value: + * "%h/java%u.log".
    • + * + *
    • java.util.FileHandler.append - specifies + * whether the handler will append log records to existing + * files, or whether the handler will clear log files + * upon switching to them. Default value: false, + * indicating that files will be cleared.
    • + * + *
    + * + *

    File Name Patterns: + * The name and location and log files are specified with pattern + * strings. The handler will replace the following character sequences + * when opening log files: + * + *

      + *
    • / - replaced by the platform-specific path name + * separator. This value is taken from the system property + * file.separator.
    • + * + *
    • %t - replaced by the platform-specific location of + * the directory intended for temporary files. This value is + * taken from the system property java.io.tmpdir.
    • + * + *
    • %h - replaced by the location of the home + * directory of the current user. This value is taken from the + * system property file.separator.
    • + * + *
    • %g - replaced by a generation number for + * distinguisthing the individual items in the rotating set + * of log files. The generation number cycles through the + * sequence 0, 1, ..., count - 1.
    • + * + *
    • %u - replaced by a unique number for + * distinguisthing the output files of several concurrently + * running processes. The FileHandler starts + * with 0 when it tries to open a log file. If the file + * cannot be opened because it is currently in use, + * the unique number is incremented by one and opening + * is tried again. These steps are repeated until the + * opening operation succeeds. + * + *

      FIXME: Is the following correct? Please review. The unique + * number is determined for each log file individually when it is + * opened upon switching to the next file. Therefore, it is not + * correct to assume that all log files in a rotating set bear the + * same unique number. + * + *

      FIXME: The Javadoc for the Sun reference implementation + * says: "Note that the use of unique ids to avoid conflicts is + * only guaranteed to work reliably when using a local disk file + * system." Why? This needs to be mentioned as well, in case + * the reviewers decide the statement is true. Otherwise, + * file a bug report with Sun.

    • + * + *
    • %% - replaced by a single percent sign.
    • + *
    + * + *

    If the pattern string does not contain %g and + * count is greater than one, the handler will append + * the string .%g to the specified pattern. + * + *

    If the handler attempts to open a log file, this log file + * is being used at the time of the attempt, and the pattern string + * does not contain %u, the handler will append + * the string .%u to the specified pattern. This + * step is performed after any generation number has been + * appended. + * + *

    Examples for the GNU platform: + * + *

      + * + *
    • %h/java%u.log will lead to a single log file + * /home/janet/java0.log, assuming count + * equals 1, the user's home directory is + * /home/janet, and the attempt to open the file + * succeeds.
    • + * + *
    • %h/java%u.log will lead to three log files + * /home/janet/java0.log.0, + * /home/janet/java0.log.1, and + * /home/janet/java0.log.2, + * assuming count equals 3, the user's home + * directory is /home/janet, and all attempts + * to open files succeed.
    • + * + *
    • %h/java%u.log will lead to three log files + * /home/janet/java0.log.0, + * /home/janet/java1.log.1, and + * /home/janet/java0.log.2, + * assuming count equals 3, the user's home + * directory is /home/janet, and the attempt + * to open /home/janet/java0.log.1 fails.
    • + * + *
    + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class FileHandler + extends StreamHandler +{ + /** + * The number of bytes a log file is approximately allowed to reach + * before it is closed and the handler switches to the next file in + * the rotating set. A value of zero means that files can grow + * without limit. + */ + private final int limit; + + + /** + * The number of log files through which this handler cycles. + */ + private final int count; + + + /** + * The pattern for the location and name of the produced log files. + * See the section on file name patterns + * for details. + */ + private final String pattern; + + + /** + * Indicates whether the handler will append log records to existing + * files (true), or whether the handler will clear log files + * upon switching to them (false). + */ + private final boolean append; + + + /** + * The number of bytes that have currently been written to the stream. + * Package private for use in inner classes. + */ + long written; + + + /** + * A linked list of files we are, or have written to. The entries + * are file path strings, kept in the order + */ + private LinkedList logFiles; + + + /** + * Constructs a FileHandler, taking all property values + * from the current {@link LogManager LogManager} configuration. + * + * @throws java.io.IOException FIXME: The Sun Javadoc says: "if + * there are IO problems opening the files." This conflicts + * with the general principle that configuration errors do + * not prohibit construction. Needs review. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + */ + public FileHandler() + throws IOException, SecurityException + { + this(/* pattern: use configiguration */ null, + + LogManager.getIntProperty("java.util.logging.FileHandler.limit", + /* default */ 0), + + LogManager.getIntProperty("java.util.logging.FileHandler.count", + /* default */ 1), + + LogManager.getBooleanProperty("java.util.logging.FileHandler.append", + /* default */ false)); + } + + + /* FIXME: Javadoc missing. */ + public FileHandler(String pattern) + throws IOException, SecurityException + { + this(pattern, + /* limit */ 0, + /* count */ 1, + /* append */ false); + } + + + /* FIXME: Javadoc missing. */ + public FileHandler(String pattern, boolean append) + throws IOException, SecurityException + { + this(pattern, + /* limit */ 0, + /* count */ 1, + append); + } + + + /* FIXME: Javadoc missing. */ + public FileHandler(String pattern, int limit, int count) + throws IOException, SecurityException + { + this(pattern, limit, count, + LogManager.getBooleanProperty( + "java.util.logging.FileHandler.append", + /* default */ false)); + } + + + /** + * Constructs a FileHandler given the pattern for the + * location and name of the produced log files, the size limit, the + * number of log files thorough which the handler will rotate, and + * the append property. All other property values are + * taken from the current {@link LogManager LogManager} + * configuration. + * + * @param pattern The pattern for the location and name of the + * produced log files. See the section on file name patterns for details. + * If pattern is null, the value is + * taken from the {@link LogManager LogManager} configuration + * property + * java.util.logging.FileHandler.pattern. + * However, this is a pecularity of the GNU implementation, + * and Sun's API specification does not mention what behavior + * is to be expected for null. Therefore, + * applications should not rely on this feature. + * + * @param limit specifies the number of bytes a log file is + * approximately allowed to reach before it is closed and the + * handler switches to the next file in the rotating set. A + * value of zero means that files can grow without limit. + * + * @param count specifies the number of log files through which this + * handler cycles. + * + * @param append specifies whether the handler will append log + * records to existing files (true), or whether the + * handler will clear log files upon switching to them + * (false). + * + * @throws java.io.IOException FIXME: The Sun Javadoc says: "if + * there are IO problems opening the files." This conflicts + * with the general principle that configuration errors do + * not prohibit construction. Needs review. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + *

    FIXME: This seems in contrast to all other handler + * constructors -- verify this by running tests against + * the Sun reference implementation. + */ + public FileHandler(String pattern, + int limit, + int count, + boolean append) + throws IOException, SecurityException + { + super(/* output stream, created below */ null, + "java.util.logging.FileHandler", + /* default level */ Level.ALL, + /* formatter */ null, + /* default formatter */ XMLFormatter.class); + + if ((limit <0) || (count < 1)) + throw new IllegalArgumentException(); + + this.pattern = pattern; + this.limit = limit; + this.count = count; + this.append = append; + this.written = 0; + this.logFiles = new LinkedList (); + + setOutputStream (createFileStream (pattern, limit, count, append, + /* generation */ 0)); + } + + + /* FIXME: Javadoc missing. */ + private OutputStream createFileStream(String pattern, + int limit, + int count, + boolean append, + int generation) + { + String path; + int unique = 0; + + /* Throws a SecurityException if the caller does not have + * LoggingPermission("control"). + */ + LogManager.getLogManager().checkAccess(); + + /* Default value from the java.util.logging.FileHandler.pattern + * LogManager configuration property. + */ + if (pattern == null) + pattern = LogManager.getLogManager().getProperty( + "java.util.logging.FileHandler.pattern"); + if (pattern == null) + pattern = "%h/java%u.log"; + + if (count > 1 && !has (pattern, 'g')) + pattern = pattern + ".%g"; + + do + { + path = replaceFileNameEscapes(pattern, generation, unique, count); + + try + { + File file = new File(path); + if (!file.exists () || append) + { + FileOutputStream fout = new FileOutputStream (file, append); + // FIXME we need file locks for this to work properly, but they + // are not implemented yet in Classpath! Madness! +// FileChannel channel = fout.getChannel (); +// FileLock lock = channel.tryLock (); +// if (lock != null) // We've locked the file. +// { + if (logFiles.isEmpty ()) + logFiles.addFirst (path); + return new ostr (fout); +// } + } + } + catch (Exception ex) + { + reportError (null, ex, ErrorManager.OPEN_FAILURE); + } + + unique = unique + 1; + if (!has (pattern, 'u')) + pattern = pattern + ".%u"; + } + while (true); + } + + + /** + * Replaces the substrings "/" by the value of the + * system property "file.separator", "%t" + * by the value of the system property + * "java.io.tmpdir", "%h" by the value of + * the system property "user.home", "%g" + * by the value of generation, "%u" by the + * value of uniqueNumber, and "%%" by a + * single percent character. If pattern does + * not contain the sequence "%g", + * the value of generation will be appended to + * the result. + * + * @throws NullPointerException if one of the system properties + * "file.separator", + * "java.io.tmpdir", or + * "user.home" has no value and the + * corresponding escape sequence appears in + * pattern. + */ + private static String replaceFileNameEscapes(String pattern, + int generation, + int uniqueNumber, + int count) + { + StringBuffer buf = new StringBuffer(pattern); + String replaceWith; + boolean foundGeneration = false; + + int pos = 0; + do + { + // Uncomment the next line for finding bugs. + // System.out.println(buf.substring(0,pos) + '|' + buf.substring(pos)); + + if (buf.charAt(pos) == '/') + { + /* The same value is also provided by java.io.File.separator. */ + replaceWith = System.getProperty("file.separator"); + buf.replace(pos, pos + 1, replaceWith); + pos = pos + replaceWith.length() - 1; + continue; + } + + if (buf.charAt(pos) == '%') + { + switch (buf.charAt(pos + 1)) + { + case 't': + replaceWith = System.getProperty("java.io.tmpdir"); + break; + + case 'h': + replaceWith = System.getProperty("user.home"); + break; + + case 'g': + replaceWith = Integer.toString(generation); + foundGeneration = true; + break; + + case 'u': + replaceWith = Integer.toString(uniqueNumber); + break; + + case '%': + replaceWith = "%"; + break; + + default: + replaceWith = "??"; + break; // FIXME: Throw exception? + } + + buf.replace(pos, pos + 2, replaceWith); + pos = pos + replaceWith.length() - 1; + continue; + } + } + while (++pos < buf.length() - 1); + + if (!foundGeneration && (count > 1)) + { + buf.append('.'); + buf.append(generation); + } + + return buf.toString(); + } + + + /* FIXME: Javadoc missing. */ + public void publish(LogRecord record) + { + if (limit > 0 && written >= limit) + rotate (); + super.publish(record); + flush (); + } + + /** + * Rotates the current log files, possibly removing one if we + * exceed the file count. + */ + private synchronized void rotate () + { + if (logFiles.size () > 0) + { + File f1 = null; + ListIterator lit = null; + + // If we reach the file count, ditch the oldest file. + if (logFiles.size () == count) + { + f1 = new File ((String) logFiles.getLast ()); + f1.delete (); + lit = logFiles.listIterator (logFiles.size () - 1); + } + // Otherwise, move the oldest to a new location. + else + { + String path = replaceFileNameEscapes (pattern, logFiles.size (), + /* unique */ 0, count); + f1 = new File (path); + logFiles.addLast (path); + lit = logFiles.listIterator (logFiles.size () - 1); + } + + // Now rotate the files. + while (lit.hasPrevious ()) + { + String s = (String) lit.previous (); + File f2 = new File (s); + f2.renameTo (f1); + f1 = f2; + } + } + + setOutputStream (createFileStream (pattern, limit, count, append, + /* generation */ 0)); + + // Reset written count. + written = 0; + } + + /** + * Tell if pattern contains the pattern sequence + * with character escape. That is, if escape + * is 'g', this method returns true if the given pattern contains + * "%g", and not just the substring "%g" (for example, in the case of + * "%%g"). + * + * @param pattern The pattern to test. + * @param escape The escape character to search for. + * @return True iff the pattern contains the escape sequence with the + * given character. + */ + private static boolean has (final String pattern, final char escape) + { + final int len = pattern.length (); + boolean sawPercent = false; + for (int i = 0; i < len; i++) + { + char c = pattern.charAt (i); + if (sawPercent) + { + if (c == escape) + return true; + if (c == '%') // Double percent + { + sawPercent = false; + continue; + } + } + sawPercent = (c == '%'); + } + return false; + } + + /** + * An output stream that tracks the number of bytes written to it. + */ + private final class ostr extends FilterOutputStream + { + private ostr (OutputStream out) + { + super (out); + } + + public void write (final int b) throws IOException + { + out.write (b); + FileHandler.this.written++; // FIXME: synchronize? + } + + public void write (final byte[] b) throws IOException + { + write (b, 0, b.length); + } + + public void write (final byte[] b, final int offset, final int length) + throws IOException + { + out.write (b, offset, length); + FileHandler.this.written += length; // FIXME: synchronize? + } + } +} diff --git a/libjava/classpath/java/util/logging/Filter.java b/libjava/classpath/java/util/logging/Filter.java new file mode 100644 index 0000000..ec45976 --- /dev/null +++ b/libjava/classpath/java/util/logging/Filter.java @@ -0,0 +1,64 @@ +/* Filter.java -- an interface for filters that decide whether a + LogRecord should be published or discarded + 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 java.util.logging; + +/** + * By implementing the Filter interface, applications + * can control what is being logged based on arbitrary properties, + * not just the severity level. Both Handler and + * Logger allow to register Filters whose + * isLoggable method will be called when a + * LogRecord has passed the test based on the + * severity level. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public interface Filter +{ + /** + * Determines whether a LogRecord should be published or discarded. + * + * @param record the LogRecord to be inspected. + * + * @return true if the record should be published, + * false if it should be discarded. + */ + boolean isLoggable(LogRecord record); +} diff --git a/libjava/classpath/java/util/logging/Formatter.java b/libjava/classpath/java/util/logging/Formatter.java new file mode 100644 index 0000000..ee747b0 --- /dev/null +++ b/libjava/classpath/java/util/logging/Formatter.java @@ -0,0 +1,171 @@ +/* Formatter.java -- + A class for formatting log messages by localizing message texts + and performing substitution of parameters + 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 java.util.logging; + +import java.text.MessageFormat; +import java.util.ResourceBundle; + +/** + * A Formatter supports handlers by localizing + * message texts and by subsituting parameter values for their + * placeholders. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public abstract class Formatter +{ + /** + * Constructs a new Formatter. + */ + protected Formatter() + { + } + + + /** + * Formats a LogRecord into a string. Usually called by handlers + * which need a string for a log record, for example to append + * a record to a log file or to transmit a record over the network. + * + * @param record the log record for which a string form is requested. + */ + public abstract String format(LogRecord record); + + + /** + * Returns a string that handlers are supposed to emit before + * the first log record. The base implementation returns an + * empty string, but subclasses such as {@link XMLFormatter} + * override this method in order to provide a suitable header. + * + * @return a string for the header. + * + * @param handler the handler which will prepend the returned + * string in front of the first log record. This method + * may inspect certain properties of the handler, for + * example its encoding, in order to construct the header. + */ + public String getHead(Handler handler) + { + return ""; + } + + + /** + * Returns a string that handlers are supposed to emit after + * the last log record. The base implementation returns an + * empty string, but subclasses such as {@link XMLFormatter} + * override this method in order to provide a suitable tail. + * + * @return a string for the header. + * + * @param handler the handler which will append the returned + * string after the last log record. This method + * may inspect certain properties of the handler + * in order to construct the tail. + */ + public String getTail(Handler handler) + { + return ""; + } + + + /** + * Formats the message part of a log record. + * + *

    First, the Formatter localizes the record message to the + * default locale by looking up the message in the record's + * localization resource bundle. If this step fails because there + * is no resource bundle associated with the record, or because the + * record message is not a key in the bundle, the raw message is + * used instead. + * + *

    Second, the Formatter substitutes appropriate strings for + * the message parameters. If the record returns a non-empty + * array for getParameters() and the localized + * message string contains the character sequence "{0", the + * formatter uses java.text.MessageFormat to format + * the message. Otherwise, no parameter substitution is performed. + * + * @param record the log record to be localized and formatted. + * + * @return the localized message text where parameters have been + * substituted by suitable strings. + * + * @throws NullPointerException if record + * is null. + */ + public String formatMessage(LogRecord record) + { + String msg; + ResourceBundle bundle; + Object[] params; + + /* This will throw a NullPointerExceptionif record is null. */ + msg = record.getMessage(); + if (msg == null) + msg = ""; + + /* Try to localize the message. */ + bundle = record.getResourceBundle(); + if (bundle != null) + { + try + { + msg = bundle.getString(msg); + } + catch (java.util.MissingResourceException _) + { + } + } + + /* Format the message if there are parameters. */ + params = record.getParameters(); + if ((params != null) + && (params.length > 0) + && (msg.indexOf("{0") >= 0)) + { + msg = MessageFormat.format(msg, params); + } + + return msg; + } +} diff --git a/libjava/classpath/java/util/logging/Handler.java b/libjava/classpath/java/util/logging/Handler.java new file mode 100644 index 0000000..c3227d6 --- /dev/null +++ b/libjava/classpath/java/util/logging/Handler.java @@ -0,0 +1,386 @@ +/* Handler.java -- a class for publishing log messages + 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 java.util.logging; + +import java.io.UnsupportedEncodingException; + +/** + * A Handler publishes LogRecords to + * a sink, for example a file, the console or a network socket. + * There are different subclasses of Handler + * to deal with different kinds of sinks. + * + *

    FIXME: Are handlers thread-safe, or is the assumption that only + * loggers are, and a handler can belong only to one single logger? If + * the latter, should we enforce it? (Spec not clear). In any + * case, it needs documentation. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public abstract class Handler +{ + Formatter formatter; + Filter filter; + Level level; + ErrorManager errorManager; + String encoding; + + /** + * Constructs a Handler with a logging severity level of + * Level.ALL, no formatter, no filter, and + * an instance of ErrorManager managing errors. + * + *

    Specification Note: The specification of the + * JavaTM Logging API does not mention which character + * encoding is to be used by freshly constructed Handlers. The GNU + * implementation uses the default platform encoding, but other + * Java implementations might behave differently. + * + *

    Specification Note: While a freshly constructed + * Handler is required to have no filter according to the + * specification, null is not a valid parameter for + * Handler.setFormatter. Therefore, the following + * code will throw a java.lang.NullPointerException: + * + *

    Handler h = new MyConcreteSubclassOfHandler();
    +h.setFormatter(h.getFormatter());
    + * + * It seems strange that a freshly constructed Handler is not + * supposed to provide a Formatter, but this is what the specification + * says. + */ + protected Handler() + { + level = Level.ALL; + } + + + /** + * Publishes a LogRecord to an appropriate sink, + * provided the record passes all tests for being loggable. The + * Handler will localize the message of the log + * record and substitute any message parameters. + * + *

    Most applications do not need to call this method directly. + * Instead, they will use use a {@link Logger}, which will + * create LogRecords and distribute them to registered handlers. + * + *

    In case of an I/O failure, the ErrorManager + * of this Handler will be informed, but the caller + * of this method will not receive an exception. + * + * @param record the log event to be published. + */ + public abstract void publish(LogRecord record); + + + /** + * Forces any data that may have been buffered to the underlying + * output device. + * + *

    In case of an I/O failure, the ErrorManager + * of this Handler will be informed, but the caller + * of this method will not receive an exception. + */ + public abstract void flush(); + + + /** + * Closes this Handler after having flushed + * the buffers. As soon as close has been called, + * a Handler should not be used anymore. Attempts + * to publish log records, to flush buffers, or to modify the + * Handler in any other way may throw runtime + * exceptions after calling close. + * + *

    In case of an I/O failure, the ErrorManager + * of this Handler will be informed, but the caller + * of this method will not receive an exception. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + */ + public abstract void close() + throws SecurityException; + + + /** + * Returns the Formatter which will be used to + * localize the text of log messages and to substitute + * message parameters. A Handler is encouraged, + * but not required to actually use an assigned + * Formatter. + * + * @return the Formatter being used, or + * null if this Handler + * does not use formatters and no formatter has + * ever been set by calling setFormatter. + */ + public Formatter getFormatter() + { + return formatter; + } + + + /** + * Sets the Formatter which will be used to + * localize the text of log messages and to substitute + * message parameters. A Handler is encouraged, + * but not required to actually use an assigned + * Formatter. + * + * @param formatter the new Formatter to use. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + * + * @throws NullPointerException if formatter is + * null. + */ + public void setFormatter(Formatter formatter) + throws SecurityException + { + LogManager.getLogManager().checkAccess(); + + /* Throws a NullPointerException if formatter is null. */ + formatter.getClass(); + + this.formatter = formatter; + } + + + /** + * Returns the character encoding which this handler uses for publishing + * log records. + * + * @param encoding the name of a character encoding, or null + * for the default platform encoding. + */ + public String getEncoding() + { + return encoding; + } + + + /** + * Sets the character encoding which this handler uses for publishing + * log records. The encoding of a Handler must be + * set before any log records have been published. + * + * @param encoding the name of a character encoding, or null + * for the default encoding. + * + * @exception SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + * + */ + public void setEncoding(String encoding) + throws SecurityException, UnsupportedEncodingException + { + /* Should any developer ever change this implementation, they are + * advised to have a look at StreamHandler.setEncoding(String), + * which overrides this method without calling super.setEncoding. + */ + LogManager.getLogManager().checkAccess(); + + /* Simple check for supported encodings. This is more expensive + * than it could be, but this method is overwritten by StreamHandler + * anyway. + */ + if (encoding != null) + new String(new byte[0], encoding); + + this.encoding = encoding; + } + + + /** + * Returns the Filter that currently controls which + * log records are being published by this Handler. + * + * @return the currently active Filter, or + * null if no filter has been associated. + * In the latter case, log records are filtered purely + * based on their severity level. + */ + public Filter getFilter() + { + return filter; + } + + + /** + * Sets the Filter for controlling which + * log records will be published by this Handler. + * + * @return the Filter to use, or + * null to filter log records purely based + * on their severity level. + */ + public void setFilter(Filter filter) + throws SecurityException + { + LogManager.getLogManager().checkAccess(); + this.filter = filter; + } + + + /** + * Returns the ErrorManager that currently deals + * with errors originating from this Handler. + * + * @exception SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + */ + public ErrorManager getErrorManager() + { + LogManager.getLogManager().checkAccess(); + + /* Developers wanting to change the subsequent code should + * have a look at Handler.reportError -- it also can create + * an ErrorManager, but does so without checking permissions + * to control the logging infrastructure. + */ + if (errorManager == null) + errorManager = new ErrorManager(); + + return errorManager; + } + + + public void setErrorManager(ErrorManager manager) + { + LogManager.getLogManager().checkAccess(); + + /* Make sure manager is not null. */ + manager.getClass(); + + this.errorManager = manager; + } + + + protected void reportError(String message, Exception ex, int code) + { + if (errorManager == null) + errorManager = new ErrorManager(); + + errorManager.error(message, ex, code); + } + + + /** + * Returns the severity level threshold for this Handler + * All log records with a lower severity level will be discarded; + * a log record of the same or a higher level will be published + * unless an installed Filter decides to discard it. + * + * @return the severity level below which all log messages + * will be discarded. + */ + public Level getLevel() + { + return level; + } + + + /** + * Sets the severity level threshold for this Handler. + * All log records with a lower severity level will be discarded; + * a log record of the same or a higher level will be published + * unless an installed Filter decides to discard it. + * + * @param level the severity level below which all log messages + * will be discarded. + * + * @exception SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + * + * @exception NullPointerException if level is + * null. + */ + public void setLevel(Level level) + { + LogManager.getLogManager().checkAccess(); + + /* Throw NullPointerException if level is null. */ + level.getClass(); + this.level = level; + } + + + /** + * Checks whether a LogRecord would be logged + * if it was passed to this Handler for publication. + * + *

    The Handler implementation considers a record as + * loggable if its level is greater than or equal to the severity + * level threshold. In a second step, if a {@link Filter} has + * been installed, its {@link Filter#isLoggable(LogRecord) isLoggable} + * method is invoked. Subclasses of Handler can override + * this method to impose their own constraints. + * + * @param record the LogRecord to be checked. + * + * @return true if record would + * be published by {@link #publish(LogRecord) publish}, + * false if it would be discarded. + * + * @see #setLevel(Level) + * @see #setFilter(Filter) + * @see Filter#isLoggable(LogRecord) + * + * @throws NullPointerException if record + * is null. + */ + public boolean isLoggable(LogRecord record) + { + if (record.getLevel().intValue() < level.intValue()) + return false; + + if (filter != null) + return filter.isLoggable(record); + else + return true; + } +} diff --git a/libjava/classpath/java/util/logging/Level.java b/libjava/classpath/java/util/logging/Level.java new file mode 100644 index 0000000..2c400dc --- /dev/null +++ b/libjava/classpath/java/util/logging/Level.java @@ -0,0 +1,414 @@ +/* Level.java -- a class for indicating logging levels + 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 java.util.logging; + +import java.io.Serializable; +import java.util.ResourceBundle; + +/** + * A class for indicating logging levels. A number of commonly used + * levels is pre-defined (such as java.util.logging.Level.INFO), + * and applications should utilize those whenever possible. For specialized + * purposes, however, applications can sub-class Level in order to define + * custom logging levels. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class Level implements Serializable +{ + /* The integer values are the same as in the Sun J2SE 1.4. + * They have been obtained with a test program. In J2SE 1.4.1, + * Sun has amended the API documentation; these values are now + * publicly documented. + */ + + /** + * The OFF level is used as a threshold for filtering + * log records, meaning that no message should be logged. + * + * @see Logger#setLevel(java.util.logging.Level) + */ + public static final Level OFF = new Level ("OFF", Integer.MAX_VALUE); + + /** + * Log records whose level is SEVERE indicate a serious + * failure that prevents normal program execution. Messages at this + * level should be understandable to an inexperienced, non-technical + * end user. Ideally, they explain in simple words what actions the + * user can take in order to resolve the problem. + */ + public static final Level SEVERE = new Level ("SEVERE", 1000); + + + /** + * Log records whose level is WARNING indicate a + * potential problem that does not prevent normal program execution. + * Messages at this level should be understandable to an + * inexperienced, non-technical end user. Ideally, they explain in + * simple words what actions the user can take in order to resolve + * the problem. + */ + public static final Level WARNING = new Level ("WARNING", 900); + + + /** + * Log records whose level is INFO are used in purely + * informational situations that do not constitute serious errors or + * potential problems. In the default logging configuration, INFO + * messages will be written to the system console. For this reason, + * the INFO level should be used only for messages that are + * important to end users and system administrators. Messages at + * this level should be understandable to an inexperienced, + * non-technical user. + */ + public static final Level INFO = new Level ("INFO", 800); + + + /** + * Log records whose level is CONFIG are used for + * describing the static configuration, for example the windowing + * environment, the operating system version, etc. + */ + public static final Level CONFIG = new Level ("CONFIG", 700); + + + /** + * Log records whose level is FINE are typically used + * for messages that are relevant for developers using + * the component generating log messages. Examples include minor, + * recoverable failures, or possible inefficiencies. + */ + public static final Level FINE = new Level ("FINE", 500); + + + /** + * Log records whose level is FINER are intended for + * rather detailed tracing, for example entering a method, returning + * from a method, or throwing an exception. + */ + public static final Level FINER = new Level ("FINER", 400); + + + /** + * Log records whose level is FINEST are used for + * highly detailed tracing, for example to indicate that a certain + * point inside the body of a method has been reached. + */ + public static final Level FINEST = new Level ("FINEST", 300); + + + /** + * The ALL level is used as a threshold for filtering + * log records, meaning that every message should be logged. + * + * @see Logger#setLevel(java.util.logging.Level) + */ + public static final Level ALL = new Level ("ALL", Integer.MIN_VALUE); + + + private static final Level[] knownLevels = { + ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, OFF + }; + + + /** + * The name of the Level without localizing it, for example + * "WARNING". + */ + private String name; + + + /** + * The integer value of this Level. + */ + private int value; + + + /** + * The name of the resource bundle used for localizing the level + * name, or null if the name does not undergo + * localization. + */ + private String resourceBundleName; + + + /** + * Creates a logging level given a name and an integer value. + * It rarely is necessary to create custom levels, + * as most applications should be well served with one of the + * standard levels such as Level.CONFIG, + * Level.INFO, or Level.FINE. + * + * @param name the name of the level. + * + * @param value the integer value of the level. Please note + * that the JavaTM + * Logging API does not specify integer + * values for standard levels (such as + * Level.FINE). Therefore, a custom + * level should pass an integer value that + * is calculated at run-time, e.g. + * (Level.FINE.intValue() + Level.CONFIG.intValue()) + * / 2 for a level between FINE and CONFIG. + */ + protected Level(String name, int value) + { + this(name, value, null); + } + + + /** + * Create a logging level given a name, an integer value and a name + * of a resource bundle for localizing the level name. It rarely + * is necessary to create custom levels, as most applications + * should be well served with one of the standard levels such as + * Level.CONFIG, Level.INFO, or + * Level.FINE. + * + * @param name the name of the level. + * + * @param value the integer value of the level. Please note + * that the JavaTM + * Logging API does not specify integer + * values for standard levels (such as + * Level.FINE). Therefore, a custom + * level should pass an integer value that + * is calculated at run-time, e.g. + * (Level.FINE.intValue() + Level.CONFIG.intValue()) + * / 2 for a level between FINE and CONFIG. + * + * @param resourceBundleName the name of a resource bundle + * for localizing the level name, or null + * if the name does not need to be localized. + */ + protected Level(String name, int value, String resourceBundleName) + { + this.name = name; + this.value = value; + this.resourceBundleName = resourceBundleName; + } + + + static final long serialVersionUID = -8176160795706313070L; + + + /** + * Checks whether the Level has the same intValue as one of the + * pre-defined levels. If so, the pre-defined level object is + * returned. + * + *
    Since the resource bundle name is not taken into + * consideration, it is possible to resolve Level objects that have + * been de-serialized by another implementation, even if the other + * implementation uses a different resource bundle for localizing + * the names of pre-defined levels. + */ + private Object readResolve() + { + for (int i = 0; i < knownLevels.length; i++) + if (value == knownLevels[i].intValue()) + return knownLevels[i]; + + return this; + } + + + /** + * Returns the name of the resource bundle used for localizing the + * level name. + * + * @return the name of the resource bundle used for localizing the + * level name, or null if the name does not undergo + * localization. + */ + public String getResourceBundleName() + { + return resourceBundleName; + } + + + /** + * Returns the name of the Level without localizing it, for example + * "WARNING". + */ + public String getName() + { + return name; + } + + + /** + * Returns the name of the Level after localizing it, for example + * "WARNUNG". + */ + public String getLocalizedName() + { + String localizedName = null; + + if (resourceBundleName != null) + { + try + { + ResourceBundle b = ResourceBundle.getBundle(resourceBundleName); + localizedName = b.getString(name); + } + catch (Exception _) + { + } + } + + if (localizedName != null) + return localizedName; + else + return name; + } + + + /** + * Returns the name of the Level without localizing it, for example + * "WARNING". + */ + public final String toString() + { + return getName(); + } + + + /** + * Returns the integer value of the Level. + */ + public final int intValue() + { + return value; + } + + + /** + * Returns one of the standard Levels given either its name or its + * integer value. Custom subclasses of Level will not be returned + * by this method. + * + * @throws IllegalArgumentException if name is neither + * the name nor the integer value of one of the pre-defined standard + * logging levels. + * + * @throws NullPointerException if name is null. + * + */ + public static Level parse(String name) + throws IllegalArgumentException + { + /* This will throw a NullPointerException if name is null, + * as required by the API specification. + */ + name = name.intern(); + + for (int i = 0; i < knownLevels.length; i++) + { + if (name == knownLevels[i].name) + return knownLevels[i]; + } + + try + { + int num = Integer.parseInt(name); + for (int i = 0; i < knownLevels.length; i++) + if (num == knownLevels[i].value) + return knownLevels[i]; + } + catch (NumberFormatException _) + { + } + + String msg = "Not the name of a standard logging level: \"" + name + "\""; + throw new IllegalArgumentException(msg); + } + + + /** + * Checks whether this Level's integer value is equal to that of + * another object. + * + * @return true if other is an instance of + * java.util.logging.Level and has the same integer + * value, false otherwise. + */ + public boolean equals(Object other) + { + if (!(other instanceof Level)) + return false; + + return value == ((Level) other).value; + } + + + /** + * Returns a hash code for this Level which is based on its numeric + * value. + */ + public int hashCode() + { + return value; + } + + + /** + * Determines whether or not this Level is one of the standard + * levels specified in the Logging API. + * + *

    This method is package-private because it is not part + * of the logging API specification. However, an XMLFormatter + * is supposed to emit the numeric value for a custom log + * level, but the name for a pre-defined level. It seems + * cleaner to put this method to Level than to write some + * procedural code for XMLFormatter. + * + * @return true if this Level is a standard level, + * false otherwise. + */ + final boolean isStandardLevel() + { + for (int i = 0; i < knownLevels.length; i++) + if (knownLevels[i] == this) + return true; + + return false; + } +} + diff --git a/libjava/classpath/java/util/logging/LogManager.java b/libjava/classpath/java/util/logging/LogManager.java new file mode 100644 index 0000000..7e3fd97 --- /dev/null +++ b/libjava/classpath/java/util/logging/LogManager.java @@ -0,0 +1,829 @@ +/* LogManager.java -- a class for maintaining Loggers and managing + configuration properties + 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 java.util.logging; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.StringTokenizer; + +/** + * The LogManager maintains a hierarchical namespace + * of Logger objects and manages properties for configuring the logging + * framework. There exists only one single LogManager + * per virtual machine. This instance can be retrieved using the + * static method {@link #getLogManager()}. + * + *

    Configuration Process: The global LogManager + * object is created and configured when the class + * java.util.logging.LogManager is initialized. + * The configuration process includes the subsequent steps: + * + *

      + *
    • If the system property java.util.logging.manager + * is set to the name of a subclass of + * java.util.logging.LogManager, an instance of + * that subclass is created and becomes the global LogManager. + * Otherwise, a new instance of LogManager is created.
    • + *
    • The LogManager constructor tries to create + * a new instance of the class specified by the system + * property java.util.logging.config.class. + * Typically, the constructor of this class will call + * LogManager.getLogManager().readConfiguration(java.io.InputStream) + * for configuring the logging framework. + * The configuration process stops at this point if + * the system property java.util.logging.config.class + * is set (irrespective of whether the class constructor + * could be called or an exception was thrown).
    • + * + *
    • If the system property java.util.logging.config.class + * is not set, the configuration parameters are read in from + * a file and passed to + * {@link #readConfiguration(java.io.InputStream)}. + * The name and location of this file are specified by the system + * property java.util.logging.config.file.
    • + *
    • If the system property java.util.logging.config.file + * is not set, however, the contents of the URL + * "{gnu.classpath.home.url}/logging.properties" are passed to + * {@link #readConfiguration(java.io.InputStream)}. + * Here, "{gnu.classpath.home.url}" stands for the value of + * the system property gnu.classpath.home.url.
    • + *
    + * + *

    The LogManager has a level of INFO by + * default, and this will be inherited by Loggers unless they + * override it either by properties or programmatically. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class LogManager +{ + /** + * The singleton LogManager instance. + */ + private static LogManager logManager; + + /** + * The registered named loggers; maps the name of a Logger to + * a WeakReference to it. + */ + private Map loggers; + final Logger rootLogger; + + /** + * The properties for the logging framework which have been + * read in last. + */ + private Properties properties; + + /** + * A delegate object that provides support for handling + * PropertyChangeEvents. The API specification does not + * mention which bean should be the source in the distributed + * PropertyChangeEvents, but Mauve test code has determined that + * the Sun J2SE 1.4 reference implementation uses the LogManager + * class object. This is somewhat strange, as the class object + * is not the bean with which listeners have to register, but + * there is no reason for the GNU Classpath implementation to + * behave differently from the reference implementation in + * this case. + */ + private final PropertyChangeSupport pcs = new PropertyChangeSupport( /* source bean */ + LogManager.class); + + protected LogManager() + { + if (logManager != null) + throw new IllegalStateException("there can be only one LogManager; use LogManager.getLogManager()"); + + logManager = this; + loggers = new java.util.HashMap(); + rootLogger = new Logger("", null); + rootLogger.setLevel(Level.INFO); + addLogger(rootLogger); + + /* Make sure that Logger.global has the rootLogger as its parent. + * + * Logger.global is set during class initialization of Logger, + * which may or may not be before this code is being executed. + * For example, on the Sun 1.3.1 and 1.4.0 JVMs, Logger.global + * has been set before this code is being executed. In contrast, + * Logger.global still is null on GCJ 3.2. Since the LogManager + * and Logger classes are mutually dependent, both behaviors are + * correct. + * + * This means that we cannot depend on Logger.global to have its + * value when this code executes, although that variable is final. + * Since Logger.getLogger will always return the same logger for + * the same name, the subsequent line works fine irrespective of + * the order in which classes are initialized. + */ + Logger.getLogger("global").setParent(rootLogger); + Logger.getLogger("global").setUseParentHandlers(true); + } + + /** + * Returns the globally shared LogManager instance. + */ + public static LogManager getLogManager() + { + return logManager; + } + + static + { + makeLogManager(); + + /* The Javadoc description of the class explains + * what is going on here. + */ + Object configurator = createInstance(System.getProperty("java.util.logging.config.class"), + /* must be instance of */ Object.class); + + try + { + if (configurator == null) + getLogManager().readConfiguration(); + } + catch (IOException ex) + { + /* FIXME: Is it ok to ignore exceptions here? */ + } + } + + private static LogManager makeLogManager() + { + String managerClassName; + LogManager manager; + + managerClassName = System.getProperty("java.util.logging.manager"); + manager = (LogManager) createInstance(managerClassName, LogManager.class); + if (manager != null) + return manager; + + if (managerClassName != null) + System.err.println("WARNING: System property \"java.util.logging.manager\"" + + " should be the name of a subclass of java.util.logging.LogManager"); + + return new LogManager(); + } + + /** + * Registers a listener which will be notified when the + * logging properties are re-read. + */ + public synchronized void addPropertyChangeListener(PropertyChangeListener listener) + { + /* do not register null. */ + listener.getClass(); + + pcs.addPropertyChangeListener(listener); + } + + /** + * Unregisters a listener. + * + * If listener has not been registered previously, + * nothing happens. Also, no exception is thrown if + * listener is null. + */ + public synchronized void removePropertyChangeListener(PropertyChangeListener listener) + { + if (listener != null) + pcs.removePropertyChangeListener(listener); + } + + /** + * Adds a named logger. If a logger with the same name has + * already been registered, the method returns false + * without adding the logger. + * + *

    The LogManager only keeps weak references + * to registered loggers. Therefore, names can become available + * after automatic garbage collection. + * + * @param logger the logger to be added. + * + * @return trueif logger was added, + * false otherwise. + * + * @throws NullPointerException if name is + * null. + */ + public synchronized boolean addLogger(Logger logger) + { + /* To developers thinking about to remove the 'synchronized' + * declaration from this method: Please read the comment + * in java.util.logging.Logger.getLogger(String, String) + * and make sure that whatever you change wrt. synchronization + * does not endanger thread-safety of Logger.getLogger. + * The current implementation of Logger.getLogger assumes + * that LogManager does its synchronization on the globally + * shared instance of LogManager. + */ + String name; + WeakReference ref; + + /* This will throw a NullPointerException if logger is null, + * as required by the API specification. + */ + name = logger.getName(); + + ref = (WeakReference) loggers.get(name); + if (ref != null) + { + if (ref.get() != null) + return false; + + /* There has been a logger under this name in the past, + * but it has been garbage collected. + */ + loggers.remove(ref); + } + + /* Adding a named logger requires a security permission. */ + if ((name != null) && ! name.equals("")) + checkAccess(); + + Logger parent = findAncestor(logger); + loggers.put(name, new WeakReference(logger)); + if (parent != logger.getParent()) + logger.setParent(parent); + + /* It can happen that existing loggers should be children of + * the newly added logger. For example, assume that there + * already exist loggers under the names "", "foo", and "foo.bar.baz". + * When adding "foo.bar", the logger "foo.bar.baz" should change + * its parent to "foo.bar". + */ + if (parent != rootLogger) + { + for (Iterator iter = loggers.keySet().iterator(); iter.hasNext();) + { + Logger possChild = (Logger) ((WeakReference) loggers.get(iter.next())) + .get(); + if ((possChild == null) || (possChild == logger) + || (possChild.getParent() != parent)) + continue; + + if (! possChild.getName().startsWith(name)) + continue; + + if (possChild.getName().charAt(name.length()) != '.') + continue; + + possChild.setParent(logger); + } + } + + return true; + } + + /** + * Finds the closest ancestor for a logger among the currently + * registered ones. For example, if the currently registered + * loggers have the names "", "foo", and "foo.bar", the result for + * "foo.bar.baz" will be the logger whose name is "foo.bar". + * + * @param child a logger for whose name no logger has been + * registered. + * + * @return the closest ancestor for child, + * or null if child + * is the root logger. + * + * @throws NullPointerException if child + * is null. + */ + private synchronized Logger findAncestor(Logger child) + { + String childName = child.getName(); + int childNameLength = childName.length(); + Logger best = rootLogger; + int bestNameLength = 0; + + Logger cand; + String candName; + int candNameLength; + + if (child == rootLogger) + return null; + + for (Iterator iter = loggers.keySet().iterator(); iter.hasNext();) + { + candName = (String) iter.next(); + candNameLength = candName.length(); + + if (candNameLength > bestNameLength + && childNameLength > candNameLength + && childName.startsWith(candName) + && childName.charAt(candNameLength) == '.') + { + cand = (Logger) ((WeakReference) loggers.get(candName)).get(); + if ((cand == null) || (cand == child)) + continue; + + bestNameLength = candName.length(); + best = cand; + } + } + + return best; + } + + /** + * Returns a Logger given its name. + * + * @param name the name of the logger. + * + * @return a named Logger, or null if there is no + * logger with that name. + * + * @throw java.lang.NullPointerException if name + * is null. + */ + public synchronized Logger getLogger(String name) + { + WeakReference ref; + + /* Throw a NullPointerException if name is null. */ + name.getClass(); + + ref = (WeakReference) loggers.get(name); + if (ref != null) + return (Logger) ref.get(); + else + return null; + } + + /** + * Returns an Enumeration of currently registered Logger names. + * Since other threads can register loggers at any time, the + * result could be different any time this method is called. + * + * @return an Enumeration with the names of the currently + * registered Loggers. + */ + public synchronized Enumeration getLoggerNames() + { + return Collections.enumeration(loggers.keySet()); + } + + /** + * Resets the logging configuration by removing all handlers for + * registered named loggers and setting their level to null. + * The level of the root logger will be set to Level.INFO. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + */ + public synchronized void reset() throws SecurityException + { + /* Throw a SecurityException if the caller does not have the + * permission to control the logging infrastructure. + */ + checkAccess(); + + properties = new Properties(); + + Iterator iter = loggers.values().iterator(); + while (iter.hasNext()) + { + WeakReference ref; + Logger logger; + + ref = (WeakReference) iter.next(); + if (ref != null) + { + logger = (Logger) ref.get(); + + if (logger == null) + iter.remove(); + else if (logger != rootLogger) + { + logger.resetLogger(); + logger.setLevel(null); + } + } + } + + rootLogger.setLevel(Level.INFO); + rootLogger.resetLogger(); + } + + /** + * Configures the logging framework by reading a configuration file. + * The name and location of this file are specified by the system + * property java.util.logging.config.file. If this + * property is not set, the URL + * "{gnu.classpath.home.url}/logging.properties" is taken, where + * "{gnu.classpath.home.url}" stands for the value of the system + * property gnu.classpath.home.url. + * + *

    The task of configuring the framework is then delegated to + * {@link #readConfiguration(java.io.InputStream)}, which will + * notify registered listeners after having read the properties. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure, or if the caller is + * not granted the permission to read the configuration + * file. + * + * @throws IOException if there is a problem reading in the + * configuration file. + */ + public synchronized void readConfiguration() + throws IOException, SecurityException + { + String path; + InputStream inputStream; + + path = System.getProperty("java.util.logging.config.file"); + if ((path == null) || (path.length() == 0)) + { + String url = (System.getProperty("gnu.classpath.home.url") + + "/logging.properties"); + inputStream = new URL(url).openStream(); + } + else + inputStream = new java.io.FileInputStream(path); + + try + { + readConfiguration(inputStream); + } + finally + { + /* Close the stream in order to save + * resources such as file descriptors. + */ + inputStream.close(); + } + } + + public synchronized void readConfiguration(InputStream inputStream) + throws IOException, SecurityException + { + Properties newProperties; + Enumeration keys; + + checkAccess(); + newProperties = new Properties(); + newProperties.load(inputStream); + reset(); + this.properties = newProperties; + keys = newProperties.propertyNames(); + + while (keys.hasMoreElements()) + { + String key = ((String) keys.nextElement()).trim(); + String value = newProperties.getProperty(key); + + if (value == null) + continue; + + value = value.trim(); + + if ("handlers".equals(key)) + { + StringTokenizer tokenizer = new StringTokenizer(value); + while (tokenizer.hasMoreTokens()) + { + String handlerName = tokenizer.nextToken(); + try + { + Class handlerClass = ClassLoader.getSystemClassLoader().loadClass(handlerName); + getLogger("").addHandler((Handler) handlerClass + .newInstance()); + } + catch (ClassCastException ex) + { + System.err.println("[LogManager] class " + handlerName + + " is not subclass of java.util.logging.Handler"); + } + catch (Exception ex) + { + //System.out.println("[LogManager.readConfiguration]"+ex); + } + } + } + + if (key.endsWith(".level")) + { + String loggerName = key.substring(0, key.length() - 6); + Logger logger = getLogger(loggerName); + + if (logger == null) + { + logger = Logger.getLogger(loggerName); + addLogger(logger); + } + try + { + logger.setLevel(Level.parse(value)); + } + catch (Exception _) + { + //System.out.println("[LogManager.readConfiguration] "+_); + } + continue; + } + } + + /* The API specification does not talk about the + * property name that is distributed with the + * PropertyChangeEvent. With test code, it could + * be determined that the Sun J2SE 1.4 reference + * implementation uses null for the property name. + */ + pcs.firePropertyChange(null, null, null); + } + + /** + * Returns the value of a configuration property as a String. + */ + public synchronized String getProperty(String name) + { + if (properties != null) + return properties.getProperty(name); + else + return null; + } + + /** + * Returns the value of a configuration property as an integer. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is not specified in the + * logging API. + * + * @param name the name of the configuration property. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if its value is not an integer + * number. + */ + static int getIntProperty(String name, int defaultValue) + { + try + { + return Integer.parseInt(getLogManager().getProperty(name)); + } + catch (Exception ex) + { + return defaultValue; + } + } + + /** + * Returns the value of a configuration property as an integer, + * provided it is inside the acceptable range. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is not specified in the + * logging API. + * + * @param name the name of the configuration property. + * + * @param minValue the lowest acceptable value. + * + * @param maxValue the highest acceptable value. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if its value is not an integer + * number, or if it is less than the minimum value, + * or if it is greater than the maximum value. + */ + static int getIntPropertyClamped(String name, int defaultValue, + int minValue, int maxValue) + { + int val = getIntProperty(name, defaultValue); + if ((val < minValue) || (val > maxValue)) + val = defaultValue; + return val; + } + + /** + * Returns the value of a configuration property as a boolean. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is not specified in the + * logging API. + * + * @param name the name of the configuration property. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if its value is neither + * "true" nor "false". + */ + static boolean getBooleanProperty(String name, boolean defaultValue) + { + try + { + return (new Boolean(getLogManager().getProperty(name))).booleanValue(); + } + catch (Exception ex) + { + return defaultValue; + } + } + + /** + * Returns the value of a configuration property as a Level. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is not specified in the + * logging API. + * + * @param propertyName the name of the configuration property. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if + * {@link Level.parse(java.lang.String)} does not like + * the property value. + */ + static Level getLevelProperty(String propertyName, Level defaultValue) + { + try + { + return Level.parse(getLogManager().getProperty(propertyName)); + } + catch (Exception ex) + { + return defaultValue; + } + } + + /** + * Returns the value of a configuration property as a Class. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is not specified in the + * logging API. + * + * @param propertyName the name of the configuration property. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if it does not specify + * the name of a loadable class. + */ + static final Class getClassProperty(String propertyName, Class defaultValue) + { + Class usingClass = null; + + try + { + String propertyValue = logManager.getProperty(propertyName); + if (propertyValue != null) + usingClass = Class.forName(propertyValue); + if (usingClass != null) + return usingClass; + } + catch (Exception _) + { + } + + return defaultValue; + } + + static final Object getInstanceProperty(String propertyName, Class ofClass, + Class defaultClass) + { + Class klass = getClassProperty(propertyName, defaultClass); + if (klass == null) + return null; + + try + { + Object obj = klass.newInstance(); + if (ofClass.isInstance(obj)) + return obj; + } + catch (Exception _) + { + } + + if (defaultClass == null) + return null; + + try + { + return defaultClass.newInstance(); + } + catch (java.lang.InstantiationException ex) + { + throw new RuntimeException(ex.getMessage()); + } + catch (java.lang.IllegalAccessException ex) + { + throw new RuntimeException(ex.getMessage()); + } + } + + /** + * An instance of LoggingPermission("control") + * that is shared between calls to checkAccess(). + */ + private static final LoggingPermission controlPermission = new LoggingPermission("control", + null); + + /** + * Checks whether the current security context allows changing + * the configuration of the logging framework. For the security + * context to be trusted, it has to be granted + * a LoggingPermission("control"). + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + */ + public void checkAccess() throws SecurityException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(controlPermission); + } + + /** + * Creates a new instance of a class specified by name. + * + * @param className the name of the class of which a new instance + * should be created. + * + * @param ofClass the class to which the new instance should + * be either an instance or an instance of a subclass. + * FIXME: This description is just terrible. + * + * @return the new instance, or null if + * className is null, if no class + * with that name could be found, if there was an error + * loading that class, or if the constructor of the class + * has thrown an exception. + */ + static final Object createInstance(String className, Class ofClass) + { + Class klass; + + if ((className == null) || (className.length() == 0)) + return null; + + try + { + klass = Class.forName(className); + if (! ofClass.isAssignableFrom(klass)) + return null; + + return klass.newInstance(); + } + catch (Exception _) + { + return null; + } + catch (java.lang.LinkageError _) + { + return null; + } + } +} diff --git a/libjava/classpath/java/util/logging/LogRecord.java b/libjava/classpath/java/util/logging/LogRecord.java new file mode 100644 index 0000000..af7f2058 --- /dev/null +++ b/libjava/classpath/java/util/logging/LogRecord.java @@ -0,0 +1,672 @@ +/* LogRecord.java -- + A class for the state associated with individual logging events + 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 java.util.logging; + +import java.util.ResourceBundle; + + +/** + * A LogRecord contains the state for an individual + * event to be logged. + * + *

    As soon as a LogRecord instance has been handed over to the + * logging framework, applications should not manipulate it anymore. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class LogRecord + implements java.io.Serializable +{ + /** + * The severity level of this LogRecord. + */ + private Level level; + + + /** + * The sequence number of this LogRecord. + */ + private long sequenceNumber; + + + /** + * The name of the class that issued the logging request, or + * null if this information could not be obtained. + */ + private String sourceClassName; + + + /** + * The name of the method that issued the logging request, or + * null if this information could not be obtained. + */ + private String sourceMethodName; + + + /** + * The message for this LogRecord before + * any localization or formatting. + */ + private String message; + + + /** + * An identifier for the thread in which this LogRecord + * was created. The identifier is not necessarily related to any + * thread identifiers used by the operating system. + */ + private int threadID; + + + /** + * The time when this LogRecord was created, + * in milliseconds since the beginning of January 1, 1970. + */ + private long millis; + + + /** + * The Throwable associated with this LogRecord, or + * null if the logged event is not related to an + * exception or error. + */ + private Throwable thrown; + + + /** + * The name of the logger where this LogRecord has + * originated, or null if this LogRecord + * does not originate from a Logger. + */ + private String loggerName; + + + /** + * The name of the resource bundle used for localizing log messages, + * or null if no bundle has been specified. + */ + private String resourceBundleName; + + private transient Object[] parameters; + + private transient ResourceBundle bundle; + + + /** + * Constructs a LogRecord given a severity level and + * an unlocalized message text. In addition, the sequence number, + * creation time (as returned by getMillis()) and + * thread ID are assigned. All other properties are set to + * null. + * + * @param level the severity level, for example Level.WARNING. + * + * @param message the message text (which will be used as key + * for looking up the localized message text + * if a resource bundle has been associated). + */ + public LogRecord(Level level, String message) + { + this.level = level; + this.message = message; + this.millis = System.currentTimeMillis(); + + /* A subclass of java.lang.Thread could override hashCode(), + * in which case the result would not be guaranteed anymore + * to be unique among all threads. While System.identityHashCode + * is not necessarily unique either, it at least cannot be + * overridden by user code. However, is might be a good idea + * to use something better for generating thread IDs. + */ + this.threadID = System.identityHashCode(Thread.currentThread()); + + sequenceNumber = allocateSeqNum(); + } + + + /** + * Determined with the serialver tool of the Sun J2SE 1.4. + */ + static final long serialVersionUID = 5372048053134512534L; + + private void readObject(java.io.ObjectInputStream in) + throws java.io.IOException, java.lang.ClassNotFoundException + { + in.defaultReadObject(); + + /* We assume that future versions will be downwards compatible, + * so we can ignore the versions. + */ + byte majorVersion = in.readByte(); + byte minorVersion = in.readByte(); + + int numParams = in.readInt(); + if (numParams >= 0) + { + parameters = new Object[numParams]; + for (int i = 0; i < numParams; i++) + parameters[i] = in.readObject(); + } + } + + + /** + * @serialData The default fields, followed by a major byte version + * number, followed by a minor byte version number, followed by + * information about the log record parameters. If + * parameters is null, the integer -1 is + * written, otherwise the length of the parameters + * array (which can be zero), followed by the result of calling + * {@link Object#toString() toString()} on the parameter (or + * null if the parameter is null). + * + *

    Specification Note: The Javadoc for the + * Sun reference implementation does not specify the version + * number. FIXME: Reverse-engineer the JDK and file a bug + * report with Sun, asking for amendment of the specification. + */ + private void writeObject(java.io.ObjectOutputStream out) + throws java.io.IOException + { + out.defaultWriteObject(); + + /* Major, minor version number: The Javadoc for J2SE1.4 does not + * specify the values. + */ + out.writeByte(0); + out.writeByte(0); + + if (parameters == null) + out.writeInt(-1); + else + { + out.writeInt(parameters.length); + for (int i = 0; i < parameters.length; i++) + { + if (parameters[i] == null) + out.writeObject(null); + else + out.writeObject(parameters[i].toString()); + } + } + } + + + /** + * Returns the name of the logger where this LogRecord + * has originated. + * + * @return the name of the source {@link Logger}, or + * null if this LogRecord + * does not originate from a Logger. + */ + public String getLoggerName() + { + return loggerName; + } + + + /** + * Sets the name of the logger where this LogRecord + * has originated. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param name the name of the source logger, or null to + * indicate that this LogRecord does not + * originate from a Logger. + */ + public void setLoggerName(String name) + { + loggerName = name; + } + + + /** + * Returns the resource bundle that is used when the message + * of this LogRecord needs to be localized. + * + * @return the resource bundle used for localization, + * or null if this message does not need + * to be localized. + */ + public ResourceBundle getResourceBundle() + { + return bundle; + } + + + /** + * Sets the resource bundle that is used when the message + * of this LogRecord needs to be localized. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param bundle the resource bundle to be used, or + * null to indicate that this + * message does not need to be localized. + */ + public void setResourceBundle(ResourceBundle bundle) + { + this.bundle = bundle; + + /* FIXME: Is there a way to infer the name + * of a resource bundle from a ResourceBundle object? + */ + this.resourceBundleName = null; + } + + + /** + * Returns the name of the resource bundle that is used when the + * message of this LogRecord needs to be localized. + * + * @return the name of the resource bundle used for localization, + * or null if this message does not need + * to be localized. + */ + public String getResourceBundleName() + { + return resourceBundleName; + } + + + /** + * Sets the name of the resource bundle that is used when the + * message of this LogRecord needs to be localized. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param name the name of the resource bundle to be used, or + * null to indicate that this message + * does not need to be localized. + */ + public void setResourceBundleName(String name) + { + resourceBundleName = name; + bundle = null; + + try + { + if (resourceBundleName != null) + bundle = ResourceBundle.getBundle(resourceBundleName); + } + catch (java.util.MissingResourceException _) + { + } + } + + + /** + * Returns the level of the LogRecord. + * + *

    Applications should be aware of the possibility that the + * result is not necessarily one of the standard logging levels, + * since the logging framework allows to create custom subclasses + * of java.util.logging.Level. Therefore, filters + * should perform checks like theRecord.getLevel().intValue() + * == Level.INFO.intValue() instead of theRecord.getLevel() + * == Level.INFO. + */ + public Level getLevel() + { + return level; + } + + + /** + * Sets the severity level of this LogRecord to a new + * value. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param level the new severity level, for example + * Level.WARNING. + */ + public void setLevel(Level level) + { + this.level = level; + } + + + /** + * The last used sequence number for any LogRecord. + */ + private static long lastSeqNum; + + + /** + * Allocates a sequence number for a new LogRecord. This class + * method is only called by the LogRecord constructor. + */ + private static synchronized long allocateSeqNum() + { + lastSeqNum += 1; + return lastSeqNum; + } + + + /** + * Returns the sequence number of this LogRecord. + */ + public long getSequenceNumber() + { + return sequenceNumber; + } + + + /** + * Sets the sequence number of this LogRecord to a new + * value. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param seqNum the new sequence number. + */ + public void setSequenceNumber(long seqNum) + { + this.sequenceNumber = seqNum; + } + + + /** + * Returns the name of the class where the event being logged + * has had its origin. This information can be passed as + * parameter to some logging calls, and in certain cases, the + * logging framework tries to determine an approximation + * (which may or may not be accurate). + * + * @return the name of the class that issued the logging request, + * or null if this information could not + * be obtained. + */ + public String getSourceClassName() + { + if (sourceClassName != null) + return sourceClassName; + + /* FIXME: Should infer this information from the call stack. */ + return null; + } + + + /** + * Sets the name of the class where the event being logged + * has had its origin. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param sourceClassName the name of the class that issued the + * logging request, or null to indicate that + * this information could not be obtained. + */ + public void setSourceClassName(String sourceClassName) + { + this.sourceClassName = sourceClassName; + } + + + /** + * Returns the name of the method where the event being logged + * has had its origin. This information can be passed as + * parameter to some logging calls, and in certain cases, the + * logging framework tries to determine an approximation + * (which may or may not be accurate). + * + * @return the name of the method that issued the logging request, + * or null if this information could not + * be obtained. + */ + public String getSourceMethodName() + { + if (sourceMethodName != null) + return sourceMethodName; + + /* FIXME: Should infer this information from the call stack. */ + return null; + } + + + /** + * Sets the name of the method where the event being logged + * has had its origin. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param sourceMethodName the name of the method that issued the + * logging request, or null to indicate that + * this information could not be obtained. + */ + public void setSourceMethodName(String sourceMethodName) + { + this.sourceMethodName = sourceMethodName; + } + + + /** + * Returns the message for this LogRecord before + * any localization or parameter substitution. + * + *

    A {@link Logger} will try to localize the message + * if a resource bundle has been associated with this + * LogRecord. In this case, the logger will call + * getMessage() and use the result as the key + * for looking up the localized message in the bundle. + * If no bundle has been associated, or if the result of + * getMessage() is not a valid key in the + * bundle, the logger will use the raw message text as + * returned by this method. + * + * @return the message text, or null if there + * is no message text. + */ + public String getMessage() + { + return message; + } + + + /** + * Sets the message for this LogRecord. + * + *

    A Logger will try to localize the message + * if a resource bundle has been associated with this + * LogRecord. In this case, the logger will call + * getMessage() and use the result as the key + * for looking up the localized message in the bundle. + * If no bundle has been associated, or if the result of + * getMessage() is not a valid key in the + * bundle, the logger will use the raw message text as + * returned by this method. + * + *

    It is possible to set the message to either an empty String or + * null, although this does not make the the message + * very helpful to human users. + * + * @param message the message text (which will be used as key + * for looking up the localized message text + * if a resource bundle has been associated). + */ + public void setMessage(String message) + { + this.message = message; + } + + + /** + * Returns the parameters to the log message. + * + * @return the parameters to the message, or null if + * the message has no parameters. + */ + public Object[] getParameters() + { + return parameters; + } + + + /** + * Sets the parameters to the log message. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param parameters the parameters to the message, or null + * to indicate that the message has no parameters. + */ + public void setParameters(Object[] parameters) + { + this.parameters = parameters; + } + + + /** + * Returns an identifier for the thread in which this + * LogRecord was created. The identifier is not + * necessarily related to any thread identifiers used by the + * operating system. + * + * @return an identifier for the source thread. + */ + public int getThreadID() + { + return threadID; + } + + + /** + * Sets the identifier indicating in which thread this + * LogRecord was created. The identifier is not + * necessarily related to any thread identifiers used by the + * operating system. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param threadID the identifier for the source thread. + */ + public void setThreadID(int threadID) + { + this.threadID = threadID; + } + + + /** + * Returns the time when this LogRecord was created. + * + * @return the time of creation in milliseconds since the beginning + * of January 1, 1970. + */ + public long getMillis() + { + return millis; + } + + + /** + * Sets the time when this LogRecord was created. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param millis the time of creation in milliseconds since the + * beginning of January 1, 1970. + */ + public void setMillis(long millis) + { + this.millis = millis; + } + + + /** + * Returns the Throwable associated with this LogRecord, + * or null if the logged event is not related to an exception + * or error. + */ + public Throwable getThrown() + { + return thrown; + } + + + /** + * Associates this LogRecord with an exception or error. + * + *

    As soon as a LogRecord has been handed over + * to the logging framework, applications should not modify it + * anymore. Therefore, this method should only be called on + * freshly constructed LogRecords. + * + * @param thrown the exception or error to associate with, or + * null if this LogRecord + * should be made unrelated to an exception or error. + */ + public void setThrown(Throwable thrown) + { + this.thrown = thrown; + } +} diff --git a/libjava/classpath/java/util/logging/Logger.java b/libjava/classpath/java/util/logging/Logger.java new file mode 100644 index 0000000..ae985a9 --- /dev/null +++ b/libjava/classpath/java/util/logging/Logger.java @@ -0,0 +1,1199 @@ +/* Logger.java -- a class for logging messages + 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 java.util.logging; + +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * A Logger is used for logging information about events. Usually, there + * is a seprate logger for each subsystem or component, although there + * is a shared instance for components that make only occasional use of + * the logging framework. + * + *

    It is common to name a logger after the name of a corresponding + * Java package. Loggers are organized into a hierarchical namespace; + * for example, the logger "org.gnu.foo" is the + * parent of logger "org.gnu.foo.bar". + * + *

    A logger for a named subsystem can be obtained through {@link + * java.util.logging.Logger#getLogger(java.lang.String)}. However, + * only code which has been granted the permission to control the + * logging infrastructure will be allowed to customize that logger. + * Untrusted code can obtain a private, anonymous logger through + * {@link #getAnonymousLogger()} if it wants to perform any + * modifications to the logger. + * + *

    FIXME: Write more documentation. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class Logger +{ + /** + * A logger provided to applications that make only occasional use + * of the logging framework, typically early prototypes. Serious + * products are supposed to create and use their own Loggers, so + * they can be controlled individually. + */ + public static final Logger global = getLogger("global"); + + + /** + * The name of the Logger, or null if the logger is + * anonymous. + * + *

    A previous version of the GNU Classpath implementation granted + * untrusted code the permission to control any logger whose name + * was null. However, test code revealed that the Sun J2SE 1.4 + * reference implementation enforces the security control for any + * logger that was not created through getAnonymousLogger, even if + * it has a null name. Therefore, a separate flag {@link + * Logger#anonymous} was introduced. + */ + private final String name; + + + /** + * The name of the resource bundle used for localization. + * + *

    This variable cannot be declared as final + * because its value can change as a result of calling + * getLogger(String,String). + */ + private String resourceBundleName; + + + /** + * The resource bundle used for localization. + * + *

    This variable cannot be declared as final + * because its value can change as a result of calling + * getLogger(String,String). + */ + private ResourceBundle resourceBundle; + + private Filter filter; + + private final List handlerList = new java.util.ArrayList(4); + private Handler[] handlers = new Handler[0]; + + /** + * Indicates whether or not this logger is anonymous. While + * a LoggingPermission is required for any modifications to + * a normal logger, untrusted code can obtain an anonymous logger + * and modify it according to its needs. + * + *

    A previous version of the GNU Classpath implementation + * granted access to every logger whose name was null. + * However, test code revealed that the Sun J2SE 1.4 reference + * implementation enforces the security control for any logger + * that was not created through getAnonymousLogger, even + * if it has a null name. + */ + private boolean anonymous; + + + private boolean useParentHandlers; + + private Level level; + + private Logger parent; + + /** + * Constructs a Logger for a subsystem. Most applications do not + * need to create new Loggers explicitly; instead, they should call + * the static factory methods + * {@link #getLogger(java.lang.String,java.lang.String) getLogger} + * (with ResourceBundle for localization) or + * {@link #getLogger(java.lang.String) getLogger} (without + * ResourceBundle), respectively. + * + * @param name the name for the logger, for example "java.awt" + * or "com.foo.bar". The name should be based on + * the name of the package issuing log records + * and consist of dot-separated Java identifiers. + * + * @param resourceBundleName the name of a resource bundle + * for localizing messages, or null + * to indicate that messages do not need to be localized. + * + * @throws java.util.MissingResourceException if + * resourceBundleName is not null + * and no such bundle could be located. + */ + protected Logger(String name, String resourceBundleName) + throws MissingResourceException + { + this.name = name; + this.resourceBundleName = resourceBundleName; + + if (resourceBundleName == null) + resourceBundle = null; + else + resourceBundle = ResourceBundle.getBundle(resourceBundleName); + + level = null; + + /* This is null when the root logger is being constructed, + * and the root logger afterwards. + */ + parent = LogManager.getLogManager().rootLogger; + + useParentHandlers = (parent != null); + } + + + + /** + * Finds a registered logger for a subsystem, or creates one in + * case no logger has been registered yet. + * + * @param name the name for the logger, for example "java.awt" + * or "com.foo.bar". The name should be based on + * the name of the package issuing log records + * and consist of dot-separated Java identifiers. + * + * @throws IllegalArgumentException if a logger for the subsystem + * identified by name has already been created, + * but uses a a resource bundle for localizing messages. + * + * @throws NullPointerException if name is + * null. + * + * @return a logger for the subsystem specified by name + * that does not localize messages. + */ + public static Logger getLogger(String name) + { + return getLogger(name, null); + } + + + /** + * Finds a registered logger for a subsystem, or creates one in case + * no logger has been registered yet. + * + *

    If a logger with the specified name has already been + * registered, the behavior depends on the resource bundle that is + * currently associated with the existing logger. + * + *

    • If the existing logger uses the same resource bundle as + * specified by resourceBundleName, the existing logger + * is returned.
    • + * + *
    • If the existing logger currently does not localize messages, + * the existing logger is modified to use the bundle specified by + * resourceBundleName. The existing logger is then + * returned. Therefore, all subsystems currently using this logger + * will produce localized messages from now on.
    • + * + *
    • If the existing logger already has an associated resource + * bundle, but a different one than specified by + * resourceBundleName, an + * IllegalArgumentException is thrown.
    + * + * @param name the name for the logger, for example "java.awt" + * or "org.gnu.foo". The name should be based on + * the name of the package issuing log records + * and consist of dot-separated Java identifiers. + * + * @param resourceBundleName the name of a resource bundle + * for localizing messages, or null + * to indicate that messages do not need to be localized. + * + * @return a logger for the subsystem specified by name. + * + * @throws java.util.MissingResourceException if + * resourceBundleName is not null + * and no such bundle could be located. + * + * @throws IllegalArgumentException if a logger for the subsystem + * identified by name has already been created, + * but uses a different resource bundle for localizing + * messages. + * + * @throws NullPointerException if name is + * null. + */ + public static Logger getLogger(String name, String resourceBundleName) + { + LogManager lm = LogManager.getLogManager(); + Logger result; + + /* Throw NullPointerException if name is null. */ + name.getClass(); + + /* Without synchronized(lm), it could happen that another thread + * would create a logger between our calls to getLogger and + * addLogger. While addLogger would indicate this by returning + * false, we could not be sure that this other logger was still + * existing when we called getLogger a second time in order + * to retrieve it -- note that LogManager is only allowed to + * keep weak references to registered loggers, so Loggers + * can be garbage collected at any time in general, and between + * our call to addLogger and our second call go getLogger + * in particular. + * + * Of course, we assume here that LogManager.addLogger etc. + * are synchronizing on the global LogManager object. There + * is a comment in the implementation of LogManager.addLogger + * referring to this comment here, so that any change in + * the synchronization of LogManager will be reflected here. + */ + synchronized (lm) + { + result = lm.getLogger(name); + if (result == null) + { + boolean couldBeAdded; + + result = new Logger(name, resourceBundleName); + couldBeAdded = lm.addLogger(result); + if (!couldBeAdded) + throw new IllegalStateException("cannot register new logger"); + } + else + { + /* The logger already exists. Make sure it uses + * the same resource bundle for localizing messages. + */ + String existingBundleName = result.getResourceBundleName(); + + /* The Sun J2SE 1.4 reference implementation will return the + * registered logger object, even if it does not have a resource + * bundle associated with it. However, it seems to change the + * resourceBundle of the registered logger to the bundle + * whose name was passed to getLogger. + */ + if ((existingBundleName == null) && (resourceBundleName != null)) + { + /* If ResourceBundle.getBundle throws an exception, the + * existing logger will be unchanged. This would be + * different if the assignment to resourceBundleName + * came first. + */ + result.resourceBundle = ResourceBundle.getBundle(resourceBundleName); + result.resourceBundleName = resourceBundleName; + return result; + } + + if ((existingBundleName != resourceBundleName) + && ((existingBundleName == null) + || !existingBundleName.equals(resourceBundleName))) + { + throw new IllegalArgumentException(); + } + } + } + + return result; + } + + + /** + * Creates a new, unnamed logger. Unnamed loggers are not + * registered in the namespace of the LogManager, and no special + * security permission is required for changing their state. + * Therefore, untrusted applets are able to modify their private + * logger instance obtained through this method. + * + *

    The parent of the newly created logger will the the root + * logger, from which the level threshold and the handlers are + * inherited. + */ + public static Logger getAnonymousLogger() + { + return getAnonymousLogger(null); + } + + + /** + * Creates a new, unnamed logger. Unnamed loggers are not + * registered in the namespace of the LogManager, and no special + * security permission is required for changing their state. + * Therefore, untrusted applets are able to modify their private + * logger instance obtained through this method. + * + *

    The parent of the newly created logger will the the root + * logger, from which the level threshold and the handlers are + * inherited. + * + * @param resourceBundleName the name of a resource bundle + * for localizing messages, or null + * to indicate that messages do not need to be localized. + * + * @throws java.util.MissingResourceException if + * resourceBundleName is not null + * and no such bundle could be located. + */ + public static Logger getAnonymousLogger(String resourceBundleName) + throws MissingResourceException + { + Logger result; + + result = new Logger(null, resourceBundleName); + result.anonymous = true; + return result; + } + + + /** + * Returns the name of the resource bundle that is being used for + * localizing messages. + * + * @return the name of the resource bundle used for localizing messages, + * or null if the parent's resource bundle + * is used for this purpose. + */ + public synchronized String getResourceBundleName() + { + return resourceBundleName; + } + + + /** + * Returns the resource bundle that is being used for localizing + * messages. + * + * @return the resource bundle used for localizing messages, + * or null if the parent's resource bundle + * is used for this purpose. + */ + public synchronized ResourceBundle getResourceBundle() + { + return resourceBundle; + } + + + /** + * Returns the severity level threshold for this Handler. + * All log records with a lower severity level will be discarded; + * a log record of the same or a higher level will be published + * unless an installed Filter decides to discard it. + * + * @return the severity level below which all log messages will be + * discarded, or null if the logger inherits + * the threshold from its parent. + */ + public synchronized Level getLevel() + { + return level; + } + + + /** + * Returns whether or not a message of the specified level + * would be logged by this logger. + * + * @throws NullPointerException if level + * is null. + */ + public synchronized boolean isLoggable(Level level) + { + if (this.level != null) + return this.level.intValue() <= level.intValue(); + + if (parent != null) + return parent.isLoggable(level); + else + return false; + } + + + /** + * Sets the severity level threshold for this Handler. + * All log records with a lower severity level will be discarded + * immediately. A log record of the same or a higher level will be + * published unless an installed Filter decides to + * discard it. + * + * @param level the severity level below which all log messages + * will be discarded, or null to + * indicate that the logger should inherit the + * threshold from its parent. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + */ + public synchronized void setLevel(Level level) + { + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + this.level = level; + } + + + public synchronized Filter getFilter() + { + return filter; + } + + + /** + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + */ + public synchronized void setFilter(Filter filter) + throws SecurityException + { + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + this.filter = filter; + } + + + + + /** + * Returns the name of this logger. + * + * @return the name of this logger, or null if + * the logger is anonymous. + */ + public String getName() + { + /* Note that the name of a logger cannot be changed during + * its lifetime, so no synchronization is needed. + */ + return name; + } + + + /** + * Passes a record to registered handlers, provided the record + * is considered as loggable both by {@link #isLoggable(Level)} + * and a possibly installed custom {@link #setFilter(Filter) filter}. + * + *

    If the logger has been configured to use parent handlers, + * the record will be forwarded to the parent of this logger + * in addition to being processed by the handlers registered with + * this logger. + * + *

    The other logging methods in this class are convenience methods + * that merely create a new LogRecord and pass it to this method. + * Therefore, subclasses usually just need to override this single + * method for customizing the logging behavior. + * + * @param record the log record to be inspected and possibly forwarded. + */ + public synchronized void log(LogRecord record) + { + if (!isLoggable(record.getLevel())) + return; + + if ((filter != null) && !filter.isLoggable(record)) + return; + + /* If no logger name has been set for the log record, + * use the name of this logger. + */ + if (record.getLoggerName() == null) + record.setLoggerName(name); + + /* Avoid that some other thread is changing the logger hierarchy + * while we are traversing it. + */ + synchronized (LogManager.getLogManager()) + { + Logger curLogger = this; + + do + { + /* The Sun J2SE 1.4 reference implementation seems to call the + * filter only for the logger whose log method is called, + * never for any of its parents. Also, parent loggers publish + * log record whatever their level might be. This is pretty + * weird, but GNU Classpath tries to be as compatible as + * possible to the reference implementation. + */ + for (int i = 0; i < curLogger.handlers.length; i++) + curLogger.handlers[i].publish(record); + + if (curLogger.getUseParentHandlers() == false) + break; + + curLogger = curLogger.getParent(); + } + while (parent != null); + } + } + + + public void log(Level level, String message) + { + log(level, message, (Object[]) null); + } + + + public synchronized void log(Level level, + String message, + Object param) + { + StackTraceElement caller = getCallerStackFrame(); + logp(level, + caller != null ? caller.getClassName() : "", + caller != null ? caller.getMethodName() : "", + message, + param); + } + + + public synchronized void log(Level level, + String message, + Object[] params) + { + StackTraceElement caller = getCallerStackFrame(); + logp(level, + caller != null ? caller.getClassName() : "", + caller != null ? caller.getMethodName() : "", + message, + params); + } + + + public synchronized void log(Level level, + String message, + Throwable thrown) + { + StackTraceElement caller = getCallerStackFrame(); + logp(level, + caller != null ? caller.getClassName() : "", + caller != null ? caller.getMethodName() : "", + message, + thrown); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message) + { + logp(level, sourceClass, sourceMethod, message, + (Object[]) null); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message, + Object param) + { + logp(level, sourceClass, sourceMethod, message, + new Object[] { param }); + } + + + private synchronized ResourceBundle findResourceBundle() + { + if (resourceBundle != null) + return resourceBundle; + + if (parent != null) + return parent.findResourceBundle(); + + return null; + } + + + private synchronized void logImpl(Level level, + String sourceClass, + String sourceMethod, + String message, + Object[] params) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundle(findResourceBundle()); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setParameters(params); + + log(rec); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message, + Object[] params) + { + logImpl(level, sourceClass, sourceMethod, message, params); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message, + Throwable thrown) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundle(resourceBundle); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setThrown(thrown); + + log(rec); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message) + { + logrb(level, sourceClass, sourceMethod, bundleName, + message, (Object[]) null); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message, + Object param) + { + logrb(level, sourceClass, sourceMethod, bundleName, + message, new Object[] { param }); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message, + Object[] params) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundleName(bundleName); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setParameters(params); + + log(rec); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message, + Throwable thrown) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundleName(bundleName); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setThrown(thrown); + + log(rec); + } + + + public synchronized void entering(String sourceClass, + String sourceMethod) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); + } + + + public synchronized void entering(String sourceClass, + String sourceMethod, + Object param) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param); + } + + + public synchronized void entering(String sourceClass, + String sourceMethod, + Object[] params) + { + if (isLoggable(Level.FINER)) + { + StringBuffer buf = new StringBuffer(80); + buf.append("ENTRY"); + for (int i = 0; i < params.length; i++) + { + buf.append(" {"); + buf.append(i); + buf.append('}'); + } + + logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params); + } + } + + + public synchronized void exiting(String sourceClass, + String sourceMethod) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); + } + + + public synchronized void exiting(String sourceClass, + String sourceMethod, + Object result) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); + } + + + public synchronized void throwing(String sourceClass, + String sourceMethod, + Throwable thrown) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown); + } + + + /** + * Logs a message with severity level SEVERE, indicating a serious + * failure that prevents normal program execution. Messages at this + * level should be understandable to an inexperienced, non-technical + * end user. Ideally, they explain in simple words what actions the + * user can take in order to resolve the problem. + * + * @see Level#SEVERE + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * null, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void severe(String message) + { + if (isLoggable(Level.SEVERE)) + log(Level.SEVERE, message); + } + + + /** + * Logs a message with severity level WARNING, indicating a + * potential problem that does not prevent normal program execution. + * Messages at this level should be understandable to an + * inexperienced, non-technical end user. Ideally, they explain in + * simple words what actions the user can take in order to resolve + * the problem. + * + * @see Level#WARNING + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * null, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void warning(String message) + { + if (isLoggable(Level.WARNING)) + log(Level.WARNING, message); + } + + + /** + * Logs a message with severity level INFO. {@link Level#INFO} is + * intended for purely informational messages that do not indicate + * error or warning situations. In the default logging + * configuration, INFO messages will be written to the system + * console. For this reason, the INFO level should be used only for + * messages that are important to end users and system + * administrators. Messages at this level should be understandable + * to an inexperienced, non-technical user. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * null, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void info(String message) + { + if (isLoggable(Level.INFO)) + log(Level.INFO, message); + } + + + /** + * Logs a message with severity level CONFIG. {@link Level#CONFIG} is + * intended for static configuration messages, for example about the + * windowing environment, the operating system version, etc. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource bundle. While + * it is possible to pass null, this is not + * recommended, since a logging message without text is unlikely + * to be helpful. + */ + public synchronized void config(String message) + { + if (isLoggable(Level.CONFIG)) + log(Level.CONFIG, message); + } + + + /** + * Logs a message with severity level FINE. {@link Level#FINE} is + * intended for messages that are relevant for developers using + * the component generating log messages. Examples include minor, + * recoverable failures, or possible inefficiencies. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * null, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void fine(String message) + { + if (isLoggable(Level.FINE)) + log(Level.FINE, message); + } + + + /** + * Logs a message with severity level FINER. {@link Level#FINER} is + * intended for rather detailed tracing, for example entering a + * method, returning from a method, or throwing an exception. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * null, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void finer(String message) + { + if (isLoggable(Level.FINER)) + log(Level.FINER, message); + } + + + /** + * Logs a message with severity level FINEST. {@link Level#FINEST} + * is intended for highly detailed tracing, for example reaching a + * certain point inside the body of a method. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * null, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void finest(String message) + { + if (isLoggable(Level.FINEST)) + log(Level.FINEST, message); + } + + + /** + * Adds a handler to the set of handlers that get notified + * when a log record is to be published. + * + * @param handler the handler to be added. + * + * @throws NullPointerException if handler + * is null. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + */ + public synchronized void addHandler(Handler handler) + throws SecurityException + { + /* Throw a new NullPointerException if handler is null. */ + handler.getClass(); + + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + if (!handlerList.contains(handler)) + { + handlerList.add(handler); + handlers = getHandlers(); + } + } + + + /** + * Removes a handler from the set of handlers that get notified + * when a log record is to be published. + * + * @param handler the handler to be removed. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted the + * permission to control the logging infrastructure by having + * LoggingPermission("control"). Untrusted code can obtain an + * anonymous logger through the static factory method {@link + * #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + * + * @throws NullPointerException if handler + * is null. + */ + public synchronized void removeHandler(Handler handler) + throws SecurityException + { + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + /* Throw a new NullPointerException if handler is null. */ + handler.getClass(); + + handlerList.remove(handler); + handlers = getHandlers(); + } + + + /** + * Returns the handlers currently registered for this Logger. + * When a log record has been deemed as being loggable, + * it will be passed to all registered handlers for + * publication. In addition, if the logger uses parent handlers + * (see {@link #getUseParentHandlers() getUseParentHandlers} + * and {@link #setUseParentHandlers(boolean) setUseParentHandlers}, + * the log record will be passed to the parent's handlers. + */ + public synchronized Handler[] getHandlers() + { + /* We cannot return our internal handlers array + * because we do not have any guarantee that the + * caller would not change the array entries. + */ + return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]); + } + + + /** + * Returns whether or not this Logger forwards log records to + * handlers registered for its parent loggers. + * + * @return false if this Logger sends log records + * merely to Handlers registered with itself; + * true if this Logger sends log records + * not only to Handlers registered with itself, but also + * to those Handlers registered with parent loggers. + */ + public synchronized boolean getUseParentHandlers() + { + return useParentHandlers; + } + + + /** + * Sets whether or not this Logger forwards log records to + * handlers registered for its parent loggers. + * + * @param useParentHandlers false to let this + * Logger send log records merely to Handlers registered + * with itself; true to let this Logger + * send log records not only to Handlers registered + * with itself, but also to those Handlers registered with + * parent loggers. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + * + */ + public synchronized void setUseParentHandlers(boolean useParentHandlers) + { + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + this.useParentHandlers = useParentHandlers; + } + + + /** + * Returns the parent of this logger. By default, the parent is + * assigned by the LogManager by inspecting the logger's name. + * + * @return the parent of this logger (as detemined by the LogManager + * by inspecting logger names), the root logger if no other + * logger has a name which is a prefix of this logger's name, or + * null for the root logger. + */ + public synchronized Logger getParent() + { + return parent; + } + + + /** + * Sets the parent of this logger. Usually, applications do not + * call this method directly. Instead, the LogManager will ensure + * that the tree of loggers reflects the hierarchical logger + * namespace. Basically, this method should not be public at all, + * but the GNU implementation follows the API specification. + * + * @throws NullPointerException if parent is + * null. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + */ + public synchronized void setParent(Logger parent) + { + LogManager lm; + + /* Throw a new NullPointerException if parent is null. */ + parent.getClass(); + + lm = LogManager.getLogManager(); + + if (this == lm.rootLogger) + throw new IllegalArgumentException( + "only the root logger can have a null parent"); + + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + this.parent = parent; + } + + /** + * Gets the StackTraceElement of the first class that is not this class. + * That should be the initial caller of a logging method. + * @return caller of the initial logging method or null if unknown. + */ + private StackTraceElement getCallerStackFrame() + { + Throwable t = new Throwable(); + StackTraceElement[] stackTrace = t.getStackTrace(); + int index = 0; + + // skip to stackentries until this class + while(index < stackTrace.length + && !stackTrace[index].getClassName().equals(getClass().getName())) + index++; + + // skip the stackentries of this class + while(index < stackTrace.length + && stackTrace[index].getClassName().equals(getClass().getName())) + index++; + + return index < stackTrace.length ? stackTrace[index] : null; + } + + /** + * Reset and close handlers attached to this logger. This function is package + * private because it must only be avaiable to the LogManager. + */ + void resetLogger() + { + for (int i = 0; i < handlers.length; i++) + { + handlers[i].close(); + handlerList.remove(handlers[i]); + } + handlers = getHandlers(); + } +} diff --git a/libjava/classpath/java/util/logging/LoggingPermission.java b/libjava/classpath/java/util/logging/LoggingPermission.java new file mode 100644 index 0000000..c7a2255 --- /dev/null +++ b/libjava/classpath/java/util/logging/LoggingPermission.java @@ -0,0 +1,73 @@ +/* LoggingPermission.java -- a class for logging permissions. + 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 java.util.logging; + +public final class LoggingPermission + extends java.security.BasicPermission +{ + /** + * Creates a new LoggingPermission. + * + * @param name the name of the permission, which must be "control". + * + * @param actions the list of actions for the permission, which + * must be either null or an empty + * string. + * + * @exception IllegalArgumentException if name + * is not "control", or actions is + * neither null nor empty. + */ + public LoggingPermission(String name, String actions) + { + super("control", ""); + + if (!"control".equals(name)) + { + throw new IllegalArgumentException( + "name of LoggingPermission must be \"control\""); + } + + if ((actions != null) && (actions.length() != 0)) + { + throw new IllegalArgumentException( + "actions of LoggingPermissions must be null or empty"); + } + } +} diff --git a/libjava/classpath/java/util/logging/MemoryHandler.java b/libjava/classpath/java/util/logging/MemoryHandler.java new file mode 100644 index 0000000..ffa589f --- /dev/null +++ b/libjava/classpath/java/util/logging/MemoryHandler.java @@ -0,0 +1,345 @@ +/* MemoryHandler.java -- a class for buffering log messages in a memory buffer + 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 java.util.logging; + +/** + * A MemoryHandler maintains a circular buffer of + * log records. + * + *

    Configuration: Values of the subsequent + * LogManager properties are taken into consideration + * when a MemoryHandler is initialized. + * If a property is not defined, or if it has an invalid + * value, a default is taken without an exception being thrown. + * + *

      + *
    • java.util.MemoryHandler.level - specifies + * the initial severity level threshold. Default value: + * Level.ALL.
    • + *
    • java.util.MemoryHandler.filter - specifies + * the name of a Filter class. Default value: No Filter.
    • + *
    • java.util.MemoryHandler.size - specifies the + * maximum number of log records that are kept in the circular + * buffer. Default value: 1000.
    • + *
    • java.util.MemoryHandler.push - specifies the + * pushLevel. Default value: + * Level.SEVERE.
    • + *
    • java.util.MemoryHandler.target - specifies the + * name of a subclass of {@link Handler} that will be used as the + * target handler. There is no default value for this property; + * if it is not set, the no-argument MemoryHandler constructor + * will throw an exception.
    • + *
    + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class MemoryHandler + extends Handler +{ + /** + * The storage area used for buffering the unpushed log records in + * memory. + */ + private final LogRecord[] buffer; + + + /** + * The current position in the circular buffer. For a new + * MemoryHandler, or immediately after {@link #push()} was called, + * the value of this variable is zero. Each call to {@link + * #publish(LogRecord)} will store the published LogRecord into + * buffer[position] before position is incremented by + * one. If position becomes greater than the size of the buffer, it + * is reset to zero. + */ + private int position; + + + /** + * The number of log records which have been published, but not + * pushed yet to the target handler. + */ + private int numPublished; + + + /** + * The push level threshold for this Handler. When a + * record is published whose severity level is greater than or equal + * to the pushLevel of this MemoryHandler, + * the {@link #push()} method will be invoked for pushing the buffer + * contents to the target Handler. + */ + private Level pushLevel; + + + /** + * The Handler to which log records are forwarded for actual + * publication. + */ + private final Handler target; + + + /** + * Constructs a MemoryHandler for keeping a circular + * buffer of LogRecords; the initial configuration is determined by + * the LogManager properties described above. + */ + public MemoryHandler() + { + this((Handler) LogManager.getInstanceProperty( + "java.util.logging.MemoryHandler.target", + Handler.class, /* default */ null), + LogManager.getIntPropertyClamped( + "java.util.logging.MemoryHandler.size", + /* default */ 1000, + /* minimum value */ 1, + /* maximum value */ Integer.MAX_VALUE), + LogManager.getLevelProperty( + "java.util.logging.MemoryHandler.push", + /* default push level */ Level.SEVERE)); + } + + + /** + * Constructs a MemoryHandler for keeping a circular + * buffer of LogRecords, given some parameters. The values of the + * other parameters are taken from LogManager properties, as + * described above. + * + * @param target the target handler that will receive those + * log records that are passed on for publication. + * + * @param size the number of log records that are kept in the buffer. + * The value must be a at least one. + * + * @param pushLevel the push level threshold for this + * MemoryHandler. When a record is published whose + * severity level is greater than or equal to + * pushLevel, the {@link #push()} method will be + * invoked in order to push the bufffer contents to + * target. + * + * @throws java.lang.IllegalArgumentException if size + * is negative or zero. The GNU implementation also throws + * an IllegalArgumentException if target or + * pushLevel are null, but the + * API specification does not prescribe what should happen + * in those cases. + */ + public MemoryHandler(Handler target, int size, Level pushLevel) + { + if ((target == null) || (size <= 0) || (pushLevel == null)) + throw new IllegalArgumentException(); + + buffer = new LogRecord[size]; + this.pushLevel = pushLevel; + this.target = target; + + setLevel(LogManager.getLevelProperty( + "java.util.logging.MemoryHandler.level", + /* default value */ Level.ALL)); + + setFilter((Filter) LogManager.getInstanceProperty( + "java.util.logging.MemoryHandler.filter", + /* must be instance of */ Filter.class, + /* default value */ null)); + } + + + /** + * Stores a LogRecord in a fixed-size circular buffer, + * provided the record passes all tests for being loggable. If the + * buffer is full, the oldest record will be discarded. + * + *

    If the record has a severity level which is greater than or + * equal to the pushLevel of this + * MemoryHandler, the {@link #push()} method will be + * invoked for pushing the buffer contents to the target + * Handler. + * + *

    Most applications do not need to call this method directly. + * Instead, they will use use a {@link Logger}, which will create + * LogRecords and distribute them to registered handlers. + * + * @param record the log event to be published. + */ + public void publish(LogRecord record) + { + if (!isLoggable(record)) + return; + + buffer[position] = record; + position = (position + 1) % buffer.length; + numPublished = numPublished + 1; + + if (record.getLevel().intValue() >= pushLevel.intValue()) + push(); + } + + + /** + * Pushes the contents of the memory buffer to the target + * Handler and clears the buffer. Note that + * the target handler will discard those records that do + * not satisfy its own severity level threshold, or that are + * not considered loggable by an installed {@link Filter}. + * + *

    In case of an I/O failure, the {@link ErrorManager} of the + * target Handler will be notified, but the caller of + * this method will not receive an exception. + */ + public void push() + { + int i; + + if (numPublished < buffer.length) + { + for (i = 0; i < position; i++) + target.publish(buffer[i]); + } + else + { + for (i = position; i < buffer.length; i++) + target.publish(buffer[i]); + for (i = 0; i < position; i++) + target.publish(buffer[i]); + } + + numPublished = 0; + position = 0; + } + + + /** + * Forces any data that may have been buffered by the target + * Handler to the underlying output device, but + * does not push the contents of the circular memory + * buffer to the target handler. + * + *

    In case of an I/O failure, the {@link ErrorManager} of the + * target Handler will be notified, but the caller of + * this method will not receive an exception. + * + * @see #push() + */ + public void flush() + { + target.flush(); + } + + + /** + * Closes this MemoryHandler and its associated target + * handler, discarding the contents of the memory buffer. However, + * any data that may have been buffered by the target + * Handler is forced to the underlying output device. + * + *

    As soon as close has been called, + * a Handler should not be used anymore. Attempts + * to publish log records, to flush buffers, or to modify the + * Handler in any other way may throw runtime + * exceptions after calling close.

    + * + *

    In case of an I/O failure, the ErrorManager of + * the associated target Handler will be informed, but + * the caller of this method will not receive an exception.

    + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + * + * @see #push() + */ + public void close() + throws SecurityException + { + push(); + + /* This will check for LoggingPermission("control"). If the + * current security context does not grant this permission, + * push() has been executed, but this does not impose a + * security risk. + */ + target.close(); + } + + + + /** + * Returns the push level threshold for this Handler. + * When a record is published whose severity level is greater + * than or equal to the pushLevel of this + * MemoryHandler, the {@link #push()} method will be + * invoked for pushing the buffer contents to the target + * Handler. + * + * @return the push level threshold for automatic pushing. + */ + public Level getPushLevel() + { + return pushLevel; + } + + + /** + * Sets the push level threshold for this Handler. + * When a record is published whose severity level is greater + * than or equal to the pushLevel of this + * MemoryHandler, the {@link #push()} method will be + * invoked for pushing the buffer contents to the target + * Handler. + * + * @param pushLevel the push level threshold for automatic pushing. + * + * @exception SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + * + * @exception NullPointerException if pushLevel is + * null. + */ + public void setPushLevel(Level pushLevel) + { + LogManager.getLogManager().checkAccess(); + + /* Throws a NullPointerException if pushLevel is null. */ + pushLevel.getClass(); + + this.pushLevel = pushLevel; + } +} diff --git a/libjava/classpath/java/util/logging/SimpleFormatter.java b/libjava/classpath/java/util/logging/SimpleFormatter.java new file mode 100644 index 0000000..f7a4427 --- /dev/null +++ b/libjava/classpath/java/util/logging/SimpleFormatter.java @@ -0,0 +1,119 @@ +/* SimpleFormatter.java -- + A class for formatting log records into short human-readable messages + 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 java.util.logging; + +import java.text.DateFormat; +import java.util.Date; + +/** + * A SimpleFormatter formats log records into + * short human-readable messages, typically one or two lines. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class SimpleFormatter + extends Formatter +{ + /** + * Constructs a SimpleFormatter. + */ + public SimpleFormatter() + { + } + + + /** + * An instance of a DateFormatter that is used for formatting + * the time of a log record into a human-readable string, + * according to the rules of the current locale. The value + * is set after the first invocation of format, since it is + * common that a JVM will instantiate a SimpleFormatter without + * ever using it. + */ + private DateFormat dateFormat; + + /** + * The character sequence that is used to separate lines in the + * generated stream. Somewhat surprisingly, the Sun J2SE 1.4 + * reference implementation always uses UNIX line endings, even on + * platforms that have different line ending conventions (i.e., + * DOS). The GNU implementation does not replicate this bug. + * + * @see Sun bug parade, bug #4462871, + * "java.util.logging.SimpleFormatter uses hard-coded line separator". + */ + static final String lineSep = System.getProperty("line.separator"); + + + /** + * Formats a log record into a String. + * + * @param the log record to be formatted. + * + * @return a short human-readable message, typically one or two + * lines. Lines are separated using the default platform line + * separator. + * + * @throws NullPointerException if record + * is null. + */ + public String format(LogRecord record) + { + StringBuffer buf = new StringBuffer(180); + + if (dateFormat == null) + dateFormat = DateFormat.getDateTimeInstance(); + + buf.append(dateFormat.format(new Date(record.getMillis()))); + buf.append(' '); + buf.append(record.getSourceClassName()); + buf.append(' '); + buf.append(record.getSourceMethodName()); + buf.append(lineSep); + + buf.append(record.getLevel()); + buf.append(": "); + buf.append(formatMessage(record)); + + buf.append(lineSep); + + return buf.toString(); + } +} diff --git a/libjava/classpath/java/util/logging/SocketHandler.java b/libjava/classpath/java/util/logging/SocketHandler.java new file mode 100644 index 0000000..002dfdb --- /dev/null +++ b/libjava/classpath/java/util/logging/SocketHandler.java @@ -0,0 +1,221 @@ +/* SocketHandler.java -- a class for publishing log messages to network sockets + 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 java.util.logging; + + +/** + * A SocketHandler publishes log records to + * a TCP/IP socket. + * + *

    Configuration: Values of the subsequent + * LogManager properties are taken into consideration + * when a SocketHandler is initialized. + * If a property is not defined, or if it has an invalid + * value, a default is taken without an exception being thrown. + * + *

      + * + *
    • java.util.SocketHandler.level - specifies + * the initial severity level threshold. Default value: + * Level.ALL.
    • + * + *
    • java.util.SocketHandler.filter - specifies + * the name of a Filter class. Default value: No Filter.
    • + * + *
    • java.util.SocketHandler.formatter - specifies + * the name of a Formatter class. Default value: + * java.util.logging.XMLFormatter.
    • + * + *
    • java.util.SocketHandler.encoding - specifies + * the name of the character encoding. Default value: + * the default platform encoding.
    • + * + *
    • java.util.SocketHandler.host - specifies + * the name of the host to which records are published. + * There is no default value for this property; if it is + * not set, the SocketHandler constructor will throw + * an exception.
    • + * + *
    • java.util.SocketHandler.port - specifies + * the TCP/IP port to which records are published. + * There is no default value for this property; if it is + * not set, the SocketHandler constructor will throw + * an exception.
    • + * + *
    + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class SocketHandler + extends StreamHandler +{ + /** + * Constructs a SocketHandler that publishes log + * records to a TCP/IP socket. Tthe initial configuration is + * determined by the LogManager properties described + * above. + * + * @throws java.io.IOException if the connection to the specified + * network host and port cannot be established. + * + * @throws java.lang.IllegalArgumentException if either the + * java.util.logging.SocketHandler.host + * or java.util.logging.SocketHandler.port + * LogManager properties is not defined, or specifies + * an invalid value. + */ + public SocketHandler() + throws java.io.IOException + { + this(LogManager.getLogManager().getProperty("java.util.logging.SocketHandler.host"), + getPortNumber()); + } + + + /** + * Constructs a SocketHandler that publishes log + * records to a TCP/IP socket. With the exception of the internet + * host and port, the initial configuration is determined by the + * LogManager properties described above. + * + * @param host the Internet host to which log records will be + * forwarded. + * + * @param port the port at the host which will accept a request + * for a TCP/IP connection. + * + * @throws java.io.IOException if the connection to the specified + * network host and port cannot be established. + * + * @throws java.lang.IllegalArgumentException if either + * host or port specify + * an invalid value. + */ + public SocketHandler(String host, int port) + throws java.io.IOException + { + super(createSocket(host, port), + "java.util.logging.SocketHandler", + /* default level */ Level.ALL, + /* formatter */ null, + /* default formatter */ XMLFormatter.class); + } + + + /** + * Retrieves the port number from the java.util.logging.SocketHandler.port + * LogManager property. + * + * @throws IllegalArgumentException if the property is not defined or + * does not specify an integer value. + */ + private static int getPortNumber() + { + try { + return Integer.parseInt(LogManager.getLogManager().getProperty("java.util.logging.SocketHandler.port")); + } catch (Exception ex) { + throw new IllegalArgumentException(); + } + } + + + /** + * Creates an OutputStream for publishing log records to an Internet + * host and port. This private method is a helper for use by the + * constructor of SocketHandler. + * + * @param host the Internet host to which log records will be + * forwarded. + * + * @param port the port at the host which will accept a request + * for a TCP/IP connection. + * + * @throws java.io.IOException if the connection to the specified + * network host and port cannot be established. + * + * @throws java.lang.IllegalArgumentException if either + * host or port specify + * an invalid value. + */ + private static java.io.OutputStream createSocket(String host, int port) + throws java.io.IOException, java.lang.IllegalArgumentException + { + java.net.Socket socket; + + if ((host == null) || (port < 1)) + throw new IllegalArgumentException(); + + socket = new java.net.Socket(host, port); + + socket.shutdownInput(); + + /* The architecture of the logging framework provides replaceable + * formatters. Because these formatters perform their task by + * returning one single String for each LogRecord to be formatted, + * there is no need to buffer. + */ + socket.setTcpNoDelay(true); + + return socket.getOutputStream(); + } + + + /** + * Publishes a LogRecord to the network socket, + * provided the record passes all tests for being loggable. + * In addition, all data that may have been buffered will + * be forced to the network stream. + * + *

    Most applications do not need to call this method directly. + * Instead, they will use a {@link Logger} instance, which will + * create LogRecords and distribute them to registered handlers. + * + *

    In case of an I/O failure, the ErrorManager + * of this SocketHandler will be informed, but the caller + * of this method will not receive an exception. + * + * @param record the log event to be published. + */ + public void publish(LogRecord record) + { + super.publish(record); + flush(); + } +} + diff --git a/libjava/classpath/java/util/logging/StreamHandler.java b/libjava/classpath/java/util/logging/StreamHandler.java new file mode 100644 index 0000000..5c35c1e --- /dev/null +++ b/libjava/classpath/java/util/logging/StreamHandler.java @@ -0,0 +1,521 @@ +/* StreamHandler.java -- + A class for publishing log messages to instances of java.io.OutputStream + 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 java.util.logging; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +/** + * A StreamHandler publishes LogRecords to + * a instances of java.io.OutputStream. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class StreamHandler + extends Handler +{ + private OutputStream out; + private Writer writer; + + + /** + * Indicates the current state of this StreamHandler. The value + * should be one of STATE_FRESH, STATE_PUBLISHED, or STATE_CLOSED. + */ + private int streamState = STATE_FRESH; + + + /** + * streamState having this value indicates that the StreamHandler + * has been created, but the publish(LogRecord) method has not been + * called yet. If the StreamHandler has been constructed without an + * OutputStream, writer will be null, otherwise it is set to a + * freshly created OutputStreamWriter. + */ + private static final int STATE_FRESH = 0; + + + /** + * streamState having this value indicates that the publish(LocRecord) + * method has been called at least once. + */ + private static final int STATE_PUBLISHED = 1; + + + /** + * streamState having this value indicates that the close() method + * has been called. + */ + private static final int STATE_CLOSED = 2; + + + /** + * Creates a StreamHandler without an output stream. + * Subclasses can later use {@link + * #setOutputStream(java.io.OutputStream)} to associate an output + * stream with this StreamHandler. + */ + public StreamHandler() + { + this(null, null); + } + + + /** + * Creates a StreamHandler that formats log messages + * with the specified Formatter and publishes them to the specified + * output stream. + * + * @param out the output stream to which the formatted log messages + * are published. + * + * @param formatter the Formatter that will be used + * to format log messages. + */ + public StreamHandler(OutputStream out, Formatter formatter) + { + this(out, "java.util.logging.StreamHandler", Level.INFO, + formatter, SimpleFormatter.class); + } + + + StreamHandler( + OutputStream out, + String propertyPrefix, + Level defaultLevel, + Formatter formatter, Class defaultFormatterClass) + { + this.level = LogManager.getLevelProperty(propertyPrefix + ".level", + defaultLevel); + + this.filter = (Filter) LogManager.getInstanceProperty( + propertyPrefix + ".filter", + /* must be instance of */ Filter.class, + /* default: new instance of */ null); + + if (formatter != null) + this.formatter = formatter; + else + this.formatter = (Formatter) LogManager.getInstanceProperty( + propertyPrefix + ".formatter", + /* must be instance of */ Formatter.class, + /* default: new instance of */ defaultFormatterClass); + + try + { + String enc = LogManager.getLogManager().getProperty(propertyPrefix + + ".encoding"); + + /* make sure enc actually is a valid encoding */ + if ((enc != null) && (enc.length() > 0)) + new String(new byte[0], enc); + + this.encoding = enc; + } + catch (Exception _) + { + } + + if (out != null) + { + try + { + changeWriter(out, getEncoding()); + } + catch (UnsupportedEncodingException uex) + { + /* This should never happen, since the validity of the encoding + * name has been checked above. + */ + throw new RuntimeException(uex.getMessage()); + } + } + } + + + private void checkOpen() + { + if (streamState == STATE_CLOSED) + throw new IllegalStateException(this.toString() + " has been closed"); + } + + private void checkFresh() + { + checkOpen(); + if (streamState != STATE_FRESH) + throw new IllegalStateException("some log records have been published to " + this); + } + + + private void changeWriter(OutputStream out, String encoding) + throws UnsupportedEncodingException + { + OutputStreamWriter writer; + + /* The logging API says that a null encoding means the default + * platform encoding. However, java.io.OutputStreamWriter needs + * another constructor for the default platform encoding, + * passing null would throw an exception. + */ + if (encoding == null) + writer = new OutputStreamWriter(out); + else + writer = new OutputStreamWriter(out, encoding); + + /* Closing the stream has side effects -- do this only after + * creating a new writer has been successful. + */ + if ((streamState != STATE_FRESH) || (this.writer != null)) + close(); + + this.writer = writer; + this.out = out; + this.encoding = encoding; + streamState = STATE_FRESH; + } + + + /** + * Sets the character encoding which this handler uses for publishing + * log records. The encoding of a StreamHandler must be + * set before any log records have been published. + * + * @param encoding the name of a character encoding, or null + * for the default encoding. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control the + * the logging infrastructure. + * + * @exception IllegalStateException if any log records have been + * published to this StreamHandler before. Please + * be aware that this is a pecularity of the GNU implementation. + * While the API specification indicates that it is an error + * if the encoding is set after records have been published, + * it does not mandate any specific behavior for that case. + */ + public void setEncoding(String encoding) + throws SecurityException, UnsupportedEncodingException + { + /* The inherited implementation first checks whether the invoking + * code indeed has the permission to control the logging infra- + * structure, and throws a SecurityException if this was not the + * case. + * + * Next, it verifies that the encoding is supported and throws + * an UnsupportedEncodingExcpetion otherwise. Finally, it remembers + * the name of the encoding. + */ + super.setEncoding(encoding); + + checkFresh(); + + /* If out is null, setEncoding is being called before an output + * stream has been set. In that case, we need to check that the + * encoding is valid, and remember it if this is the case. Since + * this is exactly what the inherited implementation of + * Handler.setEncoding does, we can delegate. + */ + if (out != null) + { + /* The logging API says that a null encoding means the default + * platform encoding. However, java.io.OutputStreamWriter needs + * another constructor for the default platform encoding, passing + * null would throw an exception. + */ + if (encoding == null) + writer = new OutputStreamWriter(out); + else + writer = new OutputStreamWriter(out, encoding); + } + } + + + /** + * Changes the output stream to which this handler publishes + * logging records. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + * + * @throws NullPointerException if out + * is null. + */ + protected void setOutputStream(OutputStream out) + throws SecurityException + { + LogManager.getLogManager().checkAccess(); + + /* Throw a NullPointerException if out is null. */ + out.getClass(); + + try + { + changeWriter(out, getEncoding()); + } + catch (UnsupportedEncodingException ex) + { + /* This seems quite unlikely to happen, unless the underlying + * implementation of java.io.OutputStreamWriter changes its + * mind (at runtime) about the set of supported character + * encodings. + */ + throw new RuntimeException(ex.getMessage()); + } + } + + + /** + * Publishes a LogRecord to the associated output + * stream, provided the record passes all tests for being loggable. + * The StreamHandler will localize the message of the + * log record and substitute any message parameters. + * + *

    Most applications do not need to call this method directly. + * Instead, they will use use a {@link Logger}, which will create + * LogRecords and distribute them to registered handlers. + * + *

    In case of an I/O failure, the ErrorManager + * of this Handler will be informed, but the caller + * of this method will not receive an exception. + * + *

    If a log record is being published to a + * StreamHandler that has been closed earlier, the Sun + * J2SE 1.4 reference can be observed to silently ignore the + * call. The GNU implementation, however, intentionally behaves + * differently by informing the ErrorManager associated + * with this StreamHandler. Since the condition + * indicates a programming error, the programmer should be + * informed. It also seems extremely unlikely that any application + * would depend on the exact behavior in this rather obscure, + * erroneous case -- especially since the API specification does not + * prescribe what is supposed to happen. + * + * @param record the log event to be published. + */ + public void publish(LogRecord record) + { + String formattedMessage; + + if (!isLoggable(record)) + return; + + if (streamState == STATE_FRESH) + { + try + { + writer.write(formatter.getHead(this)); + } + catch (java.io.IOException ex) + { + reportError(null, ex, ErrorManager.WRITE_FAILURE); + return; + } + catch (Exception ex) + { + reportError(null, ex, ErrorManager.GENERIC_FAILURE); + return; + } + + streamState = STATE_PUBLISHED; + } + + try + { + formattedMessage = formatter.format(record); + } + catch (Exception ex) + { + reportError(null, ex, ErrorManager.FORMAT_FAILURE); + return; + } + + try + { + writer.write(formattedMessage); + } + catch (Exception ex) + { + reportError(null, ex, ErrorManager.WRITE_FAILURE); + } + } + + + /** + * Checks whether or not a LogRecord would be logged + * if it was passed to this StreamHandler for publication. + * + *

    The StreamHandler implementation first checks + * whether a writer is present and the handler's level is greater + * than or equal to the severity level threshold. In a second step, + * if a {@link Filter} has been installed, its {@link + * Filter#isLoggable(LogRecord) isLoggable} method is + * invoked. Subclasses of StreamHandler can override + * this method to impose their own constraints. + * + * @param record the LogRecord to be checked. + * + * @return true if record would + * be published by {@link #publish(LogRecord) publish}, + * false if it would be discarded. + * + * @see #setLevel(Level) + * @see #setFilter(Filter) + * @see Filter#isLoggable(LogRecord) + * + * @throws NullPointerException if record is + * null. */ + public boolean isLoggable(LogRecord record) + { + return (writer != null) && super.isLoggable(record); + } + + + /** + * Forces any data that may have been buffered to the underlying + * output device. + * + *

    In case of an I/O failure, the ErrorManager + * of this Handler will be informed, but the caller + * of this method will not receive an exception. + * + *

    If a StreamHandler that has been closed earlier + * is closed a second time, the Sun J2SE 1.4 reference can be + * observed to silently ignore the call. The GNU implementation, + * however, intentionally behaves differently by informing the + * ErrorManager associated with this + * StreamHandler. Since the condition indicates a + * programming error, the programmer should be informed. It also + * seems extremely unlikely that any application would depend on the + * exact behavior in this rather obscure, erroneous case -- + * especially since the API specification does not prescribe what is + * supposed to happen. + */ + public void flush() + { + try + { + checkOpen(); + if (writer != null) + writer.flush(); + } + catch (Exception ex) + { + reportError(null, ex, ErrorManager.FLUSH_FAILURE); + } + } + + + /** + * Closes this StreamHandler after having forced any + * data that may have been buffered to the underlying output + * device. + * + *

    As soon as close has been called, + * a Handler should not be used anymore. Attempts + * to publish log records, to flush buffers, or to modify the + * Handler in any other way may throw runtime + * exceptions after calling close.

    + * + *

    In case of an I/O failure, the ErrorManager + * of this Handler will be informed, but the caller + * of this method will not receive an exception.

    + * + *

    If a StreamHandler that has been closed earlier + * is closed a second time, the Sun J2SE 1.4 reference can be + * observed to silently ignore the call. The GNU implementation, + * however, intentionally behaves differently by informing the + * ErrorManager associated with this + * StreamHandler. Since the condition indicates a + * programming error, the programmer should be informed. It also + * seems extremely unlikely that any application would depend on the + * exact behavior in this rather obscure, erroneous case -- + * especially since the API specification does not prescribe what is + * supposed to happen. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + */ + public void close() + throws SecurityException + { + LogManager.getLogManager().checkAccess(); + + try + { + /* Although flush also calls checkOpen, it catches + * any exceptions and reports them to the ErrorManager + * as flush failures. However, we want to report + * a closed stream as a close failure, not as a + * flush failure here. Therefore, we call checkOpen() + * before flush(). + */ + checkOpen(); + flush(); + + if (writer != null) + { + if (formatter != null) + { + /* Even if the StreamHandler has never published a record, + * it emits head and tail upon closing. An earlier version + * of the GNU Classpath implementation did not emitted + * anything. However, this had caused XML log files to be + * entirely empty instead of containing no log records. + */ + if (streamState == STATE_FRESH) + writer.write(formatter.getHead(this)); + if (streamState != STATE_CLOSED) + writer.write(formatter.getTail(this)); + } + streamState = STATE_CLOSED; + writer.close(); + } + } + catch (Exception ex) + { + reportError(null, ex, ErrorManager.CLOSE_FAILURE); + } + } +} diff --git a/libjava/classpath/java/util/logging/XMLFormatter.java b/libjava/classpath/java/util/logging/XMLFormatter.java new file mode 100644 index 0000000..4dd6328 --- /dev/null +++ b/libjava/classpath/java/util/logging/XMLFormatter.java @@ -0,0 +1,387 @@ +/* XMLFormatter.java -- + A class for formatting log messages into a standard XML format + 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 java.util.logging; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.ResourceBundle; + +/** + * An XMLFormatter formats LogRecords into + * a standard XML format. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class XMLFormatter + extends Formatter +{ + /** + * Constructs a new XMLFormatter. + */ + public XMLFormatter() + { + } + + + /** + * The character sequence that is used to separate lines in the + * generated XML stream. Somewhat surprisingly, the Sun J2SE 1.4 + * reference implementation always uses UNIX line endings, even on + * platforms that have different line ending conventions (i.e., + * DOS). The GNU Classpath implementation does not replicates this + * bug. + * + * See also the Sun bug parade, bug #4462871, + * "java.util.logging.SimpleFormatter uses hard-coded line separator". + */ + private static final String lineSep = SimpleFormatter.lineSep; + + + /** + * A DateFormat for emitting time in the ISO 8601 format. + * Since the API specification of SimpleDateFormat does not talk + * about its thread-safety, we cannot share a singleton instance. + */ + private final SimpleDateFormat iso8601 + = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + + + /** + * Appends a line consisting of indentation, opening element tag, + * element content, closing element tag and line separator to + * a StringBuffer, provided that the element content is + * actually existing. + * + * @param buf the StringBuffer to which the line will be appended. + * + * @param indent the indentation level. + * + * @param tag the element tag name, for instance method. + * + * @param content the element content, or null to + * have no output whatsoever appended to buf. + */ + private static void appendTag(StringBuffer buf, int indent, + String tag, String content) + { + int i; + + if (content == null) + return; + + for (i = 0; i < indent * 2; i++) + buf.append(' '); + + buf.append("<"); + buf.append(tag); + buf.append('>'); + + /* Append the content, but escape for XML by replacing + * '&', '<', '>' and all non-ASCII characters with + * appropriate escape sequences. + * The Sun J2SE 1.4 reference implementation does not + * escape non-ASCII characters. This is a bug in their + * implementation which has been reported in the Java + * bug parade as bug number (FIXME: Insert number here). + */ + for (i = 0; i < content.length(); i++) + { + char c = content.charAt(i); + switch (c) + { + case '&': + buf.append("&"); + break; + + case '<': + buf.append("<"); + break; + + case '>': + buf.append(">"); + break; + + default: + if (((c >= 0x20) && (c <= 0x7e)) + || (c == /* line feed */ 10) + || (c == /* carriage return */ 13)) + buf.append(c); + else + { + buf.append("&#"); + buf.append((int) c); + buf.append(';'); + } + break; + } /* switch (c) */ + } /* for i */ + + buf.append(""); + buf.append(lineSep); + } + + + /** + * Appends a line consisting of indentation, opening element tag, + * numeric element content, closing element tag and line separator + * to a StringBuffer. + * + * @param buf the StringBuffer to which the line will be appended. + * + * @param indent the indentation level. + * + * @param tag the element tag name, for instance method. + * + * @param content the element content. + */ + private static void appendTag(StringBuffer buf, int indent, + String tag, long content) + { + appendTag(buf, indent, tag, Long.toString(content)); + } + + + public String format(LogRecord record) + { + StringBuffer buf = new StringBuffer(400); + Level level = record.getLevel(); + long millis = record.getMillis(); + Object[] params = record.getParameters(); + ResourceBundle bundle = record.getResourceBundle(); + String message; + + buf.append(""); + buf.append(lineSep); + + + appendTag(buf, 1, "date", iso8601.format(new Date(millis))); + appendTag(buf, 1, "millis", record.getMillis()); + appendTag(buf, 1, "sequence", record.getSequenceNumber()); + appendTag(buf, 1, "logger", record.getLoggerName()); + + if (level.isStandardLevel()) + appendTag(buf, 1, "level", level.toString()); + else + appendTag(buf, 1, "level", level.intValue()); + + appendTag(buf, 1, "class", record.getSourceClassName()); + appendTag(buf, 1, "method", record.getSourceMethodName()); + appendTag(buf, 1, "thread", record.getThreadID()); + + /* The Sun J2SE 1.4 reference implementation does not emit the + * message in localized form. This is in violation of the API + * specification. The GNU Classpath implementation intentionally + * replicates the buggy behavior of the Sun implementation, as + * different log files might be a big nuisance to users. + */ + try + { + record.setResourceBundle(null); + message = formatMessage(record); + } + finally + { + record.setResourceBundle(bundle); + } + appendTag(buf, 1, "message", message); + + /* The Sun J2SE 1.4 reference implementation does not + * emit key, catalog and param tags. This is in violation + * of the API specification. The Classpath implementation + * intentionally replicates the buggy behavior of the + * Sun implementation, as different log files might be + * a big nuisance to users. + * + * FIXME: File a bug report with Sun. Insert bug number here. + * + * + * key = record.getMessage(); + * if (key == null) + * key = ""; + * + * if ((bundle != null) && !key.equals(message)) + * { + * appendTag(buf, 1, "key", key); + * appendTag(buf, 1, "catalog", record.getResourceBundleName()); + * } + * + * if (params != null) + * { + * for (int i = 0; i < params.length; i++) + * appendTag(buf, 1, "param", params[i].toString()); + * } + */ + + /* FIXME: We have no way to obtain the stacktrace before free JVMs + * support the corresponding method in java.lang.Throwable. Well, + * it would be possible to parse the output of printStackTrace, + * but this would be pretty kludgy. Instead, we postpose the + * implementation until Throwable has made progress. + */ + Throwable thrown = record.getThrown(); + if (thrown != null) + { + buf.append(" "); + buf.append(lineSep); + + /* The API specification is not clear about what exactly + * goes into the XML record for a thrown exception: It + * could be the result of getMessage(), getLocalizedMessage(), + * or toString(). Therefore, it was necessary to write a + * Mauve testlet and run it with the Sun J2SE 1.4 reference + * implementation. It turned out that the we need to call + * toString(). + * + * FIXME: File a bug report with Sun, asking for clearer + * specs. + */ + appendTag(buf, 2, "message", thrown.toString()); + + /* FIXME: The Logging DTD specifies: + * + * + * + * However, java.lang.Throwable.getStackTrace() is + * allowed to return an empty array. So, what frame should + * be emitted for an empty stack trace? We probably + * should file a bug report with Sun, asking for the DTD + * to be changed. + */ + + buf.append(" "); + buf.append(lineSep); + } + + + buf.append(""); + buf.append(lineSep); + + return buf.toString(); + } + + + /** + * Returns a string that handlers are supposed to emit before + * the first log record. The base implementation returns an + * empty string, but subclasses such as {@link XMLFormatter} + * override this method in order to provide a suitable header. + * + * @return a string for the header. + * + * @param handler the handler which will prepend the returned + * string in front of the first log record. This method + * will inspect certain properties of the handler, for + * example its encoding, in order to construct the header. + */ + public String getHead(Handler h) + { + StringBuffer buf; + String encoding; + + buf = new StringBuffer(80); + buf.append(" 2) && encoding.startsWith("Cp")) + encoding = "windows-" + encoding.substring(2); + + buf.append(encoding); + + buf.append("\" standalone=\"no\"?>"); + buf.append(lineSep); + + /* SYSTEM is not a fully qualified URL so that validating + * XML parsers do not need to connect to the Internet in + * order to read in a log file. See also the Sun Bug Parade, + * bug #4372790, "Logging APIs: need to use relative URL for XML + * doctype". + */ + buf.append(""); + buf.append(lineSep); + buf.append(""); + buf.append(lineSep); + + return buf.toString(); + } + + + public String getTail(Handler h) + { + return "" + lineSep; + } +} diff --git a/libjava/classpath/java/util/logging/package.html b/libjava/classpath/java/util/logging/package.html new file mode 100644 index 0000000..31f0494 --- /dev/null +++ b/libjava/classpath/java/util/logging/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.util.logging + + +

    Utility classes for logging events.

    + + + diff --git a/libjava/classpath/java/util/package.html b/libjava/classpath/java/util/package.html new file mode 100644 index 0000000..ff2919c --- /dev/null +++ b/libjava/classpath/java/util/package.html @@ -0,0 +1,48 @@ + + + + +GNU Classpath - java.util + + +

    Utility classes such as collections (maps, sets, lists, dictionaries and +stacks), calendars, dates, locales, properties, timers, resource bundles and +event objects.

    + + + diff --git a/libjava/classpath/java/util/prefs/AbstractPreferences.java b/libjava/classpath/java/util/prefs/AbstractPreferences.java new file mode 100644 index 0000000..3f70400 --- /dev/null +++ b/libjava/classpath/java/util/prefs/AbstractPreferences.java @@ -0,0 +1,1272 @@ +/* AbstractPreferences -- Partial implementation of a Preference node + Copyright (C) 2001, 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 java.util.prefs; + +import gnu.java.util.prefs.NodeWriter; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.TreeSet; + +/** + * Partial implementation of a Preference node. + * + * @since 1.4 + * @author Mark Wielaard (mark@klomp.org) + */ +public abstract class AbstractPreferences extends Preferences { + + // protected fields + + /** + * Object used to lock this preference node. Any thread only locks nodes + * downwards when it has the lock on the current node. No method should + * synchronize on the lock of any of its parent nodes while holding the + * lock on the current node. + */ + protected final Object lock = new Object(); + + /** + * Set to true in the contructor if the node did not exist in the backing + * store when this preference node object was created. Should be set in + * the contructor of a subclass. Defaults to false. Used to fire node + * changed events. + */ + protected boolean newNode = false; + + // private fields + + /** + * The parent preferences node or null when this is the root node. + */ + private final AbstractPreferences parent; + + /** + * The name of this node. + * Only when this is a root node (parent == null) the name is empty. + * It has a maximum of 80 characters and cannot contain any '/' characters. + */ + private final String name; + + /** True when this node has been remove, false otherwise. */ + private boolean removed = false; + + /** + * Holds all the child names and nodes of this node that have been + * accessed by earlier getChild() or childSpi() + * invocations and that have not been removed. + */ + private HashMap childCache = new HashMap(); + + // constructor + + /** + * Creates a new AbstractPreferences node with the given parent and name. + * + * @param parent the parent of this node or null when this is the root node + * @param name the name of this node, can not be null, only 80 characters + * maximum, must be empty when parent is null and cannot + * contain any '/' characters + * @exception IllegalArgumentException when name is null, greater then 80 + * characters, not the empty string but parent is null or + * contains a '/' character + */ + protected AbstractPreferences(AbstractPreferences parent, String name) { + if ( (name == null) // name should be given + || (name.length() > MAX_NAME_LENGTH) // 80 characters max + || (parent == null && name.length() != 0) // root has no name + || (parent != null && name.length() == 0) // all other nodes do + || (name.indexOf('/') != -1)) // must not contain '/' + throw new IllegalArgumentException("Illegal name argument '" + + name + + "' (parent is " + + (parent == null ? "" : "not ") + + "null)"); + this.parent = parent; + this.name = name; + } + + // identification methods + + /** + * Returns the absolute path name of this preference node. + * The absolute path name of a node is the path name of its parent node + * plus a '/' plus its own name. If the node is the root node and has no + * parent then its path name is "" and its absolute path name is "/". + */ + public String absolutePath() { + if (parent == null) + return "/"; + else + return parent.path() + '/' + name; + } + + /** + * Private helper method for absolutePath. Returns the empty string for a + * root node and otherwise the parentPath of its parent plus a '/'. + */ + private String path() { + if (parent == null) + return ""; + else + return parent.path() + '/' + name; + } + + /** + * Returns true if this node comes from the user preferences tree, false + * if it comes from the system preferences tree. + */ + public boolean isUserNode() { + AbstractPreferences root = this; + while (root.parent != null) + root = root.parent; + return root == Preferences.userRoot(); + } + + /** + * Returns the name of this preferences node. The name of the node cannot + * be null, can be mostly 80 characters and cannot contain any '/' + * characters. The root node has as name "". + */ + public String name() { + return name; + } + + /** + * Returns the String given by + * + * (isUserNode() ? "User":"System") + " Preference Node: " + absolutePath() + * + */ + public String toString() { + return (isUserNode() ? "User":"System") + + " Preference Node: " + + absolutePath(); + } + + /** + * Returns all known unremoved children of this node. + * + * @return All known unremoved children of this node + */ + protected final AbstractPreferences[] cachedChildren() + { + return (AbstractPreferences[]) childCache.values().toArray(); + } + + /** + * Returns all the direct sub nodes of this preferences node. + * Needs access to the backing store to give a meaningfull answer. + *

    + * This implementation locks this node, checks if the node has not yet + * been removed and throws an IllegalStateException when it + * has been. Then it creates a new TreeSet and adds any + * already cached child nodes names. To get any uncached names it calls + * childrenNamesSpi() and adds the result to the set. Finally + * it calls toArray() on the created set. When the call to + * childrenNamesSpi thows an BackingStoreException + * this method will not catch that exception but propagate the exception + * to the caller. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException when this node has been removed + */ + public String[] childrenNames() throws BackingStoreException { + synchronized(lock) { + if (isRemoved()) + throw new IllegalStateException("Node removed"); + + TreeSet childrenNames = new TreeSet(); + + // First get all cached node names + childrenNames.addAll(childCache.keySet()); + + // Then add any others + String names[] = childrenNamesSpi(); + for (int i = 0; i < names.length; i++) { + childrenNames.add(names[i]); + } + + // And return the array of names + String[] children = new String[childrenNames.size()]; + childrenNames.toArray(children); + return children; + + } + } + + /** + * Returns a sub node of this preferences node if the given path is + * relative (does not start with a '/') or a sub node of the root + * if the path is absolute (does start with a '/'). + *

    + * This method first locks this node and checks if the node has not been + * removed, if it has been removed it throws an exception. Then if the + * path is relative (does not start with a '/') it checks if the path is + * legal (does not end with a '/' and has no consecutive '/' characters). + * Then it recursively gets a name from the path, gets the child node + * from the child-cache of this node or calls the childSpi() + * method to create a new child sub node. This is done recursively on the + * newly created sub node with the rest of the path till the path is empty. + * If the path is absolute (starts with a '/') the lock on this node is + * droped and this method is called on the root of the preferences tree + * with as argument the complete path minus the first '/'. + * + * @exception IllegalStateException if this node has been removed + * @exception IllegalArgumentException if the path contains two or more + * consecutive '/' characters, ends with a '/' charactor and is not the + * string "/" (indicating the root node) or any name on the path is more + * then 80 characters long + */ + public Preferences node(String path) { + synchronized(lock) { + if (isRemoved()) + throw new IllegalStateException("Node removed"); + + // Is it a relative path? + if (!path.startsWith("/")) { + + // Check if it is a valid path + if (path.indexOf("//") != -1 || path.endsWith("/")) + throw new IllegalArgumentException(path); + + return getNode(path); + } + } + + // path started with a '/' so it is absolute + // we drop the lock and start from the root (omitting the first '/') + Preferences root = isUserNode() ? userRoot() : systemRoot(); + return root.node(path.substring(1)); + + } + + /** + * Private helper method for node(). Called with this node + * locked. Returns this node when path is the empty string, if it is not + * empty the next node name is taken from the path (all chars till the + * next '/' or end of path string) and the node is either taken from the + * child-cache of this node or the childSpi() method is called + * on this node with the name as argument. Then this method is called + * recursively on the just constructed child node with the rest of the + * path. + * + * @param path should not end with a '/' character and should not contain + * consecutive '/' characters + * @exception IllegalArgumentException if path begins with a name that is + * larger then 80 characters. + */ + private Preferences getNode(String path) { + // if mark is dom then goto end + + // Empty String "" indicates this node + if (path.length() == 0) + return this; + + // Calculate child name and rest of path + String childName; + String childPath; + int nextSlash = path.indexOf('/'); + if (nextSlash == -1) { + childName = path; + childPath = ""; + } else { + childName = path.substring(0, nextSlash); + childPath = path.substring(nextSlash+1); + } + + // Get the child node + AbstractPreferences child; + child = (AbstractPreferences)childCache.get(childName); + if (child == null) { + + if (childName.length() > MAX_NAME_LENGTH) + throw new IllegalArgumentException(childName); + + // Not in childCache yet so create a new sub node + child = childSpi(childName); + // XXX - check if node is new + childCache.put(childName, child); + } + + // Lock the child and go down + synchronized(child.lock) { + return child.getNode(childPath); + } + } + + /** + * Returns true if the node that the path points to exists in memory or + * in the backing store. Otherwise it returns false or an exception is + * thrown. When this node is removed the only valid parameter is the + * empty string (indicating this node), the return value in that case + * will be false. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has been removed + * and the path is not the empty string (indicating this node) + * @exception IllegalArgumentException if the path contains two or more + * consecutive '/' characters, ends with a '/' charactor and is not the + * string "/" (indicating the root node) or any name on the path is more + * then 80 characters long + */ + public boolean nodeExists(String path) throws BackingStoreException { + synchronized(lock) { + if (isRemoved() && path.length() != 0) + throw new IllegalStateException("Node removed"); + + // Is it a relative path? + if (!path.startsWith("/")) { + + // Check if it is a valid path + if (path.indexOf("//") != -1 || path.endsWith("/")) + throw new IllegalArgumentException(path); + + return existsNode(path); + } + } + + // path started with a '/' so it is absolute + // we drop the lock and start from the root (omitting the first '/') + Preferences root = isUserNode() ? userRoot() : systemRoot(); + return root.nodeExists(path.substring(1)); + + } + + private boolean existsNode(String path) throws BackingStoreException { + + // Empty String "" indicates this node + if (path.length() == 0) + return(!isRemoved()); + + // Calculate child name and rest of path + String childName; + String childPath; + int nextSlash = path.indexOf('/'); + if (nextSlash == -1) { + childName = path; + childPath = ""; + } else { + childName = path.substring(0, nextSlash); + childPath = path.substring(nextSlash+1); + } + + // Get the child node + AbstractPreferences child; + child = (AbstractPreferences)childCache.get(childName); + if (child == null) { + + if (childName.length() > MAX_NAME_LENGTH) + throw new IllegalArgumentException(childName); + + // Not in childCache yet so create a new sub node + child = getChild(childName); + + if (child == null) + return false; + + childCache.put(childName, child); + } + + // Lock the child and go down + synchronized(child.lock) { + return child.existsNode(childPath); + } + } + + /** + * Returns the child sub node if it exists in the backing store or null + * if it does not exist. Called (indirectly) by nodeExists() + * when a child node name can not be found in the cache. + *

    + * Gets the lock on this node, calls childrenNamesSpi() to + * get an array of all (possibly uncached) children and compares the + * given name with the names in the array. If the name is found in the + * array childSpi() is called to get an instance, otherwise + * null is returned. + * + * @exception BackingStoreException when the backing store cannot be + * reached + */ + protected AbstractPreferences getChild(String name) + throws BackingStoreException + { + synchronized(lock) { + // Get all the names (not yet in the cache) + String[] names = childrenNamesSpi(); + for (int i=0; i < names.length; i++) + if (name.equals(names[i])) + return childSpi(name); + + // No child with that name found + return null; + } + } + + /** + * Returns true if this node has been removed with the + * removeNode() method, false otherwise. + *

    + * Gets the lock on this node and then returns a boolean field set by + * removeNode methods. + */ + protected boolean isRemoved() { + synchronized(lock) { + return removed; + } + } + + /** + * Returns the parent preferences node of this node or null if this is + * the root of the preferences tree. + *

    + * Gets the lock on this node, checks that the node has not been removed + * and returns the parent given to the constructor. + * + * @exception IllegalStateException if this node has been removed + */ + public Preferences parent() { + synchronized(lock) { + if (isRemoved()) + throw new IllegalStateException("Node removed"); + + return parent; + } + } + + // export methods + + /** + * XXX + */ + public void exportNode(OutputStream os) + throws BackingStoreException, + IOException + { + NodeWriter nodeWriter = new NodeWriter(this, os); + nodeWriter.writePrefs(); + } + + /** + * XXX + */ + public void exportSubtree(OutputStream os) + throws BackingStoreException, + IOException + { + NodeWriter nodeWriter = new NodeWriter(this, os); + nodeWriter.writePrefsTree(); + } + + // preference entry manipulation methods + + /** + * Returns an (possibly empty) array with all the keys of the preference + * entries of this node. + *

    + * This method locks this node and checks if the node has not been + * removed, if it has been removed it throws an exception, then it returns + * the result of calling keysSpi(). + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has been removed + */ + public String[] keys() throws BackingStoreException { + synchronized(lock) { + if (isRemoved()) + throw new IllegalStateException("Node removed"); + + return keysSpi(); + } + } + + + /** + * Returns the value associated with the key in this preferences node. If + * the default value of the key cannot be found in the preferences node + * entries or something goes wrong with the backing store the supplied + * default value is returned. + *

    + * Checks that key is not null and not larger then 80 characters, + * locks this node, and checks that the node has not been removed. + * Then it calls keySpi() and returns + * the result of that method or the given default value if it returned + * null or throwed an exception. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public String get(String key, String defaultVal) { + if (key.length() > MAX_KEY_LENGTH) + throw new IllegalArgumentException(key); + + synchronized(lock) { + if (isRemoved()) + throw new IllegalStateException("Node removed"); + + String value; + try { + value = getSpi(key); + } catch (ThreadDeath death) { + throw death; + } catch (Throwable t) { + value = null; + } + + if (value != null) { + return value; + } else { + return defaultVal; + } + } + } + + /** + * Convenience method for getting the given entry as a boolean. + * When the string representation of the requested entry is either + * "true" or "false" (ignoring case) then that value is returned, + * otherwise the given default boolean value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public boolean getBoolean(String key, boolean defaultVal) { + String value = get(key, null); + + if ("true".equalsIgnoreCase(value)) + return true; + + if ("false".equalsIgnoreCase(value)) + return false; + + return defaultVal; + } + + /** + * Convenience method for getting the given entry as a byte array. + * When the string representation of the requested entry is a valid + * Base64 encoded string (without any other characters, such as newlines) + * then the decoded Base64 string is returned as byte array, + * otherwise the given default byte array value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public byte[] getByteArray(String key, byte[] defaultVal) { + String value = get(key, null); + + byte[] b = null; + if (value != null) { + b = decode64(value); + } + + if (b != null) + return b; + else + return defaultVal; + } + + /** + * Helper method for decoding a Base64 string as an byte array. + * Returns null on encoding error. This method does not allow any other + * characters present in the string then the 65 special base64 chars. + */ + private static byte[] decode64(String s) { + ByteArrayOutputStream bs = new ByteArrayOutputStream((s.length()/4)*3); + char[] c = new char[s.length()]; + s.getChars(0, s.length(), c, 0); + + // Convert from base64 chars + int endchar = -1; + for(int j = 0; j < c.length && endchar == -1; j++) { + if (c[j] >= 'A' && c[j] <= 'Z') { + c[j] -= 'A'; + } else if (c[j] >= 'a' && c[j] <= 'z') { + c[j] = (char) (c[j] + 26 - 'a'); + } else if (c[j] >= '0' && c[j] <= '9') { + c[j] = (char) (c[j] + 52 - '0'); + } else if (c[j] == '+') { + c[j] = 62; + } else if (c[j] == '/') { + c[j] = 63; + } else if (c[j] == '=') { + endchar = j; + } else { + return null; // encoding exception + } + } + + int remaining = endchar == -1 ? c.length : endchar; + int i = 0; + while (remaining > 0) { + // Four input chars (6 bits) are decoded as three bytes as + // 000000 001111 111122 222222 + + byte b0 = (byte) (c[i] << 2); + if (remaining >= 2) { + b0 += (c[i+1] & 0x30) >> 4; + } + bs.write(b0); + + if (remaining >= 3) { + byte b1 = (byte) ((c[i+1] & 0x0F) << 4); + b1 += (byte) ((c[i+2] & 0x3C) >> 2); + bs.write(b1); + } + + if (remaining >= 4) { + byte b2 = (byte) ((c[i+2] & 0x03) << 6); + b2 += c[i+3]; + bs.write(b2); + } + + i += 4; + remaining -= 4; + } + + return bs.toByteArray(); + } + + /** + * Convenience method for getting the given entry as a double. + * When the string representation of the requested entry can be decoded + * with Double.parseDouble() then that double is returned, + * otherwise the given default double value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public double getDouble(String key, double defaultVal) { + String value = get(key, null); + + if (value != null) { + try { + return Double.parseDouble(value); + } catch (NumberFormatException nfe) { /* ignore */ } + } + + return defaultVal; + } + + /** + * Convenience method for getting the given entry as a float. + * When the string representation of the requested entry can be decoded + * with Float.parseFloat() then that float is returned, + * otherwise the given default float value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public float getFloat(String key, float defaultVal) { + String value = get(key, null); + + if (value != null) { + try { + return Float.parseFloat(value); + } catch (NumberFormatException nfe) { /* ignore */ } + } + + return defaultVal; + } + + /** + * Convenience method for getting the given entry as an integer. + * When the string representation of the requested entry can be decoded + * with Integer.parseInt() then that integer is returned, + * otherwise the given default integer value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public int getInt(String key, int defaultVal) { + String value = get(key, null); + + if (value != null) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException nfe) { /* ignore */ } + } + + return defaultVal; + } + + /** + * Convenience method for getting the given entry as a long. + * When the string representation of the requested entry can be decoded + * with Long.parseLong() then that long is returned, + * otherwise the given default long value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public long getLong(String key, long defaultVal) { + String value = get(key, null); + + if (value != null) { + try { + return Long.parseLong(value); + } catch (NumberFormatException nfe) { /* ignore */ } + } + + return defaultVal; + } + + /** + * Sets the value of the given preferences entry for this node. + * Key and value cannot be null, the key cannot exceed 80 characters + * and the value cannot exceed 8192 characters. + *

    + * The result will be immediatly visible in this VM, but may not be + * immediatly written to the backing store. + *

    + * Checks that key and value are valid, locks this node, and checks that + * the node has not been removed. Then it calls putSpi(). + * + * @exception NullPointerException if either key or value are null + * @exception IllegalArgumentException if either key or value are to large + * @exception IllegalStateException when this node has been removed + */ + public void put(String key, String value) { + if (key.length() > MAX_KEY_LENGTH + || value.length() > MAX_VALUE_LENGTH) + throw new IllegalArgumentException("key (" + + key.length() + ")" + + " or value (" + + value.length() + ")" + + " to large"); + synchronized(lock) { + if (isRemoved()) + throw new IllegalStateException("Node removed"); + + putSpi(key, value); + + // XXX - fire events + } + + } + + /** + * Convenience method for setting the given entry as a boolean. + * The boolean is converted with Boolean.toString(value) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public void putBoolean(String key, boolean value) { + put(key, String.valueOf(value)); + // XXX - Use when using 1.4 compatible Boolean + // put(key, Boolean.toString(value)); + } + + /** + * Convenience method for setting the given entry as an array of bytes. + * The byte array is converted to a Base64 encoded string + * and then stored in the preference entry as that string. + *

    + * Note that a byte array encoded as a Base64 string will be about 1.3 + * times larger then the original length of the byte array, which means + * that the byte array may not be larger about 6 KB. + * + * @exception NullPointerException if either key or value are null + * @exception IllegalArgumentException if either key or value are to large + * @exception IllegalStateException when this node has been removed + */ + public void putByteArray(String key, byte[] value) { + put(key, encode64(value)); + } + + /** + * Helper method for encoding an array of bytes as a Base64 String. + */ + private static String encode64(byte[] b) { + StringBuffer sb = new StringBuffer((b.length/3)*4); + + int i = 0; + int remaining = b.length; + char c[] = new char[4]; + while (remaining > 0) { + // Three input bytes are encoded as four chars (6 bits) as + // 00000011 11112222 22333333 + + c[0] = (char) ((b[i] & 0xFC) >> 2); + c[1] = (char) ((b[i] & 0x03) << 4); + if (remaining >= 2) { + c[1] += (char) ((b[i+1] & 0xF0) >> 4); + c[2] = (char) ((b[i+1] & 0x0F) << 2); + if (remaining >= 3) { + c[2] += (char) ((b[i+2] & 0xC0) >> 6); + c[3] = (char) (b[i+2] & 0x3F); + } else { + c[3] = 64; + } + } else { + c[2] = 64; + c[3] = 64; + } + + // Convert to base64 chars + for(int j = 0; j < 4; j++) { + if (c[j] < 26) { + c[j] += 'A'; + } else if (c[j] < 52) { + c[j] = (char) (c[j] - 26 + 'a'); + } else if (c[j] < 62) { + c[j] = (char) (c[j] - 52 + '0'); + } else if (c[j] == 62) { + c[j] = '+'; + } else if (c[j] == 63) { + c[j] = '/'; + } else { + c[j] = '='; + } + } + + sb.append(c); + i += 3; + remaining -= 3; + } + + return sb.toString(); + } + + /** + * Convenience method for setting the given entry as a double. + * The double is converted with Double.toString(double) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public void putDouble(String key, double value) { + put(key, Double.toString(value)); + } + + /** + * Convenience method for setting the given entry as a float. + * The float is converted with Float.toString(float) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public void putFloat(String key, float value) { + put(key, Float.toString(value)); + } + + /** + * Convenience method for setting the given entry as an integer. + * The integer is converted with Integer.toString(int) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public void putInt(String key, int value) { + put(key, Integer.toString(value)); + } + + /** + * Convenience method for setting the given entry as a long. + * The long is converted with Long.toString(long) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public void putLong(String key, long value) { + put(key, Long.toString(value)); + } + + /** + * Removes the preferences entry from this preferences node. + *

    + * The result will be immediatly visible in this VM, but may not be + * immediatly written to the backing store. + *

    + * This implementation checks that the key is not larger then 80 + * characters, gets the lock of this node, checks that the node has + * not been removed and calls removeSpi with the given key. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public void remove(String key) { + if (key.length() > MAX_KEY_LENGTH) + throw new IllegalArgumentException(key); + + synchronized(lock) { + if (isRemoved()) + throw new IllegalStateException("Node removed"); + + removeSpi(key); + } + } + + /** + * Removes all entries from this preferences node. May need access to the + * backing store to get and clear all entries. + *

    + * The result will be immediatly visible in this VM, but may not be + * immediatly written to the backing store. + *

    + * This implementation locks this node, checks that the node has not been + * removed and calls keys() to get a complete array of keys + * for this node. For every key found removeSpi() is called. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has been removed + */ + public void clear() throws BackingStoreException { + synchronized(lock) { + if (isRemoved()) + throw new IllegalStateException("Node Removed"); + + String[] keys = keys(); + for (int i = 0; i < keys.length; i++) { + removeSpi(keys[i]); + } + } + } + + /** + * Writes all preference changes on this and any subnode that have not + * yet been written to the backing store. This has no effect on the + * preference entries in this VM, but it makes sure that all changes + * are visible to other programs (other VMs might need to call the + * sync() method to actually see the changes to the backing + * store. + *

    + * Locks this node, calls the flushSpi() method, gets all + * the (cached - already existing in this VM) subnodes and then calls + * flushSpi() on every subnode with this node unlocked and + * only that particular subnode locked. + * + * @exception BackingStoreException when the backing store cannot be + * reached + */ + public void flush() throws BackingStoreException { + flushNode(false); + } + + /** + * Writes and reads all preference changes to and from this and any + * subnodes. This makes sure that all local changes are written to the + * backing store and that all changes to the backing store are visible + * in this preference node (and all subnodes). + *

    + * Checks that this node is not removed, locks this node, calls the + * syncSpi() method, gets all the subnodes and then calls + * syncSpi() on every subnode with this node unlocked and + * only that particular subnode locked. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has been removed + */ + public void sync() throws BackingStoreException { + flushNode(true); + } + + + /** + * Private helper method that locks this node and calls either + * flushSpi() if sync is false, or + * flushSpi() if sync is true. Then it gets all + * the currently cached subnodes. For every subnode it calls this method + * recursively with this node no longer locked. + *

    + * Called by either flush() or sync() + */ + private void flushNode(boolean sync) throws BackingStoreException { + String[] keys = null; + synchronized(lock) { + if (sync) { + syncSpi(); + } else { + flushSpi(); + } + keys = (String[]) childCache.keySet().toArray(new String[]{}); + } + + if (keys != null) { + for (int i = 0; i < keys.length; i++) { + // Have to lock this node again to access the childCache + AbstractPreferences subNode; + synchronized(this) { + subNode = (AbstractPreferences) childCache.get(keys[i]); + } + + // The child could already have been removed from the cache + if (subNode != null) { + subNode.flushNode(sync); + } + } + } + } + + /** + * Removes this and all subnodes from the backing store and clears all + * entries. After removal this instance will not be useable (except for + * a few methods that don't throw a InvalidStateException), + * even when a new node with the same path name is created this instance + * will not be usable again. + *

    + * Checks that this is not a root node. If not it locks the parent node, + * then locks this node and checks that the node has not yet been removed. + * Then it makes sure that all subnodes of this node are in the child cache, + * by calling childSpi() on any children not yet in the cache. + * Then for all children it locks the subnode and removes it. After all + * subnodes have been purged the child cache is cleared, this nodes removed + * flag is set and any listeners are called. Finally this node is removed + * from the child cache of the parent node. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has already been removed + * @exception UnsupportedOperationException if this is a root node + */ + public void removeNode() throws BackingStoreException { + // Check if it is a root node + if (parent == null) + throw new UnsupportedOperationException("Cannot remove root node"); + + synchronized(parent) { + synchronized(this) { + if (isRemoved()) + throw new IllegalStateException("Node Removed"); + + purge(); + } + parent.childCache.remove(name); + } + } + + /** + * Private helper method used to completely remove this node. + * Called by removeNode with the parent node and this node + * locked. + *

    + * Makes sure that all subnodes of this node are in the child cache, + * by calling childSpi() on any children not yet in the + * cache. Then for all children it locks the subnode and calls this method + * on that node. After all subnodes have been purged the child cache is + * cleared, this nodes removed flag is set and any listeners are called. + */ + private void purge() throws BackingStoreException + { + // Make sure all children have an AbstractPreferences node in cache + String children[] = childrenNamesSpi(); + for (int i = 0; i < children.length; i++) { + if (childCache.get(children[i]) == null) + childCache.put(children[i], childSpi(children[i])); + } + + // purge all children + Iterator i = childCache.values().iterator(); + while (i.hasNext()) { + AbstractPreferences node = (AbstractPreferences) i.next(); + synchronized(node) { + node.purge(); + } + } + + // Cache is empty now + childCache.clear(); + + // remove this node + removeNodeSpi(); + removed = true; + + // XXX - check for listeners + } + + // listener methods + + /** + * XXX + */ + public void addNodeChangeListener(NodeChangeListener listener) { + // XXX + } + + public void addPreferenceChangeListener(PreferenceChangeListener listener) { + // XXX + } + + public void removeNodeChangeListener(NodeChangeListener listener) { + // XXX + } + + public void removePreferenceChangeListener + (PreferenceChangeListener listener) + { + // XXX + } + + // abstract spi methods + + /** + * Returns the names of the sub nodes of this preference node. + * This method only has to return any not yet cached child names, + * but may return all names if that is easier. It must not return + * null when there are no children, it has to return an empty array + * in that case. Since this method must consult the backing store to + * get all the sub node names it may throw a BackingStoreException. + *

    + * Called by childrenNames() with this node locked. + */ + protected abstract String[] childrenNamesSpi() throws BackingStoreException; + + /** + * Returns a child note with the given name. + * This method is called by the node() method (indirectly + * through the getNode() helper method) with this node locked + * if a sub node with this name does not already exist in the child cache. + * If the child node did not aleady exist in the backing store the boolean + * field newNode of the returned node should be set. + *

    + * Note that this method should even return a non-null child node if the + * backing store is not available since it may not throw a + * BackingStoreException. + */ + protected abstract AbstractPreferences childSpi(String name); + + /** + * Returns an (possibly empty) array with all the keys of the preference + * entries of this node. + *

    + * Called by keys() with this node locked if this node has + * not been removed. May throw an exception when the backing store cannot + * be accessed. + * + * @exception BackingStoreException when the backing store cannot be + * reached + */ + protected abstract String[] keysSpi() throws BackingStoreException; + + /** + * Returns the value associated with the key in this preferences node or + * null when the key does not exist in this preferences node. + *

    + * Called by key() with this node locked after checking that + * key is valid, not null and that the node has not been removed. + * key() will catch any exceptions that this method throws. + */ + protected abstract String getSpi(String key); + + /** + * Sets the value of the given preferences entry for this node. + * The implementation is not required to propagate the change to the + * backing store immediatly. It may not throw an exception when it tries + * to write to the backing store and that operation fails, the failure + * should be registered so a later invocation of flush() + * or sync() can signal the failure. + *

    + * Called by put() with this node locked after checking that + * key and value are valid and non-null. + */ + protected abstract void putSpi(String key, String value); + + /** + * Removes the given key entry from this preferences node. + * The implementation is not required to propagate the change to the + * backing store immediatly. It may not throw an exception when it tries + * to write to the backing store and that operation fails, the failure + * should be registered so a later invocation of flush() + * or sync() can signal the failure. + *

    + * Called by remove() with this node locked after checking + * that the key is valid and non-null. + */ + protected abstract void removeSpi(String key); + + /** + * Writes all entries of this preferences node that have not yet been + * written to the backing store and possibly creates this node in the + * backing store, if it does not yet exist. Should only write changes to + * this node and not write changes to any subnodes. + * Note that the node can be already removed in this VM. To check if + * that is the case the implementation can call isRemoved(). + *

    + * Called (indirectly) by flush() with this node locked. + */ + protected abstract void flushSpi() throws BackingStoreException; + + /** + * Writes all entries of this preferences node that have not yet been + * written to the backing store and reads any entries that have changed + * in the backing store but that are not yet visible in this VM. + * Should only sync this node and not change any of the subnodes. + * Note that the node can be already removed in this VM. To check if + * that is the case the implementation can call isRemoved(). + *

    + * Called (indirectly) by sync() with this node locked. + */ + protected abstract void syncSpi() throws BackingStoreException; + + /** + * Clears this node from this VM and removes it from the backing store. + * After this method has been called the node is marked as removed. + *

    + * Called (indirectly) by removeNode() with this node locked + * after all the sub nodes of this node have already been removed. + */ + protected abstract void removeNodeSpi() throws BackingStoreException; +} diff --git a/libjava/classpath/java/util/prefs/BackingStoreException.java b/libjava/classpath/java/util/prefs/BackingStoreException.java new file mode 100644 index 0000000..0ba358a --- /dev/null +++ b/libjava/classpath/java/util/prefs/BackingStoreException.java @@ -0,0 +1,104 @@ +/* BackingStoreException.java - chained exception thrown when backing store + fails + Copyright (C) 2001, 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 java.util.prefs; + +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * Chained exception thrown when backing store fails. This exception is + * only thrown from methods that actually have to access the backing store, + * such as clear(), keys(), childrenNames(), nodeExists(), removeNode(), + * flush(), sync(), exportNode(), exportSubTree(); normal operations + * do not throw BackingStoreExceptions. + * + *

    Note that although this class inherits the Serializable interface, an + * attempt to serialize will fail with a NotSerializableException. + * + * @author Mark Wielaard (mark@klomp.org) + * @since 1.4 + * @status updated to 1.4 + */ +public class BackingStoreException extends Exception +{ + static final long serialVersionUID = 859796500401108469L; + + /** + * Creates a new exception with a descriptive message. + * + * @param message the message + */ + public BackingStoreException(String message) + { + super(message); + } + + /** + * Create a new exception with the given cause. + * + * @param cause the cause + */ + public BackingStoreException(Throwable cause) + { + super(cause); + } + + /** + * This class should not be serialized. + * + * @param o the output stream + */ + private void writeObject(ObjectOutputStream o) throws NotSerializableException + { + throw new NotSerializableException + ("java.util.prefs.BackingStoreException"); + } + + /** + * This class should not be serialized. + * + * @param i the input stream + */ + private void readObject(ObjectInputStream i) throws NotSerializableException + { + throw new NotSerializableException + ("java.util.prefs.BackingStoreException"); + } +} diff --git a/libjava/classpath/java/util/prefs/InvalidPreferencesFormatException.java b/libjava/classpath/java/util/prefs/InvalidPreferencesFormatException.java new file mode 100644 index 0000000..f929b56 --- /dev/null +++ b/libjava/classpath/java/util/prefs/InvalidPreferencesFormatException.java @@ -0,0 +1,116 @@ +/* InvalidPreferencesFormatException - indicates reading prefs from stream + failed + Copyright (C) 2001, 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 java.util.prefs; + +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * Indicates reading prefs from stream failed. Thrown by the + * importPreferences() method when the supplied input stream + * could not be read because it was not in the correct XML format. + * + *

    Note that although this class inherits the Serializable interface, an + * attempt to serialize will fail with a NotSerializableException. + *

    + * + * @author Mark Wielaard (mark@klomp.org) + * @see Preferences + * @since 1.4 + * @status updated to 1.4 + */ +public class InvalidPreferencesFormatException extends Exception +{ + static final long serialVersionUID = -791715184232119669L; + + /** + * Creates a new exception with a descriptive message. The cause remains + * uninitialized. + * + * @param message the message + */ + public InvalidPreferencesFormatException(String message) + { + super(message); + } + + /** + * Creates a new exception with the given cause. + * + * @param cause the cause + */ + public InvalidPreferencesFormatException(Throwable cause) + { + super(cause); + } + + /** + * Creates a new exception with a descriptive message and a cause. + * + * @param message the message + * @param cause the cause + */ + public InvalidPreferencesFormatException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * This class should not be serialized. + * + * @param o the output stream + */ + private void writeObject(ObjectOutputStream o) throws NotSerializableException + { + throw new NotSerializableException + ("java.util.prefs.InvalidPreferencesFormatException"); + } + + /** + * This class should not be serialized. + * + * @param i the input stream + */ + private void readObject(ObjectInputStream i) throws NotSerializableException + { + throw new NotSerializableException + ("java.util.prefs.InvalidPreferencesFormatException"); + } +} diff --git a/libjava/classpath/java/util/prefs/NodeChangeEvent.java b/libjava/classpath/java/util/prefs/NodeChangeEvent.java new file mode 100644 index 0000000..89986db --- /dev/null +++ b/libjava/classpath/java/util/prefs/NodeChangeEvent.java @@ -0,0 +1,91 @@ +/* NodeChangeEvent - ObjectEvent fired when a Preference node is added/removed + 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 java.util.prefs; + +import java.util.EventObject; + +/** + * ObjectEvent fired when a Preference node is added/removed. + * This event is only generated when a new subnode is added or a subnode is + * removed from a preference node. Changes in the entries of a preference node + * are indicated with a PreferenceChangeEvent. + * + * @since 1.4 + * @author Mark Wielaard (mark@klomp.org) + */ +public class NodeChangeEvent extends EventObject { + + private static final long serialVersionUID =8068949086596572957L; + + /** + * The sub node that was added or removed. + * Defined transient just like EventObject.source since + * this object should be serializable, but Preferences is in general not + * serializable. + */ + private final transient Preferences child; + + /** + * Creates a new NodeChangeEvent. + * + * @param parentNode The source preference node from which a subnode was + * added or removed + * @param childNode The preference node that was added or removed + */ + public NodeChangeEvent(Preferences parentNode, Preferences childNode) { + super(parentNode); + child = childNode; + } + + /** + * Returns the source parent preference node from which a subnode was + * added or removed. + */ + public Preferences getParent() { + return (Preferences) source; + } + + /** + * Returns the child preference subnode that was added or removed. + * To see wether it is still a valid preference node one has to call + * event.getChild().nodeExists(""). + */ + public Preferences getChild() { + return child; + } +} diff --git a/libjava/classpath/java/util/prefs/NodeChangeListener.java b/libjava/classpath/java/util/prefs/NodeChangeListener.java new file mode 100644 index 0000000..19664c6 --- /dev/null +++ b/libjava/classpath/java/util/prefs/NodeChangeListener.java @@ -0,0 +1,64 @@ +/* NodeChangeListener - EventListener for Preferences node addition/removal + 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 java.util.prefs; + +import java.util.EventListener; + +/** + * EventListener for Preferences node addition/removal. + *

    + * Note that these events are only generated for the addition and removal + * of sub nodes from the preference node. Entry changes in the preference + * node can be monitored with a PreferenceChangeListener. + * + * @since 1.4 + * @author Mark Wielaard (mark@klomp.org) + */ +public interface NodeChangeListener extends EventListener { + + /** + * Fired when a sub node is added to the preference node. + */ + void childAdded(NodeChangeEvent event); + + /** + * Fired when a sub node is removed from the preference node. + */ + void childRemoved(NodeChangeEvent event); + +} diff --git a/libjava/classpath/java/util/prefs/PreferenceChangeEvent.java b/libjava/classpath/java/util/prefs/PreferenceChangeEvent.java new file mode 100644 index 0000000..fe371f1 --- /dev/null +++ b/libjava/classpath/java/util/prefs/PreferenceChangeEvent.java @@ -0,0 +1,105 @@ +/* PreferenceChangeEvent - ObjectEvent fired when a Preferences entry changes + 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 java.util.prefs; + +import java.util.EventObject; + +/** + * ObjectEvent fired when a Preferences entry changes. + * This event is generated when a entry is added, changed or removed. + * When an entry is removed then getNewValue will return null. + *

    + * Preference change events are only generated for entries in one particular + * preference node. Notification of subnode addition/removal is given by a + * NodeChangeEvent. + * + * @since 1.4 + * @author Mark Wielaard (mark@klomp.org) + */ +public class PreferenceChangeEvent extends EventObject { + + private static final long serialVersionUID = 793724513368024975L; + + /** + * The key of the changed entry. + */ + private final String key; + + /** + * The new value of the changed entry, or null when the entry was removed. + */ + private final String newValue; + + /** + * Creates a new PreferenceChangeEvent. + * + * @param node The source preference node for which an entry was added, + * changed or removed + * @param key The key of the entry that was added, changed or removed + * @param value The new value of the entry that was added or changed, or + * null when the entry was removed + */ + public PreferenceChangeEvent(Preferences node, String key, String value) { + super(node); + this.key = key; + this.newValue = value; + } + + /** + * Returns the source Preference node from which an entry was added, + * changed or removed. + */ + public Preferences getNode() { + return (Preferences) source; + } + + /** + * Returns the key of the entry that was added, changed or removed. + */ + public String getKey() { + return key; + } + + /** + * Returns the new value of the entry that was added or changed, or + * returns null when the entry was removed. + */ + public String getNewValue() { + return newValue; + } +} diff --git a/libjava/classpath/java/util/prefs/PreferenceChangeListener.java b/libjava/classpath/java/util/prefs/PreferenceChangeListener.java new file mode 100644 index 0000000..adff358 --- /dev/null +++ b/libjava/classpath/java/util/prefs/PreferenceChangeListener.java @@ -0,0 +1,60 @@ +/* PreferenceChangeListener - EventListener for Preferences entry changes + 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 java.util.prefs; + +import java.util.EventListener; + +/** + * EventListener for Preferences entry addition, change or removal. + *

    + * Preference change events are only generated for entries in one particular + * preference node. Notification of subnode addition/removal can be monitored + * with a NodeChangeListener. + * + * @since 1.4 + * @author Mark Wielaard (mark@klomp.org) + */ +public interface PreferenceChangeListener extends EventListener { + + /** + * Fired when a entry has been added, changed or removed from the + * preference node. + */ + void preferenceChange(PreferenceChangeEvent event); + +} diff --git a/libjava/classpath/java/util/prefs/Preferences.java b/libjava/classpath/java/util/prefs/Preferences.java new file mode 100644 index 0000000..c407ae6 --- /dev/null +++ b/libjava/classpath/java/util/prefs/Preferences.java @@ -0,0 +1,668 @@ +/* Preferences -- Preference node containing key value entries and subnodes + Copyright (C) 2001, 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 java.util.prefs; + +import gnu.java.util.prefs.NodeReader; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; + +/** + * Preference node containing key value entries and subnodes. + *

    + * There are two preference node trees, a system tree which can be accessed + * by calling systemRoot() containing system preferences usefull + * for all users, and a user tree that can be accessed by calling + * userRoot() containing preferences that can differ between + * different users. How different users are identified is implementation + * depended. It can be determined by Thread, Access Control Context or Subject. + *

    + * This implementation uses the "java.util.prefs.PreferencesFactory" system + * property to find a class that implement PreferencesFactory + * and initialized that class (if it has a public no arguments contructor) + * to get at the actual system or user root. If the system property is not set, + * or the class cannot be initialized it uses the default implementation + * gnu.java.util.prefs.FileBasedFactory. + *

    + * Besides the two static method above to get the roots of the system and user + * preference node trees there are also two convenience methods to access the + * default preference node for a particular package an object is in. These are + * userNodeForPackage() and systemNodeForPackage(). + * Both methods take an Object as an argument so accessing preferences values + * can be as easy as calling Preferences.userNodeForPackage(this). + *

    + * Note that if a security manager is installed all static methods check for + * RuntimePermission("preferences"). But if this permission is + * given to the code then it can access and change all (user) preference nodes + * and entries. So you should be carefull not to store to sensitive information + * or make security decissions based on preference values since there is no + * more fine grained control over what preference values can be changed once + * code has been given the correct runtime permission. + *

    + * XXX + * + * @since 1.4 + * @author Mark Wielaard (mark@klomp.org) + */ +public abstract class Preferences { + + // Static Fields + + /** + * Default PreferencesFactory class used when the system property + * "java.util.prefs.PreferencesFactory" is not set. + *

    + * XXX - Currently set to MemoryBasedFactory, should be changed + * when FileBasedPreferences backend works. + */ + private static final String defaultFactoryClass + = "gnu.java.util.prefs.MemoryBasedFactory"; + + /** Permission needed to access system or user root. */ + private static final Permission prefsPermission + = new RuntimePermission("preferences"); + + /** + * The preferences factory object that supplies the system and user root. + * Set and returned by the getFactory() method. + */ + private static PreferencesFactory factory; + + /** Maximum node name length. 80 characters. */ + public static final int MAX_NAME_LENGTH = 80; + + /** Maximum entry key length. 80 characters. */ + public static final int MAX_KEY_LENGTH = 80; + + /** Maximum entry value length. 8192 characters. */ + public static final int MAX_VALUE_LENGTH = 8192; + + // Constructors + + /** + * Creates a new Preferences node. Can only be used by subclasses. + * Empty implementation. + */ + protected Preferences() {} + + // Static methods + + /** + * Returns the system preferences root node containing usefull preferences + * for all users. It is save to cache this value since it should always + * return the same preference node. + * + * @return the root system preference node + * @exception SecurityException when a security manager is installed and + * the caller does not have RuntimePermission("preferences"). + */ + public static Preferences systemRoot() throws SecurityException { + // Get the preferences factory and check for permission + PreferencesFactory factory = getFactory(); + + return factory.systemRoot(); + } + + /** + * Returns the user preferences root node containing preferences for the + * the current user. How different users are identified is implementation + * depended. It can be determined by Thread, Access Control Context or + * Subject. + * + * @return the root user preference node + * @exception SecurityException when a security manager is installed and + * the caller does not have RuntimePermission("preferences"). + */ + public static Preferences userRoot() throws SecurityException { + // Get the preferences factory and check for permission + PreferencesFactory factory = getFactory(); + return factory.userRoot(); + } + + /** + * Private helper method for systemRoot() and + * userRoot(). Checks security permission and instantiates the + * correct factory if it has not yet been set. + *

    + * When the preferences factory has not yet been set this method first + * tries to get the system propery "java.util.prefs.PreferencesFactory" + * and tries to initializes that class. If the system property is not set + * or initialization fails it returns an instance of the default factory + * gnu.java.util.prefs.FileBasedPreferencesFactory. + * + * @return the preferences factory to use + * @exception SecurityException when a security manager is installed and + * the caller does not have RuntimePermission("preferences"). + */ + private static PreferencesFactory getFactory() throws SecurityException { + + // First check for permission + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(prefsPermission); + } + + // Get the factory + if (factory == null) { + // Caller might not have enough permissions + factory = (PreferencesFactory) AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + PreferencesFactory pf = null; + String className = System.getProperty + ("java.util.prefs.PreferencesFactory"); + if (className != null) { + try { + Class fc = Class.forName(className); + Object o = fc.newInstance(); + pf = (PreferencesFactory) o; + } catch (ClassNotFoundException cnfe) + {/*ignore*/} + catch (InstantiationException ie) + {/*ignore*/} + catch (IllegalAccessException iae) + {/*ignore*/} + catch (ClassCastException cce) + {/*ignore*/} + } + return pf; + } + }); + + // Still no factory? Use our default. + if (factory == null) + { + try + { + Class cls = Class.forName (defaultFactoryClass); + factory = (PreferencesFactory) cls.newInstance(); + } + catch (Exception e) + { + throw new RuntimeException ("Couldn't load default factory" + + " '"+ defaultFactoryClass +"'"); + // XXX - when using 1.4 compatible throwables add cause + } + } + + } + + return factory; + } + + /** + * Returns the system preferences node for the package of an object. + * The package node name of the object is determined by dropping the + * class name of the object of the fully quallified class name and + * replacing all '.' to '/' in the package name. If the class of the + * object has no package then the package node name is "<unnamed>". + * The returened node is systemRoot().node(packageNodeName). + * + * @param o Object whose default system preference node is requested + * @returns system preferences node that should be used by object o + * @exception SecurityException when a security manager is installed and + * the caller does not have RuntimePermission("preferences"). + */ + public static Preferences systemNodeForPackage(Class c) + throws SecurityException + { + return nodeForPackage(c, systemRoot()); + } + + /** + * Returns the user preferences node for the package of an object. + * The package node name of the object is determined by dropping the + * class name of the object of the fully quallified class name and + * replacing all '.' to '/' in the package name. If the class of the + * object has no package then the package node name is "<unnamed>". + * The returened node is userRoot().node(packageNodeName). + * + * @param o Object whose default user preference node is requested + * @returns user preferences node that should be used by object o + * @exception SecurityException when a security manager is installed and + * the caller does not have RuntimePermission("preferences"). + */ + public static Preferences userNodeForPackage(Class c) + throws SecurityException + { + return nodeForPackage(c, userRoot()); + } + + /** + * Private helper method for systemNodeForPackage() and + * userNodeForPackage(). Given the correct system or user + * root it returns the correct Preference node for the package node name + * of the given object. + */ + private static Preferences nodeForPackage(Class c, Preferences root) { + // Get the package path + String className = c.getName(); + String packagePath; + int index = className.lastIndexOf('.'); + if(index == -1) { + packagePath = ""; + } else { + packagePath = className.substring(0,index).replace('.','/'); + } + + return root.node(packagePath); + } + + /** + * XXX + */ + public static void importPreferences(InputStream is) + throws InvalidPreferencesFormatException, + IOException + { + PreferencesFactory factory = getFactory(); + NodeReader reader = new NodeReader(is, factory); + reader.importPreferences(); + } + + // abstract methods (identification) + + /** + * Returns the absolute path name of this preference node. + * The absolute path name of a node is the path name of its parent node + * plus a '/' plus its own name. If the node is the root node and has no + * parent then its name is "" and its absolute path name is "/". + */ + public abstract String absolutePath(); + + /** + * Returns true if this node comes from the user preferences tree, false + * if it comes from the system preferences tree. + */ + public abstract boolean isUserNode(); + + /** + * Returns the name of this preferences node. The name of the node cannot + * be null, can be mostly 80 characters and cannot contain any '/' + * characters. The root node has as name "". + */ + public abstract String name(); + + /** + * Returns the String given by + * + * (isUserNode() ? "User":"System") + " Preference Node: " + absolutePath() + * + */ + public abstract String toString(); + + // abstract methods (navigation) + + /** + * Returns all the direct sub nodes of this preferences node. + * Needs access to the backing store to give a meaningfull answer. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException when this node has been removed + */ + public abstract String[] childrenNames() throws BackingStoreException; + + /** + * Returns a sub node of this preferences node if the given path is + * relative (does not start with a '/') or a sub node of the root + * if the path is absolute (does start with a '/'). + * + * @exception IllegalStateException if this node has been removed + * @exception IllegalArgumentException if the path contains two or more + * consecutive '/' characters, ends with a '/' charactor and is not the + * string "/" (indicating the root node) or any name on the path is more + * then 80 characters long + */ + public abstract Preferences node(String path); + + /** + * Returns true if the node that the path points to exists in memory or + * in the backing store. Otherwise it returns false or an exception is + * thrown. When this node is removed the only valid parameter is the + * empty string (indicating this node), the return value in that case + * will be false. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has been removed + * and the path is not the empty string (indicating this node) + * @exception IllegalArgumentException if the path contains two or more + * consecutive '/' characters, ends with a '/' charactor and is not the + * string "/" (indicating the root node) or any name on the path is more + * then 80 characters long + */ + public abstract boolean nodeExists(String path) + throws BackingStoreException; + + /** + * Returns the parent preferences node of this node or null if this is + * the root of the preferences tree. + * + * @exception IllegalStateException if this node has been removed + */ + public abstract Preferences parent(); + + // abstract methods (export) + + /** + * XXX + */ + public abstract void exportNode(OutputStream os) + throws BackingStoreException, + IOException; + + /** + * XXX + */ + public abstract void exportSubtree(OutputStream os) + throws BackingStoreException, + IOException; + + // abstract methods (preference entry manipulation) + + /** + * Returns an (possibly empty) array with all the keys of the preference + * entries of this node. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has been removed + */ + public abstract String[] keys() throws BackingStoreException; + + /** + * Returns the value associated with the key in this preferences node. If + * the default value of the key cannot be found in the preferences node + * entries or something goes wrong with the backing store the supplied + * default value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public abstract String get(String key, String defaultVal); + + /** + * Convenience method for getting the given entry as a boolean. + * When the string representation of the requested entry is either + * "true" or "false" (ignoring case) then that value is returned, + * otherwise the given default boolean value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public abstract boolean getBoolean(String key, boolean defaultVal); + + /** + * Convenience method for getting the given entry as a byte array. + * When the string representation of the requested entry is a valid + * Base64 encoded string (without any other characters, such as newlines) + * then the decoded Base64 string is returned as byte array, + * otherwise the given default byte array value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public abstract byte[] getByteArray(String key, byte[] defaultVal); + + /** + * Convenience method for getting the given entry as a double. + * When the string representation of the requested entry can be decoded + * with Double.parseDouble() then that double is returned, + * otherwise the given default double value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public abstract double getDouble(String key, double defaultVal); + + /** + * Convenience method for getting the given entry as a float. + * When the string representation of the requested entry can be decoded + * with Float.parseFloat() then that float is returned, + * otherwise the given default float value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public abstract float getFloat(String key, float defaultVal); + + /** + * Convenience method for getting the given entry as an integer. + * When the string representation of the requested entry can be decoded + * with Integer.parseInt() then that integer is returned, + * otherwise the given default integer value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public abstract int getInt(String key, int defaultVal); + + /** + * Convenience method for getting the given entry as a long. + * When the string representation of the requested entry can be decoded + * with Long.parseLong() then that long is returned, + * otherwise the given default long value is returned. + * + * @exception IllegalArgumentException if key is larger then 80 characters + * @exception IllegalStateException if this node has been removed + * @exception NullPointerException if key is null + */ + public abstract long getLong(String key, long defaultVal); + + /** + * Sets the value of the given preferences entry for this node. + * Key and value cannot be null, the key cannot exceed 80 characters + * and the value cannot exceed 8192 characters. + *

    + * The result will be immediatly visible in this VM, but may not be + * immediatly written to the backing store. + * + * @exception NullPointerException if either key or value are null + * @exception IllegalArgumentException if either key or value are to large + * @exception IllegalStateException when this node has been removed + */ + public abstract void put(String key, String value); + + /** + * Convenience method for setting the given entry as a boolean. + * The boolean is converted with Boolean.toString(value) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public abstract void putBoolean(String key, boolean value); + + /** + * Convenience method for setting the given entry as an array of bytes. + * The byte array is converted to a Base64 encoded string + * and then stored in the preference entry as that string. + *

    + * Note that a byte array encoded as a Base64 string will be about 1.3 + * times larger then the original length of the byte array, which means + * that the byte array may not be larger about 6 KB. + * + * @exception NullPointerException if either key or value are null + * @exception IllegalArgumentException if either key or value are to large + * @exception IllegalStateException when this node has been removed + */ + public abstract void putByteArray(String key, byte[] value); + + /** + * Convenience method for setting the given entry as a double. + * The double is converted with Double.toString(double) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public abstract void putDouble(String key, double value); + + /** + * Convenience method for setting the given entry as a float. + * The float is converted with Float.toString(float) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public abstract void putFloat(String key, float value); + + /** + * Convenience method for setting the given entry as an integer. + * The integer is converted with Integer.toString(int) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public abstract void putInt(String key, int value); + + /** + * Convenience method for setting the given entry as a long. + * The long is converted with Long.toString(long) + * and then stored in the preference entry as that string. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public abstract void putLong(String key, long value); + + /** + * Removes the preferences entry from this preferences node. + *

    + * The result will be immediatly visible in this VM, but may not be + * immediatly written to the backing store. + * + * @exception NullPointerException if the key is null + * @exception IllegalArgumentException if the key length is to large + * @exception IllegalStateException when this node has been removed + */ + public abstract void remove(String key); + + // abstract methods (preference node manipulation) + + /** + * Removes all entries from this preferences node. May need access to the + * backing store to get and clear all entries. + *

    + * The result will be immediatly visible in this VM, but may not be + * immediatly written to the backing store. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has been removed + */ + public abstract void clear() throws BackingStoreException; + + /** + * Writes all preference changes on this and any subnode that have not + * yet been written to the backing store. This has no effect on the + * preference entries in this VM, but it makes sure that all changes + * are visible to other programs (other VMs might need to call the + * sync() method to actually see the changes to the backing + * store. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has been removed + */ + public abstract void flush() throws BackingStoreException; + + /** + * Writes and reads all preference changes to and from this and any + * subnodes. This makes sure that all local changes are written to the + * backing store and that all changes to the backing store are visible + * in this preference node (and all subnodes). + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has been removed + */ + public abstract void sync() throws BackingStoreException; + + /** + * Removes this and all subnodes from the backing store and clears all + * entries. After removal this instance will not be useable (except for + * a few methods that don't throw a InvalidStateException), + * even when a new node with the same path name is created this instance + * will not be usable again. The root (system or user) may never be removed. + *

    + * Note that according to the specification an implementation may delay + * removal of the node from the backing store till the flush() + * method is called. But the flush() method may throw a + * IllegalStateException when the node has been removed. + * So most implementations will actually remove the node and any subnodes + * from the backing store immediatly. + * + * @exception BackingStoreException when the backing store cannot be + * reached + * @exception IllegalStateException if this node has already been removed + * @exception UnsupportedOperationException if this is a root node + */ + public abstract void removeNode() throws BackingStoreException; + + // abstract methods (listeners) + + public abstract void addNodeChangeListener(NodeChangeListener listener); + + public abstract void addPreferenceChangeListener + (PreferenceChangeListener listener); + + public abstract void removeNodeChangeListener(NodeChangeListener listener); + + public abstract void removePreferenceChangeListener + (PreferenceChangeListener listener); +} + diff --git a/libjava/classpath/java/util/prefs/PreferencesFactory.java b/libjava/classpath/java/util/prefs/PreferencesFactory.java new file mode 100644 index 0000000..f4fe7e3 --- /dev/null +++ b/libjava/classpath/java/util/prefs/PreferencesFactory.java @@ -0,0 +1,65 @@ +/* PreferencesFactory - Preferences system and user root factory interface + 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 java.util.prefs; + +/** + * Preferences system and user root factory interface. Defines how to get + * to the system and user root preferences objects. Should be implemented by + * new preferences backends. + * + * @since 1.4 + * @author Mark Wielaard (mark@klomp.org) + */ +public interface PreferencesFactory { + + /** + * Returns the system root preferences node. Should always return the + * same object. + */ + Preferences systemRoot(); + + /** + * Returns the user root preferences node. May return different objects + * depending on the user that called this method. The user may for example + * be determined by the current Thread or the Subject associated with the + * current AccessControllContext. + */ + Preferences userRoot(); + +} diff --git a/libjava/classpath/java/util/prefs/package.html b/libjava/classpath/java/util/prefs/package.html new file mode 100644 index 0000000..65fc1ac --- /dev/null +++ b/libjava/classpath/java/util/prefs/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - java.util.prefs + + +

    Utility classes for storing and retrieving user and system preferences.

    + + + diff --git a/libjava/classpath/java/util/regex/Matcher.java b/libjava/classpath/java/util/regex/Matcher.java new file mode 100644 index 0000000..bd97ace --- /dev/null +++ b/libjava/classpath/java/util/regex/Matcher.java @@ -0,0 +1,301 @@ +/* Matcher.java -- Instance of a regular expression applied to a char sequence. + 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 java.util.regex; + +import gnu.regexp.REMatch; + +/** + * Instance of a regular expression applied to a char sequence. + * + * @since 1.4 + */ +public final class Matcher +{ + private Pattern pattern; + private CharSequence input; + private int position; + private int appendPosition; + private REMatch match; + + Matcher(Pattern pattern, CharSequence input) + { + this.pattern = pattern; + this.input = input; + } + + /** + * @param sb The target string buffer + * @param replacement The replacement string + * + * @exception IllegalStateException If no match has yet been attempted, + * or if the previous match operation failed + * @exception IndexOutOfBoundsException If the replacement string refers + * to a capturing group that does not exist in the pattern + */ + public Matcher appendReplacement (StringBuffer sb, String replacement) + throws IllegalStateException + { + assertMatchOp(); + sb.append(input.subSequence(appendPosition, + match.getStartIndex()).toString()); + sb.append(match.substituteInto(replacement)); + appendPosition = match.getEndIndex(); + return this; + } + + /** + * @param sb The target string buffer + */ + public StringBuffer appendTail (StringBuffer sb) + { + sb.append(input.subSequence(appendPosition, input.length()).toString()); + return sb; + } + + /** + * @exception IllegalStateException If no match has yet been attempted, + * or if the previous match operation failed + */ + public int end () + throws IllegalStateException + { + assertMatchOp(); + return match.getEndIndex(); + } + + /** + * @param group The index of a capturing group in this matcher's pattern + * + * @exception IllegalStateException If no match has yet been attempted, + * or if the previous match operation failed + * @exception IndexOutOfBoundsException If the replacement string refers + * to a capturing group that does not exist in the pattern + */ + public int end (int group) + throws IllegalStateException + { + assertMatchOp(); + return match.getEndIndex(group); + } + + public boolean find () + { + boolean first = (match == null); + match = pattern.getRE().getMatch(input, position); + if (match != null) + { + int endIndex = match.getEndIndex(); + // Are we stuck at the same position? + if (!first && endIndex == position) + { + match = null; + // Not at the end of the input yet? + if (position < input.length() - 1) + { + position++; + return find(position); + } + else + return false; + } + position = endIndex; + return true; + } + return false; + } + + /** + * @param start The index to start the new pattern matching + * + * @exception IndexOutOfBoundsException If the replacement string refers + * to a capturing group that does not exist in the pattern + */ + public boolean find (int start) + { + match = pattern.getRE().getMatch(input, start); + if (match != null) + { + position = match.getEndIndex(); + return true; + } + return false; + } + + /** + * @exception IllegalStateException If no match has yet been attempted, + * or if the previous match operation failed + */ + public String group () + { + assertMatchOp(); + return match.toString(); + } + + /** + * @param group The index of a capturing group in this matcher's pattern + * + * @exception IllegalStateException If no match has yet been attempted, + * or if the previous match operation failed + * @exception IndexOutOfBoundsException If the replacement string refers + * to a capturing group that does not exist in the pattern + */ + public String group (int group) + throws IllegalStateException + { + assertMatchOp(); + return match.toString(group); + } + + /** + * @param replacement The replacement string + */ + public String replaceFirst (String replacement) + { + reset(); + // Semantics might not quite match + return pattern.getRE().substitute(input, replacement, position); + } + + /** + * @param replacement The replacement string + */ + public String replaceAll (String replacement) + { + reset(); + return pattern.getRE().substituteAll(input, replacement, position); + } + + public int groupCount () + { + return pattern.getRE().getNumSubs(); + } + + public boolean lookingAt () + { + match = pattern.getRE().getMatch(input, 0); + if (match != null) + { + if (match.getStartIndex() == 0) + { + position = match.getEndIndex(); + return true; + } + match = null; + } + return false; + } + + /** + * Attempts to match the entire input sequence against the pattern. + * + * If the match succeeds then more information can be obtained via the + * start, end, and group methods. + * + * @see #start + * @see #end + * @see #group + */ + public boolean matches () + { + if (lookingAt()) + { + if (position == input.length()) + return true; + match = null; + } + return false; + } + + /** + * Returns the Pattern that is interpreted by this Matcher + */ + public Pattern pattern () + { + return pattern; + } + + public Matcher reset () + { + position = 0; + match = null; + return this; + } + + /** + * @param input The new input character sequence + */ + public Matcher reset (CharSequence input) + { + this.input = input; + return reset(); + } + + /** + * @param group The index of a capturing group in this matcher's pattern + * + * @exception IllegalStateException If no match has yet been attempted, + * or if the previous match operation failed + */ + public int start () + throws IllegalStateException + { + assertMatchOp(); + return match.getStartIndex(); + } + + /** + * @param group The index of a capturing group in this matcher's pattern + * + * @exception IllegalStateException If no match has yet been attempted, + * or if the previous match operation failed + * @exception IndexOutOfBoundsException If the replacement string refers + * to a capturing group that does not exist in the pattern + */ + public int start (int group) + throws IllegalStateException + { + assertMatchOp(); + return match.getStartIndex(group); + } + + private void assertMatchOp() + { + if (match == null) throw new IllegalStateException(); + } +} diff --git a/libjava/classpath/java/util/regex/Pattern.java b/libjava/classpath/java/util/regex/Pattern.java new file mode 100644 index 0000000..6a31ef9 --- /dev/null +++ b/libjava/classpath/java/util/regex/Pattern.java @@ -0,0 +1,254 @@ +/* Pattern.java -- Compiled regular expression ready to be applied. + 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 java.util.regex; + +import gnu.regexp.RE; +import gnu.regexp.REException; +import gnu.regexp.RESyntax; + +import java.io.Serializable; +import java.util.ArrayList; + + +/** + * Compiled regular expression ready to be applied. + * + * @since 1.4 + */ +public final class Pattern implements Serializable +{ + private static final long serialVersionUID = 5073258162644648461L; + + public static final int CANON_EQ = 128; + public static final int CASE_INSENSITIVE = 2; + public static final int COMMENTS = 4; + public static final int DOTALL = 32; + public static final int MULTILINE = 8; + public static final int UNICODE_CASE = 64; + public static final int UNIX_LINES = 1; + + private final String regex; + private final int flags; + + private final RE re; + + private Pattern (String regex, int flags) + throws PatternSyntaxException + { + this.regex = regex; + this.flags = flags; + + int gnuFlags = 0; + if ((flags & CASE_INSENSITIVE) != 0) + gnuFlags |= RE.REG_ICASE; + if ((flags & MULTILINE) != 0) + gnuFlags |= RE.REG_MULTILINE; + if ((flags & DOTALL) != 0) + gnuFlags |= RE.REG_DOT_NEWLINE; + // not yet supported: + // if ((flags & UNICODE_CASE) != 0) gnuFlags = + // if ((flags & CANON_EQ) != 0) gnuFlags = + + RESyntax syntax = RESyntax.RE_SYNTAX_JAVA_1_4; + if ((flags & UNIX_LINES) != 0) + { + // Use a syntax set with \n for linefeeds? + syntax = new RESyntax(syntax); + syntax.setLineSeparator("\n"); + } + + if ((flags & COMMENTS) != 0) + { + // Use a syntax with support for comments? + } + + try + { + this.re = new RE(regex, gnuFlags, syntax); + } + catch (REException e) + { + throw new PatternSyntaxException(e.getMessage(), + regex, e.getPosition()); + } + } + + // package private accessor method + RE getRE() + { + return re; + } + + /** + * @param regex The regular expression + * + * @exception PatternSyntaxException If the expression's syntax is invalid + */ + public static Pattern compile (String regex) + throws PatternSyntaxException + { + return compile(regex, 0); + } + + /** + * @param regex The regular expression + * @param flags The match flags, a bit mask + * + * @exception PatternSyntaxException If the expression's syntax is invalid + * @exception IllegalArgumentException If bit values other than those + * corresponding to the defined match flags are set in flags + */ + public static Pattern compile (String regex, int flags) + throws PatternSyntaxException + { + // FIXME: check which flags are really accepted + if ((flags & ~0xEF) != 0) + throw new IllegalArgumentException (); + + return new Pattern (regex, flags); + } + + public int flags () + { + return this.flags; + } + + /** + * @param regex The regular expression + * @param input The character sequence to be matched + * + * @exception PatternSyntaxException If the expression's syntax is invalid + */ + public static boolean matches (String regex, CharSequence input) + { + return compile(regex).matcher(input).matches(); + } + + /** + * @param input The character sequence to be matched + */ + public Matcher matcher (CharSequence input) + { + return new Matcher(this, input); + } + + /** + * @param input The character sequence to be matched + */ + public String[] split (CharSequence input) + { + return split(input, 0); + } + + /** + * @param input The character sequence to be matched + * @param limit The result threshold + */ + public String[] split (CharSequence input, int limit) + { + Matcher matcher = new Matcher(this, input); + ArrayList list = new ArrayList(); + int empties = 0; + int count = 0; + int start = 0; + int end; + boolean matched = matcher.find(); + + while (matched && (limit <= 0 || count < limit - 1)) + { + ++count; + end = matcher.start(); + if (start == end) + empties++; + else + { + while (empties > 0) + { + list.add(""); + empties--; + } + + String text = input.subSequence(start, end).toString(); + list.add(text); + } + start = matcher.end(); + matched = matcher.find(); + } + + // We matched nothing. + if (!matched && count == 0) + return new String[] { input.toString() }; + + // Is the last token empty? + boolean emptyLast = (start == input.length()); + + // Can/Must we add empties or an extra last token at the end? + if (list.size() < limit || limit < 0 || (limit == 0 && !emptyLast)) + { + if (limit > list.size()) + { + int max = limit - list.size(); + empties = (empties > max) ? max : empties; + } + while (empties > 0) + { + list.add(""); + empties--; + } + } + + // last token at end + if (limit != 0 || (limit == 0 && !emptyLast)) + { + String t = input.subSequence(start, input.length()).toString(); + if ("".equals(t) && limit == 0) + ; // Don't add. + else + list.add(t); + } + + String[] output = new String [list.size()]; + list.toArray(output); + return output; + } + + public String pattern () + { + return regex; + } +} diff --git a/libjava/classpath/java/util/regex/PatternSyntaxException.java b/libjava/classpath/java/util/regex/PatternSyntaxException.java new file mode 100644 index 0000000..0c80e11 --- /dev/null +++ b/libjava/classpath/java/util/regex/PatternSyntaxException.java @@ -0,0 +1,132 @@ +/* PatternSyntaxException - Indicates illegal pattern for regular expression. + 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 java.util.regex; + +/** + * Indicates illegal pattern for regular expression. + * Includes state to inspect the pattern and what and where the expression + * was not valid regular expression. + */ +public class PatternSyntaxException extends IllegalArgumentException +{ + private static final long serialVersionUID = -3864639126226059218L; + + /** + * Human readable escription of the syntax error. + */ + private final String desc; + + /** + * The original pattern that contained the syntax error. + */ + private final String pattern; + + /** + * Index of the first character in the String that was probably invalid, + * or -1 when unknown. + */ + private final int index; + + /** + * Creates a new PatternSyntaxException. + * + * @param description Human readable escription of the syntax error. + * @param pattern The original pattern that contained the syntax error. + * @param index Index of the first character in the String that was + * probably invalid, or -1 when unknown. + */ + public PatternSyntaxException(String description, + String pattern, + int index) + { + super(description); + this.desc = description; + this.pattern = pattern; + this.index = index; + } + + /** + * Returns a human readable escription of the syntax error. + */ + public String getDescription() + { + return desc; + } + + /** + * Returns the original pattern that contained the syntax error. + */ + public String getPattern() + { + return pattern; + } + + /** + * Returns the index of the first character in the String that was probably + * invalid, or -1 when unknown. + */ + public int getIndex() + { + return index; + } + + /** + * Returns a string containing a line with the description, a line with + * the original pattern and a line indicating with a ^ which character is + * probably the first invalid character in the pattern if the index is not + * negative. + */ + public String getMessage() + { + String lineSep = System.getProperty("line.separator"); + StringBuffer sb = new StringBuffer(desc); + sb.append(lineSep); + sb.append('\t'); + sb.append(pattern); + if (index != -1) + { + sb.append(lineSep); + sb.append('\t'); + for (int i=0; i + + + +GNU Classpath - java.util.regex + + +

    Regular expression patterns and matchers.

    + + + diff --git a/libjava/classpath/java/util/zip/Adler32.java b/libjava/classpath/java/util/zip/Adler32.java new file mode 100644 index 0000000..7c41138 --- /dev/null +++ b/libjava/classpath/java/util/zip/Adler32.java @@ -0,0 +1,205 @@ +/* Adler32.java - Computes Adler32 data checksum of a data stream + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.zip; + +/* + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * The actual Adler32 algorithm is taken from RFC 1950. + * Status: Believed complete and correct. + */ + +/** + * Computes Adler32 checksum for a stream of data. An Adler32 + * checksum is not as reliable as a CRC32 checksum, but a lot faster to + * compute. + *

    + * The specification for Adler32 may be found in RFC 1950. + * (ZLIB Compressed Data Format Specification version 3.3) + *

    + *

    + * From that document: + *

    + * "ADLER32 (Adler-32 checksum) + * This contains a checksum value of the uncompressed data + * (excluding any dictionary data) computed according to Adler-32 + * algorithm. This algorithm is a 32-bit extension and improvement + * of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 + * standard. + *

    + * Adler-32 is composed of two sums accumulated per byte: s1 is + * the sum of all bytes, s2 is the sum of all s1 values. Both sums + * are done modulo 65521. s1 is initialized to 1, s2 to zero. The + * Adler-32 checksum is stored as s2*65536 + s1 in most- + * significant-byte first (network) order." + *

    + * "8.2. The Adler-32 algorithm + *

    + * The Adler-32 algorithm is much faster than the CRC32 algorithm yet + * still provides an extremely low probability of undetected errors. + *

    + * The modulo on unsigned long accumulators can be delayed for 5552 + * bytes, so the modulo operation time is negligible. If the bytes + * are a, b, c, the second sum is 3a + 2b + c + 3, and so is position + * and order sensitive, unlike the first sum, which is just a + * checksum. That 65521 is prime is important to avoid a possible + * large class of two-byte errors that leave the check unchanged. + * (The Fletcher checksum uses 255, which is not prime and which also + * makes the Fletcher check insensitive to single byte changes 0 <-> + * 255.) + *

    + * The sum s1 is initialized to 1 instead of zero to make the length + * of the sequence part of s2, so that the length does not have to be + * checked separately. (Any sequence of zeroes has a Fletcher + * checksum of zero.)" + * + * @author John Leuner, Per Bothner + * @since JDK 1.1 + * + * @see InflaterInputStream + * @see DeflaterOutputStream + */ +public class Adler32 implements Checksum +{ + + /** largest prime smaller than 65536 */ + private static final int BASE = 65521; + + private int checksum; //we do all in int. + + //Note that java doesn't have unsigned integers, + //so we have to be careful with what arithmetic + //we do. We return the checksum as a long to + //avoid sign confusion. + + /** + * Creates a new instance of the Adler32 class. + * The checksum starts off with a value of 1. + */ + public Adler32 () + { + reset(); + } + + /** + * Resets the Adler32 checksum to the initial value. + */ + public void reset () + { + checksum = 1; //Initialize to 1 + } + + /** + * Updates the checksum with the byte b. + * + * @param bval the data value to add. The high byte of the int is ignored. + */ + public void update (int bval) + { + //We could make a length 1 byte array and call update again, but I + //would rather not have that overhead + int s1 = checksum & 0xffff; + int s2 = checksum >>> 16; + + s1 = (s1 + (bval & 0xFF)) % BASE; + s2 = (s1 + s2) % BASE; + + checksum = (s2 << 16) + s1; + } + + /** + * Updates the checksum with the bytes taken from the array. + * + * @param buffer an array of bytes + */ + public void update (byte[] buffer) + { + update(buffer, 0, buffer.length); + } + + /** + * Updates the checksum with the bytes taken from the array. + * + * @param buf an array of bytes + * @param off the start of the data used for this update + * @param len the number of bytes to use for this update + */ + public void update (byte[] buf, int off, int len) + { + //(By Per Bothner) + int s1 = checksum & 0xffff; + int s2 = checksum >>> 16; + + while (len > 0) + { + // We can defer the modulo operation: + // s1 maximally grows from 65521 to 65521 + 255 * 3800 + // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 + int n = 3800; + if (n > len) + n = len; + len -= n; + while (--n >= 0) + { + s1 = s1 + (buf[off++] & 0xFF); + s2 = s2 + s1; + } + s1 %= BASE; + s2 %= BASE; + } + + /*Old implementation, borrowed from somewhere: + int n; + + while (len-- > 0) { + + s1 = (s1 + (bs[offset++] & 0xff)) % BASE; + s2 = (s2 + s1) % BASE; + }*/ + + checksum = (s2 << 16) | s1; + } + + /** + * Returns the Adler32 data checksum computed so far. + */ + public long getValue() + { + return (long) checksum & 0xffffffffL; + } +} diff --git a/libjava/classpath/java/util/zip/CRC32.java b/libjava/classpath/java/util/zip/CRC32.java new file mode 100644 index 0000000..1c2b397 --- /dev/null +++ b/libjava/classpath/java/util/zip/CRC32.java @@ -0,0 +1,132 @@ +/* CRC32.java - Computes CRC32 data checksum of a data stream + Copyright (C) 1999. 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.zip; + +/* + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * The actual CRC32 algorithm is taken from RFC 1952. + * Status: Believed complete and correct. + */ + +/** + * Computes CRC32 data checksum of a data stream. + * The actual CRC32 algorithm is described in RFC 1952 + * (GZIP file format specification version 4.3). + * Can be used to get the CRC32 over a stream if used with checked input/output + * streams. + * + * @see InflaterInputStream + * @see DeflaterOutputStream + * + * @author Per Bothner + * @date April 1, 1999. + */ +public class CRC32 implements Checksum +{ + /** The crc data checksum so far. */ + private int crc = 0; + + /** The fast CRC table. Computed once when the CRC32 class is loaded. */ + private static int[] crc_table = make_crc_table(); + + /** Make the table for a fast CRC. */ + private static int[] make_crc_table () + { + int[] crc_table = new int[256]; + for (int n = 0; n < 256; n++) + { + int c = n; + for (int k = 8; --k >= 0; ) + { + if ((c & 1) != 0) + c = 0xedb88320 ^ (c >>> 1); + else + c = c >>> 1; + } + crc_table[n] = c; + } + return crc_table; + } + + /** + * Returns the CRC32 data checksum computed so far. + */ + public long getValue () + { + return (long) crc & 0xffffffffL; + } + + /** + * Resets the CRC32 data checksum as if no update was ever called. + */ + public void reset () { crc = 0; } + + /** + * Updates the checksum with the int bval. + * + * @param bval (the byte is taken as the lower 8 bits of bval) + */ + + public void update (int bval) + { + int c = ~crc; + c = crc_table[(c ^ bval) & 0xff] ^ (c >>> 8); + crc = ~c; + } + + /** + * Adds the byte array to the data checksum. + * + * @param buf the buffer which contains the data + * @param off the offset in the buffer where the data starts + * @param len the length of the data + */ + public void update (byte[] buf, int off, int len) + { + int c = ~crc; + while (--len >= 0) + c = crc_table[(c ^ buf[off++]) & 0xff] ^ (c >>> 8); + crc = ~c; + } + + /** + * Adds the complete byte array to the data checksum. + */ + public void update (byte[] buf) { update(buf, 0, buf.length); } +} diff --git a/libjava/classpath/java/util/zip/CheckedInputStream.java b/libjava/classpath/java/util/zip/CheckedInputStream.java new file mode 100644 index 0000000..d743fbb --- /dev/null +++ b/libjava/classpath/java/util/zip/CheckedInputStream.java @@ -0,0 +1,135 @@ +/* CheckedInputStream.java - Compute checksum of data being read + 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 java.util.zip; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +/** + * InputStream that computes a checksum of the data being read using a + * supplied Checksum object. + * + * @see Checksum + * + * @author Tom Tromey + * @date May 17, 1999 + */ +public class CheckedInputStream extends FilterInputStream +{ + /** + * Creates a new CheckInputStream on top of the supplied OutputStream + * using the supplied Checksum. + */ + public CheckedInputStream (InputStream in, Checksum sum) + { + super (in); + this.sum = sum; + } + + /** + * Returns the Checksum object used. To get the data checksum computed so + * far call getChecksum.getValue(). + */ + public Checksum getChecksum () + { + return sum; + } + + /** + * Reads one byte, updates the checksum and returns the read byte + * (or -1 when the end of file was reached). + */ + public int read () throws IOException + { + int x = in.read(); + if (x != -1) + sum.update(x); + return x; + } + + /** + * Reads at most len bytes in the supplied buffer and updates the checksum + * with it. Returns the number of bytes actually read or -1 when the end + * of file was reached. + */ + public int read (byte[] buf, int off, int len) throws IOException + { + int r = in.read(buf, off, len); + if (r != -1) + sum.update(buf, off, r); + return r; + } + + /** + * Skips n bytes by reading them in a temporary buffer and updating the + * the checksum with that buffer. Returns the actual number of bytes skiped + * which can be less then requested when the end of file is reached. + */ + public long skip (long n) throws IOException + { + if (n == 0) + return 0; + + int min = (int) Math.min(n, 1024); + byte[] buf = new byte[min]; + + long s = 0; + while (n > 0) + { + int r = in.read(buf, 0, min); + if (r == -1) + break; + n -= r; + s += r; + min = (int) Math.min(n, 1024); + sum.update(buf, 0, r); + } + + return s; + } + + /** The checksum object. */ + private Checksum sum; +} diff --git a/libjava/classpath/java/util/zip/CheckedOutputStream.java b/libjava/classpath/java/util/zip/CheckedOutputStream.java new file mode 100644 index 0000000..a3c1929 --- /dev/null +++ b/libjava/classpath/java/util/zip/CheckedOutputStream.java @@ -0,0 +1,100 @@ +/* CheckedOutputStream.java - Compute checksum of data being written. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util.zip; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +/** + * OutputStream that computes a checksum of data being written using a + * supplied Checksum object. + * + * @see Checksum + * + * @author Tom Tromey + * @date May 17, 1999 + */ +public class CheckedOutputStream extends FilterOutputStream +{ + /** + * Creates a new CheckInputStream on top of the supplied OutputStream + * using the supplied Checksum. + */ + public CheckedOutputStream (OutputStream out, Checksum cksum) + { + super (out); + this.sum = cksum; + } + + /** + * Returns the Checksum object used. To get the data checksum computed so + * far call getChecksum.getValue(). + */ + public Checksum getChecksum () + { + return sum; + } + + /** + * Writes one byte to the OutputStream and updates the Checksum. + */ + public void write (int bval) throws IOException + { + out.write(bval); + sum.update(bval); + } + + /** + * Writes the byte array to the OutputStream and updates the Checksum. + */ + public void write (byte[] buf, int off, int len) throws IOException + { + out.write(buf, off, len); + sum.update(buf, off, len); + } + + /** The checksum object. */ + private Checksum sum; +} diff --git a/libjava/classpath/java/util/zip/Checksum.java b/libjava/classpath/java/util/zip/Checksum.java new file mode 100644 index 0000000..3342ba3 --- /dev/null +++ b/libjava/classpath/java/util/zip/Checksum.java @@ -0,0 +1,86 @@ +/* Checksum.java - Interface to compute a data checksum + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.zip; + +/* + * 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. + */ + +/** + * Interface to compute a data checksum used by checked input/output streams. + * A data checksum can be updated by one byte or with a byte array. After each + * update the value of the current checksum can be returned by calling + * getValue. The complete checksum object can also be reset + * so it can be used again with new data. + * + * @see CheckedInputStream + * @see CheckedOutputStream + * + * @author Per Bothner + * @author Jochen Hoenicke + */ +public interface Checksum +{ + /** + * Returns the data checksum computed so far. + */ + long getValue(); + + /** + * Resets the data checksum as if no update was ever called. + */ + void reset(); + + /** + * Adds one byte to the data checksum. + * + * @param bval the data value to add. The high byte of the int is ignored. + */ + void update (int bval); + + /** + * Adds the byte array to the data checksum. + * + * @param buf the buffer which contains the data + * @param off the offset in the buffer where the data starts + * @param len the length of the data + */ + void update (byte[] buf, int off, int len); +} diff --git a/libjava/classpath/java/util/zip/DataFormatException.java b/libjava/classpath/java/util/zip/DataFormatException.java new file mode 100644 index 0000000..dc5b10d --- /dev/null +++ b/libjava/classpath/java/util/zip/DataFormatException.java @@ -0,0 +1,71 @@ +/* DataformatException.java -- thrown when compressed data is corrupt + Copyright (C) 1999, 2000, 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 java.util.zip; + +/** + * Exception thrown when compressed data is corrupt. + * + * @author Tom Tromey + * @author John Leuner + * @since 1.1 + * @status updated to 1.4 + */ +public class DataFormatException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 2219632870893641452L; + + /** + * Create an exception without a message. + */ + public DataFormatException() + { + } + + /** + * Create an exception with a message. + * + * @param msg the message + */ + public DataFormatException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/util/zip/Deflater.java b/libjava/classpath/java/util/zip/Deflater.java new file mode 100644 index 0000000..7bc1a19 --- /dev/null +++ b/libjava/classpath/java/util/zip/Deflater.java @@ -0,0 +1,520 @@ +/* Deflater.java - Compress a data stream + Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.zip; + +/** + * This is the Deflater class. The deflater class compresses input + * with the deflate algorithm described in RFC 1951. It has several + * compression levels and three different strategies described below. + * + * This class is not thread safe. This is inherent in the API, due + * to the split of deflate and setInput. + * + * @author Jochen Hoenicke + * @author Tom Tromey + */ +public class Deflater +{ + /** + * The best and slowest compression level. This tries to find very + * long and distant string repetitions. + */ + public static final int BEST_COMPRESSION = 9; + /** + * The worst but fastest compression level. + */ + public static final int BEST_SPEED = 1; + /** + * The default compression level. + */ + public static final int DEFAULT_COMPRESSION = -1; + /** + * This level won't compress at all but output uncompressed blocks. + */ + public static final int NO_COMPRESSION = 0; + + /** + * The default strategy. + */ + public static final int DEFAULT_STRATEGY = 0; + /** + * This strategy will only allow longer string repetitions. It is + * useful for random data with a small character set. + */ + public static final int FILTERED = 1; + + /** + * This strategy will not look for string repetitions at all. It + * only encodes with Huffman trees (which means, that more common + * characters get a smaller encoding. + */ + public static final int HUFFMAN_ONLY = 2; + + /** + * The compression method. This is the only method supported so far. + * There is no need to use this constant at all. + */ + public static final int DEFLATED = 8; + + /* + * The Deflater can do the following state transitions: + * + * (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---. + * / | (2) (5) | + * / v (5) | + * (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3) + * \ | (3) | ,-------' + * | | | (3) / + * v v (5) v v + * (1) -> BUSY_STATE ----> FINISHING_STATE + * | (6) + * v + * FINISHED_STATE + * \_____________________________________/ + * | (7) + * v + * CLOSED_STATE + * + * (1) If we should produce a header we start in INIT_STATE, otherwise + * we start in BUSY_STATE. + * (2) A dictionary may be set only when we are in INIT_STATE, then + * we change the state as indicated. + * (3) Whether a dictionary is set or not, on the first call of deflate + * we change to BUSY_STATE. + * (4) -- intentionally left blank -- :) + * (5) FINISHING_STATE is entered, when flush() is called to indicate that + * there is no more INPUT. There are also states indicating, that + * the header wasn't written yet. + * (6) FINISHED_STATE is entered, when everything has been flushed to the + * internal pending output buffer. + * (7) At any time (7) + * + */ + + private static final int IS_SETDICT = 0x01; + private static final int IS_FLUSHING = 0x04; + private static final int IS_FINISHING = 0x08; + + private static final int INIT_STATE = 0x00; + private static final int SETDICT_STATE = 0x01; + private static final int INIT_FINISHING_STATE = 0x08; + private static final int SETDICT_FINISHING_STATE = 0x09; + private static final int BUSY_STATE = 0x10; + private static final int FLUSHING_STATE = 0x14; + private static final int FINISHING_STATE = 0x1c; + private static final int FINISHED_STATE = 0x1e; + private static final int CLOSED_STATE = 0x7f; + + /** Compression level. */ + private int level; + + /** should we include a header. */ + private boolean noHeader; + + /** The current state. */ + private int state; + + /** The total bytes of output written. */ + private int totalOut; + + /** The pending output. */ + private DeflaterPending pending; + + /** The deflater engine. */ + private DeflaterEngine engine; + + /** + * Creates a new deflater with default compression level. + */ + public Deflater() + { + this(DEFAULT_COMPRESSION, false); + } + + /** + * Creates a new deflater with given compression level. + * @param lvl the compression level, a value between NO_COMPRESSION + * and BEST_COMPRESSION, or DEFAULT_COMPRESSION. + * @exception IllegalArgumentException if lvl is out of range. + */ + public Deflater(int lvl) + { + this(lvl, false); + } + + /** + * Creates a new deflater with given compression level. + * @param lvl the compression level, a value between NO_COMPRESSION + * and BEST_COMPRESSION. + * @param nowrap true, iff we should suppress the deflate header at the + * beginning and the adler checksum at the end of the output. This is + * useful for the GZIP format. + * @exception IllegalArgumentException if lvl is out of range. + */ + public Deflater(int lvl, boolean nowrap) + { + if (lvl == DEFAULT_COMPRESSION) + lvl = 6; + else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) + throw new IllegalArgumentException(); + + pending = new DeflaterPending(); + engine = new DeflaterEngine(pending); + this.noHeader = nowrap; + setStrategy(DEFAULT_STRATEGY); + setLevel(lvl); + reset(); + } + + /** + * Resets the deflater. The deflater acts afterwards as if it was + * just created with the same compression level and strategy as it + * had before. + */ + public void reset() + { + state = (noHeader ? BUSY_STATE : INIT_STATE); + totalOut = 0; + pending.reset(); + engine.reset(); + } + + /** + * Frees all objects allocated by the compressor. There's no + * reason to call this, since you can just rely on garbage + * collection. Exists only for compatibility against Sun's JDK, + * where the compressor allocates native memory. + * If you call any method (even reset) afterwards the behaviour is + * undefined. + * @deprecated Just clear all references to deflater instead. + */ + public void end() + { + engine = null; + pending = null; + state = CLOSED_STATE; + } + + /** + * Gets the current adler checksum of the data that was processed so + * far. + */ + public int getAdler() + { + return engine.getAdler(); + } + + /** + * Gets the number of input bytes processed so far. + */ + public int getTotalIn() + { + return engine.getTotalIn(); + } + + /** + * Gets the number of output bytes so far. + */ + public int getTotalOut() + { + return totalOut; + } + + /** + * Finalizes this object. + */ + protected void finalize() + { + /* Exists solely for compatibility. We don't have any native state. */ + } + + /** + * Flushes the current input block. Further calls to deflate() will + * produce enough output to inflate everything in the current input + * block. This is not part of Sun's JDK so I have made it package + * private. It is used by DeflaterOutputStream to implement + * flush(). + */ + void flush() { + state |= IS_FLUSHING; + } + + /** + * Finishes the deflater with the current input block. It is an error + * to give more input after this method was called. This method must + * be called to force all bytes to be flushed. + */ + public void finish() { + state |= IS_FLUSHING | IS_FINISHING; + } + + /** + * Returns true iff the stream was finished and no more output bytes + * are available. + */ + public boolean finished() + { + return state == FINISHED_STATE && pending.isFlushed(); + } + + /** + * Returns true, if the input buffer is empty. + * You should then call setInput().
    + * + * NOTE: This method can also return true when the stream + * was finished. + */ + public boolean needsInput() + { + return engine.needsInput(); + } + + /** + * Sets the data which should be compressed next. This should be only + * called when needsInput indicates that more input is needed. + * If you call setInput when needsInput() returns false, the + * previous input that is still pending will be thrown away. + * The given byte array should not be changed, before needsInput() returns + * true again. + * This call is equivalent to setInput(input, 0, input.length). + * @param input the buffer containing the input data. + * @exception IllegalStateException if the buffer was finished() or ended(). + */ + public void setInput(byte[] input) + { + setInput(input, 0, input.length); + } + + /** + * Sets the data which should be compressed next. This should be + * only called when needsInput indicates that more input is needed. + * The given byte array should not be changed, before needsInput() returns + * true again. + * @param input the buffer containing the input data. + * @param off the start of the data. + * @param len the length of the data. + * @exception IllegalStateException if the buffer was finished() or ended() + * or if previous input is still pending. + */ + public void setInput(byte[] input, int off, int len) + { + if ((state & IS_FINISHING) != 0) + throw new IllegalStateException("finish()/end() already called"); + engine.setInput(input, off, len); + } + + /** + * Sets the compression level. There is no guarantee of the exact + * position of the change, but if you call this when needsInput is + * true the change of compression level will occur somewhere near + * before the end of the so far given input. + * @param lvl the new compression level. + */ + public void setLevel(int lvl) + { + if (lvl == DEFAULT_COMPRESSION) + lvl = 6; + else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) + throw new IllegalArgumentException(); + + + if (level != lvl) + { + level = lvl; + engine.setLevel(lvl); + } + } + + /** + * Sets the compression strategy. Strategy is one of + * DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact + * position where the strategy is changed, the same as for + * setLevel() applies. + * @param stgy the new compression strategy. + */ + public void setStrategy(int stgy) + { + if (stgy != DEFAULT_STRATEGY && stgy != FILTERED + && stgy != HUFFMAN_ONLY) + throw new IllegalArgumentException(); + engine.setStrategy(stgy); + } + + /** + * Deflates the current input block to the given array. It returns + * the number of bytes compressed, or 0 if either + * needsInput() or finished() returns true or length is zero. + * @param output the buffer where to write the compressed data. + */ + public int deflate(byte[] output) + { + return deflate(output, 0, output.length); + } + + /** + * Deflates the current input block to the given array. It returns + * the number of bytes compressed, or 0 if either + * needsInput() or finished() returns true or length is zero. + * @param output the buffer where to write the compressed data. + * @param offset the offset into the output array. + * @param length the maximum number of bytes that may be written. + * @exception IllegalStateException if end() was called. + * @exception IndexOutOfBoundsException if offset and/or length + * don't match the array length. + */ + public int deflate(byte[] output, int offset, int length) + { + int origLength = length; + + if (state == CLOSED_STATE) + throw new IllegalStateException("Deflater closed"); + + if (state < BUSY_STATE) + { + /* output header */ + int header = (DEFLATED + + ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8; + int level_flags = (level - 1) >> 1; + if (level_flags < 0 || level_flags > 3) + level_flags = 3; + header |= level_flags << 6; + if ((state & IS_SETDICT) != 0) + /* Dictionary was set */ + header |= DeflaterConstants.PRESET_DICT; + header += 31 - (header % 31); + + pending.writeShortMSB(header); + if ((state & IS_SETDICT) != 0) + { + int chksum = engine.getAdler(); + engine.resetAdler(); + pending.writeShortMSB(chksum >> 16); + pending.writeShortMSB(chksum & 0xffff); + } + + state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING)); + } + + for (;;) + { + int count = pending.flush(output, offset, length); + offset += count; + totalOut += count; + length -= count; + if (length == 0 || state == FINISHED_STATE) + break; + + if (!engine.deflate((state & IS_FLUSHING) != 0, + (state & IS_FINISHING) != 0)) + { + if (state == BUSY_STATE) + /* We need more input now */ + return origLength - length; + else if (state == FLUSHING_STATE) + { + if (level != NO_COMPRESSION) + { + /* We have to supply some lookahead. 8 bit lookahead + * are needed by the zlib inflater, and we must fill + * the next byte, so that all bits are flushed. + */ + int neededbits = 8 + ((-pending.getBitCount()) & 7); + while (neededbits > 0) + { + /* write a static tree block consisting solely of + * an EOF: + */ + pending.writeBits(2, 10); + neededbits -= 10; + } + } + state = BUSY_STATE; + } + else if (state == FINISHING_STATE) + { + pending.alignToByte(); + /* We have completed the stream */ + if (!noHeader) + { + int adler = engine.getAdler(); + pending.writeShortMSB(adler >> 16); + pending.writeShortMSB(adler & 0xffff); + } + state = FINISHED_STATE; + } + } + } + + return origLength - length; + } + + /** + * Sets the dictionary which should be used in the deflate process. + * This call is equivalent to setDictionary(dict, 0, + * dict.length). + * @param dict the dictionary. + * @exception IllegalStateException if setInput () or deflate () + * were already called or another dictionary was already set. + */ + public void setDictionary(byte[] dict) + { + setDictionary(dict, 0, dict.length); + } + + /** + * Sets the dictionary which should be used in the deflate process. + * The dictionary should be a byte array containing strings that are + * likely to occur in the data which should be compressed. The + * dictionary is not stored in the compressed output, only a + * checksum. To decompress the output you need to supply the same + * dictionary again. + * @param dict the dictionary. + * @param offset an offset into the dictionary. + * @param length the length of the dictionary. + * @exception IllegalStateException if setInput () or deflate () were + * already called or another dictionary was already set. + */ + public void setDictionary(byte[] dict, int offset, int length) + { + if (state != INIT_STATE) + throw new IllegalStateException(); + + state = SETDICT_STATE; + engine.setDictionary(dict, offset, length); + } +} diff --git a/libjava/classpath/java/util/zip/DeflaterConstants.java b/libjava/classpath/java/util/zip/DeflaterConstants.java new file mode 100644 index 0000000..bfef863 --- /dev/null +++ b/libjava/classpath/java/util/zip/DeflaterConstants.java @@ -0,0 +1,78 @@ +/* java.util.zip.DeflaterConstants + 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 java.util.zip; + +interface DeflaterConstants +{ + boolean DEBUGGING = false; + + int STORED_BLOCK = 0; + int STATIC_TREES = 1; + int DYN_TREES = 2; + int PRESET_DICT = 0x20; + + int DEFAULT_MEM_LEVEL = 8; + + int MAX_MATCH = 258; + int MIN_MATCH = 3; + + int MAX_WBITS = 15; + int WSIZE = 1 << MAX_WBITS; + int WMASK = WSIZE - 1; + + int HASH_BITS = DEFAULT_MEM_LEVEL + 7; + int HASH_SIZE = 1 << HASH_BITS; + int HASH_MASK = HASH_SIZE - 1; + int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH; + + int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; + int MAX_DIST = WSIZE - MIN_LOOKAHEAD; + + int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8); + int MAX_BLOCK_SIZE = Math.min(65535, PENDING_BUF_SIZE-5); + + int DEFLATE_STORED = 0; + int DEFLATE_FAST = 1; + int DEFLATE_SLOW = 2; + + int GOOD_LENGTH[] = { 0,4, 4, 4, 4, 8, 8, 8, 32, 32 }; + int MAX_LAZY[] = { 0,4, 5, 6, 4,16, 16, 32, 128, 258 }; + int NICE_LENGTH[] = { 0,8,16,32,16,32,128,128, 258, 258 }; + int MAX_CHAIN[] = { 0,4, 8,32,16,32,128,256,1024,4096 }; + int COMPR_FUNC[] = { 0,1, 1, 1, 1, 2, 2, 2, 2, 2 }; +} diff --git a/libjava/classpath/java/util/zip/DeflaterEngine.java b/libjava/classpath/java/util/zip/DeflaterEngine.java new file mode 100644 index 0000000..3eea7c2 --- /dev/null +++ b/libjava/classpath/java/util/zip/DeflaterEngine.java @@ -0,0 +1,696 @@ +/* DeflaterEngine.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 java.util.zip; + +class DeflaterEngine implements DeflaterConstants +{ + private static final int TOO_FAR = 4096; + + private int ins_h; + + /** + * Hashtable, hashing three characters to an index for window, so + * that window[index]..window[index+2] have this hash code. + * Note that the array should really be unsigned short, so you need + * to and the values with 0xffff. + */ + private short[] head; + + /** + * prev[index & WMASK] points to the previous index that has the + * same hash code as the string starting at index. This way + * entries with the same hash code are in a linked list. + * Note that the array should really be unsigned short, so you need + * to and the values with 0xffff. + */ + private short[] prev; + + private int matchStart, matchLen; + private boolean prevAvailable; + private int blockStart; + + /** + * strstart points to the current character in window. + */ + private int strstart; + + /** + * lookahead is the number of characters starting at strstart in + * window that are valid. + * So window[strstart] until window[strstart+lookahead-1] are valid + * characters. + */ + private int lookahead; + + /** + * This array contains the part of the uncompressed stream that + * is of relevance. The current character is indexed by strstart. + */ + private byte[] window; + + private int strategy, max_chain, max_lazy, niceLength, goodLength; + + /** The current compression function. */ + private int comprFunc; + + /** The input data for compression. */ + private byte[] inputBuf; + + /** The total bytes of input read. */ + private int totalIn; + + /** The offset into inputBuf, where input data starts. */ + private int inputOff; + + /** The end offset of the input data. */ + private int inputEnd; + + private DeflaterPending pending; + private DeflaterHuffman huffman; + + /** The adler checksum */ + private Adler32 adler; + + /* DEFLATE ALGORITHM: + * + * The uncompressed stream is inserted into the window array. When + * the window array is full the first half is thrown away and the + * second half is copied to the beginning. + * + * The head array is a hash table. Three characters build a hash value + * and they the value points to the corresponding index in window of + * the last string with this hash. The prev array implements a + * linked list of matches with the same hash: prev[index & WMASK] points + * to the previous index with the same hash. + * + * + */ + + + DeflaterEngine(DeflaterPending pending) { + this.pending = pending; + huffman = new DeflaterHuffman(pending); + adler = new Adler32(); + + window = new byte[2*WSIZE]; + head = new short[HASH_SIZE]; + prev = new short[WSIZE]; + + /* We start at index 1, to avoid a implementation deficiency, that + * we cannot build a repeat pattern at index 0. + */ + blockStart = strstart = 1; + } + + public void reset() + { + huffman.reset(); + adler.reset(); + blockStart = strstart = 1; + lookahead = 0; + totalIn = 0; + prevAvailable = false; + matchLen = MIN_MATCH - 1; + for (int i = 0; i < HASH_SIZE; i++) + head[i] = 0; + for (int i = 0; i < WSIZE; i++) + prev[i] = 0; + } + + public final void resetAdler() + { + adler.reset(); + } + + public final int getAdler() + { + int chksum = (int) adler.getValue(); + return chksum; + } + + public final int getTotalIn() + { + return totalIn; + } + + public final void setStrategy(int strat) + { + strategy = strat; + } + + public void setLevel(int lvl) + { + goodLength = DeflaterConstants.GOOD_LENGTH[lvl]; + max_lazy = DeflaterConstants.MAX_LAZY[lvl]; + niceLength = DeflaterConstants.NICE_LENGTH[lvl]; + max_chain = DeflaterConstants.MAX_CHAIN[lvl]; + + if (DeflaterConstants.COMPR_FUNC[lvl] != comprFunc) + { + if (DeflaterConstants.DEBUGGING) + System.err.println("Change from "+comprFunc +" to " + + DeflaterConstants.COMPR_FUNC[lvl]); + switch (comprFunc) + { + case DEFLATE_STORED: + if (strstart > blockStart) + { + huffman.flushStoredBlock(window, blockStart, + strstart - blockStart, false); + blockStart = strstart; + } + updateHash(); + break; + case DEFLATE_FAST: + if (strstart > blockStart) + { + huffman.flushBlock(window, blockStart, strstart - blockStart, + false); + blockStart = strstart; + } + break; + case DEFLATE_SLOW: + if (prevAvailable) + huffman.tallyLit(window[strstart-1] & 0xff); + if (strstart > blockStart) + { + huffman.flushBlock(window, blockStart, strstart - blockStart, + false); + blockStart = strstart; + } + prevAvailable = false; + matchLen = MIN_MATCH - 1; + break; + } + comprFunc = COMPR_FUNC[lvl]; + } + } + + private void updateHash() { + if (DEBUGGING) + System.err.println("updateHash: "+strstart); + ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1]; + } + + /** + * Inserts the current string in the head hash and returns the previous + * value for this hash. + */ + private int insertString() { + short match; + int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)]) + & HASH_MASK; + + if (DEBUGGING) + { + if (hash != (((window[strstart] << (2*HASH_SHIFT)) + ^ (window[strstart + 1] << HASH_SHIFT) + ^ (window[strstart + 2])) & HASH_MASK)) + throw new InternalError("hash inconsistent: "+hash+"/" + +window[strstart]+"," + +window[strstart+1]+"," + +window[strstart+2]+","+HASH_SHIFT); + } + + prev[strstart & WMASK] = match = head[hash]; + head[hash] = (short) strstart; + ins_h = hash; + return match & 0xffff; + } + + private void slideWindow() + { + System.arraycopy(window, WSIZE, window, 0, WSIZE); + matchStart -= WSIZE; + strstart -= WSIZE; + blockStart -= WSIZE; + + /* Slide the hash table (could be avoided with 32 bit values + * at the expense of memory usage). + */ + for (int i = 0; i < HASH_SIZE; i++) + { + int m = head[i] & 0xffff; + head[i] = m >= WSIZE ? (short) (m - WSIZE) : 0; + } + + /* Slide the prev table. + */ + for (int i = 0; i < WSIZE; i++) + { + int m = prev[i] & 0xffff; + prev[i] = m >= WSIZE ? (short) (m - WSIZE) : 0; + } + } + + /** + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * OUT assertions: strstart + lookahead <= 2*WSIZE + * lookahead >= MIN_LOOKAHEAD or inputOff == inputEnd + */ + private void fillWindow() + { + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (strstart >= WSIZE + MAX_DIST) + slideWindow(); + + /* If there is not enough lookahead, but still some input left, + * read in the input + */ + while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd) + { + int more = 2*WSIZE - lookahead - strstart; + + if (more > inputEnd - inputOff) + more = inputEnd - inputOff; + + System.arraycopy(inputBuf, inputOff, + window, strstart + lookahead, more); + adler.update(inputBuf, inputOff, more); + inputOff += more; + totalIn += more; + lookahead += more; + } + + if (lookahead >= MIN_MATCH) + updateHash(); + } + + /** + * Find the best (longest) string in the window matching the + * string starting at strstart. + * + * Preconditions: + * strstart + MAX_MATCH <= window.length. + * + * + * @param curMatch + */ + private boolean findLongestMatch(int curMatch) { + int chainLength = this.max_chain; + int niceLength = this.niceLength; + short[] prev = this.prev; + int scan = this.strstart; + int match; + int best_end = this.strstart + matchLen; + int best_len = Math.max(matchLen, MIN_MATCH - 1); + + int limit = Math.max(strstart - MAX_DIST, 0); + + int strend = scan + MAX_MATCH - 1; + byte scan_end1 = window[best_end - 1]; + byte scan_end = window[best_end]; + + /* Do not waste too much time if we already have a good match: */ + if (best_len >= this.goodLength) + chainLength >>= 2; + + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if (niceLength > lookahead) + niceLength = lookahead; + + if (DeflaterConstants.DEBUGGING + && strstart > 2*WSIZE - MIN_LOOKAHEAD) + throw new InternalError("need lookahead"); + + do { + if (DeflaterConstants.DEBUGGING && curMatch >= strstart) + throw new InternalError("future match"); + if (window[curMatch + best_len] != scan_end + || window[curMatch + best_len - 1] != scan_end1 + || window[curMatch] != window[scan] + || window[curMatch+1] != window[scan + 1]) + continue; + + match = curMatch + 2; + scan += 2; + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + while (window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && scan < strend); + + if (scan > best_end) { +// if (DeflaterConstants.DEBUGGING && ins_h == 0) +// System.err.println("Found match: "+curMatch+"-"+(scan-strstart)); + matchStart = curMatch; + best_end = scan; + best_len = scan - strstart; + if (best_len >= niceLength) + break; + + scan_end1 = window[best_end-1]; + scan_end = window[best_end]; + } + scan = strstart; + } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit + && --chainLength != 0); + + matchLen = Math.min(best_len, lookahead); + return matchLen >= MIN_MATCH; + } + + void setDictionary(byte[] buffer, int offset, int length) { + if (DeflaterConstants.DEBUGGING && strstart != 1) + throw new IllegalStateException("strstart not 1"); + adler.update(buffer, offset, length); + if (length < MIN_MATCH) + return; + if (length > MAX_DIST) { + offset += length - MAX_DIST; + length = MAX_DIST; + } + + System.arraycopy(buffer, offset, window, strstart, length); + + updateHash(); + length--; + while (--length > 0) + { + insertString(); + strstart++; + } + strstart += 2; + blockStart = strstart; + } + + private boolean deflateStored(boolean flush, boolean finish) + { + if (!flush && lookahead == 0) + return false; + + strstart += lookahead; + lookahead = 0; + + int storedLen = strstart - blockStart; + + if ((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE) + /* Block is full */ + || (blockStart < WSIZE && storedLen >= MAX_DIST) + /* Block may move out of window */ + || flush) + { + boolean lastBlock = finish; + if (storedLen > DeflaterConstants.MAX_BLOCK_SIZE) + { + storedLen = DeflaterConstants.MAX_BLOCK_SIZE; + lastBlock = false; + } + + if (DeflaterConstants.DEBUGGING) + System.err.println("storedBlock["+storedLen+","+lastBlock+"]"); + + huffman.flushStoredBlock(window, blockStart, storedLen, lastBlock); + blockStart += storedLen; + return !lastBlock; + } + return true; + } + + private boolean deflateFast(boolean flush, boolean finish) + { + if (lookahead < MIN_LOOKAHEAD && !flush) + return false; + + while (lookahead >= MIN_LOOKAHEAD || flush) + { + if (lookahead == 0) + { + /* We are flushing everything */ + huffman.flushBlock(window, blockStart, strstart - blockStart, + finish); + blockStart = strstart; + return false; + } + + if (strstart > 2 * WSIZE - MIN_LOOKAHEAD) + { + /* slide window, as findLongestMatch need this. + * This should only happen when flushing and the window + * is almost full. + */ + slideWindow(); + } + + int hashHead; + if (lookahead >= MIN_MATCH + && (hashHead = insertString()) != 0 + && strategy != Deflater.HUFFMAN_ONLY + && strstart - hashHead <= MAX_DIST + && findLongestMatch(hashHead)) + { + /* longestMatch sets matchStart and matchLen */ + if (DeflaterConstants.DEBUGGING) + { + for (int i = 0 ; i < matchLen; i++) + { + if (window[strstart+i] != window[matchStart + i]) + throw new InternalError(); + } + } + huffman.tallyDist(strstart - matchStart, matchLen); + + lookahead -= matchLen; + if (matchLen <= max_lazy && lookahead >= MIN_MATCH) + { + while (--matchLen > 0) + { + strstart++; + insertString(); + } + strstart++; + } + else + { + strstart += matchLen; + if (lookahead >= MIN_MATCH - 1) + updateHash(); + } + matchLen = MIN_MATCH - 1; + continue; + } + else + { + /* No match found */ + huffman.tallyLit(window[strstart] & 0xff); + strstart++; + lookahead--; + } + + if (huffman.isFull()) + { + boolean lastBlock = finish && lookahead == 0; + huffman.flushBlock(window, blockStart, strstart - blockStart, + lastBlock); + blockStart = strstart; + return !lastBlock; + } + } + return true; + } + + private boolean deflateSlow(boolean flush, boolean finish) + { + if (lookahead < MIN_LOOKAHEAD && !flush) + return false; + + while (lookahead >= MIN_LOOKAHEAD || flush) + { + if (lookahead == 0) + { + if (prevAvailable) + huffman.tallyLit(window[strstart-1] & 0xff); + prevAvailable = false; + + /* We are flushing everything */ + if (DeflaterConstants.DEBUGGING && !flush) + throw new InternalError("Not flushing, but no lookahead"); + huffman.flushBlock(window, blockStart, strstart - blockStart, + finish); + blockStart = strstart; + return false; + } + + if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) + { + /* slide window, as findLongestMatch need this. + * This should only happen when flushing and the window + * is almost full. + */ + slideWindow(); + } + + int prevMatch = matchStart; + int prevLen = matchLen; + if (lookahead >= MIN_MATCH) + { + int hashHead = insertString(); + if (strategy != Deflater.HUFFMAN_ONLY + && hashHead != 0 && strstart - hashHead <= MAX_DIST + && findLongestMatch(hashHead)) + { + /* longestMatch sets matchStart and matchLen */ + + /* Discard match if too small and too far away */ + if (matchLen <= 5 + && (strategy == Deflater.FILTERED + || (matchLen == MIN_MATCH + && strstart - matchStart > TOO_FAR))) { + matchLen = MIN_MATCH - 1; + } + } + } + + /* previous match was better */ + if (prevLen >= MIN_MATCH && matchLen <= prevLen) + { + if (DeflaterConstants.DEBUGGING) + { + for (int i = 0 ; i < matchLen; i++) + { + if (window[strstart-1+i] != window[prevMatch + i]) + throw new InternalError(); + } + } + huffman.tallyDist(strstart - 1 - prevMatch, prevLen); + prevLen -= 2; + do + { + strstart++; + lookahead--; + if (lookahead >= MIN_MATCH) + insertString(); + } + while (--prevLen > 0); + strstart ++; + lookahead--; + prevAvailable = false; + matchLen = MIN_MATCH - 1; + } + else + { + if (prevAvailable) + huffman.tallyLit(window[strstart-1] & 0xff); + prevAvailable = true; + strstart++; + lookahead--; + } + + if (huffman.isFull()) + { + int len = strstart - blockStart; + if (prevAvailable) + len--; + boolean lastBlock = (finish && lookahead == 0 && !prevAvailable); + huffman.flushBlock(window, blockStart, len, lastBlock); + blockStart += len; + return !lastBlock; + } + } + return true; + } + + public boolean deflate(boolean flush, boolean finish) + { + boolean progress; + do + { + fillWindow(); + boolean canFlush = flush && inputOff == inputEnd; + if (DeflaterConstants.DEBUGGING) + System.err.println("window: ["+blockStart+","+strstart+"," + +lookahead+"], "+comprFunc+","+canFlush); + switch (comprFunc) + { + case DEFLATE_STORED: + progress = deflateStored(canFlush, finish); + break; + case DEFLATE_FAST: + progress = deflateFast(canFlush, finish); + break; + case DEFLATE_SLOW: + progress = deflateSlow(canFlush, finish); + break; + default: + throw new InternalError(); + } + } + while (pending.isFlushed() /* repeat while we have no pending output */ + && progress); /* and progress was made */ + + return progress; + } + + public void setInput(byte[] buf, int off, int len) + { + if (inputOff < inputEnd) + throw new IllegalStateException + ("Old input was not completely processed"); + + int end = off + len; + + /* We want to throw an ArrayIndexOutOfBoundsException early. The + * check is very tricky: it also handles integer wrap around. + */ + if (0 > off || off > end || end > buf.length) + throw new ArrayIndexOutOfBoundsException(); + + inputBuf = buf; + inputOff = off; + inputEnd = end; + } + + public final boolean needsInput() + { + return inputEnd == inputOff; + } +} diff --git a/libjava/classpath/java/util/zip/DeflaterHuffman.java b/libjava/classpath/java/util/zip/DeflaterHuffman.java new file mode 100644 index 0000000..d040dde --- /dev/null +++ b/libjava/classpath/java/util/zip/DeflaterHuffman.java @@ -0,0 +1,776 @@ +/* DeflaterHuffman.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 java.util.zip; + +/** + * This is the DeflaterHuffman class. + * + * This class is not thread safe. This is inherent in the API, due + * to the split of deflate and setInput. + * + * @author Jochen Hoenicke + * @date Jan 6, 2000 + */ +class DeflaterHuffman +{ + private static final int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6); + private static final int LITERAL_NUM = 286; + private static final int DIST_NUM = 30; + private static final int BITLEN_NUM = 19; + private static final int REP_3_6 = 16; + private static final int REP_3_10 = 17; + private static final int REP_11_138 = 18; + private static final int EOF_SYMBOL = 256; + private static final int[] BL_ORDER = + { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + + private static String bit4Reverse = + "\000\010\004\014\002\012\006\016\001\011\005\015\003\013\007\017"; + + class Tree { + short[] freqs; + short[] codes; + byte[] length; + int[] bl_counts; + int minNumCodes, numCodes; + int maxLength; + + Tree(int elems, int minCodes, int maxLength) { + this.minNumCodes = minCodes; + this.maxLength = maxLength; + freqs = new short[elems]; + bl_counts = new int[maxLength]; + } + + void reset() { + for (int i = 0; i < freqs.length; i++) + freqs[i] = 0; + codes = null; + length = null; + } + + final void writeSymbol(int code) + { + if (DeflaterConstants.DEBUGGING) + { + freqs[code]--; +// System.err.print("writeSymbol("+freqs.length+","+code+"): "); + } + pending.writeBits(codes[code] & 0xffff, length[code]); + } + + final void checkEmpty() + { + boolean empty = true; + for (int i = 0; i < freqs.length; i++) + if (freqs[i] != 0) + { + System.err.println("freqs["+i+"] == "+freqs[i]); + empty = false; + } + if (!empty) + throw new InternalError(); + System.err.println("checkEmpty suceeded!"); + } + + void setStaticCodes(short[] stCodes, byte[] stLength) + { + codes = stCodes; + length = stLength; + } + + public void buildCodes() { + int[] nextCode = new int[maxLength]; + int code = 0; + codes = new short[freqs.length]; + + if (DeflaterConstants.DEBUGGING) + System.err.println("buildCodes: "+freqs.length); + for (int bits = 0; bits < maxLength; bits++) + { + nextCode[bits] = code; + code += bl_counts[bits] << (15 - bits); + if (DeflaterConstants.DEBUGGING) + System.err.println("bits: "+(bits+1)+" count: "+bl_counts[bits] + +" nextCode: "+Integer.toHexString(code)); + } + if (DeflaterConstants.DEBUGGING && code != 65536) + throw new RuntimeException("Inconsistent bl_counts!"); + + for (int i=0; i < numCodes; i++) + { + int bits = length[i]; + if (bits > 0) + { + if (DeflaterConstants.DEBUGGING) + System.err.println("codes["+i+"] = rev(" + +Integer.toHexString(nextCode[bits-1])+")," + +bits); + codes[i] = bitReverse(nextCode[bits-1]); + nextCode[bits-1] += 1 << (16 - bits); + } + } + } + + private void buildLength(int childs[]) + { + this.length = new byte [freqs.length]; + int numNodes = childs.length / 2; + int numLeafs = (numNodes + 1) / 2; + int overflow = 0; + + for (int i = 0; i < maxLength; i++) + bl_counts[i] = 0; + + /* First calculate optimal bit lengths */ + int lengths[] = new int[numNodes]; + lengths[numNodes-1] = 0; + for (int i = numNodes - 1; i >= 0; i--) + { + if (childs[2*i+1] != -1) + { + int bitLength = lengths[i] + 1; + if (bitLength > maxLength) + { + bitLength = maxLength; + overflow++; + } + lengths[childs[2*i]] = lengths[childs[2*i+1]] = bitLength; + } + else + { + /* A leaf node */ + int bitLength = lengths[i]; + bl_counts[bitLength - 1]++; + this.length[childs[2*i]] = (byte) lengths[i]; + } + } + + if (DeflaterConstants.DEBUGGING) + { + System.err.println("Tree "+freqs.length+" lengths:"); + for (int i=0; i < numLeafs; i++) + System.err.println("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] + + " len: "+length[childs[2*i]]); + } + + if (overflow == 0) + return; + + int incrBitLen = maxLength - 1; + do + { + /* Find the first bit length which could increase: */ + while (bl_counts[--incrBitLen] == 0) + ; + + /* Move this node one down and remove a corresponding + * amount of overflow nodes. + */ + do + { + bl_counts[incrBitLen]--; + bl_counts[++incrBitLen]++; + overflow -= 1 << (maxLength - 1 - incrBitLen); + } + while (overflow > 0 && incrBitLen < maxLength - 1); + } + while (overflow > 0); + + /* We may have overshot above. Move some nodes from maxLength to + * maxLength-1 in that case. + */ + bl_counts[maxLength-1] += overflow; + bl_counts[maxLength-2] -= overflow; + + /* Now recompute all bit lengths, scanning in increasing + * frequency. It is simpler to reconstruct all lengths instead of + * fixing only the wrong ones. This idea is taken from 'ar' + * written by Haruhiko Okumura. + * + * The nodes were inserted with decreasing frequency into the childs + * array. + */ + int nodePtr = 2 * numLeafs; + for (int bits = maxLength; bits != 0; bits--) + { + int n = bl_counts[bits-1]; + while (n > 0) + { + int childPtr = 2*childs[nodePtr++]; + if (childs[childPtr + 1] == -1) + { + /* We found another leaf */ + length[childs[childPtr]] = (byte) bits; + n--; + } + } + } + if (DeflaterConstants.DEBUGGING) + { + System.err.println("*** After overflow elimination. ***"); + for (int i=0; i < numLeafs; i++) + System.err.println("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] + + " len: "+length[childs[2*i]]); + } + } + + void buildTree() + { + int numSymbols = freqs.length; + + /* heap is a priority queue, sorted by frequency, least frequent + * nodes first. The heap is a binary tree, with the property, that + * the parent node is smaller than both child nodes. This assures + * that the smallest node is the first parent. + * + * The binary tree is encoded in an array: 0 is root node and + * the nodes 2*n+1, 2*n+2 are the child nodes of node n. + */ + int[] heap = new int[numSymbols]; + int heapLen = 0; + int maxCode = 0; + for (int n = 0; n < numSymbols; n++) + { + int freq = freqs[n]; + if (freq != 0) + { + /* Insert n into heap */ + int pos = heapLen++; + int ppos; + while (pos > 0 && + freqs[heap[ppos = (pos - 1) / 2]] > freq) { + heap[pos] = heap[ppos]; + pos = ppos; + } + heap[pos] = n; + maxCode = n; + } + } + + /* We could encode a single literal with 0 bits but then we + * don't see the literals. Therefore we force at least two + * literals to avoid this case. We don't care about order in + * this case, both literals get a 1 bit code. + */ + while (heapLen < 2) + { + int node = maxCode < 2 ? ++maxCode : 0; + heap[heapLen++] = node; + } + + numCodes = Math.max(maxCode + 1, minNumCodes); + + int numLeafs = heapLen; + int[] childs = new int[4*heapLen - 2]; + int[] values = new int[2*heapLen - 1]; + int numNodes = numLeafs; + for (int i = 0; i < heapLen; i++) + { + int node = heap[i]; + childs[2*i] = node; + childs[2*i+1] = -1; + values[i] = freqs[node] << 8; + heap[i] = i; + } + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + do + { + int first = heap[0]; + int last = heap[--heapLen]; + + /* Propagate the hole to the leafs of the heap */ + int ppos = 0; + int path = 1; + while (path < heapLen) + { + if (path + 1 < heapLen + && values[heap[path]] > values[heap[path+1]]) + path++; + + heap[ppos] = heap[path]; + ppos = path; + path = path * 2 + 1; + } + + /* Now propagate the last element down along path. Normally + * it shouldn't go too deep. + */ + int lastVal = values[last]; + while ((path = ppos) > 0 + && values[heap[ppos = (path - 1)/2]] > lastVal) + heap[path] = heap[ppos]; + heap[path] = last; + + + int second = heap[0]; + + /* Create a new node father of first and second */ + last = numNodes++; + childs[2*last] = first; + childs[2*last+1] = second; + int mindepth = Math.min(values[first] & 0xff, values[second] & 0xff); + values[last] = lastVal = values[first] + values[second] - mindepth + 1; + + /* Again, propagate the hole to the leafs */ + ppos = 0; + path = 1; + while (path < heapLen) + { + if (path + 1 < heapLen + && values[heap[path]] > values[heap[path+1]]) + path++; + + heap[ppos] = heap[path]; + ppos = path; + path = ppos * 2 + 1; + } + + /* Now propagate the new element down along path */ + while ((path = ppos) > 0 + && values[heap[ppos = (path - 1)/2]] > lastVal) + heap[path] = heap[ppos]; + heap[path] = last; + } + while (heapLen > 1); + + if (heap[0] != childs.length / 2 - 1) + throw new RuntimeException("Weird!"); + + buildLength(childs); + } + + int getEncodedLength() + { + int len = 0; + for (int i = 0; i < freqs.length; i++) + len += freqs[i] * length[i]; + return len; + } + + void calcBLFreq(Tree blTree) { + int max_count; /* max repeat count */ + int min_count; /* min repeat count */ + int count; /* repeat count of the current code */ + int curlen = -1; /* length of current code */ + + int i = 0; + while (i < numCodes) + { + count = 1; + int nextlen = length[i]; + if (nextlen == 0) + { + max_count = 138; + min_count = 3; + } + else + { + max_count = 6; + min_count = 3; + if (curlen != nextlen) + { + blTree.freqs[nextlen]++; + count = 0; + } + } + curlen = nextlen; + i++; + + while (i < numCodes && curlen == length[i]) + { + i++; + if (++count >= max_count) + break; + } + + if (count < min_count) + blTree.freqs[curlen] += count; + else if (curlen != 0) + blTree.freqs[REP_3_6]++; + else if (count <= 10) + blTree.freqs[REP_3_10]++; + else + blTree.freqs[REP_11_138]++; + } + } + + void writeTree(Tree blTree) + { + int max_count; /* max repeat count */ + int min_count; /* min repeat count */ + int count; /* repeat count of the current code */ + int curlen = -1; /* length of current code */ + + int i = 0; + while (i < numCodes) + { + count = 1; + int nextlen = length[i]; + if (nextlen == 0) + { + max_count = 138; + min_count = 3; + } + else + { + max_count = 6; + min_count = 3; + if (curlen != nextlen) + { + blTree.writeSymbol(nextlen); + count = 0; + } + } + curlen = nextlen; + i++; + + while (i < numCodes && curlen == length[i]) + { + i++; + if (++count >= max_count) + break; + } + + if (count < min_count) + { + while (count-- > 0) + blTree.writeSymbol(curlen); + } + else if (curlen != 0) + { + blTree.writeSymbol(REP_3_6); + pending.writeBits(count - 3, 2); + } + else if (count <= 10) + { + blTree.writeSymbol(REP_3_10); + pending.writeBits(count - 3, 3); + } + else + { + blTree.writeSymbol(REP_11_138); + pending.writeBits(count - 11, 7); + } + } + } + } + + + + DeflaterPending pending; + private Tree literalTree, distTree, blTree; + + private short d_buf[]; + private byte l_buf[]; + private int last_lit; + private int extra_bits; + + private static short staticLCodes[]; + private static byte staticLLength[]; + private static short staticDCodes[]; + private static byte staticDLength[]; + + /** + * Reverse the bits of a 16 bit value. + */ + static short bitReverse(int value) { + return (short) (bit4Reverse.charAt(value & 0xf) << 12 + | bit4Reverse.charAt((value >> 4) & 0xf) << 8 + | bit4Reverse.charAt((value >> 8) & 0xf) << 4 + | bit4Reverse.charAt(value >> 12)); + } + + static { + /* See RFC 1951 3.2.6 */ + /* Literal codes */ + staticLCodes = new short[LITERAL_NUM]; + staticLLength = new byte[LITERAL_NUM]; + int i = 0; + while (i < 144) { + staticLCodes[i] = bitReverse((0x030 + i) << 8); + staticLLength[i++] = 8; + } + while (i < 256) { + staticLCodes[i] = bitReverse((0x190 - 144 + i) << 7); + staticLLength[i++] = 9; + } + while (i < 280) { + staticLCodes[i] = bitReverse((0x000 - 256 + i) << 9); + staticLLength[i++] = 7; + } + while (i < LITERAL_NUM) { + staticLCodes[i] = bitReverse((0x0c0 - 280 + i) << 8); + staticLLength[i++] = 8; + } + + /* Distant codes */ + staticDCodes = new short[DIST_NUM]; + staticDLength = new byte[DIST_NUM]; + for (i = 0; i < DIST_NUM; i++) { + staticDCodes[i] = bitReverse(i << 11); + staticDLength[i] = 5; + } + } + + public DeflaterHuffman(DeflaterPending pending) + { + this.pending = pending; + + literalTree = new Tree(LITERAL_NUM, 257, 15); + distTree = new Tree(DIST_NUM, 1, 15); + blTree = new Tree(BITLEN_NUM, 4, 7); + + d_buf = new short[BUFSIZE]; + l_buf = new byte [BUFSIZE]; + } + + public final void reset() { + last_lit = 0; + extra_bits = 0; + literalTree.reset(); + distTree.reset(); + blTree.reset(); + } + + private int l_code(int len) { + if (len == 255) + return 285; + + int code = 257; + while (len >= 8) + { + code += 4; + len >>= 1; + } + return code + len; + } + + private int d_code(int distance) { + int code = 0; + while (distance >= 4) + { + code += 2; + distance >>= 1; + } + return code + distance; + } + + public void sendAllTrees(int blTreeCodes) { + blTree.buildCodes(); + literalTree.buildCodes(); + distTree.buildCodes(); + pending.writeBits(literalTree.numCodes - 257, 5); + pending.writeBits(distTree.numCodes - 1, 5); + pending.writeBits(blTreeCodes - 4, 4); + for (int rank = 0; rank < blTreeCodes; rank++) + pending.writeBits(blTree.length[BL_ORDER[rank]], 3); + literalTree.writeTree(blTree); + distTree.writeTree(blTree); + if (DeflaterConstants.DEBUGGING) + blTree.checkEmpty(); + } + + public void compressBlock() { + for (int i = 0; i < last_lit; i++) + { + int litlen = l_buf[i] & 0xff; + int dist = d_buf[i]; + if (dist-- != 0) + { + if (DeflaterConstants.DEBUGGING) + System.err.print("["+(dist+1)+","+(litlen+3)+"]: "); + + int lc = l_code(litlen); + literalTree.writeSymbol(lc); + + int bits = (lc - 261) / 4; + if (bits > 0 && bits <= 5) + pending.writeBits(litlen & ((1 << bits) - 1), bits); + + int dc = d_code(dist); + distTree.writeSymbol(dc); + + bits = dc / 2 - 1; + if (bits > 0) + pending.writeBits(dist & ((1 << bits) - 1), bits); + } + else + { + if (DeflaterConstants.DEBUGGING) + { + if (litlen > 32 && litlen < 127) + System.err.print("("+(char)litlen+"): "); + else + System.err.print("{"+litlen+"}: "); + } + literalTree.writeSymbol(litlen); + } + } + if (DeflaterConstants.DEBUGGING) + System.err.print("EOF: "); + literalTree.writeSymbol(EOF_SYMBOL); + if (DeflaterConstants.DEBUGGING) + { + literalTree.checkEmpty(); + distTree.checkEmpty(); + } + } + + public void flushStoredBlock(byte[] stored, + int stored_offset, int stored_len, + boolean lastBlock) { + if (DeflaterConstants.DEBUGGING) + System.err.println("Flushing stored block "+ stored_len); + pending.writeBits((DeflaterConstants.STORED_BLOCK << 1) + + (lastBlock ? 1 : 0), 3); + pending.alignToByte(); + pending.writeShort(stored_len); + pending.writeShort(~stored_len); + pending.writeBlock(stored, stored_offset, stored_len); + reset(); + } + + public void flushBlock(byte[] stored, int stored_offset, int stored_len, + boolean lastBlock) { + literalTree.freqs[EOF_SYMBOL]++; + + /* Build trees */ + literalTree.buildTree(); + distTree.buildTree(); + + /* Calculate bitlen frequency */ + literalTree.calcBLFreq(blTree); + distTree.calcBLFreq(blTree); + + /* Build bitlen tree */ + blTree.buildTree(); + + int blTreeCodes = 4; + for (int i = 18; i > blTreeCodes; i--) + { + if (blTree.length[BL_ORDER[i]] > 0) + blTreeCodes = i+1; + } + int opt_len = 14 + blTreeCodes * 3 + blTree.getEncodedLength() + + literalTree.getEncodedLength() + distTree.getEncodedLength() + + extra_bits; + + int static_len = extra_bits; + for (int i = 0; i < LITERAL_NUM; i++) + static_len += literalTree.freqs[i] * staticLLength[i]; + for (int i = 0; i < DIST_NUM; i++) + static_len += distTree.freqs[i] * staticDLength[i]; + if (opt_len >= static_len) + { + /* Force static trees */ + opt_len = static_len; + } + + if (stored_offset >= 0 && stored_len+4 < opt_len >> 3) + { + /* Store Block */ + if (DeflaterConstants.DEBUGGING) + System.err.println("Storing, since " + stored_len + " < " + opt_len + + " <= " + static_len); + flushStoredBlock(stored, stored_offset, stored_len, lastBlock); + } + else if (opt_len == static_len) + { + /* Encode with static tree */ + pending.writeBits((DeflaterConstants.STATIC_TREES << 1) + + (lastBlock ? 1 : 0), 3); + literalTree.setStaticCodes(staticLCodes, staticLLength); + distTree.setStaticCodes(staticDCodes, staticDLength); + compressBlock(); + reset(); + } + else + { + /* Encode with dynamic tree */ + pending.writeBits((DeflaterConstants.DYN_TREES << 1) + + (lastBlock ? 1 : 0), 3); + sendAllTrees(blTreeCodes); + compressBlock(); + reset(); + } + } + + public final boolean isFull() + { + return last_lit == BUFSIZE; + } + + public final boolean tallyLit(int lit) + { + if (DeflaterConstants.DEBUGGING) + { + if (lit > 32 && lit < 127) + System.err.println("("+(char)lit+")"); + else + System.err.println("{"+lit+"}"); + } + d_buf[last_lit] = 0; + l_buf[last_lit++] = (byte) lit; + literalTree.freqs[lit]++; + return last_lit == BUFSIZE; + } + + public final boolean tallyDist(int dist, int len) + { + if (DeflaterConstants.DEBUGGING) + System.err.println("["+dist+","+len+"]"); + + d_buf[last_lit] = (short) dist; + l_buf[last_lit++] = (byte) (len - 3); + + int lc = l_code(len-3); + literalTree.freqs[lc]++; + if (lc >= 265 && lc < 285) + extra_bits += (lc - 261) / 4; + + int dc = d_code(dist-1); + distTree.freqs[dc]++; + if (dc >= 4) + extra_bits += dc / 2 - 1; + return last_lit == BUFSIZE; + } +} diff --git a/libjava/classpath/java/util/zip/DeflaterOutputStream.java b/libjava/classpath/java/util/zip/DeflaterOutputStream.java new file mode 100644 index 0000000..b10100d --- /dev/null +++ b/libjava/classpath/java/util/zip/DeflaterOutputStream.java @@ -0,0 +1,198 @@ +/* DeflaterOutputStream.java - Output filter for compressing. + Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util.zip; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +/** + * This is a special FilterOutputStream deflating the bytes that are + * written through it. It uses the Deflater for deflating. + * + * A special thing to be noted is that flush() doesn't flush + * everything in Sun's JDK, but it does so in jazzlib. This is because + * Sun's Deflater doesn't have a way to flush() everything, without + * finishing the stream. + * + * @author Tom Tromey, Jochen Hoenicke + * @date Jan 11, 2001 + */ +public class DeflaterOutputStream extends FilterOutputStream +{ + /** + * This buffer is used temporarily to retrieve the bytes from the + * deflater and write them to the underlying output stream. + */ + protected byte[] buf; + + /** + * The deflater which is used to deflate the stream. + */ + protected Deflater def; + + /** + * Deflates everything in the def's input buffers. This will call + * def.deflate() until all bytes from the input buffers + * are processed. + */ + protected void deflate() throws IOException + { + while (! def.needsInput()) + { + int len = def.deflate(buf, 0, buf.length); + + // System.err.println("DOS deflated " + len + " out of " + buf.length); + if (len <= 0) + break; + out.write(buf, 0, len); + } + + if (! def.needsInput()) + throw new InternalError("Can't deflate all input?"); + } + + /** + * Creates a new DeflaterOutputStream with a default Deflater and + * default buffer size. + * @param out the output stream where deflated output should be written. + */ + public DeflaterOutputStream(OutputStream out) + { + this(out, new Deflater(), 512); + } + + /** + * Creates a new DeflaterOutputStream with the given Deflater and + * default buffer size. + * @param out the output stream where deflated output should be written. + * @param defl the underlying deflater. + */ + public DeflaterOutputStream(OutputStream out, Deflater defl) + { + this(out, defl, 512); + } + + /** + * Creates a new DeflaterOutputStream with the given Deflater and + * buffer size. + * @param out the output stream where deflated output should be written. + * @param defl the underlying deflater. + * @param bufsize the buffer size. + * @exception IllegalArgumentException if bufsize isn't positive. + */ + public DeflaterOutputStream(OutputStream out, Deflater defl, int bufsize) + { + super(out); + if (bufsize <= 0) + throw new IllegalArgumentException("bufsize <= 0"); + buf = new byte[bufsize]; + def = defl; + } + + /** + * Flushes the stream by calling flush() on the deflater and then + * on the underlying stream. This ensures that all bytes are + * flushed. This function doesn't work in Sun's JDK, but only in + * jazzlib. + */ + public void flush() throws IOException + { + def.flush(); + deflate(); + out.flush(); + } + + /** + * Finishes the stream by calling finish() on the deflater. This + * was the only way to ensure that all bytes are flushed in Sun's + * JDK. + */ + public void finish() throws IOException + { + def.finish(); + while (! def.finished()) + { + int len = def.deflate(buf, 0, buf.length); + if (len <= 0) + break; + out.write(buf, 0, len); + } + if (! def.finished()) + throw new InternalError("Can't deflate all input?"); + out.flush(); + } + + /** + * Calls finish() and closes the stream. + */ + public void close() throws IOException + { + finish(); + out.close(); + } + + /** + * Writes a single byte to the compressed output stream. + * @param bval the byte value. + */ + public void write(int bval) throws IOException + { + byte[] b = new byte[1]; + b[0] = (byte) bval; + write(b, 0, 1); + } + + /** + * Writes a len bytes from an array to the compressed stream. + * @param buf the byte array. + * @param off the offset into the byte array where to start. + * @param len the number of bytes to write. + */ + public void write(byte[] buf, int off, int len) throws IOException + { + def.setInput(buf, off, len); + deflate(); + } +} diff --git a/libjava/classpath/java/util/zip/DeflaterPending.java b/libjava/classpath/java/util/zip/DeflaterPending.java new file mode 100644 index 0000000..f38212c --- /dev/null +++ b/libjava/classpath/java/util/zip/DeflaterPending.java @@ -0,0 +1,54 @@ +/* java.util.zip.DeflaterPending + 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 java.util.zip; + +/** + * This class stores the pending output of the Deflater. + * + * @author Jochen Hoenicke + * @date Jan 5, 2000 + */ + +class DeflaterPending extends PendingBuffer +{ + public DeflaterPending() + { + super(DeflaterConstants.PENDING_BUF_SIZE); + } +} + diff --git a/libjava/classpath/java/util/zip/GZIPInputStream.java b/libjava/classpath/java/util/zip/GZIPInputStream.java new file mode 100644 index 0000000..2cea755 --- /dev/null +++ b/libjava/classpath/java/util/zip/GZIPInputStream.java @@ -0,0 +1,355 @@ +/* GZIPInputStream.java - Input filter for reading gzip file + Copyright (C) 1999, 2000, 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 java.util.zip; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +/** + * This filter stream is used to decompress a "GZIP" format stream. + * The "GZIP" format is described in RFC 1952. + * + * @author John Leuner + * @author Tom Tromey + * @since JDK 1.1 + */ +public class GZIPInputStream + extends InflaterInputStream +{ + /** + * The magic number found at the start of a GZIP stream. + */ + public static final int GZIP_MAGIC = 0x8b1f; + + /** + * The mask for bit 0 of the flag byte. + */ + static final int FTEXT = 0x1; + + /** + * The mask for bit 1 of the flag byte. + */ + static final int FHCRC = 0x2; + + /** + * The mask for bit 2 of the flag byte. + */ + static final int FEXTRA = 0x4; + + /** + * The mask for bit 3 of the flag byte. + */ + static final int FNAME = 0x8; + + /** + * The mask for bit 4 of the flag byte. + */ + static final int FCOMMENT = 0x10; + + /** + * The CRC-32 checksum value for uncompressed data. + */ + protected CRC32 crc; + + /** + * Indicates whether or not the end of the stream has been reached. + */ + protected boolean eos; + + /** + * Indicates whether or not the GZIP header has been read in. + */ + private boolean readGZIPHeader; + + /** + * Creates a GZIPInputStream with the default buffer size. + * + * @param in The stream to read compressed data from + * (in GZIP format). + * + * @throws IOException if an error occurs during an I/O operation. + */ + public GZIPInputStream(InputStream in) + throws IOException + { + this(in, 4096); + } + + /** + * Creates a GZIPInputStream with the specified buffer size. + * + * @param in The stream to read compressed data from + * (in GZIP format). + * @param size The size of the buffer to use. + * + * @throws IOException if an error occurs during an I/O operation. + * @throws IllegalArgumentException if size + * is less than or equal to 0. + */ + public GZIPInputStream(InputStream in, int size) + throws IOException + { + super(in, new Inflater(true), size); + crc = new CRC32(); + readHeader(); + } + + /** + * Closes the input stream. + * + * @throws IOException if an error occurs during an I/O operation. + */ + public void close() + throws IOException + { + // Nothing to do here. + super.close(); + } + + /** + * Reads in GZIP-compressed data and stores it in uncompressed form + * into an array of bytes. The method will block until either + * enough input data becomes available or the compressed stream + * reaches its end. + * + * @param buf the buffer into which the uncompressed data will + * be stored. + * @param offset the offset indicating where in buf + * the uncompressed data should be placed. + * @param len the number of uncompressed bytes to be read. + */ + public int read(byte[] buf, int offset, int len) throws IOException + { + // We first have to slurp in the GZIP header, then we feed all the + // rest of the data to the superclass. + // + // As we do that we continually update the CRC32. Once the data is + // finished, we check the CRC32. + // + // This means we don't need our own buffer, as everything is done + // in the superclass. + if (!readGZIPHeader) + readHeader(); + + if (eos) + return -1; + + // System.err.println("GZIPIS.read(byte[], off, len ... " + offset + " and len " + len); + + /* We don't have to read the header, + * so we just grab data from the superclass. + */ + int numRead = super.read(buf, offset, len); + if (numRead > 0) + crc.update(buf, offset, numRead); + + if (inf.finished()) + readFooter(); + return numRead; + } + + + /** + * Reads in the GZIP header. + */ + private void readHeader() throws IOException + { + /* 1. Check the two magic bytes */ + CRC32 headCRC = new CRC32(); + int magic = in.read(); + if (magic < 0) + { + eos = true; + return; + } + int magic2 = in.read(); + if ((magic + (magic2 << 8)) != GZIP_MAGIC) + throw new IOException("Error in GZIP header, bad magic code"); + headCRC.update(magic); + headCRC.update(magic2); + + /* 2. Check the compression type (must be 8) */ + int CM = in.read(); + if (CM != 8) + throw new IOException("Error in GZIP header, data not in deflate format"); + headCRC.update(CM); + + /* 3. Check the flags */ + int flags = in.read(); + if (flags < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(flags); + + /* This flag byte is divided into individual bits as follows: + + bit 0 FTEXT + bit 1 FHCRC + bit 2 FEXTRA + bit 3 FNAME + bit 4 FCOMMENT + bit 5 reserved + bit 6 reserved + bit 7 reserved + */ + + /* 3.1 Check the reserved bits are zero */ + if ((flags & 0xd0) != 0) + throw new IOException("Reserved flag bits in GZIP header != 0"); + + /* 4.-6. Skip the modification time, extra flags, and OS type */ + for (int i=0; i< 6; i++) + { + int readByte = in.read(); + if (readByte < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(readByte); + } + + /* 7. Read extra field */ + if ((flags & FEXTRA) != 0) + { + /* Skip subfield id */ + for (int i=0; i< 2; i++) + { + int readByte = in.read(); + if (readByte < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(readByte); + } + if (in.read() < 0 || in.read() < 0) + throw new EOFException("Early EOF in GZIP header"); + + int len1, len2, extraLen; + len1 = in.read(); + len2 = in.read(); + if ((len1 < 0) || (len2 < 0)) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(len1); + headCRC.update(len2); + + extraLen = (len1 << 8) | len2; + for (int i = 0; i < extraLen;i++) + { + int readByte = in.read(); + if (readByte < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(readByte); + } + } + + /* 8. Read file name */ + if ((flags & FNAME) != 0) + { + int readByte; + while ( (readByte = in.read()) > 0) + headCRC.update(readByte); + if (readByte < 0) + throw new EOFException("Early EOF in GZIP file name"); + headCRC.update(readByte); + } + + /* 9. Read comment */ + if ((flags & FCOMMENT) != 0) + { + int readByte; + while ( (readByte = in.read()) > 0) + headCRC.update(readByte); + + if (readByte < 0) + throw new EOFException("Early EOF in GZIP comment"); + headCRC.update(readByte); + } + + /* 10. Read header CRC */ + if ((flags & FHCRC) != 0) + { + int tempByte; + int crcval = in.read(); + if (crcval < 0) + throw new EOFException("Early EOF in GZIP header"); + + tempByte = in.read(); + if (tempByte < 0) + throw new EOFException("Early EOF in GZIP header"); + + crcval = (crcval << 8) | tempByte; + if (crcval != ((int) headCRC.getValue() & 0xffff)) + throw new IOException("Header CRC value mismatch"); + } + + readGZIPHeader = true; + //System.err.println("Read GZIP header"); + } + + private void readFooter() throws IOException + { + byte[] footer = new byte[8]; + int avail = inf.getRemaining(); + if (avail > 8) + avail = 8; + System.arraycopy(buf, len - inf.getRemaining(), footer, 0, avail); + int needed = 8 - avail; + while (needed > 0) + { + int count = in.read(footer, 8-needed, needed); + if (count <= 0) + throw new EOFException("Early EOF in GZIP footer"); + needed -= count; //Jewel Jan 16 + } + + int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) + | ((footer[2] & 0xff) << 16) | (footer[3] << 24); + if (crcval != (int) crc.getValue()) + throw new IOException("GZIP crc sum mismatch, theirs \"" + + Integer.toHexString(crcval) + + "\" and ours \"" + + Integer.toHexString( (int) crc.getValue())); + + int total = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8) + | ((footer[6] & 0xff) << 16) | (footer[7] << 24); + if (total != inf.getTotalOut()) + throw new IOException("Number of bytes mismatch"); + + /* FIXME" XXX Should we support multiple members. + * Difficult, since there may be some bytes still in buf + */ + eos = true; + } +} diff --git a/libjava/classpath/java/util/zip/GZIPOutputStream.java b/libjava/classpath/java/util/zip/GZIPOutputStream.java new file mode 100644 index 0000000..5b7b827 --- /dev/null +++ b/libjava/classpath/java/util/zip/GZIPOutputStream.java @@ -0,0 +1,151 @@ +/* GZIPOutputStream.java - Create a file in gzip format + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.zip; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * This filter stream is used to compress a stream into a "GZIP" stream. + * The "GZIP" format is described in RFC 1952. + * + * @author John Leuner + * @author Tom Tromey + * @since JDK 1.1 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +public class GZIPOutputStream extends DeflaterOutputStream +{ + /** + * CRC-32 value for uncompressed data + */ + protected CRC32 crc; + + /** + * Creates a GZIPOutputStream with the default buffer size + * + * @param out The stream to read data (to be compressed) from + * + */ + public GZIPOutputStream(OutputStream out) throws IOException + { + this(out, 4096); + } + + /** + * Creates a GZIPOutputStream with the specified buffer size + * + * @param out The stream to read compressed data from + * @param size Size of the buffer to use + */ + public GZIPOutputStream(OutputStream out, int size) throws IOException + { + super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size); + crc = new CRC32(); + int mod_time = (int) (System.currentTimeMillis() / 1000L); + byte[] gzipHeader = + { + /* The two magic bytes */ + (byte) GZIPInputStream.GZIP_MAGIC, + (byte) (GZIPInputStream.GZIP_MAGIC >> 8), + + /* The compression type */ + (byte) Deflater.DEFLATED, + + /* The flags (not set) */ + 0, + + /* The modification time */ + (byte) mod_time, (byte) (mod_time >> 8), + (byte) (mod_time >> 16), (byte) (mod_time >> 24), + + /* The extra flags */ + 0, + + /* The OS type (unknown) */ + (byte) 255 + }; + + out.write(gzipHeader); + // System.err.println("wrote GZIP header (" + gzipHeader.length + " bytes )"); + } + + public synchronized void write(byte[] buf, int off, int len) + throws IOException + { + super.write(buf, off, len); + crc.update(buf, off, len); + } + + /** + * Writes remaining compressed output data to the output stream + * and closes it. + */ + public void close() throws IOException + { + finish(); + out.close(); + } + + public void finish() throws IOException + { + super.finish(); + + int totalin = def.getTotalIn(); + int crcval = (int) (crc.getValue() & 0xffffffff); + + // System.err.println("CRC val is " + Integer.toHexString( crcval ) + " and length " + Integer.toHexString(totalin)); + + byte[] gzipFooter = + { + (byte) crcval, (byte) (crcval >> 8), + (byte) (crcval >> 16), (byte) (crcval >> 24), + + (byte) totalin, (byte) (totalin >> 8), + (byte) (totalin >> 16), (byte) (totalin >> 24) + }; + + out.write(gzipFooter); + // System.err.println("wrote GZIP trailer (" + gzipFooter.length + " bytes )"); + } +} diff --git a/libjava/classpath/java/util/zip/Inflater.java b/libjava/classpath/java/util/zip/Inflater.java new file mode 100644 index 0000000..76de891 --- /dev/null +++ b/libjava/classpath/java/util/zip/Inflater.java @@ -0,0 +1,715 @@ +/* Inflater.java - Decompress a data stream + Copyright (C) 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.zip; + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +/** + * Inflater is used to decompress data that has been compressed according + * to the "deflate" standard described in rfc1950. + * + * The usage is as following. First you have to set some input with + * setInput(), then inflate() it. If inflate doesn't + * inflate any bytes there may be three reasons: + *

      + *
    • needsInput() returns true because the input buffer is empty. + * You have to provide more input with setInput(). + * NOTE: needsInput() also returns true when, the stream is finished. + *
    • + *
    • needsDictionary() returns true, you have to provide a preset + * dictionary with setDictionary().
    • + *
    • finished() returns true, the inflater has finished.
    • + *
    + * Once the first output byte is produced, a dictionary will not be + * needed at a later stage. + * + * @author John Leuner, Jochen Hoenicke + * @author Tom Tromey + * @date May 17, 1999 + * @since JDK 1.1 + */ +public class Inflater +{ + /* Copy lengths for literal codes 257..285 */ + private static final int CPLENS[] = + { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 + }; + + /* Extra bits for literal codes 257..285 */ + private static final int CPLEXT[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 + }; + + /* Copy offsets for distance codes 0..29 */ + private static final int CPDIST[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + + /* Extra bits for distance codes */ + private static final int CPDEXT[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13 + }; + + /* This are the state in which the inflater can be. */ + private static final int DECODE_HEADER = 0; + private static final int DECODE_DICT = 1; + private static final int DECODE_BLOCKS = 2; + private static final int DECODE_STORED_LEN1 = 3; + private static final int DECODE_STORED_LEN2 = 4; + private static final int DECODE_STORED = 5; + private static final int DECODE_DYN_HEADER = 6; + private static final int DECODE_HUFFMAN = 7; + private static final int DECODE_HUFFMAN_LENBITS = 8; + private static final int DECODE_HUFFMAN_DIST = 9; + private static final int DECODE_HUFFMAN_DISTBITS = 10; + private static final int DECODE_CHKSUM = 11; + private static final int FINISHED = 12; + + /** This variable contains the current state. */ + private int mode; + + /** + * The adler checksum of the dictionary or of the decompressed + * stream, as it is written in the header resp. footer of the + * compressed stream.
    + * + * Only valid if mode is DECODE_DICT or DECODE_CHKSUM. + */ + private int readAdler; + /** + * The number of bits needed to complete the current state. This + * is valid, if mode is DECODE_DICT, DECODE_CHKSUM, + * DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS. + */ + private int neededBits; + private int repLength, repDist; + private int uncomprLen; + /** + * True, if the last block flag was set in the last block of the + * inflated stream. This means that the stream ends after the + * current block. + */ + private boolean isLastBlock; + + /** + * The total number of inflated bytes. + */ + private int totalOut; + /** + * The total number of bytes set with setInput(). This is not the + * value returned by getTotalIn(), since this also includes the + * unprocessed input. + */ + private int totalIn; + /** + * This variable stores the nowrap flag that was given to the constructor. + * True means, that the inflated stream doesn't contain a header nor the + * checksum in the footer. + */ + private boolean nowrap; + + private StreamManipulator input; + private OutputWindow outputWindow; + private InflaterDynHeader dynHeader; + private InflaterHuffmanTree litlenTree, distTree; + private Adler32 adler; + + /** + * Creates a new inflater. + */ + public Inflater () + { + this (false); + } + + /** + * Creates a new inflater. + * @param nowrap true if no header and checksum field appears in the + * stream. This is used for GZIPed input. For compatibility with + * Sun JDK you should provide one byte of input more than needed in + * this case. + */ + public Inflater (boolean nowrap) + { + this.nowrap = nowrap; + this.adler = new Adler32(); + input = new StreamManipulator(); + outputWindow = new OutputWindow(); + mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER; + } + + /** + * Finalizes this object. + */ + protected void finalize () + { + /* Exists only for compatibility */ + } + + /** + * Frees all objects allocated by the inflater. There's no reason + * to call this, since you can just rely on garbage collection (even + * for the Sun implementation). Exists only for compatibility + * with Sun's JDK, where the compressor allocates native memory. + * If you call any method (even reset) afterwards the behaviour is + * undefined. + * @deprecated Just clear all references to inflater instead. + */ + public void end () + { + outputWindow = null; + input = null; + dynHeader = null; + litlenTree = null; + distTree = null; + adler = null; + } + + /** + * Returns true, if the inflater has finished. This means, that no + * input is needed and no output can be produced. + */ + public boolean finished() + { + return mode == FINISHED && outputWindow.getAvailable() == 0; + } + + /** + * Gets the adler checksum. This is either the checksum of all + * uncompressed bytes returned by inflate(), or if needsDictionary() + * returns true (and thus no output was yet produced) this is the + * adler checksum of the expected dictionary. + * @returns the adler checksum. + */ + public int getAdler() + { + return needsDictionary() ? readAdler : (int) adler.getValue(); + } + + /** + * Gets the number of unprocessed input. Useful, if the end of the + * stream is reached and you want to further process the bytes after + * the deflate stream. + * @return the number of bytes of the input which were not processed. + */ + public int getRemaining() + { + return input.getAvailableBytes(); + } + + /** + * Gets the total number of processed compressed input bytes. + * @return the total number of bytes of processed input bytes. + */ + public int getTotalIn() + { + return totalIn - getRemaining(); + } + + /** + * Gets the total number of output bytes returned by inflate(). + * @return the total number of output bytes. + */ + public int getTotalOut() + { + return totalOut; + } + + /** + * Inflates the compressed stream to the output buffer. If this + * returns 0, you should check, whether needsDictionary(), + * needsInput() or finished() returns true, to determine why no + * further output is produced. + * @param buf the output buffer. + * @return the number of bytes written to the buffer, 0 if no further + * output can be produced. + * @exception DataFormatException if deflated stream is invalid. + * @exception IllegalArgumentException if buf has length 0. + */ + public int inflate (byte[] buf) throws DataFormatException + { + return inflate (buf, 0, buf.length); + } + + /** + * Inflates the compressed stream to the output buffer. If this + * returns 0, you should check, whether needsDictionary(), + * needsInput() or finished() returns true, to determine why no + * further output is produced. + * @param buf the output buffer. + * @param off the offset into buffer where the output should start. + * @param len the maximum length of the output. + * @return the number of bytes written to the buffer, 0 if no further + * output can be produced. + * @exception DataFormatException if deflated stream is invalid. + * @exception IndexOutOfBoundsException if the off and/or len are wrong. + */ + public int inflate (byte[] buf, int off, int len) throws DataFormatException + { + /* Special case: len may be zero */ + if (len == 0) + return 0; + /* Check for correct buff, off, len triple */ + if (0 > off || off > off + len || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + int count = 0; + int more; + do + { + if (mode != DECODE_CHKSUM) + { + /* Don't give away any output, if we are waiting for the + * checksum in the input stream. + * + * With this trick we have always: + * needsInput() and not finished() + * implies more output can be produced. + */ + more = outputWindow.copyOutput(buf, off, len); + adler.update(buf, off, more); + off += more; + count += more; + totalOut += more; + len -= more; + if (len == 0) + return count; + } + } + while (decode() || (outputWindow.getAvailable() > 0 + && mode != DECODE_CHKSUM)); + return count; + } + + /** + * Returns true, if a preset dictionary is needed to inflate the input. + */ + public boolean needsDictionary () + { + return mode == DECODE_DICT && neededBits == 0; + } + + /** + * Returns true, if the input buffer is empty. + * You should then call setInput().
    + * + * NOTE: This method also returns true when the stream is finished. + */ + public boolean needsInput () + { + return input.needsInput (); + } + + /** + * Resets the inflater so that a new stream can be decompressed. All + * pending input and output will be discarded. + */ + public void reset () + { + mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER; + totalIn = totalOut = 0; + input.reset(); + outputWindow.reset(); + dynHeader = null; + litlenTree = null; + distTree = null; + isLastBlock = false; + adler.reset(); + } + + /** + * Sets the preset dictionary. This should only be called, if + * needsDictionary() returns true and it should set the same + * dictionary, that was used for deflating. The getAdler() + * function returns the checksum of the dictionary needed. + * @param buffer the dictionary. + * @exception IllegalStateException if no dictionary is needed. + * @exception IllegalArgumentException if the dictionary checksum is + * wrong. + */ + public void setDictionary (byte[] buffer) + { + setDictionary(buffer, 0, buffer.length); + } + + /** + * Sets the preset dictionary. This should only be called, if + * needsDictionary() returns true and it should set the same + * dictionary, that was used for deflating. The getAdler() + * function returns the checksum of the dictionary needed. + * @param buffer the dictionary. + * @param off the offset into buffer where the dictionary starts. + * @param len the length of the dictionary. + * @exception IllegalStateException if no dictionary is needed. + * @exception IllegalArgumentException if the dictionary checksum is + * wrong. + * @exception IndexOutOfBoundsException if the off and/or len are wrong. + */ + public void setDictionary (byte[] buffer, int off, int len) + { + if (!needsDictionary()) + throw new IllegalStateException(); + + adler.update(buffer, off, len); + if ((int) adler.getValue() != readAdler) + throw new IllegalArgumentException("Wrong adler checksum"); + adler.reset(); + outputWindow.copyDict(buffer, off, len); + mode = DECODE_BLOCKS; + } + + /** + * Sets the input. This should only be called, if needsInput() + * returns true. + * @param buf the input. + * @exception IllegalStateException if no input is needed. + */ + public void setInput (byte[] buf) + { + setInput (buf, 0, buf.length); + } + + /** + * Sets the input. This should only be called, if needsInput() + * returns true. + * @param buf the input. + * @param off the offset into buffer where the input starts. + * @param len the length of the input. + * @exception IllegalStateException if no input is needed. + * @exception IndexOutOfBoundsException if the off and/or len are wrong. + */ + public void setInput (byte[] buf, int off, int len) + { + input.setInput (buf, off, len); + totalIn += len; + } + + /** + * Decodes the deflate header. + * @return false if more input is needed. + * @exception DataFormatException if header is invalid. + */ + private boolean decodeHeader () throws DataFormatException + { + int header = input.peekBits(16); + if (header < 0) + return false; + input.dropBits(16); + + /* The header is written in "wrong" byte order */ + header = ((header << 8) | (header >> 8)) & 0xffff; + if (header % 31 != 0) + throw new DataFormatException("Header checksum illegal"); + + if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) + throw new DataFormatException("Compression Method unknown"); + + /* Maximum size of the backwards window in bits. + * We currently ignore this, but we could use it to make the + * inflater window more space efficient. On the other hand the + * full window (15 bits) is needed most times, anyway. + int max_wbits = ((header & 0x7000) >> 12) + 8; + */ + + if ((header & 0x0020) == 0) // Dictionary flag? + { + mode = DECODE_BLOCKS; + } + else + { + mode = DECODE_DICT; + neededBits = 32; + } + return true; + } + + /** + * Decodes the dictionary checksum after the deflate header. + * @return false if more input is needed. + */ + private boolean decodeDict () + { + while (neededBits > 0) + { + int dictByte = input.peekBits(8); + if (dictByte < 0) + return false; + input.dropBits(8); + readAdler = (readAdler << 8) | dictByte; + neededBits -= 8; + } + return false; + } + + /** + * Decodes the huffman encoded symbols in the input stream. + * @return false if more input is needed, true if output window is + * full or the current block ends. + * @exception DataFormatException if deflated stream is invalid. + */ + private boolean decodeHuffman () throws DataFormatException + { + int free = outputWindow.getFreeSpace(); + while (free >= 258) + { + int symbol; + switch (mode) + { + case DECODE_HUFFMAN: + /* This is the inner loop so it is optimized a bit */ + while (((symbol = litlenTree.getSymbol(input)) & ~0xff) == 0) + { + outputWindow.write(symbol); + if (--free < 258) + return true; + } + if (symbol < 257) + { + if (symbol < 0) + return false; + else + { + /* symbol == 256: end of block */ + distTree = null; + litlenTree = null; + mode = DECODE_BLOCKS; + return true; + } + } + + try + { + repLength = CPLENS[symbol - 257]; + neededBits = CPLEXT[symbol - 257]; + } + catch (ArrayIndexOutOfBoundsException ex) + { + throw new DataFormatException("Illegal rep length code"); + } + /* fall through */ + case DECODE_HUFFMAN_LENBITS: + if (neededBits > 0) + { + mode = DECODE_HUFFMAN_LENBITS; + int i = input.peekBits(neededBits); + if (i < 0) + return false; + input.dropBits(neededBits); + repLength += i; + } + mode = DECODE_HUFFMAN_DIST; + /* fall through */ + case DECODE_HUFFMAN_DIST: + symbol = distTree.getSymbol(input); + if (symbol < 0) + return false; + try + { + repDist = CPDIST[symbol]; + neededBits = CPDEXT[symbol]; + } + catch (ArrayIndexOutOfBoundsException ex) + { + throw new DataFormatException("Illegal rep dist code"); + } + /* fall through */ + case DECODE_HUFFMAN_DISTBITS: + if (neededBits > 0) + { + mode = DECODE_HUFFMAN_DISTBITS; + int i = input.peekBits(neededBits); + if (i < 0) + return false; + input.dropBits(neededBits); + repDist += i; + } + outputWindow.repeat(repLength, repDist); + free -= repLength; + mode = DECODE_HUFFMAN; + break; + default: + throw new IllegalStateException(); + } + } + return true; + } + + /** + * Decodes the adler checksum after the deflate stream. + * @return false if more input is needed. + * @exception DataFormatException if checksum doesn't match. + */ + private boolean decodeChksum () throws DataFormatException + { + while (neededBits > 0) + { + int chkByte = input.peekBits(8); + if (chkByte < 0) + return false; + input.dropBits(8); + readAdler = (readAdler << 8) | chkByte; + neededBits -= 8; + } + if ((int) adler.getValue() != readAdler) + throw new DataFormatException("Adler chksum doesn't match: " + +Integer.toHexString((int)adler.getValue()) + +" vs. "+Integer.toHexString(readAdler)); + mode = FINISHED; + return false; + } + + /** + * Decodes the deflated stream. + * @return false if more input is needed, or if finished. + * @exception DataFormatException if deflated stream is invalid. + */ + private boolean decode () throws DataFormatException + { + switch (mode) + { + case DECODE_HEADER: + return decodeHeader(); + case DECODE_DICT: + return decodeDict(); + case DECODE_CHKSUM: + return decodeChksum(); + + case DECODE_BLOCKS: + if (isLastBlock) + { + if (nowrap) + { + mode = FINISHED; + return false; + } + else + { + input.skipToByteBoundary(); + neededBits = 32; + mode = DECODE_CHKSUM; + return true; + } + } + + int type = input.peekBits(3); + if (type < 0) + return false; + input.dropBits(3); + + if ((type & 1) != 0) + isLastBlock = true; + switch (type >> 1) + { + case DeflaterConstants.STORED_BLOCK: + input.skipToByteBoundary(); + mode = DECODE_STORED_LEN1; + break; + case DeflaterConstants.STATIC_TREES: + litlenTree = InflaterHuffmanTree.defLitLenTree; + distTree = InflaterHuffmanTree.defDistTree; + mode = DECODE_HUFFMAN; + break; + case DeflaterConstants.DYN_TREES: + dynHeader = new InflaterDynHeader(); + mode = DECODE_DYN_HEADER; + break; + default: + throw new DataFormatException("Unknown block type "+type); + } + return true; + + case DECODE_STORED_LEN1: + { + if ((uncomprLen = input.peekBits(16)) < 0) + return false; + input.dropBits(16); + mode = DECODE_STORED_LEN2; + } + /* fall through */ + case DECODE_STORED_LEN2: + { + int nlen = input.peekBits(16); + if (nlen < 0) + return false; + input.dropBits(16); + if (nlen != (uncomprLen ^ 0xffff)) + throw new DataFormatException("broken uncompressed block"); + mode = DECODE_STORED; + } + /* fall through */ + case DECODE_STORED: + { + int more = outputWindow.copyStored(input, uncomprLen); + uncomprLen -= more; + if (uncomprLen == 0) + { + mode = DECODE_BLOCKS; + return true; + } + return !input.needsInput(); + } + + case DECODE_DYN_HEADER: + if (!dynHeader.decode(input)) + return false; + litlenTree = dynHeader.buildLitLenTree(); + distTree = dynHeader.buildDistTree(); + mode = DECODE_HUFFMAN; + /* fall through */ + case DECODE_HUFFMAN: + case DECODE_HUFFMAN_LENBITS: + case DECODE_HUFFMAN_DIST: + case DECODE_HUFFMAN_DISTBITS: + return decodeHuffman(); + case FINISHED: + return false; + default: + throw new IllegalStateException(); + } + } +} diff --git a/libjava/classpath/java/util/zip/InflaterDynHeader.java b/libjava/classpath/java/util/zip/InflaterDynHeader.java new file mode 100644 index 0000000..bff84a8 --- /dev/null +++ b/libjava/classpath/java/util/zip/InflaterDynHeader.java @@ -0,0 +1,203 @@ +/* java.util.zip.InflaterDynHeader + 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 java.util.zip; + +class InflaterDynHeader +{ + private static final int LNUM = 0; + private static final int DNUM = 1; + private static final int BLNUM = 2; + private static final int BLLENS = 3; + private static final int LENS = 4; + private static final int REPS = 5; + + private static final int repMin[] = { 3, 3, 11 }; + private static final int repBits[] = { 2, 3, 7 }; + + + private byte[] blLens; + private byte[] litdistLens; + + private InflaterHuffmanTree blTree; + + private int mode; + private int lnum, dnum, blnum, num; + private int repSymbol; + private byte lastLen; + private int ptr; + + private static final int[] BL_ORDER = + { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + + public InflaterDynHeader() + { + } + + public boolean decode(StreamManipulator input) throws DataFormatException + { + decode_loop: + for (;;) + { + switch (mode) + { + case LNUM: + lnum = input.peekBits(5); + if (lnum < 0) + return false; + lnum += 257; + input.dropBits(5); +// System.err.println("LNUM: "+lnum); + mode = DNUM; + /* fall through */ + case DNUM: + dnum = input.peekBits(5); + if (dnum < 0) + return false; + dnum++; + input.dropBits(5); +// System.err.println("DNUM: "+dnum); + num = lnum+dnum; + litdistLens = new byte[num]; + mode = BLNUM; + /* fall through */ + case BLNUM: + blnum = input.peekBits(4); + if (blnum < 0) + return false; + blnum += 4; + input.dropBits(4); + blLens = new byte[19]; + ptr = 0; +// System.err.println("BLNUM: "+blnum); + mode = BLLENS; + /* fall through */ + case BLLENS: + while (ptr < blnum) + { + int len = input.peekBits(3); + if (len < 0) + return false; + input.dropBits(3); +// System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len); + blLens[BL_ORDER[ptr]] = (byte) len; + ptr++; + } + blTree = new InflaterHuffmanTree(blLens); + blLens = null; + ptr = 0; + mode = LENS; + /* fall through */ + case LENS: + { + int symbol; + while (((symbol = blTree.getSymbol(input)) & ~15) == 0) + { + /* Normal case: symbol in [0..15] */ + +// System.err.println("litdistLens["+ptr+"]: "+symbol); + litdistLens[ptr++] = lastLen = (byte) symbol; + + if (ptr == num) + { + /* Finished */ + return true; + } + } + + /* need more input ? */ + if (symbol < 0) + return false; + + /* otherwise repeat code */ + if (symbol >= 17) + { + /* repeat zero */ +// System.err.println("repeating zero"); + lastLen = 0; + } + else + { + if (ptr == 0) + throw new DataFormatException(); + } + repSymbol = symbol-16; + mode = REPS; + } + /* fall through */ + + case REPS: + { + int bits = repBits[repSymbol]; + int count = input.peekBits(bits); + if (count < 0) + return false; + input.dropBits(bits); + count += repMin[repSymbol]; +// System.err.println("litdistLens repeated: "+count); + + if (ptr + count > num) + throw new DataFormatException(); + while (count-- > 0) + litdistLens[ptr++] = lastLen; + + if (ptr == num) + { + /* Finished */ + return true; + } + } + mode = LENS; + continue decode_loop; + } + } + } + + public InflaterHuffmanTree buildLitLenTree() throws DataFormatException + { + byte[] litlenLens = new byte[lnum]; + System.arraycopy(litdistLens, 0, litlenLens, 0, lnum); + return new InflaterHuffmanTree(litlenLens); + } + + public InflaterHuffmanTree buildDistTree() throws DataFormatException + { + byte[] distLens = new byte[dnum]; + System.arraycopy(litdistLens, lnum, distLens, 0, dnum); + return new InflaterHuffmanTree(distLens); + } +} diff --git a/libjava/classpath/java/util/zip/InflaterHuffmanTree.java b/libjava/classpath/java/util/zip/InflaterHuffmanTree.java new file mode 100644 index 0000000..6c9b217 --- /dev/null +++ b/libjava/classpath/java/util/zip/InflaterHuffmanTree.java @@ -0,0 +1,217 @@ +/* InflaterHuffmanTree.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 java.util.zip; + +class InflaterHuffmanTree +{ + private static final int MAX_BITLEN = 15; + + private short[] tree; + + static InflaterHuffmanTree defLitLenTree, defDistTree; + + static + { + try + { + byte[] codeLengths = new byte[288]; + int i = 0; + while (i < 144) + codeLengths[i++] = 8; + while (i < 256) + codeLengths[i++] = 9; + while (i < 280) + codeLengths[i++] = 7; + while (i < 288) + codeLengths[i++] = 8; + defLitLenTree = new InflaterHuffmanTree(codeLengths); + + codeLengths = new byte[32]; + i = 0; + while (i < 32) + codeLengths[i++] = 5; + defDistTree = new InflaterHuffmanTree(codeLengths); + } + catch (DataFormatException ex) + { + throw new InternalError + ("InflaterHuffmanTree: static tree length illegal"); + } + } + + /** + * Constructs a Huffman tree from the array of code lengths. + * + * @param codeLengths the array of code lengths + */ + InflaterHuffmanTree(byte[] codeLengths) throws DataFormatException + { + buildTree(codeLengths); + } + + private void buildTree(byte[] codeLengths) throws DataFormatException + { + int[] blCount = new int[MAX_BITLEN+1]; + int[] nextCode = new int[MAX_BITLEN+1]; + for (int i = 0; i < codeLengths.length; i++) + { + int bits = codeLengths[i]; + if (bits > 0) + blCount[bits]++; + } + + int code = 0; + int treeSize = 512; + for (int bits = 1; bits <= MAX_BITLEN; bits++) + { + nextCode[bits] = code; + code += blCount[bits] << (16 - bits); + if (bits >= 10) + { + /* We need an extra table for bit lengths >= 10. */ + int start = nextCode[bits] & 0x1ff80; + int end = code & 0x1ff80; + treeSize += (end - start) >> (16 - bits); + } + } + if (code != 65536) + throw new DataFormatException("Code lengths don't add up properly."); + + /* Now create and fill the extra tables from longest to shortest + * bit len. This way the sub trees will be aligned. + */ + tree = new short[treeSize]; + int treePtr = 512; + for (int bits = MAX_BITLEN; bits >= 10; bits--) + { + int end = code & 0x1ff80; + code -= blCount[bits] << (16 - bits); + int start = code & 0x1ff80; + for (int i = start; i < end; i += 1 << 7) + { + tree[DeflaterHuffman.bitReverse(i)] + = (short) ((-treePtr << 4) | bits); + treePtr += 1 << (bits-9); + } + } + + for (int i = 0; i < codeLengths.length; i++) + { + int bits = codeLengths[i]; + if (bits == 0) + continue; + code = nextCode[bits]; + int revcode = DeflaterHuffman.bitReverse(code); + if (bits <= 9) + { + do + { + tree[revcode] = (short) ((i << 4) | bits); + revcode += 1 << bits; + } + while (revcode < 512); + } + else + { + int subTree = tree[revcode & 511]; + int treeLen = 1 << (subTree & 15); + subTree = -(subTree >> 4); + do + { + tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits); + revcode += 1 << bits; + } + while (revcode < treeLen); + } + nextCode[bits] = code + (1 << (16 - bits)); + } + } + + /** + * Reads the next symbol from input. The symbol is encoded using the + * huffman tree. + * @param input the input source. + * @return the next symbol, or -1 if not enough input is available. + */ + int getSymbol(StreamManipulator input) throws DataFormatException + { + int lookahead, symbol; + if ((lookahead = input.peekBits(9)) >= 0) + { + if ((symbol = tree[lookahead]) >= 0) + { + input.dropBits(symbol & 15); + return symbol >> 4; + } + int subtree = -(symbol >> 4); + int bitlen = symbol & 15; + if ((lookahead = input.peekBits(bitlen)) >= 0) + { + symbol = tree[subtree | (lookahead >> 9)]; + input.dropBits(symbol & 15); + return symbol >> 4; + } + else + { + int bits = input.getAvailableBits(); + lookahead = input.peekBits(bits); + symbol = tree[subtree | (lookahead >> 9)]; + if ((symbol & 15) <= bits) + { + input.dropBits(symbol & 15); + return symbol >> 4; + } + else + return -1; + } + } + else + { + int bits = input.getAvailableBits(); + lookahead = input.peekBits(bits); + symbol = tree[lookahead]; + if (symbol >= 0 && (symbol & 15) <= bits) + { + input.dropBits(symbol & 15); + return symbol >> 4; + } + else + return -1; + } + } +} diff --git a/libjava/classpath/java/util/zip/InflaterInputStream.java b/libjava/classpath/java/util/zip/InflaterInputStream.java new file mode 100644 index 0000000..3c37457 --- /dev/null +++ b/libjava/classpath/java/util/zip/InflaterInputStream.java @@ -0,0 +1,261 @@ +/* InflaterInputStream.java - Input stream filter for decompressing + Copyright (C) 1999, 2000, 2001, 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 java.util.zip; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * This filter stream is used to decompress data compressed in the "deflate" + * format. The "deflate" format is described in RFC 1951. + * + * This stream may form the basis for other decompression filters, such + * as the GZIPInputStream. + * + * @author John Leuner + * @author Tom Tromey + * @since 1.1 + */ +public class InflaterInputStream extends FilterInputStream +{ + /** + * Decompressor for this filter + */ + protected Inflater inf; + + /** + * Byte array used as a buffer + */ + protected byte[] buf; + + /** + * Size of buffer + */ + protected int len; + + // We just use this if we are decoding one byte at a time with the + // read() call. + private byte[] onebytebuffer = new byte[1]; + + /** + * Create an InflaterInputStream with the default decompresseor + * and a default buffer size. + * + * @param in the InputStream to read bytes from + */ + public InflaterInputStream(InputStream in) + { + this(in, new Inflater(), 4096); + } + + /** + * Create an InflaterInputStream with the specified decompresseor + * and a default buffer size. + * + * @param in the InputStream to read bytes from + * @param inf the decompressor used to decompress data read from in + */ + public InflaterInputStream(InputStream in, Inflater inf) + { + this(in, inf, 4096); + } + + /** + * Create an InflaterInputStream with the specified decompresseor + * and a specified buffer size. + * + * @param in the InputStream to read bytes from + * @param inf the decompressor used to decompress data read from in + * @param size size of the buffer to use + */ + public InflaterInputStream(InputStream in, Inflater inf, int size) + { + super(in); + + if (in == null) + throw new NullPointerException("in may not be null"); + if (inf == null) + throw new NullPointerException("inf may not be null"); + if (size < 0) + throw new IllegalArgumentException("size may not be negative"); + + this.inf = inf; + this.buf = new byte [size]; + } + + /** + * Returns 0 once the end of the stream (EOF) has been reached. + * Otherwise returns 1. + */ + public int available() throws IOException + { + // According to the JDK 1.2 docs, this should only ever return 0 + // or 1 and should not be relied upon by Java programs. + if (inf == null) + throw new IOException("stream closed"); + return inf.finished() ? 0 : 1; + } + + /** + * Closes the input stream + */ + public synchronized void close() throws IOException + { + if (in != null) + in.close(); + in = null; + } + + /** + * Fills the buffer with more data to decompress. + */ + protected void fill() throws IOException + { + if (in == null) + throw new ZipException ("InflaterInputStream is closed"); + + len = in.read(buf, 0, buf.length); + + if (len < 0) + throw new ZipException("Deflated stream ends early."); + + inf.setInput(buf, 0, len); + } + + /** + * Reads one byte of decompressed data. + * + * The byte is in the lower 8 bits of the int. + */ + public int read() throws IOException + { + int nread = read(onebytebuffer, 0, 1); + if (nread > 0) + return onebytebuffer[0] & 0xff; + return -1; + } + + /** + * Decompresses data into the byte array + * + * @param b the array to read and decompress data into + * @param off the offset indicating where the data should be placed + * @param len the number of bytes to decompress + */ + public int read(byte[] b, int off, int len) throws IOException + { + if (inf == null) + throw new IOException("stream closed"); + if (len == 0) + return 0; + + int count = 0; + for (;;) + { + + try + { + count = inf.inflate(b, off, len); + } + catch (DataFormatException dfe) + { + throw new ZipException(dfe.getMessage()); + } + + if (count > 0) + return count; + + if (inf.needsDictionary() + | inf.finished()) + return -1; + else if (inf.needsInput()) + fill(); + else + throw new InternalError("Don't know what to do"); + } + } + + /** + * Skip specified number of bytes of uncompressed data + * + * @param n number of bytes to skip + */ + public long skip(long n) throws IOException + { + if (inf == null) + throw new IOException("stream closed"); + if (n < 0) + throw new IllegalArgumentException(); + + if (n == 0) + return 0; + + int buflen = (int) Math.min(n, 2048); + byte[] tmpbuf = new byte[buflen]; + + long skipped = 0L; + while (n > 0L) + { + int numread = read(tmpbuf, 0, buflen); + if (numread <= 0) + break; + n -= numread; + skipped += numread; + buflen = (int) Math.min(n, 2048); + } + + return skipped; + } + + public boolean markSupported() + { + return false; + } + + public void mark(int readLimit) + { + } + + public void reset() throws IOException + { + throw new IOException("reset not supported"); + } +} diff --git a/libjava/classpath/java/util/zip/OutputWindow.java b/libjava/classpath/java/util/zip/OutputWindow.java new file mode 100644 index 0000000..1f082a9 --- /dev/null +++ b/libjava/classpath/java/util/zip/OutputWindow.java @@ -0,0 +1,178 @@ +/* OutputWindow.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 java.util.zip; + +/** + * Contains the output from the Inflation process. + * + * We need to have a window so that we can refer backwards into the output stream + * to repeat stuff. + * + * @author John Leuner + * @since 1.1 + */ +class OutputWindow +{ + private static final int WINDOW_SIZE = 1 << 15; + private static final int WINDOW_MASK = WINDOW_SIZE - 1; + + private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes + private int window_end = 0; + private int window_filled = 0; + + public void write(int abyte) + { + if (window_filled++ == WINDOW_SIZE) + throw new IllegalStateException("Window full"); + window[window_end++] = (byte) abyte; + window_end &= WINDOW_MASK; + } + + private void slowRepeat(int rep_start, int len, int dist) + { + while (len-- > 0) + { + window[window_end++] = window[rep_start++]; + window_end &= WINDOW_MASK; + rep_start &= WINDOW_MASK; + } + } + + public void repeat(int len, int dist) + { + if ((window_filled += len) > WINDOW_SIZE) + throw new IllegalStateException("Window full"); + + int rep_start = (window_end - dist) & WINDOW_MASK; + int border = WINDOW_SIZE - len; + if (rep_start <= border && window_end < border) + { + if (len <= dist) + { + System.arraycopy(window, rep_start, window, window_end, len); + window_end += len; + } + else + { + /* We have to copy manually, since the repeat pattern overlaps. + */ + while (len-- > 0) + window[window_end++] = window[rep_start++]; + } + } + else + slowRepeat(rep_start, len, dist); + } + + public int copyStored(StreamManipulator input, int len) + { + len = Math.min(Math.min(len, WINDOW_SIZE - window_filled), + input.getAvailableBytes()); + int copied; + + int tailLen = WINDOW_SIZE - window_end; + if (len > tailLen) + { + copied = input.copyBytes(window, window_end, tailLen); + if (copied == tailLen) + copied += input.copyBytes(window, 0, len - tailLen); + } + else + copied = input.copyBytes(window, window_end, len); + + window_end = (window_end + copied) & WINDOW_MASK; + window_filled += copied; + return copied; + } + + public void copyDict(byte[] dict, int offset, int len) + { + if (window_filled > 0) + throw new IllegalStateException(); + + if (len > WINDOW_SIZE) + { + offset += len - WINDOW_SIZE; + len = WINDOW_SIZE; + } + System.arraycopy(dict, offset, window, 0, len); + window_end = len & WINDOW_MASK; + } + + public int getFreeSpace() + { + return WINDOW_SIZE - window_filled; + } + + public int getAvailable() + { + return window_filled; + } + + public int copyOutput(byte[] output, int offset, int len) + { + int copy_end = window_end; + if (len > window_filled) + len = window_filled; + else + copy_end = (window_end - window_filled + len) & WINDOW_MASK; + + int copied = len; + int tailLen = len - copy_end; + + if (tailLen > 0) + { + System.arraycopy(window, WINDOW_SIZE - tailLen, + output, offset, tailLen); + offset += tailLen; + len = copy_end; + } + System.arraycopy(window, copy_end - len, output, offset, len); + window_filled -= copied; + if (window_filled < 0) + throw new IllegalStateException(); + return copied; + } + + public void reset() { + window_filled = window_end = 0; + } +} + + + diff --git a/libjava/classpath/java/util/zip/PendingBuffer.java b/libjava/classpath/java/util/zip/PendingBuffer.java new file mode 100644 index 0000000..dd7ed10 --- /dev/null +++ b/libjava/classpath/java/util/zip/PendingBuffer.java @@ -0,0 +1,200 @@ +/* java.util.zip.PendingBuffer + 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 java.util.zip; + +/** + * This class is general purpose class for writing data to a buffer. + * + * It allows you to write bits as well as bytes + * + * Based on DeflaterPending.java + * + * @author Jochen Hoenicke + * @date Jan 5, 2000 + */ + +class PendingBuffer +{ + protected byte[] buf; + int start; + int end; + + int bits; + int bitCount; + + public PendingBuffer() + { + this( 4096 ); + } + + public PendingBuffer(int bufsize) + { + buf = new byte[bufsize]; + } + + public final void reset() { + start = end = bitCount = 0; + } + + public final void writeByte(int b) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException(); + buf[end++] = (byte) b; + } + + public final void writeShort(int s) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException(); + buf[end++] = (byte) s; + buf[end++] = (byte) (s >> 8); + } + + public final void writeInt(int s) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException(); + buf[end++] = (byte) s; + buf[end++] = (byte) (s >> 8); + buf[end++] = (byte) (s >> 16); + buf[end++] = (byte) (s >> 24); + } + + public final void writeBlock(byte[] block, int offset, int len) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException(); + System.arraycopy(block, offset, buf, end, len); + end += len; + } + + public final int getBitCount() { + return bitCount; + } + + public final void alignToByte() { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException(); + if (bitCount > 0) + { + buf[end++] = (byte) bits; + if (bitCount > 8) + buf[end++] = (byte) (bits >>> 8); + } + bits = 0; + bitCount = 0; + } + + public final void writeBits(int b, int count) + { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException(); + if (DeflaterConstants.DEBUGGING) + System.err.println("writeBits("+Integer.toHexString(b)+","+count+")"); + bits |= b << bitCount; + bitCount += count; + if (bitCount >= 16) { + buf[end++] = (byte) bits; + buf[end++] = (byte) (bits >>> 8); + bits >>>= 16; + bitCount -= 16; + } + } + + public final void writeShortMSB(int s) { + if (DeflaterConstants.DEBUGGING && start != 0) + throw new IllegalStateException(); + buf[end++] = (byte) (s >> 8); + buf[end++] = (byte) s; + } + + public final boolean isFlushed() { + return end == 0; + } + + /** + * Flushes the pending buffer into the given output array. If the + * output array is to small, only a partial flush is done. + * + * @param output the output array; + * @param offset the offset into output array; + * @param length the maximum number of bytes to store; + * @exception IndexOutOfBoundsException if offset or length are + * invalid. + */ + public final int flush(byte[] output, int offset, int length) { + if (bitCount >= 8) + { + buf[end++] = (byte) bits; + bits >>>= 8; + bitCount -= 8; + } + if (length > end - start) + { + length = end - start; + System.arraycopy(buf, start, output, offset, length); + start = 0; + end = 0; + } + else + { + System.arraycopy(buf, start, output, offset, length); + start += length; + } + return length; + } + + /** + * Flushes the pending buffer and returns that data in a new array + * + * @param output the output stream + */ + + public final byte[] toByteArray() + { + byte[] ret = new byte[ end - start ]; + System.arraycopy(buf, start, ret, 0, ret.length); + start = 0; + end = 0; + return ret; + } + + +} + diff --git a/libjava/classpath/java/util/zip/StreamManipulator.java b/libjava/classpath/java/util/zip/StreamManipulator.java new file mode 100644 index 0000000..57d15ae --- /dev/null +++ b/libjava/classpath/java/util/zip/StreamManipulator.java @@ -0,0 +1,216 @@ +/* java.util.zip.StreamManipulator + 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 java.util.zip; + +/** + * This class allows us to retrieve a specified amount of bits from + * the input buffer, as well as copy big byte blocks. + * + * It uses an int buffer to store up to 31 bits for direct + * manipulation. This guarantees that we can get at least 16 bits, + * but we only need at most 15, so this is all safe. + * + * There are some optimizations in this class, for example, you must + * never peek more then 8 bits more than needed, and you must first + * peek bits before you may drop them. This is not a general purpose + * class but optimized for the behaviour of the Inflater. + * + * @author John Leuner, Jochen Hoenicke + */ + +class StreamManipulator +{ + private byte[] window; + private int window_start = 0; + private int window_end = 0; + + private int buffer = 0; + private int bits_in_buffer = 0; + + /** + * Get the next n bits but don't increase input pointer. n must be + * less or equal 16 and if you if this call succeeds, you must drop + * at least n-8 bits in the next call. + * + * @return the value of the bits, or -1 if not enough bits available. */ + public final int peekBits(int n) + { + if (bits_in_buffer < n) + { + if (window_start == window_end) + return -1; + buffer |= (window[window_start++] & 0xff + | (window[window_start++] & 0xff) << 8) << bits_in_buffer; + bits_in_buffer += 16; + } + return buffer & ((1 << n) - 1); + } + + /* Drops the next n bits from the input. You should have called peekBits + * with a bigger or equal n before, to make sure that enough bits are in + * the bit buffer. + */ + public final void dropBits(int n) + { + buffer >>>= n; + bits_in_buffer -= n; + } + + /** + * Gets the next n bits and increases input pointer. This is equivalent + * to peekBits followed by dropBits, except for correct error handling. + * @return the value of the bits, or -1 if not enough bits available. + */ + public final int getBits(int n) + { + int bits = peekBits(n); + if (bits >= 0) + dropBits(n); + return bits; + } + /** + * Gets the number of bits available in the bit buffer. This must be + * only called when a previous peekBits() returned -1. + * @return the number of bits available. + */ + public final int getAvailableBits() + { + return bits_in_buffer; + } + + /** + * Gets the number of bytes available. + * @return the number of bytes available. + */ + public final int getAvailableBytes() + { + return window_end - window_start + (bits_in_buffer >> 3); + } + + /** + * Skips to the next byte boundary. + */ + public void skipToByteBoundary() + { + buffer >>= (bits_in_buffer & 7); + bits_in_buffer &= ~7; + } + + public final boolean needsInput() { + return window_start == window_end; + } + + + /* Copies length bytes from input buffer to output buffer starting + * at output[offset]. You have to make sure, that the buffer is + * byte aligned. If not enough bytes are available, copies fewer + * bytes. + * @param length the length to copy, 0 is allowed. + * @return the number of bytes copied, 0 if no byte is available. + */ + public int copyBytes(byte[] output, int offset, int length) + { + if (length < 0) + throw new IllegalArgumentException("length negative"); + if ((bits_in_buffer & 7) != 0) + /* bits_in_buffer may only be 0 or 8 */ + throw new IllegalStateException("Bit buffer is not aligned!"); + + int count = 0; + while (bits_in_buffer > 0 && length > 0) + { + output[offset++] = (byte) buffer; + buffer >>>= 8; + bits_in_buffer -= 8; + length--; + count++; + } + if (length == 0) + return count; + + int avail = window_end - window_start; + if (length > avail) + length = avail; + System.arraycopy(window, window_start, output, offset, length); + window_start += length; + + if (((window_start - window_end) & 1) != 0) + { + /* We always want an even number of bytes in input, see peekBits */ + buffer = (window[window_start++] & 0xff); + bits_in_buffer = 8; + } + return count + length; + } + + public StreamManipulator() + { + } + + public void reset() + { + window_start = window_end = buffer = bits_in_buffer = 0; + } + + public void setInput(byte[] buf, int off, int len) + { + if (window_start < window_end) + throw new IllegalStateException + ("Old input was not completely processed"); + + int end = off + len; + + /* We want to throw an ArrayIndexOutOfBoundsException early. The + * check is very tricky: it also handles integer wrap around. + */ + if (0 > off || off > end || end > buf.length) + throw new ArrayIndexOutOfBoundsException(); + + if ((len & 1) != 0) + { + /* We always want an even number of bytes in input, see peekBits */ + buffer |= (buf[off++] & 0xff) << bits_in_buffer; + bits_in_buffer += 8; + } + + window = buf; + window_start = off; + window_end = end; + } +} + diff --git a/libjava/classpath/java/util/zip/ZipConstants.java b/libjava/classpath/java/util/zip/ZipConstants.java new file mode 100644 index 0000000..952a44d --- /dev/null +++ b/libjava/classpath/java/util/zip/ZipConstants.java @@ -0,0 +1,97 @@ +/* java.util.zip.ZipConstants + 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 java.util.zip; + +interface ZipConstants +{ + /* The local file header */ + int LOCHDR = 30; + int LOCSIG = 'P'|('K'<<8)|(3<<16)|(4<<24); + + int LOCVER = 4; + int LOCFLG = 6; + int LOCHOW = 8; + int LOCTIM = 10; + int LOCCRC = 14; + int LOCSIZ = 18; + int LOCLEN = 22; + int LOCNAM = 26; + int LOCEXT = 28; + + /* The Data descriptor */ + int EXTSIG = 'P'|('K'<<8)|(7<<16)|(8<<24); + int EXTHDR = 16; + + int EXTCRC = 4; + int EXTSIZ = 8; + int EXTLEN = 12; + + /* The central directory file header */ + int CENSIG = 'P'|('K'<<8)|(1<<16)|(2<<24); + int CENHDR = 46; + + int CENVEM = 4; + int CENVER = 6; + int CENFLG = 8; + int CENHOW = 10; + int CENTIM = 12; + int CENCRC = 16; + int CENSIZ = 20; + int CENLEN = 24; + int CENNAM = 28; + int CENEXT = 30; + int CENCOM = 32; + int CENDSK = 34; + int CENATT = 36; + int CENATX = 38; + int CENOFF = 42; + + /* The entries in the end of central directory */ + int ENDSIG = 'P'|('K'<<8)|(5<<16)|(6<<24); + int ENDHDR = 22; + + /* The following two fields are missing in SUN JDK */ + int ENDNRD = 4; + int ENDDCD = 6; + int ENDSUB = 8; + int ENDTOT = 10; + int ENDSIZ = 12; + int ENDOFF = 16; + int ENDCOM = 20; +} + diff --git a/libjava/classpath/java/util/zip/ZipEntry.java b/libjava/classpath/java/util/zip/ZipEntry.java new file mode 100644 index 0000000..ae21997 --- /dev/null +++ b/libjava/classpath/java/util/zip/ZipEntry.java @@ -0,0 +1,432 @@ +/* ZipEntry.java -- + Copyright (C) 2001, 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 java.util.zip; + +import java.util.Calendar; +import java.util.Date; + +/** + * This class represents a member of a zip archive. ZipFile and + * ZipInputStream will give you instances of this class as information + * about the members in an archive. On the other hand ZipOutputStream + * needs an instance of this class to create a new member. + * + * @author Jochen Hoenicke + */ +public class ZipEntry implements ZipConstants, Cloneable +{ + private static final int KNOWN_SIZE = 1; + private static final int KNOWN_CSIZE = 2; + private static final int KNOWN_CRC = 4; + private static final int KNOWN_TIME = 8; + private static final int KNOWN_EXTRA = 16; + + private static Calendar cal; + + private String name; + private int size; + private long compressedSize = -1; + private int crc; + private int dostime; + private short known = 0; + private short method = -1; + private byte[] extra = null; + private String comment = null; + + int flags; /* used by ZipOutputStream */ + int offset; /* used by ZipFile and ZipOutputStream */ + + /** + * Compression method. This method doesn't compress at all. + */ + public static final int STORED = 0; + /** + * Compression method. This method uses the Deflater. + */ + public static final int DEFLATED = 8; + + /** + * Creates a zip entry with the given name. + * @param name the name. May include directory components separated + * by '/'. + * + * @exception NullPointerException when name is null. + * @exception IllegalArgumentException when name is bigger then 65535 chars. + */ + public ZipEntry(String name) + { + int length = name.length(); + if (length > 65535) + throw new IllegalArgumentException("name length is " + length); + this.name = name; + } + + /** + * Creates a copy of the given zip entry. + * @param e the entry to copy. + */ + public ZipEntry(ZipEntry e) + { + this(e, e.name); + } + + ZipEntry(ZipEntry e, String name) + { + this.name = name; + known = e.known; + size = e.size; + compressedSize = e.compressedSize; + crc = e.crc; + dostime = e.dostime; + method = e.method; + extra = e.extra; + comment = e.comment; + } + + final void setDOSTime(int dostime) + { + this.dostime = dostime; + known |= KNOWN_TIME; + } + + final int getDOSTime() + { + if ((known & KNOWN_TIME) == 0) + return 0; + else + return dostime; + } + + /** + * Creates a copy of this zip entry. + */ + /** + * Clones the entry. + */ + public Object clone() + { + try + { + // The JCL says that the `extra' field is also copied. + ZipEntry clone = (ZipEntry) super.clone(); + if (extra != null) + clone.extra = (byte[]) extra.clone(); + return clone; + } + catch (CloneNotSupportedException ex) + { + throw new InternalError(); + } + } + + /** + * Returns the entry name. The path components in the entry are + * always separated by slashes ('/'). + */ + public String getName() + { + return name; + } + + /** + * Sets the time of last modification of the entry. + * @time the time of last modification of the entry. + */ + public void setTime(long time) + { + Calendar cal = getCalendar(); + synchronized (cal) + { + cal.setTime(new Date(time)); + dostime = (cal.get(Calendar.YEAR) - 1980 & 0x7f) << 25 + | (cal.get(Calendar.MONTH) + 1) << 21 + | (cal.get(Calendar.DAY_OF_MONTH)) << 16 + | (cal.get(Calendar.HOUR_OF_DAY)) << 11 + | (cal.get(Calendar.MINUTE)) << 5 + | (cal.get(Calendar.SECOND)) >> 1; + } + this.known |= KNOWN_TIME; + } + + /** + * Gets the time of last modification of the entry. + * @return the time of last modification of the entry, or -1 if unknown. + */ + public long getTime() + { + if ((known & KNOWN_TIME) == 0) + return -1; + + // The extra bytes might contain the time (posix/unix extension) + parseExtra (); + + int sec = 2 * (dostime & 0x1f); + int min = (dostime >> 5) & 0x3f; + int hrs = (dostime >> 11) & 0x1f; + int day = (dostime >> 16) & 0x1f; + int mon = ((dostime >> 21) & 0xf) - 1; + int year = ((dostime >> 25) & 0x7f) + 1980; /* since 1900 */ + + try + { + cal = getCalendar(); + synchronized (cal) + { + cal.set(year, mon, day, hrs, min, sec); + return cal.getTime().getTime(); + } + } + catch (RuntimeException ex) + { + /* Ignore illegal time stamp */ + known &= ~KNOWN_TIME; + return -1; + } + } + + private static synchronized Calendar getCalendar() + { + if (cal == null) + cal = Calendar.getInstance(); + + return cal; + } + + /** + * Sets the size of the uncompressed data. + * @exception IllegalArgumentException if size is not in 0..0xffffffffL + */ + public void setSize(long size) + { + if ((size & 0xffffffff00000000L) != 0) + throw new IllegalArgumentException(); + this.size = (int) size; + this.known |= KNOWN_SIZE; + } + + /** + * Gets the size of the uncompressed data. + * @return the size or -1 if unknown. + */ + public long getSize() + { + return (known & KNOWN_SIZE) != 0 ? size & 0xffffffffL : -1L; + } + + /** + * Sets the size of the compressed data. + */ + public void setCompressedSize(long csize) + { + this.compressedSize = csize; + } + + /** + * Gets the size of the compressed data. + * @return the size or -1 if unknown. + */ + public long getCompressedSize() + { + return compressedSize; + } + + /** + * Sets the crc of the uncompressed data. + * @exception IllegalArgumentException if crc is not in 0..0xffffffffL + */ + public void setCrc(long crc) + { + if ((crc & 0xffffffff00000000L) != 0) + throw new IllegalArgumentException(); + this.crc = (int) crc; + this.known |= KNOWN_CRC; + } + + /** + * Gets the crc of the uncompressed data. + * @return the crc or -1 if unknown. + */ + public long getCrc() + { + return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L; + } + + /** + * Sets the compression method. Only DEFLATED and STORED are + * supported. + * @exception IllegalArgumentException if method is not supported. + * @see ZipOutputStream#DEFLATED + * @see ZipOutputStream#STORED + */ + public void setMethod(int method) + { + if (method != ZipOutputStream.STORED + && method != ZipOutputStream.DEFLATED) + throw new IllegalArgumentException(); + this.method = (short) method; + } + + /** + * Gets the compression method. + * @return the compression method or -1 if unknown. + */ + public int getMethod() + { + return method; + } + + /** + * Sets the extra data. + * @exception IllegalArgumentException if extra is longer than 0xffff bytes. + */ + public void setExtra(byte[] extra) + { + if (extra == null) + { + this.extra = null; + return; + } + if (extra.length > 0xffff) + throw new IllegalArgumentException(); + this.extra = extra; + } + + private void parseExtra() + { + // Already parsed? + if ((known & KNOWN_EXTRA) != 0) + return; + + if (extra == null) + { + known |= KNOWN_EXTRA; + return; + } + + try + { + int pos = 0; + while (pos < extra.length) + { + int sig = (extra[pos++] & 0xff) + | (extra[pos++] & 0xff) << 8; + int len = (extra[pos++] & 0xff) + | (extra[pos++] & 0xff) << 8; + if (sig == 0x5455) + { + /* extended time stamp */ + int flags = extra[pos]; + if ((flags & 1) != 0) + { + long time = ((extra[pos+1] & 0xff) + | (extra[pos+2] & 0xff) << 8 + | (extra[pos+3] & 0xff) << 16 + | (extra[pos+4] & 0xff) << 24); + setTime(time); + } + } + pos += len; + } + } + catch (ArrayIndexOutOfBoundsException ex) + { + /* be lenient */ + return; + } + + known |= KNOWN_EXTRA; + } + + /** + * Gets the extra data. + * @return the extra data or null if not set. + */ + public byte[] getExtra() + { + return extra; + } + + /** + * Sets the entry comment. + * @exception IllegalArgumentException if comment is longer than 0xffff. + */ + public void setComment(String comment) + { + if (comment != null && comment.length() > 0xffff) + throw new IllegalArgumentException(); + this.comment = comment; + } + + /** + * Gets the comment. + * @return the comment or null if not set. + */ + public String getComment() + { + return comment; + } + + /** + * Gets true, if the entry is a directory. This is solely + * determined by the name, a trailing slash '/' marks a directory. + */ + public boolean isDirectory() + { + int nlen = name.length(); + return nlen > 0 && name.charAt(nlen - 1) == '/'; + } + + /** + * Gets the string representation of this ZipEntry. This is just + * the name as returned by getName(). + */ + public String toString() + { + return name; + } + + /** + * Gets the hashCode of this ZipEntry. This is just the hashCode + * of the name. Note that the equals method isn't changed, though. + */ + public int hashCode() + { + return name.hashCode(); + } +} diff --git a/libjava/classpath/java/util/zip/ZipException.java b/libjava/classpath/java/util/zip/ZipException.java new file mode 100644 index 0000000..c5bfc1e --- /dev/null +++ b/libjava/classpath/java/util/zip/ZipException.java @@ -0,0 +1,72 @@ +/* ZipException.java - exception representing a zip related error + Copyright (C) 1998, 1999, 2000, 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 java.util.zip; + +import java.io.IOException; + +/** + * Thrown during the creation or input of a zip file. + * + * @author Jochen Hoenicke + * @author Per Bothner + * @status updated to 1.4 + */ +public class ZipException extends IOException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 8000196834066748623L; + + /** + * Create an exception without a message. + */ + public ZipException() + { + } + + /** + * Create an exception with a message. + * + * @param msg the message + */ + public ZipException (String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/util/zip/ZipFile.java b/libjava/classpath/java/util/zip/ZipFile.java new file mode 100644 index 0000000..33f67c7 --- /dev/null +++ b/libjava/classpath/java/util/zip/ZipFile.java @@ -0,0 +1,595 @@ +/* ZipFile.java -- + Copyright (C) 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 java.util.zip; + +import gnu.java.util.EmptyEnumeration; + +import java.io.BufferedInputStream; +import java.io.DataInput; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; + +/** + * This class represents a Zip archive. You can ask for the contained + * entries, or get an input stream for a file entry. The entry is + * automatically decompressed. + * + * This class is thread safe: You can open input streams for arbitrary + * entries in different threads. + * + * @author Jochen Hoenicke + * @author Artur Biesiadowski + */ +public class ZipFile implements ZipConstants +{ + + /** + * Mode flag to open a zip file for reading. + */ + public static final int OPEN_READ = 0x1; + + /** + * Mode flag to delete a zip file after reading. + */ + public static final int OPEN_DELETE = 0x4; + + // Name of this zip file. + private final String name; + + // File from which zip entries are read. + private final RandomAccessFile raf; + + // The entries of this zip file when initialized and not yet closed. + private HashMap entries; + + private boolean closed = false; + + /** + * Opens a Zip file with the given name for reading. + * @exception IOException if a i/o error occured. + * @exception ZipException if the file doesn't contain a valid zip + * archive. + */ + public ZipFile(String name) throws ZipException, IOException + { + this.raf = new RandomAccessFile(name, "r"); + this.name = name; + checkZipFile(); + } + + /** + * Opens a Zip file reading the given File. + * @exception IOException if a i/o error occured. + * @exception ZipException if the file doesn't contain a valid zip + * archive. + */ + public ZipFile(File file) throws ZipException, IOException + { + this.raf = new RandomAccessFile(file, "r"); + this.name = file.getPath(); + checkZipFile(); + } + + /** + * Opens a Zip file reading the given File in the given mode. + * + * If the OPEN_DELETE mode is specified, the zip file will be deleted at + * some time moment after it is opened. It will be deleted before the zip + * file is closed or the Virtual Machine exits. + * + * The contents of the zip file will be accessible until it is closed. + * + * @since JDK1.3 + * @param mode Must be one of OPEN_READ or OPEN_READ | OPEN_DELETE + * + * @exception IOException if a i/o error occured. + * @exception ZipException if the file doesn't contain a valid zip + * archive. + */ + public ZipFile(File file, int mode) throws ZipException, IOException + { + if (mode != OPEN_READ && mode != (OPEN_READ | OPEN_DELETE)) + throw new IllegalArgumentException("invalid mode"); + if ((mode & OPEN_DELETE) != 0) + file.deleteOnExit(); + this.raf = new RandomAccessFile(file, "r"); + this.name = file.getPath(); + checkZipFile(); + } + + private void checkZipFile() throws IOException, ZipException + { + byte[] magicBuf = new byte[4]; + raf.read(magicBuf); + + if (readLeInt(magicBuf, 0) != LOCSIG) + { + raf.close(); + throw new ZipException("Not a valid zip file"); + } + } + + /** + * Checks if file is closed and throws an exception. + */ + private void checkClosed() + { + if (closed) + throw new IllegalStateException("ZipFile has closed: " + name); + } + + /** + * Read an unsigned short in little endian byte order from the given + * DataInput stream using the given byte buffer. + * + * @param di DataInput stream to read from. + * @param b the byte buffer to read in (must be at least 2 bytes long). + * @return The value read. + * + * @exception IOException if a i/o error occured. + * @exception EOFException if the file ends prematurely + */ + private int readLeShort(DataInput di, byte[] b) throws IOException + { + di.readFully(b, 0, 2); + return (b[0] & 0xff) | (b[1] & 0xff) << 8; + } + + /** + * Read an int in little endian byte order from the given + * DataInput stream using the given byte buffer. + * + * @param di DataInput stream to read from. + * @param b the byte buffer to read in (must be at least 4 bytes long). + * @return The value read. + * + * @exception IOException if a i/o error occured. + * @exception EOFException if the file ends prematurely + */ + private int readLeInt(DataInput di, byte[] b) throws IOException + { + di.readFully(b, 0, 4); + return ((b[0] & 0xff) | (b[1] & 0xff) << 8) + | ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16; + } + + /** + * Read an unsigned short in little endian byte order from the given + * byte buffer at the given offset. + * + * @param b the byte array to read from. + * @param off the offset to read from. + * @return The value read. + */ + private int readLeShort(byte[] b, int off) + { + return (b[off] & 0xff) | (b[off+1] & 0xff) << 8; + } + + /** + * Read an int in little endian byte order from the given + * byte buffer at the given offset. + * + * @param b the byte array to read from. + * @param off the offset to read from. + * @return The value read. + */ + private int readLeInt(byte[] b, int off) + { + return ((b[off] & 0xff) | (b[off+1] & 0xff) << 8) + | ((b[off+2] & 0xff) | (b[off+3] & 0xff) << 8) << 16; + } + + + /** + * Read the central directory of a zip file and fill the entries + * array. This is called exactly once when first needed. It is called + * while holding the lock on raf. + * + * @exception IOException if a i/o error occured. + * @exception ZipException if the central directory is malformed + */ + private void readEntries() throws ZipException, IOException + { + /* Search for the End Of Central Directory. When a zip comment is + * present the directory may start earlier. + * FIXME: This searches the whole file in a very slow manner if the + * file isn't a zip file. + */ + long pos = raf.length() - ENDHDR; + byte[] ebs = new byte[CENHDR]; + + do + { + if (pos < 0) + throw new ZipException + ("central directory not found, probably not a zip file: " + name); + raf.seek(pos--); + } + while (readLeInt(raf, ebs) != ENDSIG); + + if (raf.skipBytes(ENDTOT - ENDNRD) != ENDTOT - ENDNRD) + throw new EOFException(name); + int count = readLeShort(raf, ebs); + if (raf.skipBytes(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ) + throw new EOFException(name); + int centralOffset = readLeInt(raf, ebs); + + entries = new HashMap(count+count/2); + raf.seek(centralOffset); + + byte[] buffer = new byte[16]; + for (int i = 0; i < count; i++) + { + raf.readFully(ebs); + if (readLeInt(ebs, 0) != CENSIG) + throw new ZipException("Wrong Central Directory signature: " + name); + + int method = readLeShort(ebs, CENHOW); + int dostime = readLeInt(ebs, CENTIM); + int crc = readLeInt(ebs, CENCRC); + int csize = readLeInt(ebs, CENSIZ); + int size = readLeInt(ebs, CENLEN); + int nameLen = readLeShort(ebs, CENNAM); + int extraLen = readLeShort(ebs, CENEXT); + int commentLen = readLeShort(ebs, CENCOM); + + int offset = readLeInt(ebs, CENOFF); + + int needBuffer = Math.max(nameLen, commentLen); + if (buffer.length < needBuffer) + buffer = new byte[needBuffer]; + + raf.readFully(buffer, 0, nameLen); + String name = new String(buffer, 0, 0, nameLen); + + ZipEntry entry = new ZipEntry(name); + entry.setMethod(method); + entry.setCrc(crc & 0xffffffffL); + entry.setSize(size & 0xffffffffL); + entry.setCompressedSize(csize & 0xffffffffL); + entry.setDOSTime(dostime); + if (extraLen > 0) + { + byte[] extra = new byte[extraLen]; + raf.readFully(extra); + entry.setExtra(extra); + } + if (commentLen > 0) + { + raf.readFully(buffer, 0, commentLen); + entry.setComment(new String(buffer, 0, commentLen)); + } + entry.offset = offset; + entries.put(name, entry); + } + } + + /** + * Closes the ZipFile. This also closes all input streams given by + * this class. After this is called, no further method should be + * called. + * + * @exception IOException if a i/o error occured. + */ + public void close() throws IOException + { + synchronized (raf) + { + closed = true; + entries = null; + raf.close(); + } + } + + /** + * Calls the close() method when this ZipFile has not yet + * been explicitly closed. + */ + protected void finalize() throws IOException + { + if (!closed && raf != null) close(); + } + + /** + * Returns an enumeration of all Zip entries in this Zip file. + * + * @exception IllegalStateException when the ZipFile has already been closed + */ + public Enumeration entries() + { + checkClosed(); + + try + { + return new ZipEntryEnumeration(getEntries().values().iterator()); + } + catch (IOException ioe) + { + return EmptyEnumeration.getInstance(); + } + } + + /** + * Checks that the ZipFile is still open and reads entries when necessary. + * + * @exception IllegalStateException when the ZipFile has already been closed. + * @exception IOEexception when the entries could not be read. + */ + private HashMap getEntries() throws IOException + { + synchronized(raf) + { + checkClosed(); + + if (entries == null) + readEntries(); + + return entries; + } + } + + /** + * Searches for a zip entry in this archive with the given name. + * + * @param the name. May contain directory components separated by + * slashes ('/'). + * @return the zip entry, or null if no entry with that name exists. + * + * @exception IllegalStateException when the ZipFile has already been closed + */ + public ZipEntry getEntry(String name) + { + checkClosed(); + + try + { + HashMap entries = getEntries(); + ZipEntry entry = (ZipEntry) entries.get(name); + // If we didn't find it, maybe it's a directory. + if (entry == null && !name.endsWith("/")) + entry = (ZipEntry) entries.get(name + '/'); + return entry != null ? new ZipEntry(entry, name) : null; + } + catch (IOException ioe) + { + return null; + } + } + + + //access should be protected by synchronized(raf) + private byte[] locBuf = new byte[LOCHDR]; + + /** + * Checks, if the local header of the entry at index i matches the + * central directory, and returns the offset to the data. + * + * @param entry to check. + * @return the start offset of the (compressed) data. + * + * @exception IOException if a i/o error occured. + * @exception ZipException if the local header doesn't match the + * central directory header + */ + private long checkLocalHeader(ZipEntry entry) throws IOException + { + synchronized (raf) + { + raf.seek(entry.offset); + raf.readFully(locBuf); + + if (readLeInt(locBuf, 0) != LOCSIG) + throw new ZipException("Wrong Local header signature: " + name); + + if (entry.getMethod() != readLeShort(locBuf, LOCHOW)) + throw new ZipException("Compression method mismatch: " + name); + + if (entry.getName().length() != readLeShort(locBuf, LOCNAM)) + throw new ZipException("file name length mismatch: " + name); + + int extraLen = entry.getName().length() + readLeShort(locBuf, LOCEXT); + return entry.offset + LOCHDR + extraLen; + } + } + + /** + * Creates an input stream reading the given zip entry as + * uncompressed data. Normally zip entry should be an entry + * returned by getEntry() or entries(). + * + * This implementation returns null if the requested entry does not + * exist. This decision is not obviously correct, however, it does + * appear to mirror Sun's implementation, and it is consistant with + * their javadoc. On the other hand, the old JCL book, 2nd Edition, + * claims that this should return a "non-null ZIP entry". We have + * chosen for now ignore the old book, as modern versions of Ant (an + * important application) depend on this behaviour. See discussion + * in this thread: + * http://gcc.gnu.org/ml/java-patches/2004-q2/msg00602.html + * + * @param entry the entry to create an InputStream for. + * @return the input stream, or null if the requested entry does not exist. + * + * @exception IllegalStateException when the ZipFile has already been closed + * @exception IOException if a i/o error occured. + * @exception ZipException if the Zip archive is malformed. + */ + public InputStream getInputStream(ZipEntry entry) throws IOException + { + checkClosed(); + + HashMap entries = getEntries(); + String name = entry.getName(); + ZipEntry zipEntry = (ZipEntry) entries.get(name); + if (zipEntry == null) + return null; + + long start = checkLocalHeader(zipEntry); + int method = zipEntry.getMethod(); + InputStream is = new BufferedInputStream(new PartialInputStream + (raf, start, zipEntry.getCompressedSize())); + switch (method) + { + case ZipOutputStream.STORED: + return is; + case ZipOutputStream.DEFLATED: + return new InflaterInputStream(is, new Inflater(true)); + default: + throw new ZipException("Unknown compression method " + method); + } + } + + /** + * Returns the (path) name of this zip file. + */ + public String getName() + { + return name; + } + + /** + * Returns the number of entries in this zip file. + * + * @exception IllegalStateException when the ZipFile has already been closed + */ + public int size() + { + checkClosed(); + + try + { + return getEntries().size(); + } + catch (IOException ioe) + { + return 0; + } + } + + private static class ZipEntryEnumeration implements Enumeration + { + private final Iterator elements; + + public ZipEntryEnumeration(Iterator elements) + { + this.elements = elements; + } + + public boolean hasMoreElements() + { + return elements.hasNext(); + } + + public Object nextElement() + { + /* We return a clone, just to be safe that the user doesn't + * change the entry. + */ + return ((ZipEntry)elements.next()).clone(); + } + } + + private static class PartialInputStream extends InputStream + { + private final RandomAccessFile raf; + long filepos, end; + + public PartialInputStream(RandomAccessFile raf, long start, long len) + { + this.raf = raf; + filepos = start; + end = start + len; + } + + public int available() + { + long amount = end - filepos; + if (amount > Integer.MAX_VALUE) + return Integer.MAX_VALUE; + return (int) amount; + } + + public int read() throws IOException + { + if (filepos == end) + return -1; + synchronized (raf) + { + raf.seek(filepos++); + return raf.read(); + } + } + + public int read(byte[] b, int off, int len) throws IOException + { + if (len > end - filepos) + { + len = (int) (end - filepos); + if (len == 0) + return -1; + } + synchronized (raf) + { + raf.seek(filepos); + int count = raf.read(b, off, len); + if (count > 0) + filepos += len; + return count; + } + } + + public long skip(long amount) + { + if (amount < 0) + throw new IllegalArgumentException(); + if (amount > end - filepos) + amount = end - filepos; + filepos += amount; + return amount; + } + } +} diff --git a/libjava/classpath/java/util/zip/ZipInputStream.java b/libjava/classpath/java/util/zip/ZipInputStream.java new file mode 100644 index 0000000..5732523 --- /dev/null +++ b/libjava/classpath/java/util/zip/ZipInputStream.java @@ -0,0 +1,371 @@ +/* ZipInputStream.java -- + Copyright (C) 2001, 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 java.util.zip; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +/** + * This is a FilterInputStream that reads the files in an zip archive + * one after another. It has a special method to get the zip entry of + * the next file. The zip entry contains information about the file name + * size, compressed size, CRC, etc. + * + * It includes support for STORED and DEFLATED entries. + * + * @author Jochen Hoenicke + */ +public class ZipInputStream extends InflaterInputStream implements ZipConstants +{ + private CRC32 crc = new CRC32(); + private ZipEntry entry = null; + + private int csize; + private int size; + private int method; + private int flags; + private int avail; + private boolean entryAtEOF; + + /** + * Creates a new Zip input stream, reading a zip archive. + */ + public ZipInputStream(InputStream in) + { + super(in, new Inflater(true)); + } + + private void fillBuf() throws IOException + { + avail = len = in.read(buf, 0, buf.length); + } + + private int readBuf(byte[] out, int offset, int length) throws IOException + { + if (avail <= 0) + { + fillBuf(); + if (avail <= 0) + return -1; + } + if (length > avail) + length = avail; + System.arraycopy(buf, len - avail, out, offset, length); + avail -= length; + return length; + } + + private void readFully(byte[] out) throws IOException + { + int off = 0; + int len = out.length; + while (len > 0) + { + int count = readBuf(out, off, len); + if (count == -1) + throw new EOFException(); + off += count; + len -= count; + } + } + + private int readLeByte() throws IOException + { + if (avail <= 0) + { + fillBuf(); + if (avail <= 0) + throw new ZipException("EOF in header"); + } + return buf[len - avail--] & 0xff; + } + + /** + * Read an unsigned short in little endian byte order. + */ + private int readLeShort() throws IOException + { + return readLeByte() | (readLeByte() << 8); + } + + /** + * Read an int in little endian byte order. + */ + private int readLeInt() throws IOException + { + return readLeShort() | (readLeShort() << 16); + } + + /** + * Open the next entry from the zip archive, and return its description. + * If the previous entry wasn't closed, this method will close it. + */ + public ZipEntry getNextEntry() throws IOException + { + if (crc == null) + throw new IOException("Stream closed."); + if (entry != null) + closeEntry(); + + int header = readLeInt(); + if (header == CENSIG) + { + /* Central Header reached. */ + close(); + return null; + } + if (header != LOCSIG) + throw new ZipException("Wrong Local header signature: " + + Integer.toHexString(header)); + /* skip version */ + readLeShort(); + flags = readLeShort(); + method = readLeShort(); + int dostime = readLeInt(); + int crc = readLeInt(); + csize = readLeInt(); + size = readLeInt(); + int nameLen = readLeShort(); + int extraLen = readLeShort(); + + if (method == ZipOutputStream.STORED && csize != size) + throw new ZipException("Stored, but compressed != uncompressed"); + + + byte[] buffer = new byte[nameLen]; + readFully(buffer); + String name = new String(buffer); + + entry = createZipEntry(name); + entryAtEOF = false; + entry.setMethod(method); + if ((flags & 8) == 0) + { + entry.setCrc(crc & 0xffffffffL); + entry.setSize(size & 0xffffffffL); + entry.setCompressedSize(csize & 0xffffffffL); + } + entry.setDOSTime(dostime); + if (extraLen > 0) + { + byte[] extra = new byte[extraLen]; + readFully(extra); + entry.setExtra(extra); + } + + if (method == ZipOutputStream.DEFLATED && avail > 0) + { + System.arraycopy(buf, len - avail, buf, 0, avail); + len = avail; + avail = 0; + inf.setInput(buf, 0, len); + } + return entry; + } + + private void readDataDescr() throws IOException + { + if (readLeInt() != EXTSIG) + throw new ZipException("Data descriptor signature not found"); + entry.setCrc(readLeInt() & 0xffffffffL); + csize = readLeInt(); + size = readLeInt(); + entry.setSize(size & 0xffffffffL); + entry.setCompressedSize(csize & 0xffffffffL); + } + + /** + * Closes the current zip entry and moves to the next one. + */ + public void closeEntry() throws IOException + { + if (crc == null) + throw new IOException("Stream closed."); + if (entry == null) + return; + + if (method == ZipOutputStream.DEFLATED) + { + if ((flags & 8) != 0) + { + /* We don't know how much we must skip, read until end. */ + byte[] tmp = new byte[2048]; + while (read(tmp) > 0) + ; + /* read will close this entry */ + return; + } + csize -= inf.getTotalIn(); + avail = inf.getRemaining(); + } + + if (avail > csize && csize >= 0) + avail -= csize; + else + { + csize -= avail; + avail = 0; + while (csize != 0) + { + long skipped = in.skip(csize & 0xffffffffL); + if (skipped <= 0) + throw new ZipException("zip archive ends early."); + csize -= skipped; + } + } + + size = 0; + crc.reset(); + if (method == ZipOutputStream.DEFLATED) + inf.reset(); + entry = null; + entryAtEOF = true; + } + + public int available() throws IOException + { + return entryAtEOF ? 0 : 1; + } + + /** + * Reads a byte from the current zip entry. + * @return the byte or -1 on EOF. + * @exception IOException if a i/o error occured. + * @exception ZipException if the deflated stream is corrupted. + */ + public int read() throws IOException + { + byte[] b = new byte[1]; + if (read(b, 0, 1) <= 0) + return -1; + return b[0] & 0xff; + } + + /** + * Reads a block of bytes from the current zip entry. + * @return the number of bytes read (may be smaller, even before + * EOF), or -1 on EOF. + * @exception IOException if a i/o error occured. + * @exception ZipException if the deflated stream is corrupted. + */ + public int read(byte[] b, int off, int len) throws IOException + { + if (len == 0) + return 0; + if (crc == null) + throw new IOException("Stream closed."); + if (entry == null) + return -1; + boolean finished = false; + switch (method) + { + case ZipOutputStream.DEFLATED: + len = super.read(b, off, len); + if (len < 0) + { + if (!inf.finished()) + throw new ZipException("Inflater not finished!?"); + avail = inf.getRemaining(); + if ((flags & 8) != 0) + readDataDescr(); + + if (inf.getTotalIn() != csize + || inf.getTotalOut() != size) + throw new ZipException("size mismatch: "+csize+";"+size+" <-> "+inf.getTotalIn()+";"+inf.getTotalOut()); + inf.reset(); + finished = true; + } + break; + + case ZipOutputStream.STORED: + + if (len > csize && csize >= 0) + len = csize; + + len = readBuf(b, off, len); + if (len > 0) + { + csize -= len; + size -= len; + } + + if (csize == 0) + finished = true; + else if (len < 0) + throw new ZipException("EOF in stored block"); + break; + } + + if (len > 0) + crc.update(b, off, len); + + if (finished) + { + if ((crc.getValue() & 0xffffffffL) != entry.getCrc()) + throw new ZipException("CRC mismatch"); + crc.reset(); + entry = null; + entryAtEOF = true; + } + return len; + } + + /** + * Closes the zip file. + * @exception IOException if a i/o error occured. + */ + public void close() throws IOException + { + super.close(); + crc = null; + entry = null; + entryAtEOF = true; + } + + /** + * Creates a new zip entry for the given name. This is equivalent + * to new ZipEntry(name). + * @param name the name of the zip entry. + */ + protected ZipEntry createZipEntry(String name) + { + return new ZipEntry(name); + } +} diff --git a/libjava/classpath/java/util/zip/ZipOutputStream.java b/libjava/classpath/java/util/zip/ZipOutputStream.java new file mode 100644 index 0000000..5699ff0 --- /dev/null +++ b/libjava/classpath/java/util/zip/ZipOutputStream.java @@ -0,0 +1,399 @@ +/* ZipOutputStream.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 java.util.zip; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Vector; + +/** + * This is a FilterOutputStream that writes the files into a zip + * archive one after another. It has a special method to start a new + * zip entry. The zip entries contains information about the file name + * size, compressed size, CRC, etc. + * + * It includes support for STORED and DEFLATED entries. + * + * This class is not thread safe. + * + * @author Jochen Hoenicke + */ +public class ZipOutputStream extends DeflaterOutputStream implements ZipConstants +{ + private Vector entries = new Vector(); + private CRC32 crc = new CRC32(); + private ZipEntry curEntry = null; + + private int curMethod; + private int size; + private int offset = 0; + + private byte[] zipComment = new byte[0]; + private int defaultMethod = DEFLATED; + + /** + * Our Zip version is hard coded to 1.0 resp. 2.0 + */ + private static final int ZIP_STORED_VERSION = 10; + private static final int ZIP_DEFLATED_VERSION = 20; + + /** + * Compression method. This method doesn't compress at all. + */ + public static final int STORED = 0; + + /** + * Compression method. This method uses the Deflater. + */ + public static final int DEFLATED = 8; + + /** + * Creates a new Zip output stream, writing a zip archive. + * @param out the output stream to which the zip archive is written. + */ + public ZipOutputStream(OutputStream out) + { + super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true)); + } + + /** + * Set the zip file comment. + * @param comment the comment. + * @exception IllegalArgumentException if encoding of comment is + * longer than 0xffff bytes. + */ + public void setComment(String comment) + { + byte[] commentBytes; + commentBytes = comment.getBytes(); + if (commentBytes.length > 0xffff) + throw new IllegalArgumentException("Comment too long."); + zipComment = commentBytes; + } + + /** + * Sets default compression method. If the Zip entry specifies + * another method its method takes precedence. + * @param method the method. + * @exception IllegalArgumentException if method is not supported. + * @see #STORED + * @see #DEFLATED + */ + public void setMethod(int method) + { + if (method != STORED && method != DEFLATED) + throw new IllegalArgumentException("Method not supported."); + defaultMethod = method; + } + + /** + * Sets default compression level. The new level will be activated + * immediately. + * @exception IllegalArgumentException if level is not supported. + * @see Deflater + */ + public void setLevel(int level) + { + def.setLevel(level); + } + + /** + * Write an unsigned short in little endian byte order. + */ + private void writeLeShort(int value) throws IOException + { + out.write(value & 0xff); + out.write((value >> 8) & 0xff); + } + + /** + * Write an int in little endian byte order. + */ + private void writeLeInt(int value) throws IOException + { + writeLeShort(value); + writeLeShort(value >> 16); + } + + /** + * Starts a new Zip entry. It automatically closes the previous + * entry if present. If the compression method is stored, the entry + * must have a valid size and crc, otherwise all elements (except + * name) are optional, but must be correct if present. If the time + * is not set in the entry, the current time is used. + * @param entry the entry. + * @exception IOException if an I/O error occured. + * @exception ZipException if stream was finished. + */ + public void putNextEntry(ZipEntry entry) throws IOException + { + if (entries == null) + throw new ZipException("ZipOutputStream was finished"); + + int method = entry.getMethod(); + int flags = 0; + if (method == -1) + method = defaultMethod; + + if (method == STORED) + { + if (entry.getCompressedSize() >= 0) + { + if (entry.getSize() < 0) + entry.setSize(entry.getCompressedSize()); + else if (entry.getSize() != entry.getCompressedSize()) + throw new ZipException + ("Method STORED, but compressed size != size"); + } + else + entry.setCompressedSize(entry.getSize()); + + if (entry.getSize() < 0) + throw new ZipException("Method STORED, but size not set"); + if (entry.getCrc() < 0) + throw new ZipException("Method STORED, but crc not set"); + } + else if (method == DEFLATED) + { + if (entry.getCompressedSize() < 0 + || entry.getSize() < 0 || entry.getCrc() < 0) + flags |= 8; + } + + if (curEntry != null) + closeEntry(); + + if (entry.getTime() < 0) + entry.setTime(System.currentTimeMillis()); + + entry.flags = flags; + entry.offset = offset; + entry.setMethod(method); + curMethod = method; + /* Write the local file header */ + writeLeInt(LOCSIG); + writeLeShort(method == STORED + ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION); + writeLeShort(flags); + writeLeShort(method); + writeLeInt(entry.getDOSTime()); + if ((flags & 8) == 0) + { + writeLeInt((int)entry.getCrc()); + writeLeInt((int)entry.getCompressedSize()); + writeLeInt((int)entry.getSize()); + } + else + { + writeLeInt(0); + writeLeInt(0); + writeLeInt(0); + } + byte[] name = entry.getName().getBytes(); + if (name.length > 0xffff) + throw new ZipException("Name too long."); + byte[] extra = entry.getExtra(); + if (extra == null) + extra = new byte[0]; + writeLeShort(name.length); + writeLeShort(extra.length); + out.write(name); + out.write(extra); + + offset += LOCHDR + name.length + extra.length; + + /* Activate the entry. */ + + curEntry = entry; + crc.reset(); + if (method == DEFLATED) + def.reset(); + size = 0; + } + + /** + * Closes the current entry. + * @exception IOException if an I/O error occured. + * @exception ZipException if no entry is active. + */ + public void closeEntry() throws IOException + { + if (curEntry == null) + throw new ZipException("No open entry"); + + /* First finish the deflater, if appropriate */ + if (curMethod == DEFLATED) + super.finish(); + + int csize = curMethod == DEFLATED ? def.getTotalOut() : size; + + if (curEntry.getSize() < 0) + curEntry.setSize(size); + else if (curEntry.getSize() != size) + throw new ZipException("size was "+size + +", but I expected "+curEntry.getSize()); + + if (curEntry.getCompressedSize() < 0) + curEntry.setCompressedSize(csize); + else if (curEntry.getCompressedSize() != csize) + throw new ZipException("compressed size was "+csize + +", but I expected "+curEntry.getSize()); + + if (curEntry.getCrc() < 0) + curEntry.setCrc(crc.getValue()); + else if (curEntry.getCrc() != crc.getValue()) + throw new ZipException("crc was " + Long.toHexString(crc.getValue()) + + ", but I expected " + + Long.toHexString(curEntry.getCrc())); + + offset += csize; + + /* Now write the data descriptor entry if needed. */ + if (curMethod == DEFLATED && (curEntry.flags & 8) != 0) + { + writeLeInt(EXTSIG); + writeLeInt((int)curEntry.getCrc()); + writeLeInt((int)curEntry.getCompressedSize()); + writeLeInt((int)curEntry.getSize()); + offset += EXTHDR; + } + + entries.addElement(curEntry); + curEntry = null; + } + + /** + * Writes the given buffer to the current entry. + * @exception IOException if an I/O error occured. + * @exception ZipException if no entry is active. + */ + public void write(byte[] b, int off, int len) throws IOException + { + if (curEntry == null) + throw new ZipException("No open entry."); + + switch (curMethod) + { + case DEFLATED: + super.write(b, off, len); + break; + + case STORED: + out.write(b, off, len); + break; + } + + crc.update(b, off, len); + size += len; + } + + /** + * Finishes the stream. This will write the central directory at the + * end of the zip file and flush the stream. + * @exception IOException if an I/O error occured. + */ + public void finish() throws IOException + { + if (entries == null) + return; + if (curEntry != null) + closeEntry(); + + int numEntries = 0; + int sizeEntries = 0; + + Enumeration e = entries.elements(); + while (e.hasMoreElements()) + { + ZipEntry entry = (ZipEntry) e.nextElement(); + + int method = entry.getMethod(); + writeLeInt(CENSIG); + writeLeShort(method == STORED + ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION); + writeLeShort(method == STORED + ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION); + writeLeShort(entry.flags); + writeLeShort(method); + writeLeInt(entry.getDOSTime()); + writeLeInt((int)entry.getCrc()); + writeLeInt((int)entry.getCompressedSize()); + writeLeInt((int)entry.getSize()); + + byte[] name = entry.getName().getBytes(); + if (name.length > 0xffff) + throw new ZipException("Name too long."); + byte[] extra = entry.getExtra(); + if (extra == null) + extra = new byte[0]; + String strComment = entry.getComment(); + byte[] comment = strComment != null + ? strComment.getBytes() : new byte[0]; + if (comment.length > 0xffff) + throw new ZipException("Comment too long."); + + writeLeShort(name.length); + writeLeShort(extra.length); + writeLeShort(comment.length); + writeLeShort(0); /* disk number */ + writeLeShort(0); /* internal file attr */ + writeLeInt(0); /* external file attr */ + writeLeInt(entry.offset); + + out.write(name); + out.write(extra); + out.write(comment); + numEntries++; + sizeEntries += CENHDR + name.length + extra.length + comment.length; + } + + writeLeInt(ENDSIG); + writeLeShort(0); /* disk number */ + writeLeShort(0); /* disk with start of central dir */ + writeLeShort(numEntries); + writeLeShort(numEntries); + writeLeInt(sizeEntries); + writeLeInt(offset); + writeLeShort(zipComment.length); + out.write(zipComment); + out.flush(); + entries = null; + } +} diff --git a/libjava/classpath/java/util/zip/package.html b/libjava/classpath/java/util/zip/package.html new file mode 100644 index 0000000..5f3ac49 --- /dev/null +++ b/libjava/classpath/java/util/zip/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - java.util.zip + + +

    Utility classes to manipulate zip and gzip archives as files or streams, +includes checksum and compression support.

    + + + -- cgit v1.1