~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/java/io/InteropObjectOutputStream.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
 
3
 * Copyright 2009 Jeroen Frijters
 
4
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
5
 *
 
6
 * This code is free software; you can redistribute it and/or modify it
 
7
 * under the terms of the GNU General Public License version 2 only, as
 
8
 * published by the Free Software Foundation.  Oracle designates this
 
9
 * particular file as subject to the "Classpath" exception as provided
 
10
 * by Oracle in the LICENSE file that accompanied this code.
 
11
 *
 
12
 * This code is distributed in the hope that it will be useful, but WITHOUT
 
13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
15
 * version 2 for more details (a copy is included in the LICENSE file that
 
16
 * accompanied this code).
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License version
 
19
 * 2 along with this work; if not, write to the Free Software Foundation,
 
20
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
21
 *
 
22
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 
23
 * or visit www.oracle.com if you need additional information or have any
 
24
 * questions.
 
25
 */
 
26
package java.io;
 
27
 
 
28
import cli.System.Runtime.Serialization.IObjectReference;
 
29
import cli.System.Runtime.Serialization.SerializationException;
 
30
import cli.System.Runtime.Serialization.SerializationInfo;
 
31
import cli.System.Runtime.Serialization.StreamingContext;
 
32
import cli.System.SerializableAttribute;
 
33
import java.util.ArrayList;
 
34
 
 
35
@ikvm.lang.Internal
 
36
public final class InteropObjectOutputStream extends ObjectOutputStream
 
