1/*
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package jdk.incubator.http.internal.hpack;
26
27import java.nio.ByteBuffer;
28import java.util.Arrays;
29
30//
31//          0   1   2   3   4   5   6   7
32//        +---+---+---+---+---+---+---+---+
33//        | H |    String Length (7+)     |
34//        +---+---------------------------+
35//        |  String Data (Length octets)  |
36//        +-------------------------------+
37//
38final class StringReader {
39
40    private static final int NEW             = 0;
41    private static final int FIRST_BYTE_READ = 1;
42    private static final int LENGTH_READ     = 2;
43    private static final int DONE            = 4;
44
45    private final IntegerReader intReader = new IntegerReader();
46    private final Huffman.Reader huffmanReader = new Huffman.Reader();
47    private final ISO_8859_1.Reader plainReader = new ISO_8859_1.Reader();
48
49    private int state = NEW;
50
51    private boolean huffman;
52    private int remainingLength;
53
54    boolean read(ByteBuffer input, Appendable output) {
55        if (state == DONE) {
56            return true;
57        }
58        if (!input.hasRemaining()) {
59            return false;
60        }
61        if (state == NEW) {
62            int p = input.position();
63            huffman = (input.get(p) & 0b10000000) != 0;
64            state = FIRST_BYTE_READ;
65            intReader.configure(7);
66        }
67        if (state == FIRST_BYTE_READ) {
68            boolean lengthRead = intReader.read(input);
69            if (!lengthRead) {
70                return false;
71            }
72            remainingLength = intReader.get();
73            state = LENGTH_READ;
74        }
75        if (state == LENGTH_READ) {
76            boolean isLast = input.remaining() >= remainingLength;
77            int oldLimit = input.limit();
78            if (isLast) {
79                input.limit(input.position() + remainingLength);
80            }
81            remainingLength -= Math.min(input.remaining(), remainingLength);
82            if (huffman) {
83                huffmanReader.read(input, output, isLast);
84            } else {
85                plainReader.read(input, output);
86            }
87            if (isLast) {
88                input.limit(oldLimit);
89                state = DONE;
90            }
91            return isLast;
92        }
93        throw new InternalError(Arrays.toString(
94                new Object[]{state, huffman, remainingLength}));
95    }
96
97    boolean isHuffmanEncoded() {
98        if (state < FIRST_BYTE_READ) {
99            throw new IllegalStateException("Has not been fully read yet");
100        }
101        return huffman;
102    }
103
104    void reset() {
105        if (huffman) {
106            huffmanReader.reset();
107        } else {
108            plainReader.reset();
109        }
110        intReader.reset();
111        state = NEW;
112    }
113}
114