1 /* 2 * Copyright (c) 2015, 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.nio.ByteBuffer; 28 import java.util.Arrays; 29 30 final class IntegerWriter { 31 32 private static final int NEW = 0; 33 private static final int CONFIGURED = 1; 34 private static final int FIRST_BYTE_WRITTEN = 2; 35 private static final int DONE = 4; 36 37 private int state = NEW; 38 39 private int payload; 40 private int N; 41 private int value; 42 43 // 44 // 0 1 2 3 4 5 6 7 45 // +---+---+---+---+---+---+---+---+ 46 // | | | | | | | | | 47 // +---+---+---+-------------------+ 48 // |<--------->|<----------------->| 49 // payload N=5 50 // 51 // payload is the contents of the left-hand side part of the octet; 52 // it is truncated to fit into 8-N bits, where 1 <= N <= 8; 53 // 54 public IntegerWriter configure(int value, int N, int payload) { 55 if (state != NEW) { 56 throw new IllegalStateException("Already configured"); 57 } 58 if (value < 0) { 59 throw new IllegalArgumentException("value >= 0: value=" + value); 60 } 61 checkPrefix(N); 62 this.value = value; 63 this.N = N; 64 this.payload = payload & 0xFF & (0xFFFFFFFF << N); 65 state = CONFIGURED; 66 return this; 67 } 68 69 public boolean write(ByteBuffer output) { 70 if (state == NEW) { 71 throw new IllegalStateException("Configure first"); 72 } 73 if (state == DONE) { 74 return true; 75 } 76 77 if (!output.hasRemaining()) { 78 return false; 79 } 80 if (state == CONFIGURED) { 81 int max = (2 << (N - 1)) - 1; 82 if (value < max) { 83 output.put((byte) (payload | value)); 84 state = DONE; 85 return true; 86 } 87 output.put((byte) (payload | max)); 88 value -= max; 89 state = FIRST_BYTE_WRITTEN; 90 } 91 if (state == FIRST_BYTE_WRITTEN) { 92 while (value >= 128 && output.hasRemaining()) { 93 output.put((byte) (value % 128 + 128)); 94 value /= 128; 95 } 96 if (!output.hasRemaining()) { 97 return false; 98 } 99 output.put((byte) value); 100 state = DONE; 101 return true; 102 } 103 throw new InternalError(Arrays.toString( 104 new Object[]{state, payload, N, value})); 105 } 106 107 private static void checkPrefix(int N) { 108 if (N < 1 || N > 8) { 109 throw new IllegalArgumentException("1 <= N <= 8: N= " + N); 110 } 111 } 112 113 public IntegerWriter reset() { 114 state = NEW; 115 return this; 116 } 117 }