37
{
 
38
    private final ObjectDataOutputStream dos;
 
39
    private Object curObj;
 
40
    private ObjectStreamClass curDesc;
 
41
    private PutFieldImpl curPut;
 
42
    
 
43
    @SerializableAttribute.Annotation
 
44
    private static final class ReplaceProxy implements IObjectReference
 
45
    {
 
46
        private Object obj;
 
47
 
 
48
        @cli.System.Security.SecurityCriticalAttribute.Annotation
 
49
        public Object GetRealObject(StreamingContext context)
 
50
        {
 
51
            return obj;
 
52
        }
 
53
    }
 
54
    
 
55
    static final class DynamicProxy implements Serializable
 
56
    {
 
57
        Object obj;
 
58
 
 
59
        private Object readResolve()
 
60
        {
 
61
            return obj;
 
62
        }
 
63
    }
 
64
    
 
65
    public static void writeObject(Object obj, SerializationInfo info)
 
66
    {
 
67
        try
 
68
        {
 
69
            boolean replaced = false;
 
70
            Class cl = obj.getClass();
 
71
            ObjectStreamClass desc;
 
72
            for (;;)
 
73
            {
 
74
                Class repCl;
 
75
                desc = ObjectStreamClass.lookup(cl, true);
 
76
                if (!desc.hasWriteReplaceMethod() ||
 
77
                    (obj = desc.invokeWriteReplace(obj)) == null ||
 
78
                    (repCl = obj.getClass()) == cl)
 
79
                {
 
80
                    break;
 
81
                }
 
82
                cl = repCl;
 
83
                replaced = true;
 
84
            }
 
85
            if (replaced)
 
86
            {
 
87
                info.AddValue("obj", obj);
 
88
                info.SetType(ikvm.runtime.Util.getInstanceTypeFromClass(ReplaceProxy.class));
 
89
            }
 
90
            else
 
91
            {
 
92
                new InteropObjectOutputStream(info, obj, cl, desc);
 
93
            }
 
94
        }
 
95
        catch (IOException x)
 
96
        {
 
97
            ikvm.runtime.Util.throwException(new SerializationException(x.getMessage(), x));
 
98
        }
 
99
    }
 
100
    
 
101
    private InteropObjectOutputStream(SerializationInfo info, Object obj, Class cl, ObjectStreamClass desc) throws IOException
 
102
    {
 
103
        dos = new ObjectDataOutputStream(info);
 
104
        if (obj instanceof ObjectStreamClass)
 
105
        {
 
106
            ObjectStreamClass osc = (ObjectStreamClass)obj;
 
107
            if (osc.isProxy())
 
108
            {
 
109
                writeProxyDesc(osc);
 
110
            }
 
111
            else
 
112
            {
 
113
                writeNonProxyDesc(osc);
 
114
            }
 
115
        }
 
116
        else if (obj instanceof Serializable)
 
117
        {
 
118
            if (desc.isDynamicClass())
 
119
            {
 
120
                info.SetType(ikvm.runtime.Util.getInstanceTypeFromClass(DynamicProxy.class));
 
121
            }
 
122
            writeOrdinaryObject(obj, desc);
 
123
        }
 
124
        else
 
125
        {
 
126
            throw new NotSerializableException(cl.getName());
 
127
        }
 
128
        dos.close();
 
129
    }
 
130
    
 
131
    private void writeProxyDesc(ObjectStreamClass desc) throws IOException
 
132
    {
 
133
        writeByte(TC_PROXYCLASSDESC);
 
134
        Class cl = desc.forClass();
 
135
        Class[] ifaces = cl.getInterfaces();
 
136
        writeInt(ifaces.length);
 
137
        for (int i = 0; i < ifaces.length; i++)
 
138
        {
 
139
            writeObject(ifaces[i]);
 
140
        }
 
141
        writeObject(desc.getSuperDesc());
 
142
    }
 
143
    
 
144
    private void writeNonProxyDesc(ObjectStreamClass desc) throws IOException
 
145
    {
 
146
        writeByte(TC_CLASSDESC);
 
147
        writeObject(desc.forClass());
 
148
        desc.writeNonProxy(this);
 
149
        writeObject(desc.getSuperDesc());
 
150
    }
 
151
    
 
152
    private void writeOrdinaryObject(Object obj, ObjectStreamClass desc) throws IOException
 
153
    {
 
154
        desc.checkSerialize();
 
155
        writeObject(desc);
 
156
        if (desc.isExternalizable() && !desc.isProxy())
 
157
        {
 
158
            writeExternalData((Externalizable)obj);
 
159
        }
 
160
        else
 
161
        {
 
162
            writeSerialData(obj, desc);
 
163
        }
 
164
    }
 
165
    
 
166
    private void writeExternalData(Externalizable obj) throws IOException
 
167
    {
 
168
        Object oldObj = curObj;
 
169
        ObjectStreamClass oldDesc = curDesc;
 
170
        PutFieldImpl oldPut = curPut;
 
171
        curObj = obj;
 
172
        curDesc = null;
 
173
        curPut = null;
 
174
 
 
175
        obj.writeExternal(this);
 
176
        dos.writeMarker();
 
177
 
 
178
        curObj = oldObj;
 
179
        curDesc = oldDesc;
 
180
        curPut = oldPut;
 
181
    }
 
182
    
 
183
    private void writeSerialData(Object obj, ObjectStreamClass desc) throws IOException
 
184
    {
 
185
        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
 
186
        for (int i = 0; i < slots.length; i++)
 
187
        {
 
188
            ObjectStreamClass slotDesc = slots[i].desc;
 
189
            if (slotDesc.hasWriteObjectMethod())
 
190
            {
 
191
                Object oldObj = curObj;
 
192
                ObjectStreamClass oldDesc = curDesc;
 
193
                PutFieldImpl oldPut = curPut;
 
194
                curObj = obj;
 
195
                curDesc = slotDesc;
 
196
                curPut = null;
 
197
                slotDesc.invokeWriteObject(obj, this);
 
198
                dos.writeMarker();
 
199
                curObj = oldObj;
 
200
                curDesc = oldDesc;
 
201
                curPut = oldPut;
 
202
            }
 
203
            else
 
204
            {
 
205
                defaultWriteFields(obj, slotDesc);
 
206
            }
 
207
        }
 
208
    }
 
209
 
 
210
    private void defaultWriteFields(Object obj, ObjectStreamClass desc) throws IOException
 
211
    {
 
212
        desc.checkDefaultSerialize();
 
213
 
 
214
        byte[] primVals = new byte[desc.getPrimDataSize()];
 
215
        desc.getPrimFieldValues(obj, primVals);
 
216
        write(primVals);
 
217
 
 
218
        Object[] objVals = new Object[desc.getNumObjFields()];
 
219
        desc.getObjFieldValues(obj, objVals);
 
220
        for (int i = 0; i < objVals.length; i++)
 
221
        {
 
222
            writeObject(objVals[i]);
 
223
        }
 
224
    }
 
225
 
 
226
    @Override    
 
227
    public void defaultWriteObject() throws IOException
 
228
    {
 
229
        defaultWriteFields(curObj, curDesc);
 
230
    }
 
231
 
 
232
    @Override    
 
233
    public void close()
 
234
    {
 
235
        throw new UnsupportedOperationException();
 
236
    }
 
237
 
 
238
    @Override    
 
239
    public void flush()
 
240
    {
 
241
    }
 
242
 
 
243
    @Override    
 
244
    public ObjectOutputStream.PutField putFields() throws IOException
 
245
    {
 
246
        if (curPut == null)
 
247
        {
 
248
            if (curObj == null || curDesc == null)
 
249
            {
 
250
                throw new NotActiveException("not in call to writeObject");
 
251
            }
 
252
            curPut = new PutFieldImpl(curDesc);
 
253
        }
 
254
        return curPut;
 
255
    }
 
256
 
 
257
    @Override    
 
258
    public void reset() throws IOException
 
259
    {
 
260
        throw new IOException("stream active");
 
261
    }
 
262
 
 
263
    @Override    
 
264
    protected void writeObjectOverride(Object obj)
 
265
    {
 
266
        // TODO consider tagging ghost arrays
 
267
        dos.writeObject(obj);
 
268
    }
 
269
 
 
270
    @Override    
 
271
    public void writeFields() throws IOException
 
272
    {
 
273
        if (curPut == null)
 
274
        {
 
275
            throw new NotActiveException("no current PutField object");
 
276
        }
 
277
        curPut.writeFields();
 
278
    }
 
279
 
 
280
    @Override    
 
281
    public void writeUnshared(Object obj)
 
282
    {
 
283
        throw new UnsupportedOperationException();
 
284
    }
 
285
 
 
286
    @Override    
 
287
    public void useProtocolVersion(int version)
 
288
    {
 
289
        throw new IllegalStateException("stream non-empty");
 
290
    }
 
291
 
 
292
    @Override    
 
293
    public void write(byte[] buf) throws IOException
 
294
    {
 
295
        write(buf, 0, buf.length);
 
296
    }
 
297
 
 
298
    @Override    
 
299
    public void write(int val) throws IOException
 
300
    {
 
301
        dos.write(val);
 
302
    }
 
303
 
 
304
    @Override    
 
305
    public void write(byte[] buf, int off, int len) throws IOException
 
306
    {
 
307
        dos.write(buf, off, len);
 
308
    }
 
309
 
 
310
    @Override    
 
311
    public void writeBoolean(boolean val) throws IOException
 
312
    {
 
313
        dos.writeBoolean(val);
 
314
    }
 
315
 
 
316
    @Override    
 
317
    public void writeByte(int val) throws IOException
 
318
    {
 
319
        dos.writeByte(val);
 
320
    }
 
321
 
 
322
    @Override    
 
323
    public void writeBytes(String str) throws IOException
 
324
    {
 
325
        dos.writeBytes(str);
 
326
    }
 
327
 
 
328
    @Override    
 
329
    public void writeChar(int val) throws IOException
 
330
    {
 
331
        dos.writeChar(val);
 
332
    }
 
333
 
 
334
    @Override    
 
335
    public void writeChars(String str) throws IOException
 
336
    {
 
337
        dos.writeChars(str);
 
338
    }
 
339
 
 
340
    @Override    
 
341
    public void writeDouble(double val) throws IOException
 
342
    {
 
343
        dos.writeDouble(val);
 
344
    }
 
345
 
 
346
    @Override    
 
347
    public void writeFloat(float val) throws IOException
 
348
    {
 
349
        dos.writeFloat(val);
 
350
    }
 
351
 
 
352
    @Override    
 
353
    public void writeInt(int val) throws IOException
 
354
    {
 
355
        dos.writeInt(val);
 
356
    }
 
357
 
 
358
    @Override    
 
359
    public void writeLong(long val) throws IOException
 
360
    {
 
361
        dos.writeLong(val);
 
362
    }
 
363
 
 
364
    @Override    
 
365
    public void writeShort(int val) throws IOException
 
366
    {
 
367
        dos.writeShort(val);
 
368
    }
 
369
 
 
370
    @Override    
 
371
    public void writeUTF(String str) throws IOException
 
372
    {
 
373
        dos.writeUTF(str);
 
374
    }
 
375
    
 
376
    // private API used by ObjectStreamClass
 
377
    @Override    
 
378
    void writeTypeString(String str) throws IOException
 
379
    {
 
380
        writeObject(str);
 
381
    }
 
382
 
 
383
    private final class PutFieldImpl extends PutField {
 
384
 
 
385
        /** class descriptor describing serializable fields */
 
386
        private final ObjectStreamClass desc;
 
387
        /** primitive field values */
 
388
        private final byte[] primVals;
 
389
        /** object field values */
 
390
        private final Object[] objVals;
 
391
 
 
392
        /**
 
393
         * Creates PutFieldImpl object for writing fields defined in given
 
394
         * class descriptor.
 
395
         */
 
396
        PutFieldImpl(ObjectStreamClass desc) {
 
397
            this.desc = desc;
 
398
            primVals = new byte[desc.getPrimDataSize()];
 
399
            objVals = new Object[desc.getNumObjFields()];
 
400
        }
 
401
 
 
402
        public void put(String name, boolean val) {
 
403
            Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
 
404
        }
 
405
 
 
406
        public void put(String name, byte val) {
 
407
            primVals[getFieldOffset(name, Byte.TYPE)] = val;
 
408
        }
 
409
 
 
410
        public void put(String name, char val) {
 
411
            Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
 
412
        }
 
413
 
 
414
        public void put(String name, short val) {
 
415
            Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
 
416
        }
 
417
 
 
418
        public void put(String name, int val) {
 
419
            Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
 
420
        }
 
421
 
 
422
        public void put(String name, float val) {
 
423
            Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
 
424
        }
 
425
 
 
426
        public void put(String name, long val) {
 
427
            Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
 
428
        }
 
429
 
 
430
        public void put(String name, double val) {
 
431
            Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
 
432
        }
 
433
 
 
434
        public void put(String name, Object val) {
 
435
            objVals[getFieldOffset(name, Object.class)] = val;
 
436
        }
 
437
 
 
438
        // deprecated in ObjectOutputStream.PutField
 
439
        public void write(ObjectOutput out) throws IOException {
 
440
            /*
 
441
             * Applications should *not* use this method to write PutField
 
442
             * data, as it will lead to stream corruption if the PutField
 
443
             * object writes any primitive data (since block data mode is not
 
444
             * unset/set properly, as is done in OOS.writeFields()).  This
 
445
             * broken implementation is being retained solely for behavioral
 
446
             * compatibility, in order to support applications which use
 
447
             * OOS.PutField.write() for writing only non-primitive data.
 
448
             *
 
449
             * Serialization of unshared objects is not implemented here since
 
450
             * it is not necessary for backwards compatibility; also, unshared
 
451
             * semantics may not be supported by the given ObjectOutput
 
452
             * instance.  Applications which write unshared objects using the
 
453
             * PutField API must use OOS.writeFields().
 
454
             */
 
455
            if (InteropObjectOutputStream.this != out) {
 
456
                throw new IllegalArgumentException("wrong stream");
 
457
            }
 
458
            out.write(primVals, 0, primVals.length);
 
459
 
 
460
            ObjectStreamField[] fields = desc.getFields(false);
 
461
            int numPrimFields = fields.length - objVals.length;
 
462
            // REMIND: warn if numPrimFields > 0?
 
463
            for (int i = 0; i < objVals.length; i++) {
 
464
                if (fields[numPrimFields + i].isUnshared()) {
 
465
                    throw new IOException("cannot write unshared object");
 
466
                }
 
467
                out.writeObject(objVals[i]);
 
468
            }
 
469
        }
 
470
 
 
471
        /**
 
472
         * Writes buffered primitive data and object fields to stream.
 
473
         */
 
474
        void writeFields() throws IOException {
 
475
            InteropObjectOutputStream.this.write(primVals, 0, primVals.length);
 
476
 
 
477
            ObjectStreamField[] fields = desc.getFields(false);
 
478
            int numPrimFields = fields.length - objVals.length;
 
479
            for (int i = 0; i < objVals.length; i++) {
 
480
                writeObject(objVals[i]);
 
481
            }
 
482
        }
 
483
 
 
484
        /**
 
485
         * Returns offset of field with given name and type.  A specified type
 
486
         * of null matches all types, Object.class matches all non-primitive
 
487
         * types, and any other non-null type matches assignable types only.
 
488
         * Throws IllegalArgumentException if no matching field found.
 
489
         */
 
490
        private int getFieldOffset(String name, Class type) {
 
491
            ObjectStreamField field = desc.getField(name, type);
 
492
            if (field == null) {
 
493
                throw new IllegalArgumentException("no such field " + name +
 
494
                                                   " with type " + type);
 
495
            }
 
496
            return field.getOffset();
 
497
        }
 
498
    }
 
499
 
 
500
    private static final class ObjectDataOutputStream extends DataOutputStream
 
501
    {
 
502
        /*
 
503
         * States:
 
504
         *  blockStart   objCount
 
505
         *          -1          0       Previous byte was a marker (or we're at the start of the stream), next byte will be MARKER, OBJECTS or BYTES
 
506
         *         >=0          0       We're currently writing a byte stream (that starts at blockStart + 1)
 
507
         *          -1         >0       We're currently writing objects (just a count of objects really)
 
508
         *
 
509
         */
 
510
        private static final byte MARKER = 0;
 
511
        private static final byte OBJECTS = 10;
 
512
        private static final byte BYTES = 20;
 
513
        private final SerializationInfo info;
 
514
        private byte[] buf = new byte[16];
 
515
        private int pos;
 
516
        private int blockStart = -1;
 
517
        private int objCount;
 
518
        private int objId;
 
519
 
 
520
        ObjectDataOutputStream(SerializationInfo info)
 
521
        {
 
522
            super(null);
 
523
            out = this;
 
524
            this.info = info;
 
525
        }
 
526
        
 
527
        private void grow(int minGrow)
 
528
        {
 
529
            int newSize = buf.length + Math.max(buf.length, minGrow);
 
530
            byte[] newBuf = new byte[newSize];
 
531
            System.arraycopy(buf, 0, newBuf, 0, pos);
 
532
            buf = newBuf;
 
533
        }
 
534
        
 
535
        private void switchToData()
 
536
        {
 
537
            if (objCount == 0)
 
538
            {
 
539
                if (pos == buf.length)
 
540
                {
 
541
                    grow(1);
 
542
                }
 
543
                buf[pos++] = BYTES;
 
544
            }
 
545
            else
 
546
            {
 
547
                int len = packedLength(objCount);
 
548
                if (pos + len >= buf.length)
 
549
                {
 
550
                    grow(len);
 
551
                }
 
552
                writePacked(pos, objCount);
 
553
                objCount = 0;
 
554
                pos += len;
 
555
            }
 
556
            blockStart = pos;
 
557
            // reserve space for the number of bytes
 
558
            // (we assume that one byte will suffice, but if it won't the endData code will copy the data to make room)
 
559
            if (pos == buf.length)
 
560
            {
 
561
                grow(1);
 
562
            }
 
563
            pos++;
 
564
        }
 
565
        
 
566
        private void endData()
 
567
        {
 
568
            if (blockStart == -1)
 
569
            {
 
570
                if (pos == buf.length)
 
571
                {
 
572
                    grow(1);
 
573
                }
 
574
                buf[pos++] = OBJECTS;
 
575
            }
 
576
            else
 
577
            {
 
578
                int len = (pos - blockStart) - 1;
 
579
                int lenlen = packedLength(len);
 
580
                if (lenlen > 1)
 
581
                {
 
582
                    lenlen--;
 
583
                    if (buf.length - pos <= lenlen)
 
584
                    {
 
585
                        grow(lenlen);
 
586
                    }
 
587
                    System.arraycopy(buf, blockStart + 1, buf, blockStart + 1 + lenlen, pos - (blockStart + 1));
 
588
                    pos += lenlen;
 
589
                }
 
590
                writePacked(blockStart, len);
 
591
                blockStart = -1;
 
592
            }
 
593
        }
 
594
        
 
595
        private int packedLength(int val)
 
596
        {
 
597
            if (val < 0)
 
598
            {
 
599
                // we only use packed integers for lengths or counts, so they can never be negative
 
600
                throw new Error();
 
601
            }
 
602
            else if (val < 128)
 
603
            {
 
604
                return 1;
 
605
            }
 
606
            else if (val < 16129)
 
607
            {
 
608
                return 2;
 
609
            }
 
610
            else
 
611
            {
 
612
                return 5;
 
613
            }
 
614
        }
 
615
        
 
616
        private void writePacked(int pos, int v)
 
617
        {
 
618
            if (v < 128)
 
619
            {
 
620
                buf[pos] = (byte)v;
 
621
            }
 
622
            else if (v < 16129)
 
623
            {
 
624
                buf[pos + 0] = (byte)(128 | (v >> 7));
 
625
                buf[pos + 1] = (byte)(v & 127);
 
626
            }
 
627
            else
 
628
            {
 
629
                buf[pos + 0] = (byte)128;
 
630
                buf[pos + 1] = (byte)(v >>> 24);
 
631
                buf[pos + 2] = (byte)(v >>> 16);
 
632
                buf[pos + 3] = (byte)(v >>>  8);
 
633
                buf[pos + 4] = (byte)(v >>>  0);
 
634
            }
 
635
        }
 
636
        
 
637
        @Override
 
638
        public void write(int b)
 
639
        {
 
640
            if (blockStart == -1)
 
641
            {
 
642
                switchToData();
 
643
            }
 
644
            if (pos == buf.length)
 
645
            {
 
646
                grow(1);
 
647
            }
 
648
            buf[pos++] = (byte)b;
 
649
        }
 
650
        
 
651
        @Override
 
652
        public void write(byte[] b, int off, int len)
 
653
        {
 
654
            if (len == 0)
 
655
            {
 
656
                return;
 
657
            }
 
658
            if (blockStart == -1)
 
659
            {
 
660
                switchToData();
 
661
            }
 
662
            if (pos + len >= buf.length)
 
663
            {
 
664
                grow(len);
 
665
            }
 
666
            System.arraycopy(b, off, buf, pos, len);
 
667
            pos += len;
 
668
        }
 
669
        
 
670
        public void writeObject(Object obj)
 
671
        {
 
672
            if (objCount == 0)
 
673
            {
 
674
                endData();
 
675
            }
 
676
            objCount++;
 
677
            info.AddValue("$" + (objId++), obj);
 
678
        }
 
679
        
 
680
        @Override
 
681
        public void close()
 
682
        {
 
683
            if (objCount == 0)
 
684
            {
 
685
                if (blockStart == -1)
 
686
                {
 
687
                    // we've just written a marker, so we don't need to do anything else
 
688
                }
 
689
                else
 
690
                {
 
691
                    endData();
 
692
                }
 
693
            }
 
694
            else
 
695
            {
 
696
                switchToData();
 
697
            }
 
698
            trim();
 
699
            info.AddValue("$data", buf);
 
700
        }
 
701
        
 
702
        private void trim()
 
703
        {
 
704
            if (buf.length != pos)
 
705
            {
 
706
                byte[] newBuf = new byte[pos];
 
707
                System.arraycopy(buf, 0, newBuf, 0, pos);
 
708
                buf = newBuf;
 
709
            }
 
710
        }
 
711
        
 
712
        @Override
 
713
        public void flush()
 
714
        {
 
715
        }
 
716
        
 
717
        public void writeMarker()
 
718
        {
 
719
            if (objCount == 0)
 
720
            {
 
721
                if (blockStart != -1)
 
722
                {
 
723
                    endData();
 
724
                }
 
725
                if (pos == buf.length)
 
726
                {
 
727
                    grow(1);
 
728
                }
 
729
                buf[pos++] = MARKER;
 
730
            }
 
731
            else
 
732
            {
 
733
                switchToData();
 
734
            }
 
735
            blockStart = -1;
 
736
        }
 
737
    }
 
738
}