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

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/sun/awt/IkvmDataTransferer.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) 2009 Jeroen Frijters
 
3
 
 
4
  This software is provided 'as-is', without any express or implied
 
5
  warranty.  In no event will the authors be held liable for any damages
 
6
  arising from the use of this software.
 
7
 
 
8
  Permission is granted to anyone to use this software for any purpose,
 
9
  including commercial applications, and to alter it and redistribute it
 
10
  freely, subject to the following restrictions:
 
11
 
 
12
  1. The origin of this software must not be misrepresented; you must not
 
13
     claim that you wrote the original software. If you use this software
 
14
     in a product, an acknowledgment in the product documentation would be
 
15
     appreciated but is not required.
 
16
  2. Altered source versions must be plainly marked as such, and must not be
 
17
     misrepresented as being the original software.
 
18
  3. This notice may not be removed or altered from any source distribution.
 
19
 
 
20
  Jeroen Frijters
 
21
  jeroen@frijters.net 
 
22
 
 
23
 */
 
24
 
 
25
package sun.awt;
 
26
 
 
27
import java.awt.Image;
 
28
import java.awt.datatransfer.DataFlavor;
 
29
import java.awt.datatransfer.FlavorTable;
 
30
import java.awt.datatransfer.Transferable;
 
31
import java.awt.datatransfer.UnsupportedFlavorException;
 
32
import java.io.BufferedInputStream;
 
33
import java.io.BufferedReader;
 
34
import java.io.ByteArrayInputStream;
 
35
import java.io.IOException;
 
36
import java.io.InputStream;
 
37
import java.io.InputStreamReader;
 
38
import java.io.UnsupportedEncodingException;
 
39
import java.net.URL;
 
40
import java.util.Arrays;
 
41
import java.util.Collections;
 
42
import java.util.HashMap;
 
43
import java.util.Map;
 
44
import java.util.SortedMap;
 
45
 
 
46
import sun.awt.datatransfer.DataTransferer;
 
47
import cli.System.Runtime.InteropServices.DllImportAttribute;
 
