src/java.net.http/share/classes/jdk/internal/net/http/hpack/HPACK.java
branchhttp-client-branch
changeset 56623 1d020b5d73f1
parent 56451 9585061fdb04
child 56795 03ece2518428
--- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/HPACK.java	Tue May 29 13:42:04 2018 +0100
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/HPACK.java	Tue May 29 23:47:07 2018 +0100
@@ -27,6 +27,7 @@
 import jdk.internal.net.http.common.Utils;
 import jdk.internal.net.http.hpack.HPACK.Logger.Level;
 
+import java.nio.ByteBuffer;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Map;
@@ -171,4 +172,124 @@
         }
 
     }
+
+    // -- low-level utilities --
+
+    @FunctionalInterface
+    interface BufferUpdateConsumer {
+        void accept(long data, int len);
+    }
+
+    @SuppressWarnings("fallthrough")
+    public static int read(ByteBuffer source,
+                           long buffer,
+                           int bufferLen,
+                           BufferUpdateConsumer consumer)
+    {
+        // read as much as possible (up to 8 bytes)
+        int nBytes = Math.min((64 - bufferLen) >> 3, source.remaining());
+        switch (nBytes) {
+            case 0:
+                break;
+            case 3:
+                buffer |= ((source.get() & 0x00000000000000ffL) << (56 - bufferLen));
+                bufferLen += 8;
+            case 2:
+                buffer |= ((source.get() & 0x00000000000000ffL) << (56 - bufferLen));
+                bufferLen += 8;
+            case 1:
+                buffer |= ((source.get() & 0x00000000000000ffL) << (56 - bufferLen));
+                bufferLen += 8;
+                consumer.accept(buffer, bufferLen);
+                break;
+            case 7:
+                buffer |= ((source.get() & 0x00000000000000ffL) << (56 - bufferLen));
+                bufferLen += 8;
+            case 6:
+                buffer |= ((source.get() & 0x00000000000000ffL) << (56 - bufferLen));
+                bufferLen += 8;
+            case 5:
+                buffer |= ((source.get() & 0x00000000000000ffL) << (56 - bufferLen));
+                bufferLen += 8;
+            case 4:
+                buffer |= ((source.getInt() & 0x00000000ffffffffL) << (32 - bufferLen));
+                bufferLen += 32;
+                consumer.accept(buffer, bufferLen);
+                break;
+            case 8:
+                buffer = source.getLong();
+                bufferLen = 64;
+                consumer.accept(buffer, bufferLen);
+                break;
+            default:
+                throw new InternalError(String.valueOf(nBytes));
+        }
+        return nBytes;
+    }
+
+    // The number of bytes that can be written at once
+    // (calculating in bytes, not bits, since
+    //  destination.remaining() * 8 might overflow)
+    @SuppressWarnings("fallthrough")
+    public static int write(long buffer,
+                            int bufferLen,
+                            BufferUpdateConsumer consumer,
+                            ByteBuffer destination)
+    {
+        int nBytes = Math.min(bufferLen >> 3, destination.remaining());
+        switch (nBytes) {
+            case 0:
+                break;
+            case 3:
+                destination.put((byte) (buffer >>> 56));
+                buffer <<= 8;
+                bufferLen -= 8;
+            case 2:
+                destination.put((byte) (buffer >>> 56));
+                buffer <<= 8;
+                bufferLen -= 8;
+            case 1:
+                destination.put((byte) (buffer >>> 56));
+                buffer <<= 8;
+                bufferLen -= 8;
+                consumer.accept(buffer, bufferLen);
+                break;
+            case 7:
+                destination.put((byte) (buffer >>> 56));
+                buffer <<= 8;
+                bufferLen -= 8;
+            case 6:
+                destination.put((byte) (buffer >>> 56));
+                buffer <<= 8;
+                bufferLen -= 8;
+            case 5:
+                destination.put((byte) (buffer >>> 56));
+                buffer <<= 8;
+                bufferLen -= 8;
+            case 4:
+                destination.putInt((int) (buffer >>> 32));
+                buffer <<= 32;
+                bufferLen -= 32;
+                consumer.accept(buffer, bufferLen);
+                break;
+            case 8:
+                destination.putLong(buffer);
+                buffer = 0;
+                bufferLen = 0;
+                consumer.accept(buffer, bufferLen);
+                break;
+            default:
+                throw new InternalError(String.valueOf(nBytes));
+        }
+        return nBytes;
+    }
+
+    /*
+     * Returns the number of bytes the given number of bits constitute.
+     */
+    static int bytesForBits(int n) {
+        assert (n / 8 + (n % 8 != 0 ? 1 : 0)) == (n + 7) / 8
+                && (n + 7) / 8 == ((n + 7) >> 3) : n;
+        return (n + 7) >> 3;
+    }
 }