1 /*
2 * Copyright (c) 2014, 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 */
25 package jdk.incubator.http.internal.hpack;
26
27 import java.nio.ByteBuffer;
28 import java.util.Arrays;
29
30 import static java.lang.String.format;
31
32 final class IntegerReader {
33
34 private static final int NEW = 0;
35 private static final int CONFIGURED = 1;
36 private static final int FIRST_BYTE_READ = 2;
37 private static final int DONE = 4;
38
39 private int state = NEW;
40
41 private int N;
42 private int maxValue;
43 private int value;
44 private long r;
45 private long b = 1;
46
56 //
57 // 1. Value wraps around long won't be unnoticed.
58 // 2. It can spit out an exception as soon as it becomes clear there's
59 // an overflow. Therefore, no need to wait for the value to be fully read.
60 //
61 public IntegerReader configure(int N, int maxValue) {
62 if (state != NEW) {
63 throw new IllegalStateException("Already configured");
64 }
65 checkPrefix(N);
66 if (maxValue < 0) {
67 throw new IllegalArgumentException(
68 "maxValue >= 0: maxValue=" + maxValue);
69 }
70 this.maxValue = maxValue;
71 this.N = N;
72 state = CONFIGURED;
73 return this;
74 }
75
76 public boolean read(ByteBuffer input) {
77 if (state == NEW) {
78 throw new IllegalStateException("Configure first");
79 }
80 if (state == DONE) {
81 return true;
82 }
83 if (!input.hasRemaining()) {
84 return false;
85 }
86 if (state == CONFIGURED) {
87 int max = (2 << (N - 1)) - 1;
88 int n = input.get() & max;
89 if (n != max) {
90 value = n;
91 state = DONE;
92 return true;
93 } else {
94 r = max;
95 }
96 state = FIRST_BYTE_READ;
97 }
98 if (state == FIRST_BYTE_READ) {
99 // variable-length quantity (VLQ)
100 byte i;
101 do {
102 if (!input.hasRemaining()) {
103 return false;
104 }
105 i = input.get();
106 long increment = b * (i & 127);
107 if (r + increment > maxValue) {
108 throw new IllegalArgumentException(format(
109 "Integer overflow: maxValue=%,d, value=%,d",
110 maxValue, r + increment));
111 }
112 r += increment;
113 b *= 128;
114 } while ((128 & i) == 128);
115
116 value = (int) r;
117 state = DONE;
118 return true;
119 }
120 throw new InternalError(Arrays.toString(
121 new Object[]{state, N, maxValue, value, r, b}));
122 }
123
124 public int get() throws IllegalStateException {
125 if (state != DONE) {
126 throw new IllegalStateException("Has not been fully read yet");
127 }
128 return value;
|
1 /*
2 * Copyright (c) 2014, 2017, 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 */
25 package jdk.incubator.http.internal.hpack;
26
27 import java.io.IOException;
28 import java.nio.ByteBuffer;
29 import java.util.Arrays;
30
31 import static java.lang.String.format;
32
33 final class IntegerReader {
34
35 private static final int NEW = 0;
36 private static final int CONFIGURED = 1;
37 private static final int FIRST_BYTE_READ = 2;
38 private static final int DONE = 4;
39
40 private int state = NEW;
41
42 private int N;
43 private int maxValue;
44 private int value;
45 private long r;
46 private long b = 1;
47
57 //
58 // 1. Value wraps around long won't be unnoticed.
59 // 2. It can spit out an exception as soon as it becomes clear there's
60 // an overflow. Therefore, no need to wait for the value to be fully read.
61 //
62 public IntegerReader configure(int N, int maxValue) {
63 if (state != NEW) {
64 throw new IllegalStateException("Already configured");
65 }
66 checkPrefix(N);
67 if (maxValue < 0) {
68 throw new IllegalArgumentException(
69 "maxValue >= 0: maxValue=" + maxValue);
70 }
71 this.maxValue = maxValue;
72 this.N = N;
73 state = CONFIGURED;
74 return this;
75 }
76
77 public boolean read(ByteBuffer input) throws IOException {
78 if (state == NEW) {
79 throw new IllegalStateException("Configure first");
80 }
81 if (state == DONE) {
82 return true;
83 }
84 if (!input.hasRemaining()) {
85 return false;
86 }
87 if (state == CONFIGURED) {
88 int max = (2 << (N - 1)) - 1;
89 int n = input.get() & max;
90 if (n != max) {
91 value = n;
92 state = DONE;
93 return true;
94 } else {
95 r = max;
96 }
97 state = FIRST_BYTE_READ;
98 }
99 if (state == FIRST_BYTE_READ) {
100 // variable-length quantity (VLQ)
101 byte i;
102 do {
103 if (!input.hasRemaining()) {
104 return false;
105 }
106 i = input.get();
107 long increment = b * (i & 127);
108 if (r + increment > maxValue) {
109 throw new IOException(format(
110 "Integer overflow: maxValue=%,d, value=%,d",
111 maxValue, r + increment));
112 }
113 r += increment;
114 b *= 128;
115 } while ((128 & i) == 128);
116
117 value = (int) r;
118 state = DONE;
119 return true;
120 }
121 throw new InternalError(Arrays.toString(
122 new Object[]{state, N, maxValue, value, r, b}));
123 }
124
125 public int get() throws IllegalStateException {
126 if (state != DONE) {
127 throw new IllegalStateException("Has not been fully read yet");
128 }
129 return value;
|