File: C2BConverter.java

package info (click to toggle)
tomcat7 7.0.56-3%2Bdeb8u11
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 35,688 kB
  • ctags: 41,823
  • sloc: java: 249,464; xml: 51,553; jsp: 3,037; sh: 1,361; perl: 269; makefile: 195
file content (127 lines) | stat: -rw-r--r-- 4,737 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.apache.tomcat.util.buf;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;

/**
 * NIO based character encoder.
 */
public final class C2BConverter {

    protected CharsetEncoder encoder = null;
    protected ByteBuffer bb = null;
    protected CharBuffer cb = null;

    /**
     * Leftover buffer used for multi-characters characters.
     */
    protected CharBuffer leftovers = null;

    public C2BConverter(String encoding) throws IOException {
        encoder = B2CConverter.getCharset(encoding).newEncoder();
        // FIXME: See if unmappable/malformed behavior configuration is needed
        //        in practice
        encoder.onUnmappableCharacter(CodingErrorAction.REPLACE)
            .onMalformedInput(CodingErrorAction.REPLACE);
        char[] left = new char[4];
        leftovers = CharBuffer.wrap(left);
    }

    /**
     * Reset the encoder state.
     */
    public void recycle() {
        encoder.reset();
        leftovers.position(0);
    }

    public boolean isUndeflow() {
        return (leftovers.position() > 0);
    }

    /**
     * Convert the given characters to bytes.
     * 
     * @param cc char input
     * @param bc byte output
     */
    public void convert(CharChunk cc, ByteChunk bc) 
            throws IOException {
        if ((bb == null) || (bb.array() != bc.getBuffer())) {
            // Create a new byte buffer if anything changed
            bb = ByteBuffer.wrap(bc.getBuffer(), bc.getEnd(), 
                    bc.getBuffer().length - bc.getEnd());
        } else {
            // Initialize the byte buffer
            bb.limit(bc.getBuffer().length);
            bb.position(bc.getEnd());
        }
        if ((cb == null) || (cb.array() != cc.getBuffer())) {
            // Create a new char buffer if anything changed
            cb = CharBuffer.wrap(cc.getBuffer(), cc.getStart(), 
                    cc.getLength());
        } else {
            // Initialize the char buffer
            cb.limit(cc.getEnd());
            cb.position(cc.getStart());
        }
        CoderResult result = null;
        // Parse leftover if any are present
        if (leftovers.position() > 0) {
            int pos = bb.position();
            // Loop until one char is encoded or there is a encoder error
            do {
                leftovers.put((char) cc.substract());
                leftovers.flip();
                result = encoder.encode(leftovers, bb, false);
                leftovers.position(leftovers.limit());
                leftovers.limit(leftovers.array().length);
            } while (result.isUnderflow() && (bb.position() == pos));
            if (result.isError() || result.isMalformed()) {
                result.throwException();
            }
            cb.position(cc.getStart());
            leftovers.position(0);
        }
        // Do the decoding and get the results into the byte chunk and the char
        // chunk
        result = encoder.encode(cb, bb, false);
        if (result.isError() || result.isMalformed()) {
            result.throwException();
        } else if (result.isOverflow()) {
            // Propagate current positions to the byte chunk and char chunk
            bc.setEnd(bb.position());
            cc.setOffset(cb.position());
        } else if (result.isUnderflow()) {
            // Propagate current positions to the byte chunk and char chunk
            bc.setEnd(bb.position());
            cc.setOffset(cb.position());
            // Put leftovers in the leftovers char buffer
            if (cc.getLength() > 0) {
                leftovers.limit(leftovers.array().length);
                leftovers.position(cc.getLength());
                cc.substract(leftovers.array(), 0, cc.getLength());
            }
        }
    }
}