~ubuntu-branches/ubuntu/lucid/libjcommon-java/lucid

« back to all changes in this revision

Viewing changes to source/org/jfree/io/SerialUtilities.java

  • Committer: Bazaar Package Importer
  • Author(s): Wolfgang Baer
  • Date: 2006-02-09 15:58:13 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060209155813-fzi9zwh2rzedbllq
Tags: 1.0.0-1
* New stable upstream release (closes: #328574)
* Move to main - build with kaffe
* Use cdbs build system - added cdbs build-dependency
* Move package to pkg-java-maintainers for comaintenance, 
  added Christian Bayle and myself as uploaders
* Removed unneeded README.Debian
* Added README.Debian-source how the upstream tarball was cleaned
* Move big documentation in an own -doc package
* Register javadoc api with doc-base
* Standards-Version 3.6.2 (no changes)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ========================================================================
 
2
 * JCommon : a free general purpose class library for the Java(tm) platform
 
3
 * ========================================================================
 
4
 *
 
5
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 
6
 * 
 
7
 * Project Info:  http://www.jfree.org/jcommon/index.html
 
8
 *
 
9
 * This library is free software; you can redistribute it and/or modify it 
 
10
 * under the terms of the GNU Lesser General Public License as published by 
 
11
 * the Free Software Foundation; either version 2.1 of the License, or 
 
12
 * (at your option) any later version.
 
13
 *
 
14
 * This library is distributed in the hope that it will be useful, but 
 
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 
16
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 
17
 * License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU Lesser General Public
 
20
 * License along with this library; if not, write to the Free Software
 
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 
22
 * USA.  
 
23
 *
 
24
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 
25
 * in the United States and other countries.]
 
26
 * 
 
27
 * --------------------
 
28
 * SerialUtilities.java
 
29
 * --------------------
 
30
 * (C) Copyright 2000-2005, by Object Refinery Limited.
 
31
 *
 
32
 * Original Author:  David Gilbert (for Object Refinery Limited);
 
33
 * Contributor(s):   Arik Levin;
 
34
 *
 
35
 * $Id: SerialUtilities.java,v 1.13 2005/11/03 09:55:27 mungady Exp $
 
36
 *
 
37
 * Changes
 
38
 * -------
 
39
 * 25-Mar-2003 : Version 1 (DG);
 
40
 * 18-Sep-2003 : Added capability to serialize GradientPaint (DG);
 
41
 * 26-Apr-2004 : Added read/writePoint2D() methods (DG);
 
42
 * 22-Feb-2005 : Added support for Arc2D - see patch 1147035 by Arik Levin (DG);
 
43
 * 29-Jul-2005 : Added support for AttributedString (DG);
 
44
 * 
 
45
 */
 
46
 
 
47
package org.jfree.io;
 
48
 
 
49
import java.awt.BasicStroke;
 
50
import java.awt.Color;
 
51
import java.awt.GradientPaint;
 
52
import java.awt.Paint;
 
53
import java.awt.Shape;
 
54
import java.awt.Stroke;
 
55
import java.awt.geom.Arc2D;
 
56
import java.awt.geom.Ellipse2D;
 
57
import java.awt.geom.GeneralPath;
 
58
import java.awt.geom.Line2D;
 
59
import java.awt.geom.PathIterator;
 
60
import java.awt.geom.Point2D;
 
61
import java.awt.geom.Rectangle2D;
 
62
import java.io.IOException;
 
63
import java.io.ObjectInputStream;
 
64
import java.io.ObjectOutputStream;
 
65
import java.io.Serializable;
 
66
import java.text.AttributedCharacterIterator;
 
67
import java.text.AttributedString;
 
68
import java.text.CharacterIterator;
 
69
import java.util.HashMap;
 
70
import java.util.Map;
 
71
 
 
72
/**
 
73
 * A class containing useful utility methods relating to serialization.
 
74
 *
 
75
 * @author David Gilbert
 
76
 */
 