48
 
 
49
public abstract class IkvmDataTransferer extends DataTransferer {
 
50
        public static final int CF_TEXT = 1;
 
51
        public static final int CF_METAFILEPICT = 3;
 
52
        public static final int CF_DIB = 8;
 
53
        public static final int CF_ENHMETAFILE = 14;
 
54
        public static final int CF_HDROP = 15;
 
55
        public static final int CF_LOCALE = 16;
 
56
 
 
57
        public static final long CF_HTML = RegisterClipboardFormat("HTML Format");
 
58
        public static final long CFSTR_INETURL = RegisterClipboardFormat("UniformResourceLocator");
 
59
        public static final long CF_PNG = RegisterClipboardFormat("PNG");
 
60
        public static final long CF_JFIF = RegisterClipboardFormat("JFIF");
 
61
        
 
62
    private static final String[] predefinedClipboardNames = {
 
63
        "",
 
64
        "TEXT",
 
65
        "BITMAP",
 
66
        "METAFILEPICT",
 
67
        "SYLK",
 
68
        "DIF",
 
69
        "TIFF",
 
70
        "OEM TEXT",
 
71
        "DIB",
 
72
        "PALETTE",
 
73
        "PENDATA",
 
74
        "RIFF",
 
75
        "WAVE",
 
76
        "UNICODE TEXT",
 
77
        "ENHMETAFILE",
 
78
        "HDROP",
 
79
        "LOCALE",
 
80
        "DIBV5"
 
81
    };
 
82
 
 
83
    private static final Map<String, Long> predefinedClipboardNameMap;
 
84
 
 
85
    static {
 
86
        Map<String, Long> tempMap = new HashMap<String, Long>(predefinedClipboardNames.length, 1.0f);
 
87
        for (int i = 1; i < predefinedClipboardNames.length; i++) {
 
88
            tempMap.put(predefinedClipboardNames[i], Long.valueOf(i));
 
89
        }
 
90
        predefinedClipboardNameMap = Collections.synchronizedMap(tempMap);
 
91
    }
 
92
 
 
93
    private static final Long L_CF_LOCALE = (Long) predefinedClipboardNameMap.get(predefinedClipboardNames[CF_LOCALE]);
 
94
    
 
95
    @DllImportAttribute.Annotation(value = "user32.dll", EntryPoint = "RegisterClipboardFormat")
 
96
    private native static int _RegisterClipboardFormat(String format);
 
97
 
 
98
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
99
    private static int RegisterClipboardFormat(String format)
 
100
    {
 
101
        return _RegisterClipboardFormat(format);
 
102
    }
 
103
 
 
104
    public SortedMap getFormatsForFlavors(DataFlavor[] flavors, FlavorTable map) {
 
105
        SortedMap retval = super.getFormatsForFlavors(flavors, map);
 
106
 
 
107
        // The Win32 native code does not support exporting LOCALE data, nor
 
108
        // should it.
 
109
        retval.remove(L_CF_LOCALE);
 
110
 
 
111
        return retval;
 
112
    }
 
113
 
 
114
    public String getDefaultUnicodeEncoding() {
 
115
        return "utf-16le";
 
116
    }
 
117
 
 
118
    public byte[] translateTransferable(Transferable contents,
 
119
                                        DataFlavor flavor,
 
120
                                        long format) throws IOException
 
121
    {
 
122
        byte[] bytes = super.translateTransferable(contents, flavor, format);
 
123
 
 
124
        if (format == CF_HTML) {
 
125
            bytes = HTMLCodec.convertToHTMLFormat(bytes);
 
126
        }
 
127
        return bytes;
 
128
    }
 
129
 
 
130
    protected Object translateBytesOrStream(InputStream str, byte[] bytes,
 
131
                                            DataFlavor flavor, long format,
 
132
                                            Transferable localeTransferable)
 
133
        throws IOException
 
134
    {
 
135
        if (format == CF_HTML && flavor.isFlavorTextType()) {
 
136
            if (str == null) {
 
137
                str = new ByteArrayInputStream(bytes);
 
138
                bytes = null;
 
139
            }
 
140
 
 
141
            str = new HTMLCodec(str,  EHTMLReadMode.HTML_READ_SELECTION);
 
142
        }
 
143
 
 
144
        if (format == CFSTR_INETURL &&
 
145
            URL.class.equals(flavor.getRepresentationClass()))
 
146
        {
 
147
            if (bytes == null) {
 
148
                bytes = inputStreamToByteArray(str);
 
149
                str = null;
 
150
            }
 
151
            String charset = getDefaultTextCharset();
 
152
            if (localeTransferable != null && localeTransferable.
 
153
                isDataFlavorSupported(javaTextEncodingFlavor))
 
154
            {
 
155
                try {
 
156
                    charset = new String((byte[])localeTransferable.
 
157
                                   getTransferData(javaTextEncodingFlavor),
 
158
                                   "UTF-8");
 
159
                } catch (UnsupportedFlavorException cannotHappen) {
 
160
                }
 
161
            }
 
162
            return new URL(new String(bytes, charset));
 
163
        }
 
164
 
 
165
        return super.translateBytesOrStream(str, bytes, flavor, format,
 
166
                                            localeTransferable);
 
167
    }
 
168
    
 
169
        protected byte[] imageToPlatformBytes(Image image, long format)
 
170
                        throws IOException {
 
171
                String mimeType = null;
 
172
                if (format == CF_PNG) {
 
173
                        mimeType = "image/png";
 
174
                } else if (format == CF_JFIF) {
 
175
                        mimeType = "image/jpeg";
 
176
                }
 
177
                if (mimeType != null) {
 
178
                        return imageToStandardBytes(image, mimeType);
 
179
                }
 
180
                throw new Error("Not implemented");
 
181
        }
 
182
 
 
183
        protected abstract byte[] imageToStandardBytes(Image image, String mimeType)
 
184
                        throws IOException;
 
185
 
 
186
        protected Image platformImageBytesOrStreamToImage(InputStream str,
 
187
                        byte[] bytes, long format) {
 
188
                throw new Error("Not implemented");
 
189
        }
 
190
 
 
191
        protected String[] dragQueryFile(byte[] bytes) {
 
192
                throw new Error("Not implemented");
 
193
        }
 
194
 
 
195
    protected String getNativeForFormat(long format) {
 
196
        return (format < predefinedClipboardNames.length && format>=0)
 
197
            ? predefinedClipboardNames[(int)format]
 
198
            : getClipboardFormatName(format);
 
199
    }
 
200
 
 
201
        protected Long getFormatForNativeAsLong(String str) {
 
202
        Long format = (Long)predefinedClipboardNameMap.get(str);
 
203
        if (format == null) {
 
204
            format = Long.valueOf(RegisterClipboardFormat(str));
 
205
        }
 
206
        return format;  }
 
207
        
 
208
        protected abstract String getClipboardFormatName(long format);
 
209
 
 
210
    public boolean isImageFormat(long format) {
 
211
        return format == CF_DIB || format == CF_ENHMETAFILE ||
 
212
               format == CF_METAFILEPICT || format == CF_PNG ||
 
213
               format == CF_JFIF;
 
214
    }
 
215
 
 
216
    public boolean isLocaleDependentTextFormat(long format) {
 
217
        return format == CF_TEXT || format == CFSTR_INETURL;
 
218
    }
 
219
 
 
220
    public boolean isFileFormat(long format) {
 
221
        return format == CF_HDROP;
 
222
    }
 
223
 
 
224
}
 