77
public class SerialUtilities {
 
78
 
 
79
    /**
 
80
     * Private constructor prevents object creation.
 
81
     */
 
82
    private SerialUtilities() {
 
83
    }
 
84
 
 
85
    /**
 
86
     * Returns <code>true</code> if a class implements <code>Serializable</code>
 
87
     * and <code>false</code> otherwise.
 
88
     * 
 
89
     * @param c  the class.
 
90
     * 
 
91
     * @return A boolean.
 
92
     */
 
93
    public static boolean isSerializable(final Class c) {
 
94
        /**
 
95
        final Class[] interfaces = c.getInterfaces();
 
96
        for (int i = 0; i < interfaces.length; i++) {
 
97
            if (interfaces[i].equals(Serializable.class)) {
 
98
                return true;                
 
99
            }
 
100
        }
 
101
        Class cc = c.getSuperclass();
 
102
        if (cc != null) {
 
103
            return isSerializable(cc);   
 
104
        }
 
105
         */
 
106
        return (Serializable.class.isAssignableFrom(c));
 
107
    }
 
108
    
 
109
    /**
 
110
     * Reads a <code>Paint</code> object that has been serialised by the
 
111
     * {@link SerialUtilities#writePaint(Paint, ObjectOutputStream)} method.
 
112
     *
 
113
     * @param stream  the input stream (<code>null</code> not permitted).
 
114
     *
 
115
     * @return The paint object (possibly <code>null</code>).
 
116
     *
 
117
     * @throws IOException  if there is an I/O problem.
 
118
     * @throws ClassNotFoundException  if there is a problem loading a class.
 
119
     */
 
120
    public static Paint readPaint(final ObjectInputStream stream)
 
121
        throws IOException, ClassNotFoundException {
 
122
 
 
123
        if (stream == null) {
 
124
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
125
        }
 
126
        Paint result = null;
 
127
        final boolean isNull = stream.readBoolean();
 
128
        if (!isNull) {
 
129
            final Class c = (Class) stream.readObject();
 
130
            if (isSerializable(c)) {
 
131
                result = (Paint) stream.readObject();
 
132
            }
 
133
            else if (c.equals(GradientPaint.class)) {
 
134
                final float x1 = stream.readFloat();
 
135
                final float y1 = stream.readFloat();
 
136
                final Color c1 = (Color) stream.readObject();
 
137
                final float x2 = stream.readFloat();
 
138
                final float y2 = stream.readFloat();
 
139
                final Color c2 = (Color) stream.readObject();
 
140
                final boolean isCyclic = stream.readBoolean();
 
141
                result = new GradientPaint(x1, y1, c1, x2, y2, c2, isCyclic);
 
142
            }
 
143
        }
 
144
        return result;
 
145
 
 
146
    }
 
147
 
 
148
    /**
 
149
     * Serialises a <code>Paint</code> object.
 
150
     *
 
151
     * @param paint  the paint object (<code>null</code> permitted).
 
152
     * @param stream  the output stream (<code>null</code> not permitted).
 
153
     *
 
154
     * @throws IOException if there is an I/O error.
 
155
     */
 
156
    public static void writePaint(final Paint paint,
 
157
                                  final ObjectOutputStream stream) 
 
158
        throws IOException {
 
159
 
 
160
        if (stream == null) {
 
161
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
162
        }
 
163
        if (paint != null) {
 
164
            stream.writeBoolean(false);
 
165
            stream.writeObject(paint.getClass());
 
166
            if (paint instanceof Serializable) {
 
167
                stream.writeObject(paint);
 
168
            }
 
169
            else if (paint instanceof GradientPaint) {
 
170
                final GradientPaint gp = (GradientPaint) paint;
 
171
                stream.writeFloat((float) gp.getPoint1().getX());
 
172
                stream.writeFloat((float) gp.getPoint1().getY());
 
173
                stream.writeObject(gp.getColor1());
 
174
                stream.writeFloat((float) gp.getPoint2().getX());
 
175
                stream.writeFloat((float) gp.getPoint2().getY());
 
176
                stream.writeObject(gp.getColor2());
 
177
                stream.writeBoolean(gp.isCyclic());
 
178
            }
 
179
        }
 
180
        else {
 
181
            stream.writeBoolean(true);
 
182
        }
 
183
 
 
184
    }
 
185
 
 
186
    /**
 
187
     * Reads a <code>Stroke</code> object that has been serialised by the
 
188
     * {@link SerialUtilities#writeStroke(Stroke, ObjectOutputStream)} method.
 
189
     *
 
190
     * @param stream  the input stream (<code>null</code> not permitted).
 
191
     *
 
192
     * @return The stroke object (possibly <code>null</code>).
 
193
     *
 
194
     * @throws IOException  if there is an I/O problem.
 
195
     * @throws ClassNotFoundException  if there is a problem loading a class.
 
196
     */
 
197
    public static Stroke readStroke(final ObjectInputStream stream)
 
198
        throws IOException, ClassNotFoundException {
 
199
 
 
200
        if (stream == null) {
 
201
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
202
        }
 
203
        Stroke result = null;
 
204
        final boolean isNull = stream.readBoolean();
 
205
        if (!isNull) {
 
206
            final Class c = (Class) stream.readObject();
 
207
            if (c.equals(BasicStroke.class)) {
 
208
                final float width = stream.readFloat();
 
209
                final int cap = stream.readInt();
 
210
                final int join = stream.readInt();
 
211
                final float miterLimit = stream.readFloat();
 
212
                final float[] dash = (float[]) stream.readObject();
 
213
                final float dashPhase = stream.readFloat();
 
214
                result = new BasicStroke(
 
215
                    width, cap, join, miterLimit, dash, dashPhase
 
216
                );
 
217
            }
 
218
            else {
 
219
                result = (Stroke) stream.readObject();
 
220
            }
 
221
        }
 
222
        return result;
 
223
 
 
224
    }
 
225
 
 
226
    /**
 
227
     * Serialises a <code>Stroke</code> object.  This code handles the
 
228
     * <code>BasicStroke</code> class which is the only <code>Stroke</code> 
 
229
     * implementation provided by the JDK (and isn't directly 
 
230
     * <code>Serializable</code>).
 
231
     *
 
232
     * @param stroke  the stroke object (<code>null</code> permitted).
 
233
     * @param stream  the output stream (<code>null</code> not permitted).
 
234
     *
 
235
     * @throws IOException if there is an I/O error.
 
236
     */
 
237
    public static void writeStroke(final Stroke stroke,
 
238
                                   final ObjectOutputStream stream) 
 
239
        throws IOException {
 
240
 
 
241
        if (stream == null) {
 
242
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
243
        }
 
244
        if (stroke != null) {
 
245
            stream.writeBoolean(false);
 
246
            if (stroke instanceof BasicStroke) {
 
247
                final BasicStroke s = (BasicStroke) stroke;
 
248
                stream.writeObject(BasicStroke.class);
 
249
                stream.writeFloat(s.getLineWidth());
 
250
                stream.writeInt(s.getEndCap());
 
251
                stream.writeInt(s.getLineJoin());
 
252
                stream.writeFloat(s.getMiterLimit());
 
253
                stream.writeObject(s.getDashArray());
 
254
                stream.writeFloat(s.getDashPhase());
 
255
            }
 
256
            else {
 
257
                stream.writeObject(stroke.getClass());
 
258
                stream.writeObject(stroke);
 
259
            }
 
260
        }
 
261
        else {
 
262
            stream.writeBoolean(true);
 
263
        }
 
264
    }
 
265
 
 
266
    /**
 
267
     * Reads a <code>Shape</code> object that has been serialised by the 
 
268
     * {@link #writeShape(Shape, ObjectOutputStream)} method.
 
269
     *
 
270
     * @param stream  the input stream (<code>null</code> not permitted).
 
271
     *
 
272
     * @return The shape object (possibly <code>null</code>).
 
273
     *
 
274
     * @throws IOException  if there is an I/O problem.
 
275
     * @throws ClassNotFoundException  if there is a problem loading a class.
 
276
     */
 
277
    public static Shape readShape(final ObjectInputStream stream)
 
278
        throws IOException, ClassNotFoundException {
 
279
 
 
280
        if (stream == null) {
 
281
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
282
        }
 
283
        Shape result = null;
 
284
        final boolean isNull = stream.readBoolean();
 
285
        if (!isNull) {
 
286
            final Class c = (Class) stream.readObject();
 
287
            if (c.equals(Line2D.class)) {
 
288
                final double x1 = stream.readDouble();
 
289
                final double y1 = stream.readDouble();
 
290
                final double x2 = stream.readDouble();
 
291
                final double y2 = stream.readDouble();
 
292
                result = new Line2D.Double(x1, y1, x2, y2);
 
293
            }
 
294
            else if (c.equals(Rectangle2D.class)) {
 
295
                final double x = stream.readDouble();
 
296
                final double y = stream.readDouble();
 
297
                final double w = stream.readDouble();
 
298
                final double h = stream.readDouble();
 
299
                result = new Rectangle2D.Double(x, y, w, h);
 
300
            }
 
301
            else if (c.equals(Ellipse2D.class)) {
 
302
                final double x = stream.readDouble();
 
303
                final double y = stream.readDouble();
 
304
                final double w = stream.readDouble();
 
305
                final double h = stream.readDouble();
 
306
                result = new Ellipse2D.Double(x, y, w, h);
 
307
            }
 
308
            else if (c.equals(Arc2D.class)) {
 
309
                final double x = stream.readDouble();
 
310
                final double y = stream.readDouble();
 
311
                final double w = stream.readDouble();
 
312
                final double h = stream.readDouble();
 
313
                final double as = stream.readDouble(); // Angle Start
 
314
                final double ae = stream.readDouble(); // Angle Extent
 
315
                final int at = stream.readInt();       // Arc type
 
316
                result = new Arc2D.Double(x, y, w, h, as, ae, at);
 
317
            }            
 
318
            else if (c.equals(GeneralPath.class)) {
 
319
                final GeneralPath gp = new GeneralPath();
 
320
                final float[] args = new float[6];
 
321
                boolean hasNext = stream.readBoolean();
 
322
                while (!hasNext) {
 
323
                    final int type = stream.readInt();
 
324
                    for (int i = 0; i < 6; i++) {
 
325
                        args[i] = stream.readFloat();
 
326
                    }
 
327
                    switch (type) { 
 
328
                        case PathIterator.SEG_MOVETO :  
 
329
                            gp.moveTo(args[0], args[1]);
 
330
                            break;
 
331
                        case PathIterator.SEG_LINETO :                           
 
332
                            gp.lineTo(args[0], args[1]);
 
333
                            break; 
 
334
                        case PathIterator.SEG_CUBICTO :
 
335
                            gp.curveTo(
 
336
                                args[0], args[1], args[2], 
 
337
                                args[3], args[4], args[5]
 
338
                            );
 
339
                            break;
 
340
                        case PathIterator.SEG_QUADTO :
 
341
                            gp.quadTo(args[0], args[1], args[2], args[3]);
 
342
                            break;                  
 
343
                        case PathIterator.SEG_CLOSE :
 
344
                            //result = gp;
 
345
                            break;
 
346
                        default : 
 
347
                            throw new RuntimeException(
 
348
                                "JFreeChart - No path exists"
 
349
                            ); 
 
350
                    } 
 
351
                    gp.setWindingRule(stream.readInt());    
 
352
                    hasNext = stream.readBoolean();
 
353
                }
 
354
                result = gp;
 
355
            }
 
356
            else {
 
357
                result = (Shape) stream.readObject();
 
358
            }
 
359
        }
 
360
        return result;
 
361
 
 
362
    }
 
363
 
 
364
    /**
 
365
     * Serialises a <code>Shape</code> object.
 
366
     *
 
367
     * @param shape  the shape object (<code>null</code> permitted).
 
368
     * @param stream  the output stream (<code>null</code> not permitted).
 
369
     *
 
370
     * @throws IOException if there is an I/O error.
 
371
     */
 
372
    public static void writeShape(final Shape shape,
 
373
                                  final ObjectOutputStream stream) 
 
374
        throws IOException {
 
375
 
 
376
        if (stream == null) {
 
377
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
378
        }
 
379
        if (shape != null) {
 
380
            stream.writeBoolean(false);
 
381
            if (shape instanceof Line2D) {
 
382
                final Line2D line = (Line2D) shape;
 
383
                stream.writeObject(Line2D.class);
 
384
                stream.writeDouble(line.getX1());
 
385
                stream.writeDouble(line.getY1());
 
386
                stream.writeDouble(line.getX2());
 
387
                stream.writeDouble(line.getY2());
 
388
            }
 
389
            else if (shape instanceof Rectangle2D) {
 
390
                final Rectangle2D rectangle = (Rectangle2D) shape;
 
391
                stream.writeObject(Rectangle2D.class);
 
392
                stream.writeDouble(rectangle.getX());
 
393
                stream.writeDouble(rectangle.getY());
 
394
                stream.writeDouble(rectangle.getWidth());
 
395
                stream.writeDouble(rectangle.getHeight());
 
396
            }
 
397
            else if (shape instanceof Ellipse2D) {
 
398
                final Ellipse2D ellipse = (Ellipse2D) shape;
 
399
                stream.writeObject(Ellipse2D.class);
 
400
                stream.writeDouble(ellipse.getX());
 
401
                stream.writeDouble(ellipse.getY());
 
402
                stream.writeDouble(ellipse.getWidth());
 
403
                stream.writeDouble(ellipse.getHeight());
 
404
            }
 
405
            else if (shape instanceof Arc2D) {
 
406
                final Arc2D arc = (Arc2D) shape;
 
407
                stream.writeObject(Arc2D.class);
 
408
                stream.writeDouble(arc.getX());
 
409
                stream.writeDouble(arc.getY());
 
410
                stream.writeDouble(arc.getWidth());
 
411
                stream.writeDouble(arc.getHeight());
 
412
                stream.writeDouble(arc.getAngleStart());
 
413
                stream.writeDouble(arc.getAngleExtent());
 
414
                stream.writeInt(arc.getArcType());
 
415
            }
 
416
            else if (shape instanceof GeneralPath) {
 
417
                stream.writeObject(GeneralPath.class);
 
418
                final PathIterator pi = shape.getPathIterator(null);
 
419
                final float[] args = new float[6];
 
420
                stream.writeBoolean(pi.isDone());
 
421
                while (!pi.isDone()) {
 
422
                    final int type = pi.currentSegment(args);
 
423
                    stream.writeInt(type);
 
424
                    // TODO: could write this to only stream the values
 
425
                    // required for the segment type
 
426
                    for (int i = 0; i < 6; i++) {
 
427
                        stream.writeFloat(args[i]);
 
428
                    }
 
429
                    stream.writeInt(pi.getWindingRule());
 
430
                    pi.next();
 
431
                    stream.writeBoolean(pi.isDone());
 
432
                }
 
433
            }
 
434
            else {
 
435
                stream.writeObject(shape.getClass());
 
436
                stream.writeObject(shape);
 
437
            }
 
438
        }
 
439
        else {
 
440
            stream.writeBoolean(true);
 
441
        }
 
442
    }
 
443
 
 
444
    /**
 
445
     * Reads a <code>Point2D</code> object that has been serialised by the 
 
446
     * {@link #writePoint2D(Point2D, ObjectOutputStream)} method.
 
447
     *
 
448
     * @param stream  the input stream (<code>null</code> not permitted).
 
449
     *
 
450
     * @return The point object (possibly <code>null</code>).
 
451
     *
 
452
     * @throws IOException  if there is an I/O problem.
 
453
     */
 
454
    public static Point2D readPoint2D(final ObjectInputStream stream)
 
455
        throws IOException {
 
456
 
 
457
        if (stream == null) {
 
458
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
459
        }
 
460
        Point2D result = null;
 
461
        final boolean isNull = stream.readBoolean();
 
462
        if (!isNull) {
 
463
            final double x = stream.readDouble();
 
464
            final double y = stream.readDouble();
 
465
            result = new Point2D.Double(x, y);
 
466
        }
 
467
        return result;
 
468
 
 
469
    }
 
470
 
 
471
    /**
 
472
     * Serialises a <code>Point2D</code> object.
 
473
     *
 
474
     * @param p  the point object (<code>null</code> permitted).
 
475
     * @param stream  the output stream (<code>null</code> not permitted).
 
476
     *
 
477
     * @throws IOException if there is an I/O error.
 
478
     */
 
479
    public static void writePoint2D(final Point2D p,
 
480
                                    final ObjectOutputStream stream) 
 
481
        throws IOException {
 
482
 
 
483
        if (stream == null) {
 
484
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
485
        }
 
486
        if (p != null) {
 
487
            stream.writeBoolean(false);
 
488
            stream.writeDouble(p.getX());
 
489
            stream.writeDouble(p.getY());
 
490
        }
 
491
        else {
 
492
            stream.writeBoolean(true);
 
493
        }
 
494
    }
 
495
    
 
496
    /**
 
497
     * Reads a <code>AttributedString</code> object that has been serialised by 
 
498
     * the {@link SerialUtilities#writeAttributedString(AttributedString, 
 
499
     * ObjectOutputStream)} method.
 
500
     *
 
501
     * @param stream  the input stream (<code>null</code> not permitted).
 
502
     *
 
503
     * @return The attributed string object (possibly <code>null</code>).
 
504
     *
 
505
     * @throws IOException  if there is an I/O problem.
 
506
     * @throws ClassNotFoundException  if there is a problem loading a class.
 
507
     */
 
508
    public static AttributedString readAttributedString(
 
509
            ObjectInputStream stream) 
 
510
            throws IOException, ClassNotFoundException {
 
511
        
 
512
        if (stream == null) {
 
513
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
514
        }
 
515
        AttributedString result = null;
 
516
        final boolean isNull = stream.readBoolean();
 
517
        if (!isNull) {
 
518
            // read string and attributes then create result
 
519
            String plainStr = (String) stream.readObject();
 
520
            result = new AttributedString(plainStr);
 
521
            char c = stream.readChar();
 
522
            int start = 0;
 
523
            while (c != CharacterIterator.DONE) {
 
524
                int limit = stream.readInt();
 
525
                Map atts = (Map) stream.readObject();
 
526
                result.addAttributes(atts, start, limit);
 
527
                start = limit;
 
528
                c = stream.readChar();
 
529
            }
 
530
        }
 
531
        return result;
 
532
    }
 
533
    
 
534
    /**
 
535
     * Serialises an <code>AttributedString</code> object.
 
536
     *
 
537
     * @param as  the attributed string object (<code>null</code> permitted).
 
538
     * @param stream  the output stream (<code>null</code> not permitted).
 
539
     *
 
540
     * @throws IOException if there is an I/O error.
 
541
     */
 
542
    public static void writeAttributedString(AttributedString as, 
 
543
            ObjectOutputStream stream) throws IOException {
 
544
        
 
545
        if (stream == null) {
 
546
            throw new IllegalArgumentException("Null 'stream' argument.");   
 
547
        }
 
548
        if (as != null) {
 
549
            stream.writeBoolean(false);
 
550
            AttributedCharacterIterator aci = as.getIterator();
 
551
            // build a plain string from aci
 
552
            // then write the string
 
553
            StringBuffer plainStr = new StringBuffer();
 
554
            char current = aci.first();
 
555
            while (current != CharacterIterator.DONE) {
 
556
                plainStr = plainStr.append(current);
 
557
                current = aci.next();
 
558
            }
 
559
            stream.writeObject(plainStr.toString());
 
560
            
 
561
            // then write the attributes and limits for each run
 
562
            current = aci.first();
 
563
            int begin = aci.getBeginIndex();
 
564
            while (current != CharacterIterator.DONE) {
 
565
                // write the current character - when the reader sees that this
 
566
                // is not CharacterIterator.DONE, it will know to read the
 
567
                // run limits and attributes
 
568
                stream.writeChar(current);
 
569
                
 
570
                // now write the limit, adjusted as if beginIndex is zero
 
571
                int limit = aci.getRunLimit();
 
572
                stream.writeInt(limit - begin);
 
573
                
 
574
                // now write the attribute set
 
575
                Map atts = new HashMap(aci.getAttributes());
 
576
                stream.writeObject(atts);
 
577
                current = aci.setIndex(limit);
 
578
            }
 
579
            // write a character that signals to the reader that all runs
 
580
            // are done...
 
581
            stream.writeChar(CharacterIterator.DONE);  
 
582
        }
 
583
        else {
 
584
            // write a flag that indicates a null
 
585
            stream.writeBoolean(true);
 
586
        }
 
587
 
 
588
    }
 
589
 
 
590
}
 
591