225
 
 
226
enum EHTMLReadMode {
 
227
    HTML_READ_ALL,
 
228
    HTML_READ_FRAGMENT,
 
229
    HTML_READ_SELECTION
 
230
}
 
231
 
 
232
/**
 
233
 * on decode: This stream takes an InputStream which provides data in CF_HTML format,
 
234
 * strips off the description and context to extract the original HTML data.
 
235
 *
 
236
 * on encode: static convertToHTMLFormat is responsible for HTML clipboard header creation
 
237
 */
 
238
class HTMLCodec extends InputStream {
 
239
    //static section
 
240
    public static final String ENCODING = "UTF-8";
 
241
 
 
242
    public static final String VERSION = "Version:";
 
243
    public static final String START_HTML = "StartHTML:";
 
244
    public static final String END_HTML = "EndHTML:";
 
245
    public static final String START_FRAGMENT = "StartFragment:";
 
246
    public static final String END_FRAGMENT = "EndFragment:";
 
247
    public static final String START_SELECTION = "StartSelection:"; //optional
 
248
    public static final String END_SELECTION = "EndSelection:"; //optional
 
249
 
 
250
    public static final String START_FRAGMENT_CMT = "<!--StartFragment-->";
 
251
    public static final String END_FRAGMENT_CMT = "<!--EndFragment-->";
 
252
    public static final String SOURCE_URL = "SourceURL:";
 
253
    public static final String DEF_SOURCE_URL = "about:blank";
 
254
 
 
255
    public static final String EOLN = "\r\n";
 
256
 
 
257
    private static final String VERSION_NUM = "1.0";
 
258
    private static final int PADDED_WIDTH = 10;
 
259
 
 
260
    private static String toPaddedString(int n, int width) {
 
261
        String string = "" + n;
 
262
        int len = string.length();
 
263
        if (n >= 0 && len < width) {
 
264
            char[] array = new char[width - len];
 
265
            Arrays.fill(array, '0');
 
266
            StringBuffer buffer = new StringBuffer(width);
 
267
            buffer.append(array);
 
268
            buffer.append(string);
 
269
            string = buffer.toString();
 
270
        }
 
271
        return string;
 
272
    }
 
273
 
 
274
    /**
 
275
     * convertToHTMLFormat adds the MS HTML clipboard header to byte array that
 
276
     * contains the parameters pairs.
 
277
     *
 
278
     * The consequence of parameters is fixed, but some or all of them could be
 
279
     * omitted. One parameter per one text line.
 
280
     * It looks like that:
 
281
     *
 
282
     * Version:1.0\r\n                -- current supported version
 
283
     * StartHTML:000000192\r\n        -- shift in array to the first byte after the header
 
284
     * EndHTML:000000757\r\n          -- shift in array of last byte for HTML syntax analysis
 
285
     * StartFragment:000000396\r\n    -- shift in array jast after <!--StartFragment-->
 
286
     * EndFragment:000000694\r\n      -- shift in array before start  <!--EndFragment-->
 
287
     * StartSelection:000000398\r\n   -- shift in array of the first char in copied selection
 
288
     * EndSelection:000000692\r\n     -- shift in array of the last char in copied selection
 
289
     * SourceURL:http://sun.com/\r\n  -- base URL for related referenses
 
290
     * <HTML>...<BODY>...<!--StartFragment-->.....................<!--EndFragment-->...</BODY><HTML>
 
291
     * ^                                     ^ ^                ^^                                 ^
 
292
     * \ StartHTML                           | \-StartSelection | \EndFragment              EndHTML/
 
293
     *                                       \-StartFragment    \EndSelection
 
294
     *
 
295
     *Combinations with tags sequence
 
296
     *<!--StartFragment--><HTML>...<BODY>...</BODY><HTML><!--EndFragment-->
 
297
     * or
 
298
     *<HTML>...<!--StartFragment-->...<BODY>...</BODY><!--EndFragment--><HTML>
 
299
     * are vailid too.
 
300
     */
 
301
    public static byte[] convertToHTMLFormat(byte[] bytes) {
 
302
        // Calculate section offsets
 
303
        String htmlPrefix = "";
 
304
        String htmlSuffix = "";
 
305
        {
 
306
            //we have extend the fragment to full HTML document correctly
 
307
            //to avoid HTML and BODY tags doubling
 
308
            String stContext = new String(bytes);
 
309
            String stUpContext = stContext.toUpperCase();
 
310
            if( -1 == stUpContext.indexOf("<HTML") ) {
 
311
                htmlPrefix = "<HTML>";
 
312
                htmlSuffix = "</HTML>";
 
313
                if( -1 == stUpContext.indexOf("<BODY") ) {
 
314
                    htmlPrefix = htmlPrefix +"<BODY>";
 
315
                    htmlSuffix = "</BODY>" + htmlSuffix;
 
316
                };
 
317
            };
 
318
            htmlPrefix = htmlPrefix + START_FRAGMENT_CMT;
 
319
            htmlSuffix = END_FRAGMENT_CMT + htmlSuffix;
 
320
        }
 
321
 
 
322
        String stBaseUrl = DEF_SOURCE_URL;
 
323
        int nStartHTML =
 
324
            VERSION.length() + VERSION_NUM.length() + EOLN.length()
 
325
            + START_HTML.length() + PADDED_WIDTH + EOLN.length()
 
326
            + END_HTML.length() + PADDED_WIDTH + EOLN.length()
 
327
            + START_FRAGMENT.length() + PADDED_WIDTH + EOLN.length()
 
328
            + END_FRAGMENT.length() + PADDED_WIDTH + EOLN.length()
 
329
            + SOURCE_URL.length() + stBaseUrl.length() + EOLN.length()
 
330
            ;
 
331
        int nStartFragment = nStartHTML + htmlPrefix.length();
 
332
        int nEndFragment = nStartFragment + bytes.length - 1;
 
333
        int nEndHTML = nEndFragment + htmlSuffix.length();
 
334
 
 
335
        StringBuilder header = new StringBuilder(
 
336
            nStartFragment
 
337
            + START_FRAGMENT_CMT.length()
 
338
        );
 
339
        //header
 
340
        header.append(VERSION);
 
341
        header.append(VERSION_NUM);
 
342
        header.append(EOLN);
 
343
 
 
344
        header.append(START_HTML);
 
345
        header.append(toPaddedString(nStartHTML, PADDED_WIDTH));
 
346
        header.append(EOLN);
 
347
 
 
348
        header.append(END_HTML);
 
349
        header.append(toPaddedString(nEndHTML, PADDED_WIDTH));
 
350
        header.append(EOLN);
 
351
 
 
352
        header.append(START_FRAGMENT);
 
353
        header.append(toPaddedString(nStartFragment, PADDED_WIDTH));
 
354
        header.append(EOLN);
 
355
 
 
356
        header.append(END_FRAGMENT);
 
357
        header.append(toPaddedString(nEndFragment, PADDED_WIDTH));
 
358
        header.append(EOLN);
 
359
 
 
360
        header.append(SOURCE_URL);
 
361
        header.append(stBaseUrl);
 
362
        header.append(EOLN);
 
363
 
 
364
        //HTML
 
365
        header.append(htmlPrefix);
 
366
 
 
367
        byte[] headerBytes = null, trailerBytes = null;
 
368
 
 
369
        try {
 
370
            headerBytes = new String(header).getBytes(ENCODING);
 
371
            trailerBytes = htmlSuffix.getBytes(ENCODING);
 
372
        } catch (UnsupportedEncodingException cannotHappen) {
 
373
        }
 
374
 
 
375
        byte[] retval = new byte[headerBytes.length + bytes.length +
 
376
                                 trailerBytes.length];
 
377
 
 
378
        System.arraycopy(headerBytes, 0, retval, 0, headerBytes.length);
 
379
        System.arraycopy(bytes, 0, retval, headerBytes.length,
 
380
                       bytes.length - 1);
 
381
        System.arraycopy(trailerBytes, 0, retval,
 
382
                         headerBytes.length + bytes.length - 1,
 
383
                         trailerBytes.length);
 
384
        retval[retval.length-1] = 0;
 
385
 
 
386
        return retval;
 
387
    }
 
388
 
 
389
    ////////////////////////////////////
 
390
    //decoder instance data and methods:
 
391
 
 
392
    private final BufferedInputStream bufferedStream;
 
393
    private boolean descriptionParsed = false;
 
394
    private boolean closed = false;
 
395
 
 
396
     // InputStreamReader uses an 8K buffer. The size is not customizable.
 
397
    public static final int BYTE_BUFFER_LEN = 8192;
 
398
 
 
399
    // CharToByteUTF8.getMaxBytesPerChar returns 3, so we should not buffer
 
400
    // more chars than 3 times the number of bytes we can buffer.
 
401
    public static final int CHAR_BUFFER_LEN = BYTE_BUFFER_LEN / 3;
 
402
 
 
403
    private static final String FAILURE_MSG =
 
404
        "Unable to parse HTML description: ";
 
405
    private static final String INVALID_MSG =
 
406
        " invalid";
 
407
 
 
408
    //HTML header mapping:
 
409
    private long   iHTMLStart,// StartHTML -- shift in array to the first byte after the header
 
410
                   iHTMLEnd,  // EndHTML -- shift in array of last byte for HTML syntax analysis
 
411
                   iFragStart,// StartFragment -- shift in array jast after <!--StartFragment-->
 
412
                   iFragEnd,  // EndFragment -- shift in array before start <!--EndFragment-->
 
413
                   iSelStart, // StartSelection -- shift in array of the first char in copied selection
 
414
                   iSelEnd;   // EndSelection -- shift in array of the last char in copied selection
 
415
    private String stBaseURL; // SourceURL -- base URL for related referenses
 
416
    private String stVersion; // Version -- current supported version
 
417
 
 
418
    //Stream reader markers:
 
419
    private long iStartOffset,
 
420
                 iEndOffset,
 
421
                 iReadCount;
 
422
 
 
423
    private EHTMLReadMode readMode;
 
424
 
 
425
    public HTMLCodec(
 
426
        InputStream _bytestream,
 
427
        EHTMLReadMode _readMode) throws IOException
 
428
    {
 
429
        bufferedStream = new BufferedInputStream(_bytestream, BYTE_BUFFER_LEN);
 
430
        readMode = _readMode;
 
431
    }
 
432
 
 
433
    public synchronized String getBaseURL() throws IOException
 
434
    {
 
435
        if( !descriptionParsed ) {
 
436
            parseDescription();
 
437
        }
 
438
        return stBaseURL;
 
439
    }
 
440
    public synchronized String getVersion() throws IOException
 
441
    {
 
442
        if( !descriptionParsed ) {
 
443
            parseDescription();
 
444
        }
 
445
        return stVersion;
 
446
    }
 
447
 
 
448
    /**
 
449
     * parseDescription parsing HTML clipboard header as it described in
 
450
     * comment to convertToHTMLFormat
 
451
     */
 
452
    private void parseDescription() throws IOException
 
453
    {
 
454
        stBaseURL = null;
 
455
        stVersion = null;
 
456
 
 
457
        // initialization of array offset pointers
 
458
        // to the same "uninitialized" state.
 
459
        iHTMLEnd =
 
460
            iHTMLStart =
 
461
                iFragEnd =
 
462
                    iFragStart =
 
463
                        iSelEnd =
 
464
                            iSelStart = -1;
 
465
 
 
466
        bufferedStream.mark(BYTE_BUFFER_LEN);
 
467
        String astEntries[] = new String[] {
 
468
            //common
 
469
            VERSION,
 
470
            START_HTML,
 
471
            END_HTML,
 
472
            START_FRAGMENT,
 
473
            END_FRAGMENT,
 
474
            //ver 1.0
 
475
            START_SELECTION,
 
476
            END_SELECTION,
 
477
            SOURCE_URL
 
478
        };
 
479
        BufferedReader bufferedReader = new BufferedReader(
 
480
            new InputStreamReader(
 
481
                bufferedStream,
 
482
                ENCODING
 
483
            ),
 
484
            CHAR_BUFFER_LEN
 
485
        );
 
486
        long iHeadSize = 0;
 
487
        long iCRSize = EOLN.length();
 
488
        int iEntCount = astEntries.length;
 
489
        boolean bContinue = true;
 
490
 
 
491
        for( int  iEntry = 0; iEntry < iEntCount; ++iEntry ){
 
492
            String stLine = bufferedReader.readLine();
 
493
            if( null==stLine ) {
 
494
                break;
 
495
            }
 
496
            //some header entries are optional, but the order is fixed.
 
497
            for( ; iEntry < iEntCount; ++iEntry ){
 
498
                if( !stLine.startsWith(astEntries[iEntry]) ) {
 
499
                    continue;
 
500
                }
 
501
                iHeadSize += stLine.length() + iCRSize;
 
502
                String stValue = stLine.substring(astEntries[iEntry].length()).trim();
 
503
                if( null!=stValue ) {
 
504
                    try{
 
505
                        switch( iEntry ){
 
506
                        case 0:
 
507
                            stVersion = stValue;
 
508
                            break;
 
509
                        case 1:
 
510
                            iHTMLStart = Integer.parseInt(stValue);
 
511
                            break;
 
512
                        case 2:
 
513
                            iHTMLEnd = Integer.parseInt(stValue);
 
514
                            break;
 
515
                        case 3:
 
516
                            iFragStart = Integer.parseInt(stValue);
 
517
                            break;
 
518
                        case 4:
 
519
                            iFragEnd = Integer.parseInt(stValue);
 
520
                            break;
 
521
                        case 5:
 
522
                            iSelStart = Integer.parseInt(stValue);
 
523
                            break;
 
524
                        case 6:
 
525
                            iSelEnd = Integer.parseInt(stValue);
 
526
                            break;
 
527
                        case 7:
 
528
                            stBaseURL = stValue;
 
529
                            break;
 
530
                        };
 
531
                    } catch ( NumberFormatException e ) {
 
532
                        throw new IOException(FAILURE_MSG + astEntries[iEntry]+ " value " + e + INVALID_MSG);
 
533
                    }
 
534
                }
 
535
                break;
 
536
            }
 
537
        }
 
538
        //some entries could absent in HTML header,
 
539
        //so we have find they by another way.
 
540
        if( -1 == iHTMLStart )
 
541
            iHTMLStart = iHeadSize;
 
542
        if( -1 == iFragStart )
 
543
            iFragStart = iHTMLStart;
 
544
        if( -1 == iFragEnd )
 
545
            iFragEnd = iHTMLEnd;
 
546
        if( -1 == iSelStart )
 
547
            iSelStart = iFragStart;
 
548
        if( -1 == iSelEnd )
 
549
            iSelEnd = iFragEnd;
 
550
 
 
551
        //one of possible modes
 
552
        switch( readMode ){
 
553
        case HTML_READ_ALL:
 
554
            iStartOffset = iHTMLStart;
 
555
            iEndOffset = iHTMLEnd;
 
556
            break;
 
557
        case HTML_READ_FRAGMENT:
 
558
            iStartOffset = iFragStart;
 
559
            iEndOffset = iFragEnd;
 
560
            break;
 
561
        case HTML_READ_SELECTION:
 
562
        default:
 
563
            iStartOffset = iSelStart;
 
564
            iEndOffset = iSelEnd;
 
565
            break;
 
566
        }
 
567
 
 
568
        bufferedStream.reset();
 
569
        if( -1 == iStartOffset ){
 
570
            throw new IOException(FAILURE_MSG + "invalid HTML format.");
 
571
        }
 
572
        iReadCount = bufferedStream.skip(iStartOffset);
 
573
        if( iStartOffset != iReadCount ){
 
574
            throw new IOException(FAILURE_MSG + "Byte stream ends in description.");
 
575
        }
 
576
        descriptionParsed = true;
 
577
    }
 
578
 
 
579
    public synchronized int read() throws IOException {
 
580
        if( closed ){
 
581
            throw new IOException("Stream closed");
 
582
        }
 
583
 
 
584
        if( !descriptionParsed ){
 
585
            parseDescription();
 
586
        }
 
587
        if( -1 != iEndOffset && iReadCount >= iEndOffset ) {
 
588
            return -1;
 
589
        }
 
590
 
 
591
        int retval = bufferedStream.read();
 
592
        if( retval == -1 ) {
 
593
            return -1;
 
594
        }
 
595
        ++iReadCount;
 
596
        return retval;
 
597
    }
 
598
 
 
599
    public synchronized void close() throws IOException {
 
600
        if( !closed ){
 
601
            closed = true;
 
602
            bufferedStream.close();
 
603
        }
 
604
    }
 
605
}