├── .appveyor.yml ├── .cirrus.yml ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── bin ├── CMakeLists.txt ├── calc-xxh.c ├── encode-qif.c ├── find-xxh.c ├── gen-fast-dec-table.c ├── gen-fast-enc-table.c ├── huff-decode.c └── huff-encode.c ├── compat ├── queue │ └── sys │ │ └── queue.h └── windows │ └── sys │ └── uio.h ├── deps └── xxhash │ ├── xxhash.c │ └── xxhash.h ├── huff-tables.h ├── lshpack.c ├── lshpack.h ├── lsxpack_header.h └── test ├── CMakeLists.txt ├── lshpack-test.h ├── test_hpack.c └── test_int.c /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | 3 | build_script: 4 | 5 | - cmd: >- 6 | echo %path% 7 | 8 | cmake . 9 | 10 | msbuild ALL_BUILD.vcxproj 11 | 12 | test_script: 13 | 14 | - cmd: ctest 15 | -------------------------------------------------------------------------------- /.cirrus.yml: -------------------------------------------------------------------------------- 1 | freebsd_instance: 2 | image: freebsd-13-3-release-amd64 3 | 4 | task: 5 | install_script: pkg install -y cmake 6 | script: cmake . && make && make test 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: false 3 | addons: 4 | apt: 5 | matrix: 6 | include: 7 | - name: Linux (gcc-8) 8 | os: linux 9 | dist: xenial 10 | compiler: gcc-8 11 | addons: 12 | apt: 13 | sources: 14 | - ubuntu-toolchain-r-test 15 | packages: g++-8 16 | - name: Linux (clang) 17 | os: linux 18 | dist: xenial 19 | compiler: clang 20 | before_install: 21 | - $CC --version 22 | - cmake --version 23 | before_script: 24 | - cmake . 25 | script: 26 | - make 27 | - make test 28 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following variable can be defined on the command line: 2 | # 3 | # SHARED 4 | # NDEBUG 5 | # XXH_HEADER_NAME 6 | # XXH_INCLUDE_DIR 7 | # LSHPACK_XXH 8 | 9 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 10 | PROJECT(ls-hpack C) 11 | 12 | include(CheckIncludeFiles) 13 | 14 | IF (SHARED EQUAL 1) 15 | ADD_LIBRARY(ls-hpack SHARED lshpack.c) 16 | ELSE() 17 | ADD_LIBRARY(ls-hpack STATIC lshpack.c) 18 | ENDIF() 19 | INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}) 20 | 21 | IF (NOT DEFINED XXH_HEADER_NAME) 22 | SET(XXH_HEADER_NAME "xxhash.h") 23 | ENDIF() 24 | 25 | IF (DEFINED XXH_INCLUDE_DIR) 26 | INCLUDE_DIRECTORIES("${XXH_INCLUDE_DIR}") 27 | ELSE() 28 | INCLUDE_DIRECTORIES(deps/xxhash) 29 | ENDIF() 30 | 31 | IF (LSHPACK_XXH) 32 | TARGET_SOURCES(ls-hpack PRIVATE deps/xxhash/xxhash.c) 33 | ENDIF() 34 | 35 | check_include_files("sys/queue.h" HAVE_SYS_QUEUE_H) 36 | 37 | IF (NOT HAVE_SYS_QUEUE_H) 38 | INCLUDE_DIRECTORIES(compat/queue) 39 | ENDIF() 40 | 41 | IF (MSVC) 42 | INCLUDE_DIRECTORIES(compat/windows) 43 | ENDIF() 44 | 45 | IF (CMAKE_C_COMPILER_ID STREQUAL GNU 46 | OR CMAKE_C_COMPILER_ID STREQUAL Clang) 47 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Wall -Wextra -Wno-unused-parameter") 48 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -fno-omit-frame-pointer") 49 | INCLUDE(CheckCCompilerFlag) 50 | CHECK_C_COMPILER_FLAG(-Wno-implicit-fallthrough HAS_NO_IMPLICIT_FALLTHROUGH) 51 | IF (HAS_NO_IMPLICIT_FALLTHROUGH) 52 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Wno-implicit-fallthrough") 53 | ENDIF() 54 | IF (PROFILE EQUAL 1) 55 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -g -pg") 56 | ENDIF() 57 | IF (CMAKE_BUILD_TYPE STREQUAL Release) 58 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -g0 -O3") 59 | ELSE() 60 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -g3 -O0 -fsanitize=address") 61 | ENDIF() 62 | ENDIF() 63 | 64 | IF (NOT CMAKE_BUILD_TYPE STREQUAL Release) 65 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DLS_HPACK_EMIT_TEST_CODE=1") 66 | ENDIF() 67 | 68 | IF (CMAKE_BUILD_TYPE STREQUAL MinSizeRel) 69 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DLS_HPACK_USE_LARGE_TABLES=0") 70 | ENDIF() 71 | 72 | IF (NDEBUG EQUAL 1) 73 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DNDEBUG") 74 | ENDIF() 75 | 76 | SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DXXH_HEADER_NAME=\\\"${XXH_HEADER_NAME}\\\"") 77 | 78 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MY_CMAKE_FLAGS} $ENV{EXTRA_CFLAGS}") 79 | 80 | MESSAGE(STATUS "Compiler flags: ${CMAKE_C_FLAGS}") 81 | 82 | IF (NOT CMAKE_BUILD_TYPE STREQUAL Release) 83 | ENABLE_TESTING() 84 | INCLUDE_DIRECTORIES("test") 85 | ADD_SUBDIRECTORY("test") 86 | ENDIF() 87 | 88 | IF (CMAKE_SYSTEM_NAME STREQUAL Linux) 89 | ADD_SUBDIRECTORY(bin) 90 | ENDIF() 91 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 - 2023 LiteSpeed Technologies Inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/litespeedtech/ls-hpack.svg?branch=master)](https://travis-ci.com/litespeedtech/ls-hpack) 2 | [![Build Status](https://api.cirrus-ci.com/github/litespeedtech/ls-hpack.svg)](https://cirrus-ci.com/github/litespeedtech/ls-hpack) 3 | [![Build status](https://ci.appveyor.com/api/projects/status/6ev71ecmm3j2u9o5?svg=true)](https://ci.appveyor.com/project/litespeedtech/ls-hpack) 4 | 5 | LS-HPACK: LiteSpeed HPACK Library 6 | ================================= 7 | 8 | Description 9 | ----------- 10 | 11 | LS-HPACK provides functionality to encode and decode HTTP headers using 12 | HPACK compression mechanism specified in RFC 7541. 13 | 14 | Documentation 15 | ------------- 16 | 17 | The API is documented in include/lshpack.h. To see usage examples, 18 | see the unit tests. 19 | 20 | Requirements 21 | ------------ 22 | 23 | To build LS-HPACK, you need CMake. The library uses XXHASH at runtime. 24 | 25 | Platforms 26 | --------- 27 | 28 | The library has been tested on the following platforms: 29 | - Linux 30 | - FreeBSD 31 | - Windows 32 | 33 | Copyright (c) 2018 - 2020 LiteSpeed Technologies Inc 34 | -------------------------------------------------------------------------------- /bin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(encode-qif encode-qif.c ../deps/xxhash/xxhash.c) 2 | target_link_libraries(encode-qif PRIVATE ls-hpack) 3 | 4 | add_executable(gen-fast-dec-table gen-fast-dec-table.c) 5 | 6 | add_executable(gen-fast-enc-table gen-fast-enc-table.c) 7 | 8 | add_executable(huff-decode huff-decode.c ../deps/xxhash/xxhash.c) 9 | target_link_libraries(huff-decode PRIVATE ls-hpack) 10 | 11 | add_executable(huff-encode huff-encode.c ../deps/xxhash/xxhash.c) 12 | target_link_libraries(huff-encode PRIVATE ls-hpack) 13 | 14 | add_executable(calc-xxh calc-xxh.c ../deps/xxhash/xxhash.c) 15 | 16 | add_executable(find-xxh find-xxh.c ../deps/xxhash/xxhash.c) 17 | -------------------------------------------------------------------------------- /bin/calc-xxh.c: -------------------------------------------------------------------------------- 1 | /* calc-xxh: calculate XXH32 hashes for name and value strings */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include XXH_HEADER_NAME 10 | 11 | int 12 | main (int argc, char **argv) 13 | { 14 | uint32_t seed, name_hash, nameval_hash; 15 | size_t name_len, value_len; 16 | const char *name, *value; 17 | XXH32_state_t hash_state; 18 | int mode; 19 | 20 | if (argc != 5) 21 | { 22 | fprintf(stderr, 23 | "Usage: %s mode seed name value\n" 24 | "\n" 25 | " mode is one of:\n" 26 | " 0 Single seed, update\n" 27 | " 1 Use name hash as seed for calculating nameval hash\n" 28 | "\n" 29 | " seed is the initial seed\n" 30 | "\n", argv[0]); 31 | return 0; 32 | } 33 | 34 | mode = atoi(argv[1]); 35 | if (!(mode == 0 || mode == 1)) 36 | { 37 | fprintf(stderr, "mode `%s' is invalid\n", argv[1]); 38 | return 1; 39 | } 40 | 41 | seed = atoi(argv[2]); 42 | name = argv[3]; 43 | value = argv[4]; 44 | name_len = strlen(name); 45 | value_len = strlen(value); 46 | 47 | switch (mode) 48 | { 49 | case 0: 50 | XXH32_reset(&hash_state, seed); 51 | XXH32_update(&hash_state, name, name_len); 52 | name_hash = XXH32_digest(&hash_state); 53 | XXH32_update(&hash_state, value, value_len); 54 | nameval_hash = XXH32_digest(&hash_state); 55 | break; 56 | default: 57 | name_hash = XXH32(name, name_len, seed); 58 | nameval_hash = XXH32(value, value_len, name_hash); 59 | break; 60 | } 61 | 62 | printf( 63 | "In mode %d, name: `%s', value: `%s' hash to:\n" 64 | "name hash 0x%08"PRIX32"\n" 65 | "nameval hash 0x%08"PRIX32"\n" 66 | , mode, name, value, name_hash, nameval_hash); 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /bin/encode-qif.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Read QIF and encode it using HPACK. Use for benchmarking. 3 | * 4 | * Based on ls-qpack's interop-encode. 5 | * 6 | * How it works: read in QIF into a list of header set objects and encode 7 | * the list a number of times. 8 | * 9 | * QIF Format: 10 | * https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop 11 | */ 12 | 13 | #define _GNU_SOURCE /* for memmem */ 14 | #include 15 | 16 | #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) 17 | #include 18 | #define bswap_16 bswap16 19 | #define bswap_32 bswap32 20 | #define bswap_64 bswap64 21 | #elif defined(__APPLE__) 22 | #include 23 | #define bswap_16 OSSwapInt16 24 | #define bswap_32 OSSwapInt32 25 | #define bswap_64 OSSwapInt64 26 | #elif defined(WIN32) 27 | #error Not supported on Windows 28 | #else 29 | #include 30 | #endif 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "lshpack.h" 44 | 45 | static int s_verbose; 46 | 47 | #define TABLE_SIZE 4096 48 | 49 | static void 50 | usage (const char *name) 51 | { 52 | fprintf(stderr, 53 | "Usage: %s [options] [-i input] [-o output]\n" 54 | "\n" 55 | "Options:\n" 56 | " -i FILE Input file.\n" 57 | " -o FILE Output file. If not spepcified or set to `-', the output\n" 58 | " is written to stdout.\n" 59 | " -K Discard output: encoded output is discarded.\n" 60 | " -H Do not use the history heuristic.\n" 61 | " -n NUMBER Number of times to iterate over the header set list.\n" 62 | " -t NUMBER Dynamic table size. Defaults to %u.\n" 63 | " -v Verbose: print various messages to stderr.\n" 64 | "\n" 65 | " -h Print this help screen and exit\n" 66 | , name, TABLE_SIZE); 67 | } 68 | 69 | 70 | struct header 71 | { 72 | const char *name; 73 | const char *val; 74 | size_t name_len; 75 | size_t val_len; 76 | }; 77 | 78 | 79 | #define MAX_HEADERS 32 80 | 81 | struct header_set 82 | { 83 | STAILQ_ENTRY(header_set) next; 84 | unsigned n_headers; 85 | struct header headers[MAX_HEADERS]; 86 | }; 87 | 88 | 89 | static inline void 90 | lsxpack_header_set_ptr(lsxpack_header_t *hdr, 91 | const char *name, size_t name_len, 92 | const char *val, size_t val_len) 93 | { 94 | static char buf[65536]; 95 | memcpy(buf, name, name_len); 96 | memcpy(&buf[name_len], val, val_len); 97 | lsxpack_header_set_offset2(hdr, buf, 0, name_len, name_len, val_len); 98 | } 99 | 100 | 101 | int 102 | main (int argc, char **argv) 103 | { 104 | FILE *out = stdout; 105 | int opt, qif_fd = -1; 106 | int discard = 0, use_history = 1; 107 | unsigned n_iters = 1, n, i; 108 | unsigned dyn_table_size = TABLE_SIZE; 109 | STAILQ_HEAD(, header_set) header_sets = STAILQ_HEAD_INITIALIZER(header_sets); 110 | struct stat st; 111 | const unsigned char *qif = NULL, *p, *tab, *nl, *nlnl; 112 | unsigned char *s; 113 | struct header *header; 114 | struct header_set *hset; 115 | struct lshpack_enc encoder; 116 | unsigned char buf[0x2000]; 117 | 118 | while (-1 != (opt = getopt(argc, argv, "Hi:o:Kn:t:vh"))) 119 | { 120 | switch (opt) 121 | { 122 | case 'n': 123 | n_iters = atoi(optarg); 124 | break; 125 | case 'i': 126 | qif_fd = open(optarg, O_RDONLY); 127 | if (qif_fd < 0) 128 | { 129 | perror("open"); 130 | exit(EXIT_FAILURE); 131 | } 132 | if (0 != fstat(qif_fd, &st)) 133 | { 134 | perror("fstat"); 135 | exit(EXIT_FAILURE); 136 | } 137 | qif = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, qif_fd, 0); 138 | if (!qif) 139 | { 140 | perror("mmap"); 141 | exit(EXIT_FAILURE); 142 | } 143 | break; 144 | case 'o': 145 | if (0 != strcmp(optarg, "-")) 146 | { 147 | out = fopen(optarg, "wb"); 148 | if (!out) 149 | { 150 | fprintf(stderr, "cannot open `%s' for writing: %s\n", 151 | optarg, strerror(errno)); 152 | exit(EXIT_FAILURE); 153 | } 154 | } 155 | break; 156 | case 'K': 157 | discard = 1; 158 | break; 159 | case 'H': 160 | use_history = 0; 161 | break; 162 | case 't': 163 | dyn_table_size = atoi(optarg); 164 | break; 165 | case 'h': 166 | usage(argv[0]); 167 | exit(EXIT_SUCCESS); 168 | case 'v': 169 | ++s_verbose; 170 | break; 171 | default: 172 | exit(EXIT_FAILURE); 173 | } 174 | } 175 | 176 | if (!qif) 177 | { 178 | fprintf(stderr, "Please specify input QIF file using -i flag\n"); 179 | exit(EXIT_FAILURE); 180 | } 181 | 182 | const unsigned char *const begin = qif; 183 | const unsigned char *const end = begin + st.st_size; 184 | while (qif + 2 < end) 185 | { 186 | nlnl = memmem(qif, end - qif, "\n\n", 2); 187 | if (!nlnl) 188 | nlnl = end; 189 | hset = calloc(1, sizeof(*hset)); 190 | if (!hset) 191 | { 192 | perror("malloc"); 193 | exit(EXIT_FAILURE); 194 | } 195 | STAILQ_INSERT_TAIL(&header_sets, hset, next); 196 | p = qif; 197 | while (p < nlnl) 198 | { 199 | if (hset->n_headers >= MAX_HEADERS) 200 | { 201 | fprintf(stderr, "max headers > 32, off: %u", 202 | (unsigned) (p - begin)); 203 | exit(EXIT_FAILURE); 204 | } 205 | tab = memmem(p, nlnl - p, "\t", 1); 206 | if (!tab) 207 | { 208 | fprintf(stderr, "tab not found, off: %u", 209 | (unsigned) (p - begin)); 210 | exit(EXIT_FAILURE); 211 | } 212 | nl = memmem(tab + 1, nlnl - tab - 1, "\n", 1); 213 | if (!nl) 214 | nl = nlnl; 215 | hset->headers[ hset->n_headers ] = (struct header) { 216 | .name = (const char *) p, 217 | .val = (const char *) tab + 1, 218 | .name_len = tab - p, 219 | .val_len = nl - tab - 1, 220 | }; 221 | ++hset->n_headers; 222 | p = nl + 1; 223 | } 224 | qif = nlnl + 2; 225 | } 226 | 227 | lsxpack_header_t hdr; 228 | for (n = 0; n < n_iters; ++n) 229 | { 230 | if (0 != lshpack_enc_init(&encoder)) 231 | { 232 | perror("lshpack_enc_init"); 233 | exit(EXIT_FAILURE); 234 | } 235 | (void) lshpack_enc_use_hist(&encoder, use_history); 236 | 237 | STAILQ_FOREACH(hset, &header_sets, next) 238 | { 239 | for (i = 0; i < hset->n_headers; ++i) 240 | { 241 | header = &hset->headers[i]; 242 | lsxpack_header_set_ptr(&hdr, header->name, header->name_len, 243 | header->val, header->val_len); 244 | s = lshpack_enc_encode(&encoder, buf, buf + sizeof(buf), &hdr); 245 | if (s <= buf) 246 | { 247 | fprintf(stderr, "cannot encode\n"); 248 | exit(EXIT_FAILURE); 249 | } 250 | if (!discard) 251 | (void) fwrite(buf, 1, s - buf, out); 252 | } 253 | } 254 | 255 | lshpack_enc_set_max_capacity(&encoder, dyn_table_size); 256 | lshpack_enc_cleanup(&encoder); 257 | } 258 | 259 | munmap((void *) begin, st.st_size); 260 | if (qif_fd >= 0) 261 | close(qif_fd); 262 | exit(EXIT_SUCCESS); 263 | } 264 | -------------------------------------------------------------------------------- /bin/find-xxh.c: -------------------------------------------------------------------------------- 1 | /* find-xxh -- find XXH seed common for ls-hpack and ls-qpack 2 | * 3 | * To speed up decoding/encoding process in a proxy, we need to use the 4 | * same name and nameval XXH hashes in ls-hpack and ls-qpack libraries. 5 | * This program finds an XXH seed common to both and shifts and offsets 6 | * for construction of name and nameval XXH tables in both libraries. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include XXH_HEADER_NAME 18 | 19 | #define NAME_VAL(a, b) sizeof(a) - 1, sizeof(b) - 1, (a), (b) 20 | 21 | struct table_elem 22 | { 23 | unsigned name_len; 24 | unsigned val_len; 25 | const char *name; 26 | const char *val; 27 | }; 28 | 29 | 30 | static const struct table_elem hpack_table[] = 31 | { 32 | { NAME_VAL(":authority", "") }, 33 | { NAME_VAL(":method", "GET") }, 34 | { NAME_VAL(":method", "POST") }, 35 | { NAME_VAL(":path", "/") }, 36 | { NAME_VAL(":path", "/index.html") }, 37 | { NAME_VAL(":scheme", "http") }, 38 | { NAME_VAL(":scheme", "https") }, 39 | { NAME_VAL(":status", "200") }, 40 | { NAME_VAL(":status", "204") }, 41 | { NAME_VAL(":status", "206") }, 42 | { NAME_VAL(":status", "304") }, 43 | { NAME_VAL(":status", "400") }, 44 | { NAME_VAL(":status", "404") }, 45 | { NAME_VAL(":status", "500") }, 46 | { NAME_VAL("accept-charset", "") }, 47 | { NAME_VAL("accept-encoding", "gzip, deflate") }, 48 | { NAME_VAL("accept-language", "") }, 49 | { NAME_VAL("accept-ranges", "") }, 50 | { NAME_VAL("accept", "") }, 51 | { NAME_VAL("access-control-allow-origin", "") }, 52 | { NAME_VAL("age", "") }, 53 | { NAME_VAL("allow", "") }, 54 | { NAME_VAL("authorization", "") }, 55 | { NAME_VAL("cache-control", "") }, 56 | { NAME_VAL("content-disposition", "") }, 57 | { NAME_VAL("content-encoding", "") }, 58 | { NAME_VAL("content-language", "") }, 59 | { NAME_VAL("content-length", "") }, 60 | { NAME_VAL("content-location", "") }, 61 | { NAME_VAL("content-range", "") }, 62 | { NAME_VAL("content-type", "") }, 63 | { NAME_VAL("cookie", "") }, 64 | { NAME_VAL("date", "") }, 65 | { NAME_VAL("etag", "") }, 66 | { NAME_VAL("expect", "") }, 67 | { NAME_VAL("expires", "") }, 68 | { NAME_VAL("from", "") }, 69 | { NAME_VAL("host", "") }, 70 | { NAME_VAL("if-match", "") }, 71 | { NAME_VAL("if-modified-since", "") }, 72 | { NAME_VAL("if-none-match", "") }, 73 | { NAME_VAL("if-range", "") }, 74 | { NAME_VAL("if-unmodified-since", "") }, 75 | { NAME_VAL("last-modified", "") }, 76 | { NAME_VAL("link", "") }, 77 | { NAME_VAL("location", "") }, 78 | { NAME_VAL("max-forwards", "") }, 79 | { NAME_VAL("proxy-authenticate", "") }, 80 | { NAME_VAL("proxy-authorization", "") }, 81 | { NAME_VAL("range", "") }, 82 | { NAME_VAL("referer", "") }, 83 | { NAME_VAL("refresh", "") }, 84 | { NAME_VAL("retry-after", "") }, 85 | { NAME_VAL("server", "") }, 86 | { NAME_VAL("set-cookie", "") }, 87 | { NAME_VAL("strict-transport-security", "") }, 88 | { NAME_VAL("transfer-encoding", "") }, 89 | { NAME_VAL("user-agent", "") }, 90 | { NAME_VAL("vary", "") }, 91 | { NAME_VAL("via", "") }, 92 | { NAME_VAL("www-authenticate", "") } 93 | }; 94 | #define HPACK_STATIC_TABLE_SIZE (sizeof(hpack_table) / sizeof(hpack_table[0])) 95 | 96 | static const unsigned hpack_name_indexes[] = { 97 | 0, 1, 3, 5, 7, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 98 | 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 99 | 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 100 | }; 101 | #define HPACK_NAME_SIZE (sizeof(hpack_name_indexes) / sizeof(hpack_name_indexes[0])) 102 | 103 | /* [draft-ietf-quic-qpack-03] Appendix A */ 104 | static const struct table_elem qpack_table[] = 105 | { 106 | { NAME_VAL(":authority", "") }, 107 | { NAME_VAL(":path", "/") }, 108 | { NAME_VAL("age", "0") }, 109 | { NAME_VAL("content-disposition", "") }, 110 | { NAME_VAL("content-length", "0") }, 111 | { NAME_VAL("cookie", "") }, 112 | { NAME_VAL("date", "") }, 113 | { NAME_VAL("etag", "") }, 114 | { NAME_VAL("if-modified-since", "") }, 115 | { NAME_VAL("if-none-match", "") }, 116 | { NAME_VAL("last-modified", "") }, 117 | { NAME_VAL("link", "") }, 118 | { NAME_VAL("location", "") }, 119 | { NAME_VAL("referer", "") }, 120 | { NAME_VAL("set-cookie", "") }, 121 | { NAME_VAL(":method", "CONNECT") }, 122 | { NAME_VAL(":method", "DELETE") }, 123 | { NAME_VAL(":method", "GET") }, 124 | { NAME_VAL(":method", "HEAD") }, 125 | { NAME_VAL(":method", "OPTIONS") }, 126 | { NAME_VAL(":method", "POST") }, 127 | { NAME_VAL(":method", "PUT") }, 128 | { NAME_VAL(":scheme", "http") }, 129 | { NAME_VAL(":scheme", "https") }, 130 | { NAME_VAL(":status", "103") }, 131 | { NAME_VAL(":status", "200") }, 132 | { NAME_VAL(":status", "304") }, 133 | { NAME_VAL(":status", "404") }, 134 | { NAME_VAL(":status", "503") }, 135 | { NAME_VAL("accept", "*/*") }, 136 | { NAME_VAL("accept", "application/dns-message") }, 137 | { NAME_VAL("accept-encoding", "gzip, deflate, br") }, 138 | { NAME_VAL("accept-ranges", "bytes") }, 139 | { NAME_VAL("access-control-allow-headers", "cache-control") }, 140 | { NAME_VAL("access-control-allow-headers", "content-type") }, 141 | { NAME_VAL("access-control-allow-origin", "*") }, 142 | { NAME_VAL("cache-control", "max-age=0") }, 143 | { NAME_VAL("cache-control", "max-age=2592000") }, 144 | { NAME_VAL("cache-control", "max-age=604800") }, 145 | { NAME_VAL("cache-control", "no-cache") }, 146 | { NAME_VAL("cache-control", "no-store") }, 147 | { NAME_VAL("cache-control", "public, max-age=31536000") }, 148 | { NAME_VAL("content-encoding", "br") }, 149 | { NAME_VAL("content-encoding", "gzip") }, 150 | { NAME_VAL("content-type", "application/dns-message") }, 151 | { NAME_VAL("content-type", "application/javascript") }, 152 | { NAME_VAL("content-type", "application/json") }, 153 | { NAME_VAL("content-type", "application/x-www-form-urlencoded") }, 154 | { NAME_VAL("content-type", "image/gif") }, 155 | { NAME_VAL("content-type", "image/jpeg") }, 156 | { NAME_VAL("content-type", "image/png") }, 157 | { NAME_VAL("content-type", "text/css") }, 158 | { NAME_VAL("content-type", "text/html; charset=utf-8") }, 159 | { NAME_VAL("content-type", "text/plain") }, 160 | { NAME_VAL("content-type", "text/plain;charset=utf-8") }, 161 | { NAME_VAL("range", "bytes=0-") }, 162 | { NAME_VAL("strict-transport-security", "max-age=31536000") }, 163 | { NAME_VAL("strict-transport-security", "max-age=31536000; includesubdomains") }, 164 | { NAME_VAL("strict-transport-security", "max-age=31536000; includesubdomains; preload") }, 165 | { NAME_VAL("vary", "accept-encoding") }, 166 | { NAME_VAL("vary", "origin") }, 167 | { NAME_VAL("x-content-type-options", "nosniff") }, 168 | { NAME_VAL("x-xss-protection", "1; mode=block") }, 169 | { NAME_VAL(":status", "100") }, 170 | { NAME_VAL(":status", "204") }, 171 | { NAME_VAL(":status", "206") }, 172 | { NAME_VAL(":status", "302") }, 173 | { NAME_VAL(":status", "400") }, 174 | { NAME_VAL(":status", "403") }, 175 | { NAME_VAL(":status", "421") }, 176 | { NAME_VAL(":status", "425") }, 177 | { NAME_VAL(":status", "500") }, 178 | { NAME_VAL("accept-language", "") }, 179 | { NAME_VAL("access-control-allow-credentials", "FALSE") }, 180 | { NAME_VAL("access-control-allow-credentials", "TRUE") }, 181 | { NAME_VAL("access-control-allow-headers", "*") }, 182 | { NAME_VAL("access-control-allow-methods", "get") }, 183 | { NAME_VAL("access-control-allow-methods", "get, post, options") }, 184 | { NAME_VAL("access-control-allow-methods", "options") }, 185 | { NAME_VAL("access-control-expose-headers", "content-length") }, 186 | { NAME_VAL("access-control-request-headers", "content-type") }, 187 | { NAME_VAL("access-control-request-method", "get") }, 188 | { NAME_VAL("access-control-request-method", "post") }, 189 | { NAME_VAL("alt-svc", "clear") }, 190 | { NAME_VAL("authorization", "") }, 191 | { NAME_VAL("content-security-policy", "script-src 'none'; object-src 'none'; base-uri 'none'") }, 192 | { NAME_VAL("early-data", "1") }, 193 | { NAME_VAL("expect-ct", "") }, 194 | { NAME_VAL("forwarded", "") }, 195 | { NAME_VAL("if-range", "") }, 196 | { NAME_VAL("origin", "") }, 197 | { NAME_VAL("purpose", "prefetch") }, 198 | { NAME_VAL("server", "") }, 199 | { NAME_VAL("timing-allow-origin", "*") }, 200 | { NAME_VAL("upgrade-insecure-requests", "1") }, 201 | { NAME_VAL("user-agent", "") }, 202 | { NAME_VAL("x-forwarded-for", "") }, 203 | { NAME_VAL("x-frame-options", "deny") }, 204 | { NAME_VAL("x-frame-options", "sameorigin") }, 205 | }; 206 | #define QPACK_STATIC_TABLE_SIZE (sizeof(qpack_table) / sizeof(qpack_table[0])) 207 | 208 | /* This is calculated at runtime */ 209 | static unsigned qpack_name_indexes[QPACK_STATIC_TABLE_SIZE]; 210 | static unsigned n_qpack_name_indexes; 211 | 212 | /* QPACK static table has an interesting property that headers names are 213 | * not all placed in contiguous sequences. For example, :status appears 214 | * in two places in the table. 215 | */ 216 | static void 217 | calculate_qpack_name_indexes (void) 218 | { 219 | unsigned i, n; 220 | 221 | qpack_name_indexes[0] = 0; 222 | n_qpack_name_indexes = 1; 223 | for (n = 1; n < QPACK_STATIC_TABLE_SIZE; ++n) 224 | { 225 | for (i = 0; i < n 226 | && !(qpack_table[i].name_len == qpack_table[n].name_len 227 | && 0 == memcmp(qpack_table[i].name, 228 | qpack_table[n].name, qpack_table[n].name_len)); ++i) 229 | ; 230 | if (i == n) 231 | qpack_name_indexes[n_qpack_name_indexes++] = n; 232 | } 233 | } 234 | 235 | 236 | /* Need to strike some balance here. A small start width will result in 237 | * potentially long search time and -- more importantly -- in a hpack_table that 238 | * is very small, which may require lookup code to perform more comparisons. 239 | * On the other hand, a large width will result in a hpack_table that may be 240 | * slower to use. 241 | */ 242 | static unsigned MIN_WIDTH = 9; 243 | static unsigned MAX_WIDTH = 9; 244 | 245 | static unsigned MIN_SHIFT = 0; 246 | static unsigned MAX_SHIFT = 31; 247 | 248 | /* Return true if acceptable shift and width were found, false otherwise */ 249 | static int 250 | find_shift_and_width (const uint32_t *hashes, const unsigned n_hashes, 251 | unsigned *shift_p, unsigned *width_p) 252 | { 253 | unsigned shift, width, hash, i, j; 254 | 255 | for (width = MIN_WIDTH; width <= MAX_WIDTH; ++width) 256 | { 257 | for (shift = MIN_SHIFT; shift <= MAX_SHIFT 258 | && shift < 32 - width; ++shift) 259 | { 260 | for (i = 1; i < n_hashes; ++i) 261 | { 262 | hash = hashes[i] & (((1u << width) - 1) << shift); 263 | for (j = 0; j < i; ++j) 264 | if ((hashes[j] & (((1u << width) - 1) << shift)) == hash) 265 | goto check; 266 | } 267 | check: if (i >= n_hashes) 268 | { 269 | *shift_p = shift; 270 | *width_p = width; 271 | return 1; 272 | } 273 | } 274 | } 275 | 276 | return 0; 277 | } 278 | 279 | 280 | int 281 | main (int argc, char **argv) 282 | { 283 | uint32_t hpack_name_hashes[HPACK_NAME_SIZE]; 284 | uint32_t hpack_nameval_hashes[HPACK_STATIC_TABLE_SIZE]; 285 | uint32_t qpack_nameval_hashes[QPACK_STATIC_TABLE_SIZE]; 286 | uint32_t qpack_name_hashes[QPACK_STATIC_TABLE_SIZE]; 287 | uint32_t seed, init_seed = 0; 288 | unsigned n, idx; 289 | unsigned hpack_nameval_shift, hpack_name_width, hpack_nameval_width, 290 | hpack_name_shift; 291 | unsigned qpack_nameval_shift, qpack_name_width, qpack_nameval_width, 292 | qpack_name_shift; 293 | int opt, dont_stop = 0, print_tables = 0; 294 | 295 | while (-1 != (opt = getopt(argc, argv, "i:w:W:s:S:phN"))) 296 | { 297 | switch (opt) 298 | { 299 | case 'i': 300 | init_seed = atoi(optarg); 301 | break; 302 | case 'w': 303 | MIN_WIDTH = atoi(optarg); 304 | break; 305 | case 'W': 306 | MAX_WIDTH = atoi(optarg); 307 | break; 308 | case 's': 309 | MIN_SHIFT = atoi(optarg); 310 | break; 311 | case 'S': 312 | MAX_SHIFT = atoi(optarg); 313 | break; 314 | case 'p': 315 | print_tables = 1; 316 | break; 317 | case 'N': 318 | dont_stop = 1; 319 | break; 320 | case 'h': printf( 321 | "Usage: %s [options]\n" 322 | "\n" 323 | " -i seed Initial seed (defaults to 0)\n" 324 | " -w width Minimum width (defaults to %u)\n" 325 | " -W width Maximum width (defaults to %u)\n" 326 | " -s shift Minimum shift (defaults to %u)\n" 327 | " -S shift Maximum shift (defaults to %u)\n" 328 | " -N Don't stop after finding a match, keep searching\n" 329 | " -p Print resulting HPACK and QPACK tables\n" 330 | " -h Print this help screen and exit\n" 331 | , argv[0], MIN_WIDTH, MAX_WIDTH, MIN_SHIFT, MAX_SHIFT); 332 | return 0; 333 | } 334 | } 335 | 336 | seed = init_seed; 337 | calculate_qpack_name_indexes(); 338 | 339 | again: 340 | for (n = 0; n < HPACK_NAME_SIZE; ++n) 341 | { 342 | idx = hpack_name_indexes[n]; 343 | hpack_name_hashes[n] = XXH32(hpack_table[idx].name, 344 | hpack_table[idx].name_len, seed); 345 | } 346 | if (!find_shift_and_width(hpack_name_hashes, HPACK_NAME_SIZE, 347 | &hpack_name_shift, &hpack_name_width)) 348 | goto incr_seed; 349 | 350 | for (n = 0; n < HPACK_STATIC_TABLE_SIZE; ++n) 351 | { 352 | hpack_nameval_hashes[n] = XXH32(hpack_table[n].name, 353 | hpack_table[n].name_len, seed); 354 | hpack_nameval_hashes[n] = XXH32(hpack_table[n].val, 355 | hpack_table[n].val_len, hpack_nameval_hashes[n]); 356 | } 357 | if (!find_shift_and_width(hpack_nameval_hashes, HPACK_STATIC_TABLE_SIZE, 358 | &hpack_nameval_shift, &hpack_nameval_width)) 359 | goto incr_seed; 360 | 361 | for (n = 0; n < n_qpack_name_indexes; ++n) 362 | { 363 | idx = qpack_name_indexes[n]; 364 | qpack_name_hashes[n] = XXH32(qpack_table[idx].name, 365 | qpack_table[idx].name_len, seed); 366 | } 367 | if (!find_shift_and_width(qpack_name_hashes, n_qpack_name_indexes, 368 | &qpack_name_shift, &qpack_name_width)) 369 | goto incr_seed; 370 | 371 | for (n = 0; n < QPACK_STATIC_TABLE_SIZE; ++n) 372 | { 373 | qpack_nameval_hashes[n] = XXH32(qpack_table[n].name, 374 | qpack_table[n].name_len, seed); 375 | qpack_nameval_hashes[n] = XXH32(qpack_table[n].val, 376 | qpack_table[n].val_len, qpack_nameval_hashes[n]); 377 | } 378 | if (!find_shift_and_width(qpack_nameval_hashes, QPACK_STATIC_TABLE_SIZE, 379 | &qpack_nameval_shift, &qpack_nameval_width)) 380 | goto incr_seed; 381 | 382 | printf("unique set: seed %u\n" 383 | " hpack:\n" 384 | " name shift: %u; width: %u\n" 385 | " nameval shift: %u; width: %u\n" 386 | " qpack:\n" 387 | " name shift: %u; width: %u\n" 388 | " nameval shift: %u; width: %u\n" 389 | , seed 390 | , hpack_name_shift, hpack_name_width 391 | , hpack_nameval_shift, hpack_nameval_width 392 | , qpack_name_shift, qpack_name_width 393 | , qpack_nameval_shift, qpack_nameval_width 394 | ); 395 | 396 | if (print_tables) 397 | { 398 | printf("#define XXH_SEED %"PRIu32"\n", seed); 399 | 400 | printf("#define XXH_HPACK_NAME_WIDTH %"PRIu32"\n", hpack_name_width); 401 | printf("#define XXH_HPACK_NAME_SHIFT %"PRIu32"\n", hpack_name_shift); 402 | printf("static const unsigned char hpack_name2id[ 1 << XXH_HPACK_NAME_WIDTH ] =\n{\n"); 403 | for (n = 0; n < HPACK_NAME_SIZE; ++n) 404 | printf("[%u] = %u, ", (hpack_name_hashes[n] >> hpack_name_shift) 405 | & ((1 << hpack_name_width) - 1), hpack_name_indexes[n] + 1); 406 | printf("\n};\n"); 407 | 408 | printf("#define XXH_HPACK_NAMEVAL_WIDTH %"PRIu32"\n", hpack_nameval_width); 409 | printf("#define XXH_HPACK_NAMEVAL_SHIFT %"PRIu32"\n", hpack_nameval_shift); 410 | printf("static const unsigned char hpack_nameval2id[ 1 << XXH_HPACK_NAMEVAL_WIDTH ] =\n{\n"); 411 | for (n = 0; n < HPACK_STATIC_TABLE_SIZE; ++n) 412 | printf("[%u] = %u, ", (hpack_nameval_hashes[n] >> hpack_nameval_shift) 413 | & ((1 << hpack_nameval_width) - 1), n + 1); 414 | printf("\n};\n"); 415 | 416 | printf("#define XXH_QPACK_NAME_WIDTH %"PRIu32"\n", qpack_name_width); 417 | printf("#define XXH_QPACK_NAME_SHIFT %"PRIu32"\n", qpack_name_shift); 418 | printf("static const unsigned char qpack_name2id[ 1 << XXH_QPACK_NAME_WIDTH ] =\n{\n"); 419 | for (n = 0; n < n_qpack_name_indexes; ++n) 420 | printf("[%u] = %u, ", (qpack_name_hashes[n] >> qpack_name_shift) 421 | & ((1 << qpack_name_width) - 1), qpack_name_indexes[n] + 1); 422 | printf("\n};\n"); 423 | 424 | printf("#define XXH_QPACK_NAMEVAL_WIDTH %"PRIu32"\n", qpack_nameval_width); 425 | printf("#define XXH_QPACK_NAMEVAL_SHIFT %"PRIu32"\n", qpack_nameval_shift); 426 | printf("static const unsigned char qpack_nameval2id[ 1 << XXH_QPACK_NAMEVAL_WIDTH ] =\n{\n"); 427 | for (n = 0; n < QPACK_STATIC_TABLE_SIZE; ++n) 428 | printf("[%u] = %u, ", (qpack_nameval_hashes[n] >> qpack_nameval_shift) 429 | & ((1 << qpack_nameval_width) - 1), n + 1); 430 | printf("\n};\n"); 431 | } 432 | 433 | if (dont_stop) 434 | { 435 | fflush(stdout); 436 | goto incr_seed; 437 | } 438 | 439 | #if 0 /* TODO */ 440 | for (i = 0; i < TABLE_SIZE; ++i) 441 | #if NAMEVAL_SEARCH 442 | printf("[%u] = %u,\n", (hashes[i] >> min_shift) & ((1 << min_width) - 1), nameval_indexes[i] + 1); 443 | #else 444 | printf("[%u] = %u,\n", (hashes[i] >> min_shift) & ((1 << min_width) - 1), name_indexes[i] + 1); 445 | #endif 446 | #endif 447 | 448 | return 0; 449 | 450 | incr_seed: 451 | ++seed; 452 | if ((seed - init_seed) % 100000 == 0) 453 | fprintf(stderr, ".... seed: %u\n", seed); 454 | goto again; 455 | } 456 | -------------------------------------------------------------------------------- /bin/gen-fast-dec-table.c: -------------------------------------------------------------------------------- 1 | /* Generate table for fast Huffman decoding */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | struct el 10 | { 11 | uint16_t code; 12 | unsigned bits; 13 | uint8_t out; 14 | }; 15 | 16 | static const struct el els[] = 17 | { 18 | { 0x0, 5, 48, }, 19 | { 0x1, 5, 49, }, 20 | { 0x2, 5, 50, }, 21 | { 0x3, 5, 97, }, 22 | { 0x4, 5, 99, }, 23 | { 0x5, 5, 101, }, 24 | { 0x6, 5, 105, }, 25 | { 0x7, 5, 111, }, 26 | { 0x8, 5, 115, }, 27 | { 0x9, 5, 116, }, 28 | { 0x14, 6, 32, }, 29 | { 0x15, 6, 37, }, 30 | { 0x16, 6, 45, }, 31 | { 0x17, 6, 46, }, 32 | { 0x18, 6, 47, }, 33 | { 0x19, 6, 51, }, 34 | { 0x1a, 6, 52, }, 35 | { 0x1b, 6, 53, }, 36 | { 0x1c, 6, 54, }, 37 | { 0x1d, 6, 55, }, 38 | { 0x1e, 6, 56, }, 39 | { 0x1f, 6, 57, }, 40 | { 0x20, 6, 61, }, 41 | { 0x21, 6, 65, }, 42 | { 0x22, 6, 95, }, 43 | { 0x23, 6, 98, }, 44 | { 0x24, 6, 100, }, 45 | { 0x25, 6, 102, }, 46 | { 0x26, 6, 103, }, 47 | { 0x27, 6, 104, }, 48 | { 0x28, 6, 108, }, 49 | { 0x29, 6, 109, }, 50 | { 0x2a, 6, 110, }, 51 | { 0x2b, 6, 112, }, 52 | { 0x2c, 6, 114, }, 53 | { 0x2d, 6, 117, }, 54 | { 0x5c, 7, 58, }, 55 | { 0x5d, 7, 66, }, 56 | { 0x5e, 7, 67, }, 57 | { 0x5f, 7, 68, }, 58 | { 0x60, 7, 69, }, 59 | { 0x61, 7, 70, }, 60 | { 0x62, 7, 71, }, 61 | { 0x63, 7, 72, }, 62 | { 0x64, 7, 73, }, 63 | { 0x65, 7, 74, }, 64 | { 0x66, 7, 75, }, 65 | { 0x67, 7, 76, }, 66 | { 0x68, 7, 77, }, 67 | { 0x69, 7, 78, }, 68 | { 0x6a, 7, 79, }, 69 | { 0x6b, 7, 80, }, 70 | { 0x6c, 7, 81, }, 71 | { 0x6d, 7, 82, }, 72 | { 0x6e, 7, 83, }, 73 | { 0x6f, 7, 84, }, 74 | { 0x70, 7, 85, }, 75 | { 0x71, 7, 86, }, 76 | { 0x72, 7, 87, }, 77 | { 0x73, 7, 89, }, 78 | { 0x74, 7, 106, }, 79 | { 0x75, 7, 107, }, 80 | { 0x76, 7, 113, }, 81 | { 0x77, 7, 118, }, 82 | { 0x78, 7, 119, }, 83 | { 0x79, 7, 120, }, 84 | { 0x7a, 7, 121, }, 85 | { 0x7b, 7, 122, }, 86 | { 0xf8, 8, 38, }, 87 | { 0xf9, 8, 42, }, 88 | { 0xfa, 8, 44, }, 89 | { 0xfb, 8, 59, }, 90 | { 0xfc, 8, 88, }, 91 | { 0xfd, 8, 90, }, 92 | { 0x3f8, 10, 33, }, 93 | { 0x3f9, 10, 34, }, 94 | { 0x3fa, 10, 40, }, 95 | { 0x3fb, 10, 41, }, 96 | { 0x3fc, 10, 63, }, 97 | { 0x7fa, 11, 39, }, 98 | { 0x7fb, 11, 43, }, 99 | { 0x7fc, 11, 124, }, 100 | { 0xffa, 12, 35, }, 101 | { 0xffb, 12, 62, }, 102 | { 0x1ff8, 13, 0, }, 103 | { 0x1ff9, 13, 36, }, 104 | { 0x1ffa, 13, 64, }, 105 | { 0x1ffb, 13, 91, }, 106 | { 0x1ffc, 13, 93, }, 107 | { 0x1ffd, 13, 126, }, 108 | { 0x3ffc, 14, 94, }, 109 | { 0x3ffd, 14, 125, }, 110 | { 0x7ffc, 15, 60, }, 111 | { 0x7ffd, 15, 96, }, 112 | { 0x7ffe, 15, 123, }, 113 | }; 114 | 115 | 116 | static void 117 | generate_entry (uint16_t idx) 118 | { 119 | unsigned int bits_left, n_outs; 120 | const struct el *el; 121 | uint8_t outs[3]; 122 | 123 | bits_left = 16; 124 | n_outs = 0; 125 | do 126 | { 127 | for (el = els; el < els + sizeof(els) 128 | / sizeof(els[0]) && el->bits <= bits_left; ++el) 129 | if (el->code == (uint32_t) ((idx >> (bits_left - el->bits)) & ((1 << el->bits) - 1))) 130 | break; 131 | if (el >= els + sizeof(els) / sizeof(els[0]) || el->bits > bits_left) 132 | break; 133 | outs[n_outs++] = el->out; 134 | bits_left -= el->bits; 135 | } 136 | while (bits_left >= 5 /* shortest code */); 137 | 138 | printf("/* %"PRIu16" */ ", idx); 139 | if (n_outs) 140 | { 141 | printf("{(%u<<2)|%u,{", 16 - bits_left, n_outs); 142 | switch (n_outs) 143 | { 144 | case 3: 145 | printf("%u,%u,%u", outs[0], outs[1], outs[2]); 146 | break; 147 | case 2: 148 | printf("%u,%u,0", outs[0], outs[1]); 149 | break; 150 | case 1: 151 | printf("%u,0,0", outs[0]); 152 | break; 153 | default: exit(EXIT_FAILURE); 154 | } 155 | printf("}}"); 156 | } 157 | else 158 | printf("{0,0,0,0,}"); 159 | printf(",\n"); 160 | } 161 | 162 | 163 | int 164 | main (void) 165 | { 166 | unsigned idx; 167 | 168 | printf("static const struct hdec { uint8_t lens; uint8_t out[3]; } " 169 | "hdecs[] =\n{\n"); 170 | for (idx = 0; idx <= UINT16_MAX; ++idx) 171 | generate_entry(idx); 172 | printf("};\n"); 173 | 174 | return 0; 175 | } 176 | -------------------------------------------------------------------------------- /bin/gen-fast-enc-table.c: -------------------------------------------------------------------------------- 1 | /* Generate table for fast Huffman encoding */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct encode_el 9 | { 10 | uint32_t code; 11 | int bits; 12 | }; 13 | 14 | static const struct encode_el encode_table[257] = 15 | { 16 | { 0x1ff8, 13}, // ( 0) 17 | { 0x7fffd8, 23}, // ( 1) 18 | { 0xfffffe2, 28}, // ( 2) 19 | { 0xfffffe3, 28}, // ( 3) 20 | { 0xfffffe4, 28}, // ( 4) 21 | { 0xfffffe5, 28}, // ( 5) 22 | { 0xfffffe6, 28}, // ( 6) 23 | { 0xfffffe7, 28}, // ( 7) 24 | { 0xfffffe8, 28}, // ( 8) 25 | { 0xffffea, 24}, // ( 9) 26 | { 0x3ffffffc, 30}, // ( 10) 27 | { 0xfffffe9, 28}, // ( 11) 28 | { 0xfffffea, 28}, // ( 12) 29 | { 0x3ffffffd, 30}, // ( 13) 30 | { 0xfffffeb, 28}, // ( 14) 31 | { 0xfffffec, 28}, // ( 15) 32 | { 0xfffffed, 28}, // ( 16) 33 | { 0xfffffee, 28}, // ( 17) 34 | { 0xfffffef, 28}, // ( 18) 35 | { 0xffffff0, 28}, // ( 19) 36 | { 0xffffff1, 28}, // ( 20) 37 | { 0xffffff2, 28}, // ( 21) 38 | { 0x3ffffffe, 30}, // ( 22) 39 | { 0xffffff3, 28}, // ( 23) 40 | { 0xffffff4, 28}, // ( 24) 41 | { 0xffffff5, 28}, // ( 25) 42 | { 0xffffff6, 28}, // ( 26) 43 | { 0xffffff7, 28}, // ( 27) 44 | { 0xffffff8, 28}, // ( 28) 45 | { 0xffffff9, 28}, // ( 29) 46 | { 0xffffffa, 28}, // ( 30) 47 | { 0xffffffb, 28}, // ( 31) 48 | { 0x14, 6}, // ' ' ( 32) 49 | { 0x3f8, 10}, // '!' ( 33) 50 | { 0x3f9, 10}, // '"' ( 34) 51 | { 0xffa, 12}, // '#' ( 35) 52 | { 0x1ff9, 13}, // '$' ( 36) 53 | { 0x15, 6}, // '%' ( 37) 54 | { 0xf8, 8}, // '&' ( 38) 55 | { 0x7fa, 11}, // ''' ( 39) 56 | { 0x3fa, 10}, // '(' ( 40) 57 | { 0x3fb, 10}, // ')' ( 41) 58 | { 0xf9, 8}, // '*' ( 42) 59 | { 0x7fb, 11}, // '+' ( 43) 60 | { 0xfa, 8}, // ',' ( 44) 61 | { 0x16, 6}, // '-' ( 45) 62 | { 0x17, 6}, // '.' ( 46) 63 | { 0x18, 6}, // '/' ( 47) 64 | { 0x0, 5}, // '0' ( 48) 65 | { 0x1, 5}, // '1' ( 49) 66 | { 0x2, 5}, // '2' ( 50) 67 | { 0x19, 6}, // '3' ( 51) 68 | { 0x1a, 6}, // '4' ( 52) 69 | { 0x1b, 6}, // '5' ( 53) 70 | { 0x1c, 6}, // '6' ( 54) 71 | { 0x1d, 6}, // '7' ( 55) 72 | { 0x1e, 6}, // '8' ( 56) 73 | { 0x1f, 6}, // '9' ( 57) 74 | { 0x5c, 7}, // ':' ( 58) 75 | { 0xfb, 8}, // ';' ( 59) 76 | { 0x7ffc, 15}, // '<' ( 60) 77 | { 0x20, 6}, // '=' ( 61) 78 | { 0xffb, 12}, // '>' ( 62) 79 | { 0x3fc, 10}, // '?' ( 63) 80 | { 0x1ffa, 13}, // '@' ( 64) 81 | { 0x21, 6}, // 'A' ( 65) 82 | { 0x5d, 7}, // 'B' ( 66) 83 | { 0x5e, 7}, // 'C' ( 67) 84 | { 0x5f, 7}, // 'D' ( 68) 85 | { 0x60, 7}, // 'E' ( 69) 86 | { 0x61, 7}, // 'F' ( 70) 87 | { 0x62, 7}, // 'G' ( 71) 88 | { 0x63, 7}, // 'H' ( 72) 89 | { 0x64, 7}, // 'I' ( 73) 90 | { 0x65, 7}, // 'J' ( 74) 91 | { 0x66, 7}, // 'K' ( 75) 92 | { 0x67, 7}, // 'L' ( 76) 93 | { 0x68, 7}, // 'M' ( 77) 94 | { 0x69, 7}, // 'N' ( 78) 95 | { 0x6a, 7}, // 'O' ( 79) 96 | { 0x6b, 7}, // 'P' ( 80) 97 | { 0x6c, 7}, // 'Q' ( 81) 98 | { 0x6d, 7}, // 'R' ( 82) 99 | { 0x6e, 7}, // 'S' ( 83) 100 | { 0x6f, 7}, // 'T' ( 84) 101 | { 0x70, 7}, // 'U' ( 85) 102 | { 0x71, 7}, // 'V' ( 86) 103 | { 0x72, 7}, // 'W' ( 87) 104 | { 0xfc, 8}, // 'X' ( 88) 105 | { 0x73, 7}, // 'Y' ( 89) 106 | { 0xfd, 8}, // 'Z' ( 90) 107 | { 0x1ffb, 13}, // '[' ( 91) 108 | { 0x7fff0, 19}, // '\' ( 92) 109 | { 0x1ffc, 13}, // ']' ( 93) 110 | { 0x3ffc, 14}, // '^' ( 94) 111 | { 0x22, 6}, // '_' ( 95) 112 | { 0x7ffd, 15}, // '`' ( 96) 113 | { 0x3, 5}, // 'a' ( 97) 114 | { 0x23, 6}, // 'b' ( 98) 115 | { 0x4, 5}, // 'c' ( 99) 116 | { 0x24, 6}, // 'd' (100) 117 | { 0x5, 5}, // 'e' (101) 118 | { 0x25, 6}, // 'f' (102) 119 | { 0x26, 6}, // 'g' (103) 120 | { 0x27, 6}, // 'h' (104) 121 | { 0x6, 5}, // 'i' (105) 122 | { 0x74, 7}, // 'j' (106) 123 | { 0x75, 7}, // 'k' (107) 124 | { 0x28, 6}, // 'l' (108) 125 | { 0x29, 6}, // 'm' (109) 126 | { 0x2a, 6}, // 'n' (110) 127 | { 0x7, 5}, // 'o' (111) 128 | { 0x2b, 6}, // 'p' (112) 129 | { 0x76, 7}, // 'q' (113) 130 | { 0x2c, 6}, // 'r' (114) 131 | { 0x8, 5}, // 's' (115) 132 | { 0x9, 5}, // 't' (116) 133 | { 0x2d, 6}, // 'u' (117) 134 | { 0x77, 7}, // 'v' (118) 135 | { 0x78, 7}, // 'w' (119) 136 | { 0x79, 7}, // 'x' (120) 137 | { 0x7a, 7}, // 'y' (121) 138 | { 0x7b, 7}, // 'z' (122) 139 | { 0x7ffe, 15}, // '{' (123) 140 | { 0x7fc, 11}, // '|' (124) 141 | { 0x3ffd, 14}, // '}' (125) 142 | { 0x1ffd, 13}, // '~' (126) 143 | { 0xffffffc, 28}, // (127) 144 | { 0xfffe6, 20}, // (128) 145 | { 0x3fffd2, 22}, // (129) 146 | { 0xfffe7, 20}, // (130) 147 | { 0xfffe8, 20}, // (131) 148 | { 0x3fffd3, 22}, // (132) 149 | { 0x3fffd4, 22}, // (133) 150 | { 0x3fffd5, 22}, // (134) 151 | { 0x7fffd9, 23}, // (135) 152 | { 0x3fffd6, 22}, // (136) 153 | { 0x7fffda, 23}, // (137) 154 | { 0x7fffdb, 23}, // (138) 155 | { 0x7fffdc, 23}, // (139) 156 | { 0x7fffdd, 23}, // (140) 157 | { 0x7fffde, 23}, // (141) 158 | { 0xffffeb, 24}, // (142) 159 | { 0x7fffdf, 23}, // (143) 160 | { 0xffffec, 24}, // (144) 161 | { 0xffffed, 24}, // (145) 162 | { 0x3fffd7, 22}, // (146) 163 | { 0x7fffe0, 23}, // (147) 164 | { 0xffffee, 24}, // (148) 165 | { 0x7fffe1, 23}, // (149) 166 | { 0x7fffe2, 23}, // (150) 167 | { 0x7fffe3, 23}, // (151) 168 | { 0x7fffe4, 23}, // (152) 169 | { 0x1fffdc, 21}, // (153) 170 | { 0x3fffd8, 22}, // (154) 171 | { 0x7fffe5, 23}, // (155) 172 | { 0x3fffd9, 22}, // (156) 173 | { 0x7fffe6, 23}, // (157) 174 | { 0x7fffe7, 23}, // (158) 175 | { 0xffffef, 24}, // (159) 176 | { 0x3fffda, 22}, // (160) 177 | { 0x1fffdd, 21}, // (161) 178 | { 0xfffe9, 20}, // (162) 179 | { 0x3fffdb, 22}, // (163) 180 | { 0x3fffdc, 22}, // (164) 181 | { 0x7fffe8, 23}, // (165) 182 | { 0x7fffe9, 23}, // (166) 183 | { 0x1fffde, 21}, // (167) 184 | { 0x7fffea, 23}, // (168) 185 | { 0x3fffdd, 22}, // (169) 186 | { 0x3fffde, 22}, // (170) 187 | { 0xfffff0, 24}, // (171) 188 | { 0x1fffdf, 21}, // (172) 189 | { 0x3fffdf, 22}, // (173) 190 | { 0x7fffeb, 23}, // (174) 191 | { 0x7fffec, 23}, // (175) 192 | { 0x1fffe0, 21}, // (176) 193 | { 0x1fffe1, 21}, // (177) 194 | { 0x3fffe0, 22}, // (178) 195 | { 0x1fffe2, 21}, // (179) 196 | { 0x7fffed, 23}, // (180) 197 | { 0x3fffe1, 22}, // (181) 198 | { 0x7fffee, 23}, // (182) 199 | { 0x7fffef, 23}, // (183) 200 | { 0xfffea, 20}, // (184) 201 | { 0x3fffe2, 22}, // (185) 202 | { 0x3fffe3, 22}, // (186) 203 | { 0x3fffe4, 22}, // (187) 204 | { 0x7ffff0, 23}, // (188) 205 | { 0x3fffe5, 22}, // (189) 206 | { 0x3fffe6, 22}, // (190) 207 | { 0x7ffff1, 23}, // (191) 208 | { 0x3ffffe0, 26}, // (192) 209 | { 0x3ffffe1, 26}, // (193) 210 | { 0xfffeb, 20}, // (194) 211 | { 0x7fff1, 19}, // (195) 212 | { 0x3fffe7, 22}, // (196) 213 | { 0x7ffff2, 23}, // (197) 214 | { 0x3fffe8, 22}, // (198) 215 | { 0x1ffffec, 25}, // (199) 216 | { 0x3ffffe2, 26}, // (200) 217 | { 0x3ffffe3, 26}, // (201) 218 | { 0x3ffffe4, 26}, // (202) 219 | { 0x7ffffde, 27}, // (203) 220 | { 0x7ffffdf, 27}, // (204) 221 | { 0x3ffffe5, 26}, // (205) 222 | { 0xfffff1, 24}, // (206) 223 | { 0x1ffffed, 25}, // (207) 224 | { 0x7fff2, 19}, // (208) 225 | { 0x1fffe3, 21}, // (209) 226 | { 0x3ffffe6, 26}, // (210) 227 | { 0x7ffffe0, 27}, // (211) 228 | { 0x7ffffe1, 27}, // (212) 229 | { 0x3ffffe7, 26}, // (213) 230 | { 0x7ffffe2, 27}, // (214) 231 | { 0xfffff2, 24}, // (215) 232 | { 0x1fffe4, 21}, // (216) 233 | { 0x1fffe5, 21}, // (217) 234 | { 0x3ffffe8, 26}, // (218) 235 | { 0x3ffffe9, 26}, // (219) 236 | { 0xffffffd, 28}, // (220) 237 | { 0x7ffffe3, 27}, // (221) 238 | { 0x7ffffe4, 27}, // (222) 239 | { 0x7ffffe5, 27}, // (223) 240 | { 0xfffec, 20}, // (224) 241 | { 0xfffff3, 24}, // (225) 242 | { 0xfffed, 20}, // (226) 243 | { 0x1fffe6, 21}, // (227) 244 | { 0x3fffe9, 22}, // (228) 245 | { 0x1fffe7, 21}, // (229) 246 | { 0x1fffe8, 21}, // (230) 247 | { 0x7ffff3, 23}, // (231) 248 | { 0x3fffea, 22}, // (232) 249 | { 0x3fffeb, 22}, // (233) 250 | { 0x1ffffee, 25}, // (234) 251 | { 0x1ffffef, 25}, // (235) 252 | { 0xfffff4, 24}, // (236) 253 | { 0xfffff5, 24}, // (237) 254 | { 0x3ffffea, 26}, // (238) 255 | { 0x7ffff4, 23}, // (239) 256 | { 0x3ffffeb, 26}, // (240) 257 | { 0x7ffffe6, 27}, // (241) 258 | { 0x3ffffec, 26}, // (242) 259 | { 0x3ffffed, 26}, // (243) 260 | { 0x7ffffe7, 27}, // (244) 261 | { 0x7ffffe8, 27}, // (245) 262 | { 0x7ffffe9, 27}, // (246) 263 | { 0x7ffffea, 27}, // (247) 264 | { 0x7ffffeb, 27}, // (248) 265 | { 0xffffffe, 28}, // (249) 266 | { 0x7ffffec, 27}, // (250) 267 | { 0x7ffffed, 27}, // (251) 268 | { 0x7ffffee, 27}, // (252) 269 | { 0x7ffffef, 27}, // (253) 270 | { 0x7fffff0, 27}, // (254) 271 | { 0x3ffffee, 26}, // (255) 272 | { 0x3fffffff, 30} // EOS (256) 273 | }; 274 | 275 | 276 | static void 277 | generate_entry (uint16_t idx) 278 | { 279 | uint8_t i, j; 280 | 281 | j = idx >> 8; 282 | i = idx; 283 | 284 | if (encode_table[i].bits + encode_table[j].bits <= 32) 285 | printf(" [I(%hhu,%hhu)] = {%u,0x%X},\n", 286 | i, j, 287 | encode_table[i].bits + encode_table[j].bits, 288 | (encode_table[i].code << encode_table[j].bits) 289 | | encode_table[j].code); 290 | else 291 | printf(" [I(%hhu,%hhu)] = {64,0},\n", i, j); 292 | } 293 | 294 | 295 | int 296 | main (void) 297 | { 298 | unsigned idx; 299 | 300 | printf( 301 | "#if __BYTE_ORDER == __LITTLE_ENDIAN\n" 302 | "#define I(i,j) ((j<<8)|i)\n" 303 | "#else\n" 304 | "#define I(i,j) ((i<<8)|j)\n" 305 | "#endif\n" 306 | ); 307 | printf("static const struct henc { unsigned lens; uint32_t code; } " 308 | "hencs[] =\n{\n"); 309 | for (idx = 0; idx <= UINT16_MAX; ++idx) 310 | generate_entry(idx); 311 | printf("};\n"); 312 | printf("#undef I\n"); 313 | 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /bin/huff-decode.c: -------------------------------------------------------------------------------- 1 | /* Decode Huffman string -- use for benchmarking 2 | * 3 | * Usage: huff-decode $file $count $mode 4 | * 5 | * $mode is either "fast" or "slow" 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef LS_HPACK_USE_LARGE_TABLES 13 | #define LS_HPACK_USE_LARGE_TABLES 1 14 | #endif 15 | 16 | #if LS_HPACK_USE_LARGE_TABLES 17 | int 18 | lshpack_dec_huff_decode_full (const unsigned char *src, int src_len, 19 | unsigned char *dst, int dst_len); 20 | #endif 21 | 22 | int 23 | lshpack_dec_huff_decode (const unsigned char *src, int src_len, 24 | unsigned char *dst, int dst_len); 25 | 26 | int 27 | main (int argc, char **argv) 28 | { 29 | size_t in_sz; 30 | int count, i, rv; 31 | FILE *in; 32 | int (*decode)(const unsigned char *, int, unsigned char *, int); 33 | unsigned char in_buf[0x1000]; 34 | unsigned char out_buf[0x4000]; 35 | 36 | if (argc != 4) 37 | { 38 | fprintf(stderr, "Usage: %s $file $count $mode\n", argv[0]); 39 | exit(EXIT_FAILURE); 40 | } 41 | 42 | if (strcasecmp(argv[3], "slow") == 0) 43 | #if LS_HPACK_USE_LARGE_TABLES 44 | decode = lshpack_dec_huff_decode_full; 45 | #else 46 | decode = lshpack_dec_huff_decode; 47 | #endif 48 | else if (strcasecmp(argv[3], "fast") == 0) 49 | #if LS_HPACK_USE_LARGE_TABLES 50 | decode = lshpack_dec_huff_decode; 51 | #else 52 | { 53 | fprintf(stderr, "support for fast decoder is compiled out\n"); 54 | exit(EXIT_FAILURE); 55 | } 56 | #endif 57 | else 58 | { 59 | fprintf(stderr, "Mode `%s' is invalid. Specify either `slow' or " 60 | "`fast'.\n", argv[3]); 61 | exit(EXIT_FAILURE); 62 | } 63 | 64 | in = fopen(argv[1], "rb"); 65 | if (!in) 66 | { 67 | perror("fopen"); 68 | exit(EXIT_FAILURE); 69 | } 70 | 71 | in_sz = fread(in_buf, 1, sizeof(in_buf), in); 72 | if (in_sz == 0 || in_sz == sizeof(in_buf)) 73 | { 74 | fprintf(stderr, "input file is either too short or too long\n"); 75 | exit(EXIT_FAILURE); 76 | } 77 | (void) fclose(in); 78 | 79 | count = atoi(argv[2]); 80 | if (!count) 81 | count = 1; 82 | 83 | /* TODO: validate against slow if fast is selected */ 84 | 85 | rv = decode(in_buf, in_sz, out_buf, sizeof(out_buf)); 86 | if (rv < 0) 87 | { 88 | fprintf(stderr, "decode-%s returned %d\n", argv[3], rv); 89 | exit(EXIT_FAILURE); 90 | } 91 | 92 | for (i = 0; i < count; ++i) 93 | { 94 | rv = decode(in_buf, in_sz, out_buf, sizeof(out_buf)); 95 | (void) rv; 96 | } 97 | 98 | exit(EXIT_SUCCESS); 99 | } 100 | -------------------------------------------------------------------------------- /bin/huff-encode.c: -------------------------------------------------------------------------------- 1 | /* huff-encode -- Huffman-encode string */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | lshpack_enc_huff_encode (const unsigned char *src, 9 | const unsigned char *const src_end, unsigned char *const dst, int dst_len); 10 | 11 | int 12 | main (int argc, char **argv) 13 | { 14 | unsigned char buf[0x1000]; 15 | size_t len; 16 | int sz; 17 | 18 | if (argc != 2) 19 | { 20 | fprintf(stderr, "Usage: %s string > output\n", argv[0]); 21 | exit(EXIT_FAILURE); 22 | } 23 | 24 | len = strlen(argv[1]); 25 | sz = lshpack_enc_huff_encode((unsigned char *) argv[1], 26 | (unsigned char *) argv[1] + len, buf, sizeof(buf)); 27 | fwrite(buf, 1, sz, stdout); 28 | 29 | exit(EXIT_SUCCESS); 30 | } 31 | -------------------------------------------------------------------------------- /compat/queue/sys/queue.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * SPDX-License-Identifier: BSD-3-Clause 3 | * 4 | * Copyright (c) 1991, 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. Neither the name of the University nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | * 31 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 32 | * $FreeBSD$ 33 | */ 34 | 35 | #ifndef _SYS_QUEUE_H_ 36 | #define _SYS_QUEUE_H_ 37 | 38 | 39 | /* 40 | * This file defines four types of data structures: singly-linked lists, 41 | * singly-linked tail queues, lists and tail queues. 42 | * 43 | * A singly-linked list is headed by a single forward pointer. The elements 44 | * are singly linked for minimum space and pointer manipulation overhead at 45 | * the expense of O(n) removal for arbitrary elements. New elements can be 46 | * added to the list after an existing element or at the head of the list. 47 | * Elements being removed from the head of the list should use the explicit 48 | * macro for this purpose for optimum efficiency. A singly-linked list may 49 | * only be traversed in the forward direction. Singly-linked lists are ideal 50 | * for applications with large datasets and few or no removals or for 51 | * implementing a LIFO queue. 52 | * 53 | * A singly-linked tail queue is headed by a pair of pointers, one to the 54 | * head of the list and the other to the tail of the list. The elements are 55 | * singly linked for minimum space and pointer manipulation overhead at the 56 | * expense of O(n) removal for arbitrary elements. New elements can be added 57 | * to the list after an existing element, at the head of the list, or at the 58 | * end of the list. Elements being removed from the head of the tail queue 59 | * should use the explicit macro for this purpose for optimum efficiency. 60 | * A singly-linked tail queue may only be traversed in the forward direction. 61 | * Singly-linked tail queues are ideal for applications with large datasets 62 | * and few or no removals or for implementing a FIFO queue. 63 | * 64 | * A list is headed by a single forward pointer (or an array of forward 65 | * pointers for a hash table header). The elements are doubly linked 66 | * so that an arbitrary element can be removed without a need to 67 | * traverse the list. New elements can be added to the list before 68 | * or after an existing element or at the head of the list. A list 69 | * may be traversed in either direction. 70 | * 71 | * A tail queue is headed by a pair of pointers, one to the head of the 72 | * list and the other to the tail of the list. The elements are doubly 73 | * linked so that an arbitrary element can be removed without a need to 74 | * traverse the list. New elements can be added to the list before or 75 | * after an existing element, at the head of the list, or at the end of 76 | * the list. A tail queue may be traversed in either direction. 77 | * 78 | * For details on the use of these macros, see the queue(3) manual page. 79 | * 80 | * Below is a summary of implemented functions where: 81 | * + means the macro is available 82 | * - means the macro is not available 83 | * s means the macro is available but is slow (runs in O(n) time) 84 | * 85 | * SLIST LIST STAILQ TAILQ 86 | * _HEAD + + + + 87 | * _CLASS_HEAD + + + + 88 | * _HEAD_INITIALIZER + + + + 89 | * _ENTRY + + + + 90 | * _CLASS_ENTRY + + + + 91 | * _INIT + + + + 92 | * _EMPTY + + + + 93 | * _FIRST + + + + 94 | * _NEXT + + + + 95 | * _PREV - + - + 96 | * _LAST - - + + 97 | * _FOREACH + + + + 98 | * _FOREACH_FROM + + + + 99 | * _FOREACH_SAFE + + + + 100 | * _FOREACH_FROM_SAFE + + + + 101 | * _FOREACH_REVERSE - - - + 102 | * _FOREACH_REVERSE_FROM - - - + 103 | * _FOREACH_REVERSE_SAFE - - - + 104 | * _FOREACH_REVERSE_FROM_SAFE - - - + 105 | * _INSERT_HEAD + + + + 106 | * _INSERT_BEFORE - + - + 107 | * _INSERT_AFTER + + + + 108 | * _INSERT_TAIL - - + + 109 | * _CONCAT s s + + 110 | * _REMOVE_AFTER + - + - 111 | * _REMOVE_HEAD + - + - 112 | * _REMOVE s + s + 113 | * _SWAP + + + + 114 | * 115 | */ 116 | #ifdef QUEUE_MACRO_DEBUG 117 | #warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH 118 | #define QUEUE_MACRO_DEBUG_TRACE 119 | #define QUEUE_MACRO_DEBUG_TRASH 120 | #endif 121 | 122 | #ifdef QUEUE_MACRO_DEBUG_TRACE 123 | /* Store the last 2 places the queue element or head was altered */ 124 | struct qm_trace { 125 | unsigned long lastline; 126 | unsigned long prevline; 127 | const char *lastfile; 128 | const char *prevfile; 129 | }; 130 | 131 | #define TRACEBUF struct qm_trace trace; 132 | #define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } , 133 | 134 | #define QMD_TRACE_HEAD(head) do { \ 135 | (head)->trace.prevline = (head)->trace.lastline; \ 136 | (head)->trace.prevfile = (head)->trace.lastfile; \ 137 | (head)->trace.lastline = __LINE__; \ 138 | (head)->trace.lastfile = __FILE__; \ 139 | } while (0) 140 | 141 | #define QMD_TRACE_ELEM(elem) do { \ 142 | (elem)->trace.prevline = (elem)->trace.lastline; \ 143 | (elem)->trace.prevfile = (elem)->trace.lastfile; \ 144 | (elem)->trace.lastline = __LINE__; \ 145 | (elem)->trace.lastfile = __FILE__; \ 146 | } while (0) 147 | 148 | #else /* !QUEUE_MACRO_DEBUG_TRACE */ 149 | #define QMD_TRACE_ELEM(elem) 150 | #define QMD_TRACE_HEAD(head) 151 | #define TRACEBUF 152 | #define TRACEBUF_INITIALIZER 153 | #endif /* QUEUE_MACRO_DEBUG_TRACE */ 154 | 155 | #ifdef QUEUE_MACRO_DEBUG_TRASH 156 | #define TRASHIT(x) do {(x) = (void *)-1;} while (0) 157 | #define QMD_IS_TRASHED(x) ((x) == (void *)(intptr_t)-1) 158 | #else /* !QUEUE_MACRO_DEBUG_TRASH */ 159 | #define TRASHIT(x) 160 | #define QMD_IS_TRASHED(x) 0 161 | #endif /* QUEUE_MACRO_DEBUG_TRASH */ 162 | 163 | #if defined(QUEUE_MACRO_DEBUG_TRACE) || defined(QUEUE_MACRO_DEBUG_TRASH) 164 | #define QMD_SAVELINK(name, link) void **name = (void *)&(link) 165 | #else /* !QUEUE_MACRO_DEBUG_TRACE && !QUEUE_MACRO_DEBUG_TRASH */ 166 | #define QMD_SAVELINK(name, link) 167 | #endif /* QUEUE_MACRO_DEBUG_TRACE || QUEUE_MACRO_DEBUG_TRASH */ 168 | 169 | #ifdef __cplusplus 170 | /* 171 | * In C++ there can be structure lists and class lists: 172 | */ 173 | #define QUEUE_TYPEOF(type) type 174 | #else 175 | #define QUEUE_TYPEOF(type) struct type 176 | #endif 177 | 178 | /* 179 | * Singly-linked List declarations. 180 | */ 181 | #define SLIST_HEAD(name, type) \ 182 | struct name { \ 183 | struct type *slh_first; /* first element */ \ 184 | } 185 | 186 | #define SLIST_CLASS_HEAD(name, type) \ 187 | struct name { \ 188 | class type *slh_first; /* first element */ \ 189 | } 190 | 191 | #define SLIST_HEAD_INITIALIZER(head) \ 192 | { NULL } 193 | 194 | #define SLIST_ENTRY(type) \ 195 | struct { \ 196 | struct type *sle_next; /* next element */ \ 197 | } 198 | 199 | #define SLIST_CLASS_ENTRY(type) \ 200 | struct { \ 201 | class type *sle_next; /* next element */ \ 202 | } 203 | 204 | /* 205 | * Singly-linked List functions. 206 | */ 207 | #if (defined(_KERNEL) && defined(INVARIANTS)) 208 | #define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \ 209 | if (*(prevp) != (elm)) \ 210 | panic("Bad prevptr *(%p) == %p != %p", \ 211 | (prevp), *(prevp), (elm)); \ 212 | } while (0) 213 | #else 214 | #define QMD_SLIST_CHECK_PREVPTR(prevp, elm) 215 | #endif 216 | 217 | #define SLIST_CONCAT(head1, head2, type, field) do { \ 218 | QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \ 219 | if (curelm == NULL) { \ 220 | if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \ 221 | SLIST_INIT(head2); \ 222 | } else if (SLIST_FIRST(head2) != NULL) { \ 223 | while (SLIST_NEXT(curelm, field) != NULL) \ 224 | curelm = SLIST_NEXT(curelm, field); \ 225 | SLIST_NEXT(curelm, field) = SLIST_FIRST(head2); \ 226 | SLIST_INIT(head2); \ 227 | } \ 228 | } while (0) 229 | 230 | #define SLIST_EMPTY(head) ((head)->slh_first == NULL) 231 | 232 | #define SLIST_FIRST(head) ((head)->slh_first) 233 | 234 | #define SLIST_FOREACH(var, head, field) \ 235 | for ((var) = SLIST_FIRST((head)); \ 236 | (var); \ 237 | (var) = SLIST_NEXT((var), field)) 238 | 239 | #define SLIST_FOREACH_FROM(var, head, field) \ 240 | for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ 241 | (var); \ 242 | (var) = SLIST_NEXT((var), field)) 243 | 244 | #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ 245 | for ((var) = SLIST_FIRST((head)); \ 246 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ 247 | (var) = (tvar)) 248 | 249 | #define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ 250 | for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ 251 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ 252 | (var) = (tvar)) 253 | 254 | #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ 255 | for ((varp) = &SLIST_FIRST((head)); \ 256 | ((var) = *(varp)) != NULL; \ 257 | (varp) = &SLIST_NEXT((var), field)) 258 | 259 | #define SLIST_INIT(head) do { \ 260 | SLIST_FIRST((head)) = NULL; \ 261 | } while (0) 262 | 263 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 264 | SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ 265 | SLIST_NEXT((slistelm), field) = (elm); \ 266 | } while (0) 267 | 268 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 269 | SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ 270 | SLIST_FIRST((head)) = (elm); \ 271 | } while (0) 272 | 273 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 274 | 275 | #define SLIST_REMOVE(head, elm, type, field) do { \ 276 | QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ 277 | if (SLIST_FIRST((head)) == (elm)) { \ 278 | SLIST_REMOVE_HEAD((head), field); \ 279 | } \ 280 | else { \ 281 | QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \ 282 | while (SLIST_NEXT(curelm, field) != (elm)) \ 283 | curelm = SLIST_NEXT(curelm, field); \ 284 | SLIST_REMOVE_AFTER(curelm, field); \ 285 | } \ 286 | TRASHIT(*oldnext); \ 287 | } while (0) 288 | 289 | #define SLIST_REMOVE_AFTER(elm, field) do { \ 290 | SLIST_NEXT(elm, field) = \ 291 | SLIST_NEXT(SLIST_NEXT(elm, field), field); \ 292 | } while (0) 293 | 294 | #define SLIST_REMOVE_HEAD(head, field) do { \ 295 | SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ 296 | } while (0) 297 | 298 | #define SLIST_REMOVE_PREVPTR(prevp, elm, field) do { \ 299 | QMD_SLIST_CHECK_PREVPTR(prevp, elm); \ 300 | *(prevp) = SLIST_NEXT(elm, field); \ 301 | TRASHIT((elm)->field.sle_next); \ 302 | } while (0) 303 | 304 | #define SLIST_SWAP(head1, head2, type) do { \ 305 | QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \ 306 | SLIST_FIRST(head1) = SLIST_FIRST(head2); \ 307 | SLIST_FIRST(head2) = swap_first; \ 308 | } while (0) 309 | 310 | /* 311 | * Singly-linked Tail queue declarations. 312 | */ 313 | #define STAILQ_HEAD(name, type) \ 314 | struct name { \ 315 | struct type *stqh_first;/* first element */ \ 316 | struct type **stqh_last;/* addr of last next element */ \ 317 | } 318 | 319 | #define STAILQ_CLASS_HEAD(name, type) \ 320 | struct name { \ 321 | class type *stqh_first; /* first element */ \ 322 | class type **stqh_last; /* addr of last next element */ \ 323 | } 324 | 325 | #define STAILQ_HEAD_INITIALIZER(head) \ 326 | { NULL, &(head).stqh_first } 327 | 328 | #define STAILQ_ENTRY(type) \ 329 | struct { \ 330 | struct type *stqe_next; /* next element */ \ 331 | } 332 | 333 | #define STAILQ_CLASS_ENTRY(type) \ 334 | struct { \ 335 | class type *stqe_next; /* next element */ \ 336 | } 337 | 338 | /* 339 | * Singly-linked Tail queue functions. 340 | */ 341 | #define STAILQ_CONCAT(head1, head2) do { \ 342 | if (!STAILQ_EMPTY((head2))) { \ 343 | *(head1)->stqh_last = (head2)->stqh_first; \ 344 | (head1)->stqh_last = (head2)->stqh_last; \ 345 | STAILQ_INIT((head2)); \ 346 | } \ 347 | } while (0) 348 | 349 | #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) 350 | 351 | #define STAILQ_FIRST(head) ((head)->stqh_first) 352 | 353 | #define STAILQ_FOREACH(var, head, field) \ 354 | for((var) = STAILQ_FIRST((head)); \ 355 | (var); \ 356 | (var) = STAILQ_NEXT((var), field)) 357 | 358 | #define STAILQ_FOREACH_FROM(var, head, field) \ 359 | for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ 360 | (var); \ 361 | (var) = STAILQ_NEXT((var), field)) 362 | 363 | #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ 364 | for ((var) = STAILQ_FIRST((head)); \ 365 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ 366 | (var) = (tvar)) 367 | 368 | #define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ 369 | for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ 370 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ 371 | (var) = (tvar)) 372 | 373 | #define STAILQ_INIT(head) do { \ 374 | STAILQ_FIRST((head)) = NULL; \ 375 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 376 | } while (0) 377 | 378 | #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ 379 | if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ 380 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 381 | STAILQ_NEXT((tqelm), field) = (elm); \ 382 | } while (0) 383 | 384 | #define STAILQ_INSERT_HEAD(head, elm, field) do { \ 385 | if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ 386 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 387 | STAILQ_FIRST((head)) = (elm); \ 388 | } while (0) 389 | 390 | #define STAILQ_INSERT_TAIL(head, elm, field) do { \ 391 | STAILQ_NEXT((elm), field) = NULL; \ 392 | *(head)->stqh_last = (elm); \ 393 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 394 | } while (0) 395 | 396 | #define STAILQ_LAST(head, type, field) \ 397 | (STAILQ_EMPTY((head)) ? NULL : \ 398 | __containerof((head)->stqh_last, \ 399 | QUEUE_TYPEOF(type), field.stqe_next)) 400 | 401 | #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) 402 | 403 | #define STAILQ_REMOVE(head, elm, type, field) do { \ 404 | QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ 405 | if (STAILQ_FIRST((head)) == (elm)) { \ 406 | STAILQ_REMOVE_HEAD((head), field); \ 407 | } \ 408 | else { \ 409 | QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \ 410 | while (STAILQ_NEXT(curelm, field) != (elm)) \ 411 | curelm = STAILQ_NEXT(curelm, field); \ 412 | STAILQ_REMOVE_AFTER(head, curelm, field); \ 413 | } \ 414 | TRASHIT(*oldnext); \ 415 | } while (0) 416 | 417 | #define STAILQ_REMOVE_AFTER(head, elm, field) do { \ 418 | if ((STAILQ_NEXT(elm, field) = \ 419 | STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ 420 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 421 | } while (0) 422 | 423 | #define STAILQ_REMOVE_HEAD(head, field) do { \ 424 | if ((STAILQ_FIRST((head)) = \ 425 | STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ 426 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 427 | } while (0) 428 | 429 | #define STAILQ_SWAP(head1, head2, type) do { \ 430 | QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \ 431 | QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \ 432 | STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ 433 | (head1)->stqh_last = (head2)->stqh_last; \ 434 | STAILQ_FIRST(head2) = swap_first; \ 435 | (head2)->stqh_last = swap_last; \ 436 | if (STAILQ_EMPTY(head1)) \ 437 | (head1)->stqh_last = &STAILQ_FIRST(head1); \ 438 | if (STAILQ_EMPTY(head2)) \ 439 | (head2)->stqh_last = &STAILQ_FIRST(head2); \ 440 | } while (0) 441 | 442 | 443 | /* 444 | * List declarations. 445 | */ 446 | #define LIST_HEAD(name, type) \ 447 | struct name { \ 448 | struct type *lh_first; /* first element */ \ 449 | } 450 | 451 | #define LIST_CLASS_HEAD(name, type) \ 452 | struct name { \ 453 | class type *lh_first; /* first element */ \ 454 | } 455 | 456 | #define LIST_HEAD_INITIALIZER(head) \ 457 | { NULL } 458 | 459 | #define LIST_ENTRY(type) \ 460 | struct { \ 461 | struct type *le_next; /* next element */ \ 462 | struct type **le_prev; /* address of previous next element */ \ 463 | } 464 | 465 | #define LIST_CLASS_ENTRY(type) \ 466 | struct { \ 467 | class type *le_next; /* next element */ \ 468 | class type **le_prev; /* address of previous next element */ \ 469 | } 470 | 471 | /* 472 | * List functions. 473 | */ 474 | 475 | #if (defined(_KERNEL) && defined(INVARIANTS)) 476 | /* 477 | * QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME) 478 | * 479 | * If the list is non-empty, validates that the first element of the list 480 | * points back at 'head.' 481 | */ 482 | #define QMD_LIST_CHECK_HEAD(head, field) do { \ 483 | if (LIST_FIRST((head)) != NULL && \ 484 | LIST_FIRST((head))->field.le_prev != \ 485 | &LIST_FIRST((head))) \ 486 | panic("Bad list head %p first->prev != head", (head)); \ 487 | } while (0) 488 | 489 | /* 490 | * QMD_LIST_CHECK_NEXT(TYPE *elm, LIST_ENTRY NAME) 491 | * 492 | * If an element follows 'elm' in the list, validates that the next element 493 | * points back at 'elm.' 494 | */ 495 | #define QMD_LIST_CHECK_NEXT(elm, field) do { \ 496 | if (LIST_NEXT((elm), field) != NULL && \ 497 | LIST_NEXT((elm), field)->field.le_prev != \ 498 | &((elm)->field.le_next)) \ 499 | panic("Bad link elm %p next->prev != elm", (elm)); \ 500 | } while (0) 501 | 502 | /* 503 | * QMD_LIST_CHECK_PREV(TYPE *elm, LIST_ENTRY NAME) 504 | * 505 | * Validates that the previous element (or head of the list) points to 'elm.' 506 | */ 507 | #define QMD_LIST_CHECK_PREV(elm, field) do { \ 508 | if (*(elm)->field.le_prev != (elm)) \ 509 | panic("Bad link elm %p prev->next != elm", (elm)); \ 510 | } while (0) 511 | #else 512 | #define QMD_LIST_CHECK_HEAD(head, field) 513 | #define QMD_LIST_CHECK_NEXT(elm, field) 514 | #define QMD_LIST_CHECK_PREV(elm, field) 515 | #endif /* (_KERNEL && INVARIANTS) */ 516 | 517 | #define LIST_CONCAT(head1, head2, type, field) do { \ 518 | QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \ 519 | if (curelm == NULL) { \ 520 | if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) { \ 521 | LIST_FIRST(head2)->field.le_prev = \ 522 | &LIST_FIRST((head1)); \ 523 | LIST_INIT(head2); \ 524 | } \ 525 | } else if (LIST_FIRST(head2) != NULL) { \ 526 | while (LIST_NEXT(curelm, field) != NULL) \ 527 | curelm = LIST_NEXT(curelm, field); \ 528 | LIST_NEXT(curelm, field) = LIST_FIRST(head2); \ 529 | LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field); \ 530 | LIST_INIT(head2); \ 531 | } \ 532 | } while (0) 533 | 534 | #define LIST_EMPTY(head) ((head)->lh_first == NULL) 535 | 536 | #define LIST_FIRST(head) ((head)->lh_first) 537 | 538 | #define LIST_FOREACH(var, head, field) \ 539 | for ((var) = LIST_FIRST((head)); \ 540 | (var); \ 541 | (var) = LIST_NEXT((var), field)) 542 | 543 | #define LIST_FOREACH_FROM(var, head, field) \ 544 | for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ 545 | (var); \ 546 | (var) = LIST_NEXT((var), field)) 547 | 548 | #define LIST_FOREACH_SAFE(var, head, field, tvar) \ 549 | for ((var) = LIST_FIRST((head)); \ 550 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \ 551 | (var) = (tvar)) 552 | 553 | #define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ 554 | for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ 555 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \ 556 | (var) = (tvar)) 557 | 558 | #define LIST_INIT(head) do { \ 559 | LIST_FIRST((head)) = NULL; \ 560 | } while (0) 561 | 562 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 563 | QMD_LIST_CHECK_NEXT(listelm, field); \ 564 | if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ 565 | LIST_NEXT((listelm), field)->field.le_prev = \ 566 | &LIST_NEXT((elm), field); \ 567 | LIST_NEXT((listelm), field) = (elm); \ 568 | (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ 569 | } while (0) 570 | 571 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 572 | QMD_LIST_CHECK_PREV(listelm, field); \ 573 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 574 | LIST_NEXT((elm), field) = (listelm); \ 575 | *(listelm)->field.le_prev = (elm); \ 576 | (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ 577 | } while (0) 578 | 579 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 580 | QMD_LIST_CHECK_HEAD((head), field); \ 581 | if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ 582 | LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ 583 | LIST_FIRST((head)) = (elm); \ 584 | (elm)->field.le_prev = &LIST_FIRST((head)); \ 585 | } while (0) 586 | 587 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 588 | 589 | #define LIST_PREV(elm, head, type, field) \ 590 | ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ 591 | __containerof((elm)->field.le_prev, \ 592 | QUEUE_TYPEOF(type), field.le_next)) 593 | 594 | #define LIST_REMOVE(elm, field) do { \ 595 | QMD_SAVELINK(oldnext, (elm)->field.le_next); \ 596 | QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ 597 | QMD_LIST_CHECK_NEXT(elm, field); \ 598 | QMD_LIST_CHECK_PREV(elm, field); \ 599 | if (LIST_NEXT((elm), field) != NULL) \ 600 | LIST_NEXT((elm), field)->field.le_prev = \ 601 | (elm)->field.le_prev; \ 602 | *(elm)->field.le_prev = LIST_NEXT((elm), field); \ 603 | TRASHIT(*oldnext); \ 604 | TRASHIT(*oldprev); \ 605 | } while (0) 606 | 607 | #define LIST_SWAP(head1, head2, type, field) do { \ 608 | QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \ 609 | LIST_FIRST((head1)) = LIST_FIRST((head2)); \ 610 | LIST_FIRST((head2)) = swap_tmp; \ 611 | if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ 612 | swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ 613 | if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ 614 | swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ 615 | } while (0) 616 | 617 | /* 618 | * Tail queue declarations. 619 | */ 620 | #define TAILQ_HEAD(name, type) \ 621 | struct name { \ 622 | struct type *tqh_first; /* first element */ \ 623 | struct type **tqh_last; /* addr of last next element */ \ 624 | TRACEBUF \ 625 | } 626 | 627 | #define TAILQ_CLASS_HEAD(name, type) \ 628 | struct name { \ 629 | class type *tqh_first; /* first element */ \ 630 | class type **tqh_last; /* addr of last next element */ \ 631 | TRACEBUF \ 632 | } 633 | 634 | #define TAILQ_HEAD_INITIALIZER(head) \ 635 | { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER } 636 | 637 | #define TAILQ_ENTRY(type) \ 638 | struct { \ 639 | struct type *tqe_next; /* next element */ \ 640 | struct type **tqe_prev; /* address of previous next element */ \ 641 | TRACEBUF \ 642 | } 643 | 644 | #define TAILQ_CLASS_ENTRY(type) \ 645 | struct { \ 646 | class type *tqe_next; /* next element */ \ 647 | class type **tqe_prev; /* address of previous next element */ \ 648 | TRACEBUF \ 649 | } 650 | 651 | /* 652 | * Tail queue functions. 653 | */ 654 | #if (defined(_KERNEL) && defined(INVARIANTS)) 655 | /* 656 | * QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME) 657 | * 658 | * If the tailq is non-empty, validates that the first element of the tailq 659 | * points back at 'head.' 660 | */ 661 | #define QMD_TAILQ_CHECK_HEAD(head, field) do { \ 662 | if (!TAILQ_EMPTY(head) && \ 663 | TAILQ_FIRST((head))->field.tqe_prev != \ 664 | &TAILQ_FIRST((head))) \ 665 | panic("Bad tailq head %p first->prev != head", (head)); \ 666 | } while (0) 667 | 668 | /* 669 | * QMD_TAILQ_CHECK_TAIL(TAILQ_HEAD *head, TAILQ_ENTRY NAME) 670 | * 671 | * Validates that the tail of the tailq is a pointer to pointer to NULL. 672 | */ 673 | #define QMD_TAILQ_CHECK_TAIL(head, field) do { \ 674 | if (*(head)->tqh_last != NULL) \ 675 | panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ 676 | } while (0) 677 | 678 | /* 679 | * QMD_TAILQ_CHECK_NEXT(TYPE *elm, TAILQ_ENTRY NAME) 680 | * 681 | * If an element follows 'elm' in the tailq, validates that the next element 682 | * points back at 'elm.' 683 | */ 684 | #define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ 685 | if (TAILQ_NEXT((elm), field) != NULL && \ 686 | TAILQ_NEXT((elm), field)->field.tqe_prev != \ 687 | &((elm)->field.tqe_next)) \ 688 | panic("Bad link elm %p next->prev != elm", (elm)); \ 689 | } while (0) 690 | 691 | /* 692 | * QMD_TAILQ_CHECK_PREV(TYPE *elm, TAILQ_ENTRY NAME) 693 | * 694 | * Validates that the previous element (or head of the tailq) points to 'elm.' 695 | */ 696 | #define QMD_TAILQ_CHECK_PREV(elm, field) do { \ 697 | if (*(elm)->field.tqe_prev != (elm)) \ 698 | panic("Bad link elm %p prev->next != elm", (elm)); \ 699 | } while (0) 700 | #else 701 | #define QMD_TAILQ_CHECK_HEAD(head, field) 702 | #define QMD_TAILQ_CHECK_TAIL(head, headname) 703 | #define QMD_TAILQ_CHECK_NEXT(elm, field) 704 | #define QMD_TAILQ_CHECK_PREV(elm, field) 705 | #endif /* (_KERNEL && INVARIANTS) */ 706 | 707 | #define TAILQ_CONCAT(head1, head2, field) do { \ 708 | if (!TAILQ_EMPTY(head2)) { \ 709 | *(head1)->tqh_last = (head2)->tqh_first; \ 710 | (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ 711 | (head1)->tqh_last = (head2)->tqh_last; \ 712 | TAILQ_INIT((head2)); \ 713 | QMD_TRACE_HEAD(head1); \ 714 | QMD_TRACE_HEAD(head2); \ 715 | } \ 716 | } while (0) 717 | 718 | #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 719 | 720 | #define TAILQ_FIRST(head) ((head)->tqh_first) 721 | 722 | #define TAILQ_FOREACH(var, head, field) \ 723 | for ((var) = TAILQ_FIRST((head)); \ 724 | (var); \ 725 | (var) = TAILQ_NEXT((var), field)) 726 | 727 | #define TAILQ_FOREACH_FROM(var, head, field) \ 728 | for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ 729 | (var); \ 730 | (var) = TAILQ_NEXT((var), field)) 731 | 732 | #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ 733 | for ((var) = TAILQ_FIRST((head)); \ 734 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 735 | (var) = (tvar)) 736 | 737 | #define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ 738 | for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ 739 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 740 | (var) = (tvar)) 741 | 742 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 743 | for ((var) = TAILQ_LAST((head), headname); \ 744 | (var); \ 745 | (var) = TAILQ_PREV((var), headname, field)) 746 | 747 | #define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ 748 | for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ 749 | (var); \ 750 | (var) = TAILQ_PREV((var), headname, field)) 751 | 752 | #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ 753 | for ((var) = TAILQ_LAST((head), headname); \ 754 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ 755 | (var) = (tvar)) 756 | 757 | #define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \ 758 | for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ 759 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ 760 | (var) = (tvar)) 761 | 762 | #define TAILQ_INIT(head) do { \ 763 | TAILQ_FIRST((head)) = NULL; \ 764 | (head)->tqh_last = &TAILQ_FIRST((head)); \ 765 | QMD_TRACE_HEAD(head); \ 766 | } while (0) 767 | 768 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 769 | QMD_TAILQ_CHECK_NEXT(listelm, field); \ 770 | if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ 771 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 772 | &TAILQ_NEXT((elm), field); \ 773 | else { \ 774 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 775 | QMD_TRACE_HEAD(head); \ 776 | } \ 777 | TAILQ_NEXT((listelm), field) = (elm); \ 778 | (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ 779 | QMD_TRACE_ELEM(&(elm)->field); \ 780 | QMD_TRACE_ELEM(&(listelm)->field); \ 781 | } while (0) 782 | 783 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 784 | QMD_TAILQ_CHECK_PREV(listelm, field); \ 785 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 786 | TAILQ_NEXT((elm), field) = (listelm); \ 787 | *(listelm)->field.tqe_prev = (elm); \ 788 | (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ 789 | QMD_TRACE_ELEM(&(elm)->field); \ 790 | QMD_TRACE_ELEM(&(listelm)->field); \ 791 | } while (0) 792 | 793 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 794 | QMD_TAILQ_CHECK_HEAD(head, field); \ 795 | if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ 796 | TAILQ_FIRST((head))->field.tqe_prev = \ 797 | &TAILQ_NEXT((elm), field); \ 798 | else \ 799 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 800 | TAILQ_FIRST((head)) = (elm); \ 801 | (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ 802 | QMD_TRACE_HEAD(head); \ 803 | QMD_TRACE_ELEM(&(elm)->field); \ 804 | } while (0) 805 | 806 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 807 | QMD_TAILQ_CHECK_TAIL(head, field); \ 808 | TAILQ_NEXT((elm), field) = NULL; \ 809 | (elm)->field.tqe_prev = (head)->tqh_last; \ 810 | *(head)->tqh_last = (elm); \ 811 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 812 | QMD_TRACE_HEAD(head); \ 813 | QMD_TRACE_ELEM(&(elm)->field); \ 814 | } while (0) 815 | 816 | #define TAILQ_LAST(head, headname) \ 817 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 818 | 819 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 820 | 821 | #define TAILQ_PREV(elm, headname, field) \ 822 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 823 | 824 | #define TAILQ_REMOVE(head, elm, field) do { \ 825 | QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ 826 | QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ 827 | QMD_TAILQ_CHECK_NEXT(elm, field); \ 828 | QMD_TAILQ_CHECK_PREV(elm, field); \ 829 | if ((TAILQ_NEXT((elm), field)) != NULL) \ 830 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 831 | (elm)->field.tqe_prev; \ 832 | else { \ 833 | (head)->tqh_last = (elm)->field.tqe_prev; \ 834 | QMD_TRACE_HEAD(head); \ 835 | } \ 836 | *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ 837 | TRASHIT(*oldnext); \ 838 | TRASHIT(*oldprev); \ 839 | QMD_TRACE_ELEM(&(elm)->field); \ 840 | } while (0) 841 | 842 | #define TAILQ_SWAP(head1, head2, type, field) do { \ 843 | QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \ 844 | QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \ 845 | (head1)->tqh_first = (head2)->tqh_first; \ 846 | (head1)->tqh_last = (head2)->tqh_last; \ 847 | (head2)->tqh_first = swap_first; \ 848 | (head2)->tqh_last = swap_last; \ 849 | if ((swap_first = (head1)->tqh_first) != NULL) \ 850 | swap_first->field.tqe_prev = &(head1)->tqh_first; \ 851 | else \ 852 | (head1)->tqh_last = &(head1)->tqh_first; \ 853 | if ((swap_first = (head2)->tqh_first) != NULL) \ 854 | swap_first->field.tqe_prev = &(head2)->tqh_first; \ 855 | else \ 856 | (head2)->tqh_last = &(head2)->tqh_first; \ 857 | } while (0) 858 | 859 | #endif /* !_SYS_QUEUE_H_ */ 860 | -------------------------------------------------------------------------------- /compat/windows/sys/uio.h: -------------------------------------------------------------------------------- 1 | #ifndef WINCOMPAT_SYS_UIO_H 2 | #define WINCOMPAT_SYS_UIO_H 3 | 4 | struct iovec 5 | { 6 | void *iov_base; 7 | size_t iov_len; 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /deps/xxhash/xxhash.c: -------------------------------------------------------------------------------- 1 | /* 2 | xxHash - Fast Hash algorithm 3 | Copyright (C) 2012-2014, Yann Collet. 4 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following disclaimer 14 | in the documentation and/or other materials provided with the 15 | distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | You can contact the author at : 30 | - xxHash source repository : http://code.google.com/p/xxhash/ 31 | - public discussion board : https://groups.google.com/forum/#!forum/lz4c 32 | */ 33 | 34 | 35 | //************************************** 36 | // Tuning parameters 37 | //************************************** 38 | // Unaligned memory access is automatically enabled for "common" CPU, such as x86. 39 | // For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected. 40 | // If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance. 41 | // You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32). 42 | #if defined(__ARM_FEATURE_UNALIGNED) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) 43 | # define XXH_USE_UNALIGNED_ACCESS 1 44 | #endif 45 | 46 | // XXH_ACCEPT_NULL_INPUT_POINTER : 47 | // If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer. 48 | // When this option is enabled, xxHash output for null input pointers will be the same as a null-length input. 49 | // This option has a very small performance cost (only measurable on small inputs). 50 | // By default, this option is disabled. To enable it, uncomment below define : 51 | // #define XXH_ACCEPT_NULL_INPUT_POINTER 1 52 | 53 | // XXH_FORCE_NATIVE_FORMAT : 54 | // By default, xxHash library provides endian-independant Hash values, based on little-endian convention. 55 | // Results are therefore identical for little-endian and big-endian CPU. 56 | // This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. 57 | // Should endian-independance be of no importance for your application, you may set the #define below to 1. 58 | // It will improve speed for Big-endian CPU. 59 | // This option has no impact on Little_Endian CPU. 60 | #define XXH_FORCE_NATIVE_FORMAT 0 61 | 62 | //************************************** 63 | // Compiler Specific Options 64 | //************************************** 65 | // Disable some Visual warning messages 66 | #ifdef _MSC_VER // Visual Studio 67 | # pragma warning(disable : 4127) // disable: C4127: conditional expression is constant 68 | #endif 69 | 70 | #ifdef _MSC_VER // Visual Studio 71 | # define FORCE_INLINE static __forceinline 72 | #else 73 | # ifdef __GNUC__ 74 | # define FORCE_INLINE static inline __attribute__((always_inline)) 75 | # else 76 | # define FORCE_INLINE static inline 77 | # endif 78 | #endif 79 | 80 | //************************************** 81 | // Includes & Memory related functions 82 | //************************************** 83 | #include "xxhash.h" 84 | // Modify the local functions below should you wish to use some other memory routines 85 | // for malloc(), free() 86 | #include 87 | static void *XXH_malloc(size_t s) { return malloc(s); } 88 | static void XXH_free(void *p) { free(p); } 89 | // for memcpy() 90 | #include 91 | static void *XXH_memcpy(void *dest, const void *src, size_t size) 92 | { 93 | return memcpy(dest, src, size); 94 | } 95 | 96 | 97 | //************************************** 98 | // Basic Types 99 | //************************************** 100 | #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99 101 | # include 102 | typedef uint8_t BYTE; 103 | typedef uint16_t U16; 104 | typedef uint32_t U32; 105 | typedef int32_t S32; 106 | typedef uint64_t U64; 107 | #else 108 | typedef unsigned char BYTE; 109 | typedef unsigned short U16; 110 | typedef unsigned int U32; 111 | typedef signed int S32; 112 | typedef unsigned long long U64; 113 | #endif 114 | 115 | #if defined(__GNUC__) && !defined(XXH_USE_UNALIGNED_ACCESS) 116 | # define _PACKED __attribute__ ((packed)) 117 | #else 118 | # define _PACKED 119 | #endif 120 | 121 | #if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__) 122 | # ifdef __IBMC__ 123 | # pragma pack(1) 124 | # else 125 | # pragma pack(push, 1) 126 | # endif 127 | #endif 128 | 129 | typedef struct _U32_S 130 | { 131 | U32 v; 132 | } _PACKED U32_S; 133 | typedef struct _U64_S 134 | { 135 | U64 v; 136 | } _PACKED U64_S; 137 | 138 | #if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__) 139 | # pragma pack(pop) 140 | #endif 141 | 142 | #define A32(x) (((U32_S *)(x))->v) 143 | #define A64(x) (((U64_S *)(x))->v) 144 | 145 | 146 | //*************************************** 147 | // Compiler-specific Functions and Macros 148 | //*************************************** 149 | #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) 150 | 151 | // Note : although _rotl exists for minGW (GCC under windows), performance seems poor 152 | #if defined(_MSC_VER) 153 | # define XXH_rotl32(x,r) _rotl(x,r) 154 | # define XXH_rotl64(x,r) _rotl64(x,r) 155 | #else 156 | # define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) 157 | # define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) 158 | #endif 159 | 160 | #if defined(_MSC_VER) // Visual Studio 161 | # define XXH_swap32 _byteswap_ulong 162 | # define XXH_swap64 _byteswap_uint64 163 | #elif GCC_VERSION >= 403 164 | # define XXH_swap32 __builtin_bswap32 165 | # define XXH_swap64 __builtin_bswap64 166 | #else 167 | static inline U32 XXH_swap32(U32 x) 168 | { 169 | return ((x << 24) & 0xff000000) | 170 | ((x << 8) & 0x00ff0000) | 171 | ((x >> 8) & 0x0000ff00) | 172 | ((x >> 24) & 0x000000ff); 173 | } 174 | static inline U64 XXH_swap64(U64 x) 175 | { 176 | return ((x << 56) & 0xff00000000000000ULL) | 177 | ((x << 40) & 0x00ff000000000000ULL) | 178 | ((x << 24) & 0x0000ff0000000000ULL) | 179 | ((x << 8) & 0x000000ff00000000ULL) | 180 | ((x >> 8) & 0x00000000ff000000ULL) | 181 | ((x >> 24) & 0x0000000000ff0000ULL) | 182 | ((x >> 40) & 0x000000000000ff00ULL) | 183 | ((x >> 56) & 0x00000000000000ffULL); 184 | } 185 | #endif 186 | 187 | 188 | //************************************** 189 | // Constants 190 | //************************************** 191 | #define PRIME32_1 2654435761U 192 | #define PRIME32_2 2246822519U 193 | #define PRIME32_3 3266489917U 194 | #define PRIME32_4 668265263U 195 | #define PRIME32_5 374761393U 196 | 197 | #define PRIME64_1 11400714785074694791ULL 198 | #define PRIME64_2 14029467366897019727ULL 199 | #define PRIME64_3 1609587929392839161ULL 200 | #define PRIME64_4 9650029242287828579ULL 201 | #define PRIME64_5 2870177450012600261ULL 202 | 203 | //************************************** 204 | // Architecture Macros 205 | //************************************** 206 | typedef enum { XXH_bigEndian = 0, XXH_littleEndian = 1 } XXH_endianess; 207 | #ifndef XXH_CPU_LITTLE_ENDIAN // It is possible to define XXH_CPU_LITTLE_ENDIAN externally, for example using a compiler switch 208 | static const int one = 1; 209 | # define XXH_CPU_LITTLE_ENDIAN (*(char*)(&one)) 210 | #endif 211 | 212 | 213 | //************************************** 214 | // Macros 215 | //************************************** 216 | #define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(!!(c)) }; } // use only *after* variable declarations 217 | 218 | 219 | //**************************** 220 | // Memory reads 221 | //**************************** 222 | typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; 223 | 224 | FORCE_INLINE U32 XXH_readLE32_align(const void *ptr, XXH_endianess endian, 225 | XXH_alignment align) 226 | { 227 | if (align == XXH_unaligned) 228 | return endian == XXH_littleEndian ? A32(ptr) : XXH_swap32(A32(ptr)); 229 | else 230 | return endian == XXH_littleEndian ? *(U32 *)ptr : XXH_swap32(*(U32 *)ptr); 231 | } 232 | 233 | FORCE_INLINE U32 XXH_readLE32(const void *ptr, XXH_endianess endian) 234 | { 235 | return XXH_readLE32_align(ptr, endian, XXH_unaligned); 236 | } 237 | 238 | FORCE_INLINE U64 XXH_readLE64_align(const void *ptr, XXH_endianess endian, 239 | XXH_alignment align) 240 | { 241 | if (align == XXH_unaligned) 242 | return endian == XXH_littleEndian ? A64(ptr) : XXH_swap64(A64(ptr)); 243 | else 244 | return endian == XXH_littleEndian ? *(U64 *)ptr : XXH_swap64(*(U64 *)ptr); 245 | } 246 | 247 | FORCE_INLINE U64 XXH_readLE64(const void *ptr, XXH_endianess endian) 248 | { 249 | return XXH_readLE64_align(ptr, endian, XXH_unaligned); 250 | } 251 | 252 | 253 | //**************************** 254 | // Simple Hash Functions 255 | //**************************** 256 | FORCE_INLINE U32 XXH32_endian_align(const void *input, size_t len, 257 | U32 seed, XXH_endianess endian, XXH_alignment align) 258 | { 259 | const BYTE *p = (const BYTE *)input; 260 | const BYTE *bEnd = p + len; 261 | U32 h32; 262 | #define XXH_get32bits(p) XXH_readLE32_align(p, endian, align) 263 | 264 | #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 265 | if (p == NULL) 266 | { 267 | len = 0; 268 | bEnd = p = (const BYTE *)(size_t)16; 269 | } 270 | #endif 271 | 272 | if (len >= 16) 273 | { 274 | const BYTE *const limit = bEnd - 16; 275 | U32 v1 = seed + PRIME32_1 + PRIME32_2; 276 | U32 v2 = seed + PRIME32_2; 277 | U32 v3 = seed + 0; 278 | U32 v4 = seed - PRIME32_1; 279 | 280 | do 281 | { 282 | v1 += XXH_get32bits(p) * PRIME32_2; 283 | v1 = XXH_rotl32(v1, 13); 284 | v1 *= PRIME32_1; 285 | p += 4; 286 | v2 += XXH_get32bits(p) * PRIME32_2; 287 | v2 = XXH_rotl32(v2, 13); 288 | v2 *= PRIME32_1; 289 | p += 4; 290 | v3 += XXH_get32bits(p) * PRIME32_2; 291 | v3 = XXH_rotl32(v3, 13); 292 | v3 *= PRIME32_1; 293 | p += 4; 294 | v4 += XXH_get32bits(p) * PRIME32_2; 295 | v4 = XXH_rotl32(v4, 13); 296 | v4 *= PRIME32_1; 297 | p += 4; 298 | } 299 | while (p <= limit); 300 | 301 | h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 302 | 12) + XXH_rotl32(v4, 18); 303 | } 304 | else 305 | h32 = seed + PRIME32_5; 306 | 307 | h32 += (U32) len; 308 | 309 | while (p + 4 <= bEnd) 310 | { 311 | h32 += XXH_get32bits(p) * PRIME32_3; 312 | h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; 313 | p += 4; 314 | } 315 | 316 | while (p < bEnd) 317 | { 318 | h32 += (*p) * PRIME32_5; 319 | h32 = XXH_rotl32(h32, 11) * PRIME32_1 ; 320 | p++; 321 | } 322 | 323 | h32 ^= h32 >> 15; 324 | h32 *= PRIME32_2; 325 | h32 ^= h32 >> 13; 326 | h32 *= PRIME32_3; 327 | h32 ^= h32 >> 16; 328 | 329 | return h32; 330 | } 331 | 332 | 333 | unsigned int XXH32(const void *input, size_t len, unsigned seed) 334 | { 335 | #if 0 336 | // Simple version, good for code maintenance, but unfortunately slow for small inputs 337 | XXH32_state_t state; 338 | XXH32_reset(&state, seed); 339 | XXH32_update(&state, input, len); 340 | return XXH32_digest(&state); 341 | #else 342 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 343 | 344 | # if !defined(XXH_USE_UNALIGNED_ACCESS) 345 | if ((((size_t)input) & 3) == 346 | 0) // Input is aligned, let's leverage the speed advantage 347 | { 348 | if ((endian_detected == XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 349 | return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); 350 | else 351 | return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); 352 | } 353 | # endif 354 | 355 | if ((endian_detected == XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 356 | return XXH32_endian_align(input, len, seed, XXH_littleEndian, 357 | XXH_unaligned); 358 | else 359 | return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); 360 | #endif 361 | } 362 | 363 | FORCE_INLINE U64 XXH64_endian_align(const void *input, size_t len, 364 | U64 seed, XXH_endianess endian, XXH_alignment align) 365 | { 366 | const BYTE *p = (const BYTE *)input; 367 | const BYTE *bEnd = p + len; 368 | U64 h64; 369 | #define XXH_get64bits(p) XXH_readLE64_align(p, endian, align) 370 | 371 | #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 372 | if (p == NULL) 373 | { 374 | len = 0; 375 | bEnd = p = (const BYTE *)(size_t)32; 376 | } 377 | #endif 378 | 379 | if (len >= 32) 380 | { 381 | const BYTE *const limit = bEnd - 32; 382 | U64 v1 = seed + PRIME64_1 + PRIME64_2; 383 | U64 v2 = seed + PRIME64_2; 384 | U64 v3 = seed + 0; 385 | U64 v4 = seed - PRIME64_1; 386 | 387 | do 388 | { 389 | v1 += XXH_get64bits(p) * PRIME64_2; 390 | p += 8; 391 | v1 = XXH_rotl64(v1, 31); 392 | v1 *= PRIME64_1; 393 | v2 += XXH_get64bits(p) * PRIME64_2; 394 | p += 8; 395 | v2 = XXH_rotl64(v2, 31); 396 | v2 *= PRIME64_1; 397 | v3 += XXH_get64bits(p) * PRIME64_2; 398 | p += 8; 399 | v3 = XXH_rotl64(v3, 31); 400 | v3 *= PRIME64_1; 401 | v4 += XXH_get64bits(p) * PRIME64_2; 402 | p += 8; 403 | v4 = XXH_rotl64(v4, 31); 404 | v4 *= PRIME64_1; 405 | } 406 | while (p <= limit); 407 | 408 | h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 409 | 12) + XXH_rotl64(v4, 18); 410 | 411 | v1 *= PRIME64_2; 412 | v1 = XXH_rotl64(v1, 31); 413 | v1 *= PRIME64_1; 414 | h64 ^= v1; 415 | h64 = h64 * PRIME64_1 + PRIME64_4; 416 | 417 | v2 *= PRIME64_2; 418 | v2 = XXH_rotl64(v2, 31); 419 | v2 *= PRIME64_1; 420 | h64 ^= v2; 421 | h64 = h64 * PRIME64_1 + PRIME64_4; 422 | 423 | v3 *= PRIME64_2; 424 | v3 = XXH_rotl64(v3, 31); 425 | v3 *= PRIME64_1; 426 | h64 ^= v3; 427 | h64 = h64 * PRIME64_1 + PRIME64_4; 428 | 429 | v4 *= PRIME64_2; 430 | v4 = XXH_rotl64(v4, 31); 431 | v4 *= PRIME64_1; 432 | h64 ^= v4; 433 | h64 = h64 * PRIME64_1 + PRIME64_4; 434 | } 435 | else 436 | h64 = seed + PRIME64_5; 437 | 438 | h64 += (U64) len; 439 | 440 | while (p + 8 <= bEnd) 441 | { 442 | U64 k1 = XXH_get64bits(p); 443 | k1 *= PRIME64_2; 444 | k1 = XXH_rotl64(k1, 31); 445 | k1 *= PRIME64_1; 446 | h64 ^= k1; 447 | h64 = XXH_rotl64(h64, 27) * PRIME64_1 + PRIME64_4; 448 | p += 8; 449 | } 450 | 451 | if (p + 4 <= bEnd) 452 | { 453 | h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; 454 | h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; 455 | p += 4; 456 | } 457 | 458 | while (p < bEnd) 459 | { 460 | h64 ^= (*p) * PRIME64_5; 461 | h64 = XXH_rotl64(h64, 11) * PRIME64_1; 462 | p++; 463 | } 464 | 465 | h64 ^= h64 >> 33; 466 | h64 *= PRIME64_2; 467 | h64 ^= h64 >> 29; 468 | h64 *= PRIME64_3; 469 | h64 ^= h64 >> 32; 470 | 471 | return h64; 472 | } 473 | 474 | 475 | unsigned long long XXH64(const void *input, size_t len, 476 | unsigned long long seed) 477 | { 478 | #if 0 479 | // Simple version, good for code maintenance, but unfortunately slow for small inputs 480 | XXH64_state_t state; 481 | XXH64_reset(&state, seed); 482 | XXH64_update(&state, input, len); 483 | return XXH64_digest(&state); 484 | #else 485 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 486 | 487 | # if !defined(XXH_USE_UNALIGNED_ACCESS) 488 | if ((((size_t)input) & 7) == 489 | 0) // Input is aligned, let's leverage the speed advantage 490 | { 491 | if ((endian_detected == XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 492 | return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); 493 | else 494 | return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); 495 | } 496 | # endif 497 | 498 | if ((endian_detected == XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 499 | return XXH64_endian_align(input, len, seed, XXH_littleEndian, 500 | XXH_unaligned); 501 | else 502 | return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); 503 | #endif 504 | } 505 | 506 | /**************************************************** 507 | * Advanced Hash Functions 508 | ****************************************************/ 509 | 510 | /*** Allocation ***/ 511 | typedef struct 512 | { 513 | U64 total_len; 514 | U32 seed; 515 | U32 v1; 516 | U32 v2; 517 | U32 v3; 518 | U32 v4; 519 | U32 mem32[4]; /* defined as U32 for alignment */ 520 | U32 memsize; 521 | } XXH_istate32_t; 522 | 523 | typedef struct 524 | { 525 | U64 total_len; 526 | U64 seed; 527 | U64 v1; 528 | U64 v2; 529 | U64 v3; 530 | U64 v4; 531 | U64 mem64[4]; /* defined as U64 for alignment */ 532 | U32 memsize; 533 | } XXH_istate64_t; 534 | 535 | 536 | XXH32_state_t *XXH32_createState(void) 537 | { 538 | XXH_STATIC_ASSERT(sizeof(XXH32_state_t) >= sizeof( 539 | XXH_istate32_t)); // A compilation error here means XXH32_state_t is not large enough 540 | return (XXH32_state_t *)XXH_malloc(sizeof(XXH32_state_t)); 541 | } 542 | XXH_errorcode XXH32_freeState(XXH32_state_t *statePtr) 543 | { 544 | XXH_free(statePtr); 545 | return XXH_OK; 546 | }; 547 | 548 | XXH64_state_t *XXH64_createState(void) 549 | { 550 | XXH_STATIC_ASSERT(sizeof(XXH64_state_t) >= sizeof( 551 | XXH_istate64_t)); // A compilation error here means XXH64_state_t is not large enough 552 | return (XXH64_state_t *)XXH_malloc(sizeof(XXH64_state_t)); 553 | } 554 | XXH_errorcode XXH64_freeState(XXH64_state_t *statePtr) 555 | { 556 | XXH_free(statePtr); 557 | return XXH_OK; 558 | }; 559 | 560 | 561 | /*** Hash feed ***/ 562 | 563 | XXH_errorcode XXH32_reset(XXH32_state_t *state_in, U32 seed) 564 | { 565 | XXH_istate32_t *state = (XXH_istate32_t *) state_in; 566 | state->seed = seed; 567 | state->v1 = seed + PRIME32_1 + PRIME32_2; 568 | state->v2 = seed + PRIME32_2; 569 | state->v3 = seed + 0; 570 | state->v4 = seed - PRIME32_1; 571 | state->total_len = 0; 572 | state->memsize = 0; 573 | return XXH_OK; 574 | } 575 | 576 | XXH_errorcode XXH64_reset(XXH64_state_t *state_in, unsigned long long seed) 577 | { 578 | XXH_istate64_t *state = (XXH_istate64_t *) state_in; 579 | state->seed = seed; 580 | state->v1 = seed + PRIME64_1 + PRIME64_2; 581 | state->v2 = seed + PRIME64_2; 582 | state->v3 = seed + 0; 583 | state->v4 = seed - PRIME64_1; 584 | state->total_len = 0; 585 | state->memsize = 0; 586 | return XXH_OK; 587 | } 588 | 589 | 590 | FORCE_INLINE XXH_errorcode XXH32_update_endian(XXH32_state_t *state_in, 591 | const void *input, size_t len, XXH_endianess endian) 592 | { 593 | XXH_istate32_t *state = (XXH_istate32_t *) state_in; 594 | const BYTE *p = (const BYTE *)input; 595 | const BYTE *const bEnd = p + len; 596 | 597 | #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 598 | if (input == NULL) return XXH_ERROR; 599 | #endif 600 | 601 | state->total_len += len; 602 | 603 | if (state->memsize + len < 16) // fill in tmp buffer 604 | { 605 | XXH_memcpy((BYTE *)(state->mem32) + state->memsize, input, len); 606 | state->memsize += (U32)len; 607 | return XXH_OK; 608 | } 609 | 610 | if (state->memsize) // some data left from previous update 611 | { 612 | XXH_memcpy((BYTE *)(state->mem32) + state->memsize, input, 613 | 16 - state->memsize); 614 | { 615 | const U32 *p32 = state->mem32; 616 | state->v1 += XXH_readLE32(p32, endian) * PRIME32_2; 617 | state->v1 = XXH_rotl32(state->v1, 13); 618 | state->v1 *= PRIME32_1; 619 | p32++; 620 | state->v2 += XXH_readLE32(p32, endian) * PRIME32_2; 621 | state->v2 = XXH_rotl32(state->v2, 13); 622 | state->v2 *= PRIME32_1; 623 | p32++; 624 | state->v3 += XXH_readLE32(p32, endian) * PRIME32_2; 625 | state->v3 = XXH_rotl32(state->v3, 13); 626 | state->v3 *= PRIME32_1; 627 | p32++; 628 | state->v4 += XXH_readLE32(p32, endian) * PRIME32_2; 629 | state->v4 = XXH_rotl32(state->v4, 13); 630 | state->v4 *= PRIME32_1; 631 | p32++; 632 | } 633 | p += 16 - state->memsize; 634 | state->memsize = 0; 635 | } 636 | 637 | if (p <= bEnd - 16) 638 | { 639 | const BYTE *const limit = bEnd - 16; 640 | U32 v1 = state->v1; 641 | U32 v2 = state->v2; 642 | U32 v3 = state->v3; 643 | U32 v4 = state->v4; 644 | 645 | do 646 | { 647 | v1 += XXH_readLE32(p, endian) * PRIME32_2; 648 | v1 = XXH_rotl32(v1, 13); 649 | v1 *= PRIME32_1; 650 | p += 4; 651 | v2 += XXH_readLE32(p, endian) * PRIME32_2; 652 | v2 = XXH_rotl32(v2, 13); 653 | v2 *= PRIME32_1; 654 | p += 4; 655 | v3 += XXH_readLE32(p, endian) * PRIME32_2; 656 | v3 = XXH_rotl32(v3, 13); 657 | v3 *= PRIME32_1; 658 | p += 4; 659 | v4 += XXH_readLE32(p, endian) * PRIME32_2; 660 | v4 = XXH_rotl32(v4, 13); 661 | v4 *= PRIME32_1; 662 | p += 4; 663 | } 664 | while (p <= limit); 665 | 666 | state->v1 = v1; 667 | state->v2 = v2; 668 | state->v3 = v3; 669 | state->v4 = v4; 670 | } 671 | 672 | if (p < bEnd) 673 | { 674 | XXH_memcpy(state->mem32, p, bEnd - p); 675 | state->memsize = (int)(bEnd - p); 676 | } 677 | 678 | return XXH_OK; 679 | } 680 | 681 | XXH_errorcode XXH32_update(XXH32_state_t *state_in, const void *input, 682 | size_t len) 683 | { 684 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 685 | 686 | if ((endian_detected == XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 687 | return XXH32_update_endian(state_in, input, len, XXH_littleEndian); 688 | else 689 | return XXH32_update_endian(state_in, input, len, XXH_bigEndian); 690 | } 691 | 692 | 693 | 694 | FORCE_INLINE U32 XXH32_digest_endian(const XXH32_state_t *state_in, 695 | XXH_endianess endian) 696 | { 697 | XXH_istate32_t *state = (XXH_istate32_t *) state_in; 698 | const BYTE *p = (const BYTE *)state->mem32; 699 | BYTE *bEnd = (BYTE *)(state->mem32) + state->memsize; 700 | U32 h32; 701 | 702 | if (state->total_len >= 16) 703 | h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 704 | 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18); 705 | else 706 | h32 = state->seed + PRIME32_5; 707 | 708 | h32 += (U32) state->total_len; 709 | 710 | while (p + 4 <= bEnd) 711 | { 712 | h32 += XXH_readLE32(p, endian) * PRIME32_3; 713 | h32 = XXH_rotl32(h32, 17) * PRIME32_4; 714 | p += 4; 715 | } 716 | 717 | while (p < bEnd) 718 | { 719 | h32 += (*p) * PRIME32_5; 720 | h32 = XXH_rotl32(h32, 11) * PRIME32_1; 721 | p++; 722 | } 723 | 724 | h32 ^= h32 >> 15; 725 | h32 *= PRIME32_2; 726 | h32 ^= h32 >> 13; 727 | h32 *= PRIME32_3; 728 | h32 ^= h32 >> 16; 729 | 730 | return h32; 731 | } 732 | 733 | 734 | U32 XXH32_digest(const XXH32_state_t *state_in) 735 | { 736 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 737 | 738 | if ((endian_detected == XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 739 | return XXH32_digest_endian(state_in, XXH_littleEndian); 740 | else 741 | return XXH32_digest_endian(state_in, XXH_bigEndian); 742 | } 743 | 744 | 745 | FORCE_INLINE XXH_errorcode XXH64_update_endian(XXH64_state_t *state_in, 746 | const void *input, size_t len, XXH_endianess endian) 747 | { 748 | XXH_istate64_t *state = (XXH_istate64_t *) state_in; 749 | const BYTE *p = (const BYTE *)input; 750 | const BYTE *const bEnd = p + len; 751 | 752 | #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 753 | if (input == NULL) return XXH_ERROR; 754 | #endif 755 | 756 | state->total_len += len; 757 | 758 | if (state->memsize + len < 32) // fill in tmp buffer 759 | { 760 | XXH_memcpy(((BYTE *)state->mem64) + state->memsize, input, len); 761 | state->memsize += (U32)len; 762 | return XXH_OK; 763 | } 764 | 765 | if (state->memsize) // some data left from previous update 766 | { 767 | XXH_memcpy(((BYTE *)state->mem64) + state->memsize, input, 768 | 32 - state->memsize); 769 | { 770 | const U64 *p64 = state->mem64; 771 | state->v1 += XXH_readLE64(p64, endian) * PRIME64_2; 772 | state->v1 = XXH_rotl64(state->v1, 31); 773 | state->v1 *= PRIME64_1; 774 | p64++; 775 | state->v2 += XXH_readLE64(p64, endian) * PRIME64_2; 776 | state->v2 = XXH_rotl64(state->v2, 31); 777 | state->v2 *= PRIME64_1; 778 | p64++; 779 | state->v3 += XXH_readLE64(p64, endian) * PRIME64_2; 780 | state->v3 = XXH_rotl64(state->v3, 31); 781 | state->v3 *= PRIME64_1; 782 | p64++; 783 | state->v4 += XXH_readLE64(p64, endian) * PRIME64_2; 784 | state->v4 = XXH_rotl64(state->v4, 31); 785 | state->v4 *= PRIME64_1; 786 | p64++; 787 | } 788 | p += 32 - state->memsize; 789 | state->memsize = 0; 790 | } 791 | 792 | if (p + 32 <= bEnd) 793 | { 794 | const BYTE *const limit = bEnd - 32; 795 | U64 v1 = state->v1; 796 | U64 v2 = state->v2; 797 | U64 v3 = state->v3; 798 | U64 v4 = state->v4; 799 | 800 | do 801 | { 802 | v1 += XXH_readLE64(p, endian) * PRIME64_2; 803 | v1 = XXH_rotl64(v1, 31); 804 | v1 *= PRIME64_1; 805 | p += 8; 806 | v2 += XXH_readLE64(p, endian) * PRIME64_2; 807 | v2 = XXH_rotl64(v2, 31); 808 | v2 *= PRIME64_1; 809 | p += 8; 810 | v3 += XXH_readLE64(p, endian) * PRIME64_2; 811 | v3 = XXH_rotl64(v3, 31); 812 | v3 *= PRIME64_1; 813 | p += 8; 814 | v4 += XXH_readLE64(p, endian) * PRIME64_2; 815 | v4 = XXH_rotl64(v4, 31); 816 | v4 *= PRIME64_1; 817 | p += 8; 818 | } 819 | while (p <= limit); 820 | 821 | state->v1 = v1; 822 | state->v2 = v2; 823 | state->v3 = v3; 824 | state->v4 = v4; 825 | } 826 | 827 | if (p < bEnd) 828 | { 829 | XXH_memcpy(state->mem64, p, bEnd - p); 830 | state->memsize = (int)(bEnd - p); 831 | } 832 | 833 | return XXH_OK; 834 | } 835 | 836 | XXH_errorcode XXH64_update(XXH64_state_t *state_in, const void *input, 837 | size_t len) 838 | { 839 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 840 | 841 | if ((endian_detected == XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 842 | return XXH64_update_endian(state_in, input, len, XXH_littleEndian); 843 | else 844 | return XXH64_update_endian(state_in, input, len, XXH_bigEndian); 845 | } 846 | 847 | 848 | 849 | FORCE_INLINE U64 XXH64_digest_endian(const XXH64_state_t *state_in, 850 | XXH_endianess endian) 851 | { 852 | XXH_istate64_t *state = (XXH_istate64_t *) state_in; 853 | const BYTE *p = (const BYTE *)state->mem64; 854 | BYTE *bEnd = (BYTE *)state->mem64 + state->memsize; 855 | U64 h64; 856 | 857 | if (state->total_len >= 32) 858 | { 859 | U64 v1 = state->v1; 860 | U64 v2 = state->v2; 861 | U64 v3 = state->v3; 862 | U64 v4 = state->v4; 863 | 864 | h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 865 | 12) + XXH_rotl64(v4, 18); 866 | 867 | v1 *= PRIME64_2; 868 | v1 = XXH_rotl64(v1, 31); 869 | v1 *= PRIME64_1; 870 | h64 ^= v1; 871 | h64 = h64 * PRIME64_1 + PRIME64_4; 872 | 873 | v2 *= PRIME64_2; 874 | v2 = XXH_rotl64(v2, 31); 875 | v2 *= PRIME64_1; 876 | h64 ^= v2; 877 | h64 = h64 * PRIME64_1 + PRIME64_4; 878 | 879 | v3 *= PRIME64_2; 880 | v3 = XXH_rotl64(v3, 31); 881 | v3 *= PRIME64_1; 882 | h64 ^= v3; 883 | h64 = h64 * PRIME64_1 + PRIME64_4; 884 | 885 | v4 *= PRIME64_2; 886 | v4 = XXH_rotl64(v4, 31); 887 | v4 *= PRIME64_1; 888 | h64 ^= v4; 889 | h64 = h64 * PRIME64_1 + PRIME64_4; 890 | } 891 | else 892 | h64 = state->seed + PRIME64_5; 893 | 894 | h64 += (U64) state->total_len; 895 | 896 | while (p + 8 <= bEnd) 897 | { 898 | U64 k1 = XXH_readLE64(p, endian); 899 | k1 *= PRIME64_2; 900 | k1 = XXH_rotl64(k1, 31); 901 | k1 *= PRIME64_1; 902 | h64 ^= k1; 903 | h64 = XXH_rotl64(h64, 27) * PRIME64_1 + PRIME64_4; 904 | p += 8; 905 | } 906 | 907 | if (p + 4 <= bEnd) 908 | { 909 | h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1; 910 | h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; 911 | p += 4; 912 | } 913 | 914 | while (p < bEnd) 915 | { 916 | h64 ^= (*p) * PRIME64_5; 917 | h64 = XXH_rotl64(h64, 11) * PRIME64_1; 918 | p++; 919 | } 920 | 921 | h64 ^= h64 >> 33; 922 | h64 *= PRIME64_2; 923 | h64 ^= h64 >> 29; 924 | h64 *= PRIME64_3; 925 | h64 ^= h64 >> 32; 926 | 927 | return h64; 928 | } 929 | 930 | 931 | unsigned long long XXH64_digest(const XXH64_state_t *state_in) 932 | { 933 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 934 | 935 | if ((endian_detected == XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 936 | return XXH64_digest_endian(state_in, XXH_littleEndian); 937 | else 938 | return XXH64_digest_endian(state_in, XXH_bigEndian); 939 | } 940 | 941 | 942 | -------------------------------------------------------------------------------- /deps/xxhash/xxhash.h: -------------------------------------------------------------------------------- 1 | /* 2 | xxHash - Extremely Fast Hash algorithm 3 | Header File 4 | Copyright (C) 2012-2014, Yann Collet. 5 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following disclaimer 15 | in the documentation and/or other materials provided with the 16 | distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | You can contact the author at : 31 | - xxHash source repository : http://code.google.com/p/xxhash/ 32 | */ 33 | 34 | /* Notice extracted from xxHash homepage : 35 | 36 | xxHash is an extremely fast Hash algorithm, running at RAM speed limits. 37 | It also successfully passes all tests from the SMHasher suite. 38 | 39 | Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) 40 | 41 | Name Speed Q.Score Author 42 | xxHash 5.4 GB/s 10 43 | CrapWow 3.2 GB/s 2 Andrew 44 | MumurHash 3a 2.7 GB/s 10 Austin Appleby 45 | SpookyHash 2.0 GB/s 10 Bob Jenkins 46 | SBox 1.4 GB/s 9 Bret Mulvey 47 | Lookup3 1.2 GB/s 9 Bob Jenkins 48 | SuperFastHash 1.2 GB/s 1 Paul Hsieh 49 | CityHash64 1.05 GB/s 10 Pike & Alakuijala 50 | FNV 0.55 GB/s 5 Fowler, Noll, Vo 51 | CRC32 0.43 GB/s 9 52 | MD5-32 0.33 GB/s 10 Ronald L. Rivest 53 | SHA1-32 0.28 GB/s 10 54 | 55 | Q.Score is a measure of quality of the hash function. 56 | It depends on successfully passing SMHasher test set. 57 | 10 is a perfect score. 58 | */ 59 | 60 | #pragma once 61 | 62 | #if defined (__cplusplus) 63 | extern "C" { 64 | #endif 65 | 66 | 67 | /***************************** 68 | Includes 69 | *****************************/ 70 | #include /* size_t */ 71 | 72 | 73 | /***************************** 74 | Type 75 | *****************************/ 76 | typedef enum { XXH_OK = 0, XXH_ERROR } XXH_errorcode; 77 | 78 | 79 | 80 | /***************************** 81 | Simple Hash Functions 82 | *****************************/ 83 | 84 | unsigned int XXH32(const void *input, size_t length, unsigned seed); 85 | unsigned long long XXH64(const void *input, size_t length, 86 | unsigned long long seed); 87 | 88 | /* 89 | XXH32() : 90 | Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input". 91 | The memory between input & input+length must be valid (allocated and read-accessible). 92 | "seed" can be used to alter the result predictably. 93 | This function successfully passes all SMHasher tests. 94 | Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s 95 | XXH64() : 96 | Calculate the 64-bits hash of sequence of length "len" stored at memory address "input". 97 | */ 98 | 99 | 100 | 101 | /***************************** 102 | Advanced Hash Functions 103 | *****************************/ 104 | typedef struct { long long ll[ 6]; } XXH32_state_t; 105 | typedef struct { long long ll[11]; } XXH64_state_t; 106 | 107 | /* 108 | These structures allow static allocation of XXH states. 109 | States must then be initialized using XXHnn_reset() before first use. 110 | 111 | If you prefer dynamic allocation, please refer to functions below. 112 | */ 113 | 114 | XXH32_state_t *XXH32_createState(void); 115 | XXH_errorcode XXH32_freeState(XXH32_state_t *statePtr); 116 | 117 | XXH64_state_t *XXH64_createState(void); 118 | XXH_errorcode XXH64_freeState(XXH64_state_t *statePtr); 119 | 120 | /* 121 | These functions create and release memory for XXH state. 122 | States must then be initialized using XXHnn_reset() before first use. 123 | */ 124 | 125 | 126 | XXH_errorcode XXH32_reset(XXH32_state_t *statePtr, unsigned seed); 127 | XXH_errorcode XXH32_update(XXH32_state_t *statePtr, const void *input, 128 | size_t length); 129 | unsigned int XXH32_digest(const XXH32_state_t *statePtr); 130 | 131 | XXH_errorcode XXH64_reset(XXH64_state_t *statePtr, 132 | unsigned long long seed); 133 | XXH_errorcode XXH64_update(XXH64_state_t *statePtr, const void *input, 134 | size_t length); 135 | unsigned long long XXH64_digest(const XXH64_state_t *statePtr); 136 | 137 | /* 138 | These functions calculate the xxHash of an input provided in multiple smaller packets, 139 | as opposed to an input provided as a single block. 140 | 141 | XXH state space must first be allocated, using either static or dynamic method provided above. 142 | 143 | Start a new hash by initializing state with a seed, using XXHnn_reset(). 144 | 145 | Then, feed the hash state by calling XXHnn_update() as many times as necessary. 146 | Obviously, input must be valid, meaning allocated and read accessible. 147 | The function returns an error code, with 0 meaning OK, and any other value meaning there is an error. 148 | 149 | Finally, you can produce a hash anytime, by using XXHnn_digest(). 150 | This function returns the final nn-bits hash. 151 | You can nonetheless continue feeding the hash state with more input, 152 | and therefore get some new hashes, by calling again XXHnn_digest(). 153 | 154 | When you are done, don't forget to free XXH state space, using typically XXHnn_freeState(). 155 | */ 156 | 157 | 158 | #if defined (__cplusplus) 159 | } 160 | #endif 161 | -------------------------------------------------------------------------------- /lshpack.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2018 - 2023 LiteSpeed Technologies Inc 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "lshpack.h" 33 | #if LS_HPACK_EMIT_TEST_CODE 34 | #include "lshpack-test.h" 35 | #endif 36 | #include XXH_HEADER_NAME 37 | 38 | #ifdef _MSC_VER 39 | # define FALL_THROUGH 40 | #endif 41 | 42 | #ifndef FALL_THROUGH 43 | # if defined __has_attribute && __has_attribute (fallthrough) 44 | # define FALL_THROUGH __attribute__ ((fallthrough)) 45 | # else 46 | # define FALL_THROUGH 47 | # endif 48 | #endif 49 | 50 | #ifndef LS_HPACK_USE_LARGE_TABLES 51 | #define LS_HPACK_USE_LARGE_TABLES 1 52 | #endif 53 | 54 | #include "huff-tables.h" 55 | 56 | #define HPACK_STATIC_TABLE_SIZE 61 57 | #define INITIAL_DYNAMIC_TABLE_SIZE 4096 58 | 59 | /* RFC 7541, Section 4.1: 60 | * 61 | * " The size of the dynamic table is the sum of the size of its entries. 62 | * " 63 | * " The size of an entry is the sum of its name's length in octets (as 64 | * " defined in Section 5.2), its value's length in octets, and 32. 65 | */ 66 | #define DYNAMIC_ENTRY_OVERHEAD 32 67 | 68 | #define NAME_VAL(a, b) sizeof(a) - 1, sizeof(b) - 1, (a), (b) 69 | 70 | static const struct 71 | { 72 | unsigned name_len; 73 | unsigned val_len; 74 | const char *name; 75 | const char *val; 76 | } 77 | static_table[HPACK_STATIC_TABLE_SIZE] = 78 | { 79 | { NAME_VAL(":authority", "") }, 80 | { NAME_VAL(":method", "GET") }, 81 | { NAME_VAL(":method", "POST") }, 82 | { NAME_VAL(":path", "/") }, 83 | { NAME_VAL(":path", "/index.html") }, 84 | { NAME_VAL(":scheme", "http") }, 85 | { NAME_VAL(":scheme", "https") }, 86 | { NAME_VAL(":status", "200") }, 87 | { NAME_VAL(":status", "204") }, 88 | { NAME_VAL(":status", "206") }, 89 | { NAME_VAL(":status", "304") }, 90 | { NAME_VAL(":status", "400") }, 91 | { NAME_VAL(":status", "404") }, 92 | { NAME_VAL(":status", "500") }, 93 | { NAME_VAL("accept-charset", "") }, 94 | { NAME_VAL("accept-encoding", "gzip, deflate") }, 95 | { NAME_VAL("accept-language", "") }, 96 | { NAME_VAL("accept-ranges", "") }, 97 | { NAME_VAL("accept", "") }, 98 | { NAME_VAL("access-control-allow-origin", "") }, 99 | { NAME_VAL("age", "") }, 100 | { NAME_VAL("allow", "") }, 101 | { NAME_VAL("authorization", "") }, 102 | { NAME_VAL("cache-control", "") }, 103 | { NAME_VAL("content-disposition", "") }, 104 | { NAME_VAL("content-encoding", "") }, 105 | { NAME_VAL("content-language", "") }, 106 | { NAME_VAL("content-length", "") }, 107 | { NAME_VAL("content-location", "") }, 108 | { NAME_VAL("content-range", "") }, 109 | { NAME_VAL("content-type", "") }, 110 | { NAME_VAL("cookie", "") }, 111 | { NAME_VAL("date", "") }, 112 | { NAME_VAL("etag", "") }, 113 | { NAME_VAL("expect", "") }, 114 | { NAME_VAL("expires", "") }, 115 | { NAME_VAL("from", "") }, 116 | { NAME_VAL("host", "") }, 117 | { NAME_VAL("if-match", "") }, 118 | { NAME_VAL("if-modified-since", "") }, 119 | { NAME_VAL("if-none-match", "") }, 120 | { NAME_VAL("if-range", "") }, 121 | { NAME_VAL("if-unmodified-since", "") }, 122 | { NAME_VAL("last-modified", "") }, 123 | { NAME_VAL("link", "") }, 124 | { NAME_VAL("location", "") }, 125 | { NAME_VAL("max-forwards", "") }, 126 | { NAME_VAL("proxy-authenticate", "") }, 127 | { NAME_VAL("proxy-authorization", "") }, 128 | { NAME_VAL("range", "") }, 129 | { NAME_VAL("referer", "") }, 130 | { NAME_VAL("refresh", "") }, 131 | { NAME_VAL("retry-after", "") }, 132 | { NAME_VAL("server", "") }, 133 | { NAME_VAL("set-cookie", "") }, 134 | { NAME_VAL("strict-transport-security", "") }, 135 | { NAME_VAL("transfer-encoding", "") }, 136 | { NAME_VAL("user-agent", "") }, 137 | { NAME_VAL("vary", "") }, 138 | { NAME_VAL("via", "") }, 139 | { NAME_VAL("www-authenticate", "") } 140 | }; 141 | 142 | 143 | static const uint32_t static_table_name_hash[HPACK_STATIC_TABLE_SIZE] = 144 | { 145 | 0x653A915Bu, 0xC7742BE4u, 0xC7742BE4u, 0x3513518Du, 0x3513518Du, 146 | 0xF49F1451u, 0xF49F1451u, 0x672BDA53u, 0x672BDA53u, 0x672BDA53u, 147 | 0x672BDA53u, 0x672BDA53u, 0x672BDA53u, 0x672BDA53u, 0xCD2C0296u, 148 | 0xF93AD8A9u, 0x98BD32D3u, 0x1DC691C8u, 0x1AB214F8u, 0x7D3B7A3Bu, 149 | 0xBEC8E440u, 0xE9C1D9E1u, 0x19D88141u, 0xC25511F2u, 0x16020A90u, 150 | 0x48011191u, 0x7D9AAB7Eu, 0x48F5CC19u, 0x8847A08Cu, 0x0D19F766u, 151 | 0x085EF7C5u, 0x0B486ED8u, 0x1A7AA369u, 0x6DE855BAu, 0xA6006EFDu, 152 | 0xA1BB4284u, 0xAE56E25Fu, 0xB6787110u, 0x791C6A0Du, 0xF2BADABEu, 153 | 0xD8CA2594u, 0xFBA64C54u, 0x4BEB0951u, 0x6B86C0B5u, 0xC62FECD2u, 154 | 0x8DA64A26u, 0x6CA35045u, 0xF614D165u, 0xE4D1DF14u, 0xB396750Au, 155 | 0x01F10233u, 0x798BEE18u, 0x5239F142u, 0x82E1B4E1u, 0x8F7E493Eu, 156 | 0x85E74C58u, 0xBD17F160u, 0x34C0456Au, 0x1A04DF3Du, 0xB1B15AB2u, 157 | 0xDDDAB6FFu, 158 | }; 159 | 160 | 161 | static const uint32_t static_table_nameval_hash[HPACK_STATIC_TABLE_SIZE] = 162 | { 163 | 0xF8614896u, 0x25D95A15u, 0x33968BB7u, 0xC8C267F6u, 0x8351136Fu, 164 | 0x98573F68u, 0x16DDE443u, 0x352A6556u, 0xD4F462D2u, 0x125E66E0u, 165 | 0xD7988BC9u, 0x4C3C90DEu, 0x65E6ECA1u, 0xB05B7B87u, 0x96816317u, 166 | 0x8BBF5398u, 0x97E01849u, 0xD7B48DD4u, 0x9C180569u, 0xC7C63B45u, 167 | 0xF4223EE5u, 0x12C8A744u, 0xAA95A0BCu, 0x14F65730u, 0x8410A906u, 168 | 0x98F440DDu, 0x627E4803u, 0x5A5CC325u, 0x137FC223u, 0x1529262Fu, 169 | 0x7950B9BDu, 0x51D448A4u, 0x52C167CFu, 0xFB22AA54u, 0x540DB9FEu, 170 | 0x75A6C685u, 0xE1C54196u, 0xDC0C3733u, 0x6D78CB84u, 0x4F5272CDu, 171 | 0x9D4170E4u, 0xD4E28BA1u, 0x028C7846u, 0x4E8C1DC3u, 0x684BDDBCu, 172 | 0xE113A2B0u, 0x55F7BBD1u, 0x15BD3710u, 0xE82B715Du, 0x3674BC1Fu, 173 | 0x5010D24Bu, 0x953DE1CBu, 0x9F2C92D9u, 0xB2DE5570u, 0xBCA5998Fu, 174 | 0x0FF5B88Eu, 0x1FED156Bu, 0xDC83E7ECu, 0x07B79E35u, 0xA6D145A9u, 175 | 0x43638CBAu, 176 | }; 177 | 178 | 179 | #define lshpack_arr_init(a) do { \ 180 | memset((a), 0, sizeof(*(a))); \ 181 | } while (0) 182 | 183 | #define lshpack_arr_cleanup(a) do { \ 184 | free((a)->els); \ 185 | memset((a), 0, sizeof(*(a))); \ 186 | } while (0) 187 | 188 | #define lshpack_arr_get(a, i) ( \ 189 | assert((i) < (a)->nelem), \ 190 | (a)->els[(a)->off + (i)] \ 191 | ) 192 | 193 | #define lshpack_arr_shift(a) ( \ 194 | assert((a)->nelem > 0), \ 195 | (a)->nelem -= 1, \ 196 | (a)->els[(a)->off++] \ 197 | ) 198 | 199 | #define lshpack_arr_pop(a) ( \ 200 | assert((a)->nelem > 0), \ 201 | (a)->nelem -= 1, \ 202 | (a)->els[(a)->off + (a)->nelem] \ 203 | ) 204 | 205 | #define lshpack_arr_count(a) (+(a)->nelem) 206 | 207 | static int 208 | lshpack_arr_push (struct lshpack_arr *arr, uintptr_t val) 209 | { 210 | uintptr_t *new_els; 211 | unsigned n; 212 | 213 | if (arr->off + arr->nelem < arr->nalloc) 214 | { 215 | arr->els[arr->off + arr->nelem] = val; 216 | ++arr->nelem; 217 | return 0; 218 | } 219 | 220 | if (arr->off > arr->nalloc / 2) 221 | { 222 | memmove(arr->els, arr->els + arr->off, 223 | sizeof(arr->els[0]) * arr->nelem); 224 | arr->off = 0; 225 | arr->els[arr->nelem] = val; 226 | ++arr->nelem; 227 | return 0; 228 | } 229 | 230 | if (arr->nalloc) 231 | n = arr->nalloc * 2; 232 | else 233 | n = 64; 234 | new_els = malloc(n * sizeof(arr->els[0])); 235 | if (!new_els) 236 | return -1; 237 | memcpy(new_els, arr->els + arr->off, sizeof(arr->els[0]) * arr->nelem); 238 | free(arr->els); 239 | arr->off = 0; 240 | arr->els = new_els; 241 | arr->nalloc = n; 242 | arr->els[arr->off + arr->nelem] = val; 243 | ++arr->nelem; 244 | return 0; 245 | } 246 | 247 | struct lshpack_double_enc_head 248 | { 249 | struct lshpack_enc_head by_name; 250 | struct lshpack_enc_head by_nameval; 251 | }; 252 | 253 | struct lshpack_enc_table_entry 254 | { 255 | /* An entry always lives on the `all' and `nameval' lists. If its name 256 | * is not in the static table, it also lives on the `name' list. 257 | */ 258 | STAILQ_ENTRY(lshpack_enc_table_entry) 259 | ete_next_nameval, 260 | ete_next_name, 261 | ete_next_all; 262 | unsigned ete_id; 263 | unsigned ete_nameval_hash; 264 | unsigned ete_name_hash; 265 | unsigned ete_name_len; 266 | unsigned ete_val_len; 267 | char ete_buf[]; 268 | }; 269 | 270 | #define ETE_NAME(ete) ((ete)->ete_buf) 271 | #define ETE_VALUE(ete) (&(ete)->ete_buf[(ete)->ete_name_len]) 272 | 273 | 274 | #define N_BUCKETS(n_bits) (1U << (n_bits)) 275 | #define BUCKNO(n_bits, hash) ((hash) & (N_BUCKETS(n_bits) - 1)) 276 | 277 | 278 | /* We estimate average number of entries in the dynamic table to be 1/3 279 | * of the theoretical maximum. This number is used to size the history 280 | * buffer: we want it large enough to cover recent entries, yet not too 281 | * large to cover entries that appear with a period larger than the 282 | * dynamic table. 283 | */ 284 | static unsigned 285 | henc_hist_size (unsigned max_capacity) 286 | { 287 | return max_capacity / DYNAMIC_ENTRY_OVERHEAD / 3; 288 | } 289 | 290 | 291 | int 292 | lshpack_enc_init (struct lshpack_enc *enc) 293 | { 294 | struct lshpack_double_enc_head *buckets; 295 | unsigned nbits = 2; 296 | unsigned i; 297 | 298 | buckets = malloc(sizeof(buckets[0]) * N_BUCKETS(nbits)); 299 | if (!buckets) 300 | return -1; 301 | 302 | for (i = 0; i < N_BUCKETS(nbits); ++i) 303 | { 304 | STAILQ_INIT(&buckets[i].by_name); 305 | STAILQ_INIT(&buckets[i].by_nameval); 306 | } 307 | 308 | memset(enc, 0, sizeof(*enc)); 309 | STAILQ_INIT(&enc->hpe_all_entries); 310 | enc->hpe_max_capacity = INITIAL_DYNAMIC_TABLE_SIZE; 311 | enc->hpe_buckets = buckets; 312 | /* The initial value of the entry ID is completely arbitrary. As long as 313 | * there are fewer than 2^32 dynamic table entries, the math to calculate 314 | * the entry ID works. To prove to ourselves that the wraparound works 315 | * and to have the unit tests cover it, we initialize the next ID so that 316 | * it is just about to wrap around. 317 | */ 318 | enc->hpe_next_id = ~0 - 3; 319 | enc->hpe_nbits = nbits; 320 | enc->hpe_nelem = 0; 321 | return 0; 322 | } 323 | 324 | 325 | void 326 | lshpack_enc_cleanup (struct lshpack_enc *enc) 327 | { 328 | struct lshpack_enc_table_entry *entry, *next; 329 | for (entry = STAILQ_FIRST(&enc->hpe_all_entries); entry; entry = next) 330 | { 331 | next = STAILQ_NEXT(entry, ete_next_all); 332 | free(entry); 333 | } 334 | free(enc->hpe_hist_buf); 335 | free(enc->hpe_buckets); 336 | } 337 | 338 | 339 | static int 340 | henc_use_hist (struct lshpack_enc *enc) 341 | { 342 | unsigned hist_size; 343 | 344 | if (enc->hpe_hist_buf) 345 | return 0; 346 | 347 | hist_size = henc_hist_size(INITIAL_DYNAMIC_TABLE_SIZE); 348 | if (!hist_size) 349 | return 0; 350 | 351 | enc->hpe_hist_buf = malloc(sizeof(enc->hpe_hist_buf[0]) * (hist_size + 1)); 352 | if (!enc->hpe_hist_buf) 353 | return -1; 354 | 355 | enc->hpe_hist_size = hist_size; 356 | enc->hpe_flags |= LSHPACK_ENC_USE_HIST; 357 | return 0; 358 | } 359 | 360 | 361 | int 362 | lshpack_enc_use_hist (struct lshpack_enc *enc, int on) 363 | { 364 | if (on) 365 | return henc_use_hist(enc); 366 | else 367 | { 368 | enc->hpe_flags &= ~LSHPACK_ENC_USE_HIST; 369 | free(enc->hpe_hist_buf); 370 | enc->hpe_hist_buf = NULL; 371 | enc->hpe_hist_size = 0; 372 | enc->hpe_hist_idx = 0; 373 | enc->hpe_hist_wrapped = 0; 374 | return 0; 375 | } 376 | } 377 | 378 | 379 | int 380 | lshpack_enc_hist_used (const struct lshpack_enc *enc) 381 | { 382 | return (enc->hpe_flags & LSHPACK_ENC_USE_HIST) != 0; 383 | } 384 | 385 | 386 | #define LSHPACK_XXH_SEED 39378473 387 | #define XXH_NAMEVAL_WIDTH 9 388 | #define XXH_NAMEVAL_SHIFT 0 389 | #define XXH_NAME_WIDTH 9 390 | #define XXH_NAME_SHIFT 0 391 | 392 | static const unsigned char nameval2id[ 1 << XXH_NAMEVAL_WIDTH ] = 393 | { 394 | [150] = 1, [21] = 2, [439] = 3, [502] = 4, [367] = 5, 395 | [360] = 6, [67] = 7, [342] = 8, [210] = 9, [224] = 10, 396 | [457] = 11, [222] = 12, [161] = 13, [391] = 14, [279] = 15, 397 | [408] = 16, [73] = 17, [468] = 18, [361] = 19, [325] = 20, 398 | [229] = 21, [324] = 22, [188] = 23, [304] = 24, [262] = 25, 399 | [221] = 26, [3] = 27, [293] = 28, [35] = 29, [47] = 30, 400 | [445] = 31, [164] = 32, [463] = 33, [84] = 34, [510] = 35, 401 | [133] = 36, [406] = 37, [307] = 38, [388] = 39, [205] = 40, 402 | [228] = 41, [417] = 42, [70] = 43, [451] = 44, [444] = 45, 403 | [176] = 46, [465] = 47, [272] = 48, [349] = 49, [31] = 50, 404 | [75] = 51, [459] = 52, [217] = 53, [368] = 54, [399] = 55, 405 | [142] = 56, [363] = 57, [492] = 58, [53] = 59, [425] = 60, 406 | [186] = 61, 407 | }; 408 | 409 | static const unsigned char name2id[ 1 << XXH_NAME_WIDTH ] = 410 | { 411 | [347] = 1, [484] = 2, [397] = 4, [81] = 6, [83] = 8, 412 | [150] = 15, [169] = 16, [211] = 17, [456] = 18, [248] = 19, 413 | [59] = 20, [64] = 21, [481] = 22, [321] = 23, [498] = 24, 414 | [144] = 25, [401] = 26, [382] = 27, [25] = 28, [140] = 29, 415 | [358] = 30, [453] = 31, [216] = 32, [361] = 33, [442] = 34, 416 | [253] = 35, [132] = 36, [95] = 37, [272] = 38, [13] = 39, 417 | [190] = 40, [404] = 41, [84] = 42, [337] = 43, [181] = 44, 418 | [210] = 45, [38] = 46, [69] = 47, [357] = 48, [276] = 49, 419 | [266] = 50, [51] = 51, [24] = 52, [322] = 53, [225] = 54, 420 | [318] = 55, [88] = 56, [352] = 57, [362] = 58, [317] = 59, 421 | [178] = 60, [255] = 61, 422 | }; 423 | 424 | //not find return 0, otherwise return the index 425 | #if !LS_HPACK_EMIT_TEST_CODE 426 | static 427 | #endif 428 | unsigned 429 | lshpack_enc_get_static_nameval (const struct lsxpack_header *input) 430 | { 431 | unsigned i; 432 | 433 | assert(input->name_len > 0); 434 | assert(input->flags & LSXPACK_NAMEVAL_HASH); 435 | i = (input->nameval_hash >> XXH_NAMEVAL_SHIFT) & ((1 << XXH_NAMEVAL_WIDTH) - 1); 436 | if (nameval2id[i]) 437 | { 438 | i = nameval2id[i] - 1; 439 | if (static_table[i].name_len == input->name_len 440 | && static_table[i].val_len == input->val_len 441 | && memcmp(lsxpack_header_get_name(input), static_table[i].name, input->name_len) == 0 442 | && memcmp(lsxpack_header_get_value(input), static_table[i].val, input->val_len) == 0) 443 | { 444 | return i + 1; 445 | } 446 | } 447 | 448 | return 0; 449 | } 450 | 451 | #if !LS_HPACK_EMIT_TEST_CODE 452 | static 453 | #endif 454 | unsigned 455 | lshpack_enc_get_static_name (const struct lsxpack_header *input) 456 | { 457 | unsigned i; 458 | 459 | assert(input->flags & LSXPACK_NAME_HASH); 460 | i = (input->name_hash >> XXH_NAME_SHIFT) & ((1 << XXH_NAME_WIDTH) - 1); 461 | if (name2id[i]) 462 | { 463 | i = name2id[i] - 1; 464 | if (static_table[i].name_len == input->name_len 465 | && memcmp(lsxpack_header_get_name(input), static_table[i].name, 466 | input->name_len) == 0) 467 | { 468 | return i + 1; 469 | } 470 | } 471 | 472 | return 0; 473 | } 474 | 475 | 476 | static void 477 | update_hash (struct lsxpack_header *input) 478 | { 479 | if (!(input->flags & LSXPACK_NAME_HASH)) 480 | input->name_hash = XXH32(lsxpack_header_get_name(input), 481 | input->name_len, LSHPACK_XXH_SEED); 482 | else 483 | assert(input->name_hash == XXH32(lsxpack_header_get_name(input), 484 | input->name_len, LSHPACK_XXH_SEED)); 485 | 486 | if (!(input->flags & LSXPACK_NAMEVAL_HASH)) 487 | input->nameval_hash = XXH32(input->buf + input->val_offset, 488 | input->val_len, input->name_hash); 489 | else 490 | assert(input->nameval_hash == XXH32(input->buf + input->val_offset, 491 | input->val_len, input->name_hash)); 492 | 493 | input->flags |= (LSXPACK_NAME_HASH | LSXPACK_NAMEVAL_HASH); 494 | } 495 | 496 | 497 | unsigned 498 | lshpack_enc_get_stx_tab_id (struct lsxpack_header *input) 499 | { 500 | unsigned i; 501 | 502 | update_hash(input); 503 | 504 | i = (input->nameval_hash >> XXH_NAMEVAL_SHIFT) & ((1 << XXH_NAMEVAL_WIDTH) - 1); 505 | if (nameval2id[i]) 506 | { 507 | i = nameval2id[i] - 1; 508 | if (static_table[i].name_len == input->name_len 509 | && static_table[i].val_len == input->val_len 510 | && memcmp(lsxpack_header_get_name(input), static_table[i].name, 511 | input->name_len) == 0 512 | && memcmp(input->buf + input->val_offset, static_table[i].val, 513 | input->val_len) == 0) 514 | { 515 | return i + 1; 516 | } 517 | } 518 | 519 | i = (input->name_hash >> XXH_NAME_SHIFT) & ((1 << XXH_NAME_WIDTH) - 1); 520 | if (name2id[i]) 521 | { 522 | i = name2id[i] - 1; 523 | if (static_table[i].name_len == input->name_len 524 | && memcmp(lsxpack_header_get_name(input), static_table[i].name, 525 | input->name_len) == 0) 526 | { 527 | return i + 1; 528 | } 529 | } 530 | 531 | return 0; 532 | } 533 | 534 | 535 | /* Given a dynamic entry, return its table ID */ 536 | static unsigned 537 | henc_calc_table_id (const struct lshpack_enc *enc, 538 | const struct lshpack_enc_table_entry *entry) 539 | { 540 | return HPACK_STATIC_TABLE_SIZE 541 | + (enc->hpe_next_id - entry->ete_id) 542 | ; 543 | } 544 | 545 | 546 | static unsigned 547 | henc_find_table_id (struct lshpack_enc *enc, lsxpack_header_t *input, 548 | int *val_matched) 549 | { 550 | struct lshpack_enc_table_entry *entry; 551 | unsigned buckno, id; 552 | const char *val_ptr = input->buf + input->val_offset; 553 | const char *name; 554 | unsigned int name_len; 555 | 556 | name_len = input->name_len; 557 | name = lsxpack_header_get_name(input); 558 | 559 | /* First, look for a match in the static table: */ 560 | if (input->hpack_index) 561 | { 562 | id = input->hpack_index - 1; 563 | #ifndef NDEBUG 564 | if (name_len) 565 | { 566 | lsxpack_header_t input_copy = *input; 567 | const unsigned hpack_index = lshpack_enc_get_stx_tab_id(&input_copy); 568 | assert(input_copy.hpack_index == hpack_index); 569 | } 570 | #endif 571 | if (id <= LSHPACK_HDR_ACCEPT_ENCODING || input->val_len == 0) 572 | { 573 | if (static_table[id].val_len == input->val_len 574 | && memcmp(val_ptr, static_table[id].val, input->val_len) == 0) 575 | { 576 | input->flags |= LSXPACK_HPACK_VAL_MATCHED; 577 | *val_matched = 1; 578 | return input->hpack_index; 579 | } 580 | } 581 | if (!name_len) 582 | { 583 | name = static_table[id].name; 584 | name_len = static_table[id].name_len; 585 | } 586 | 587 | if (!(input->flags & LSXPACK_NAME_HASH)) 588 | input->name_hash = static_table_name_hash[id]; 589 | else 590 | assert(input->name_hash == static_table_name_hash[id]); 591 | if (!(input->flags & LSXPACK_NAMEVAL_HASH)) 592 | input->nameval_hash = XXH32(val_ptr, input->val_len, 593 | input->name_hash); 594 | else 595 | assert(input->nameval_hash == XXH32(val_ptr, input->val_len, 596 | input->name_hash)); 597 | input->flags |= (LSXPACK_NAME_HASH | LSXPACK_NAMEVAL_HASH); 598 | } 599 | else 600 | { 601 | update_hash(input); 602 | input->hpack_index = lshpack_enc_get_static_nameval(input); 603 | if (input->hpack_index != LSHPACK_HDR_UNKNOWN) 604 | { 605 | input->flags |= LSXPACK_HPACK_VAL_MATCHED; 606 | *val_matched = 1; 607 | return input->hpack_index; 608 | } 609 | } 610 | 611 | /* Search by name and value: */ 612 | buckno = BUCKNO(enc->hpe_nbits, input->nameval_hash); 613 | STAILQ_FOREACH(entry, &enc->hpe_buckets[buckno].by_nameval, 614 | ete_next_nameval) 615 | if (input->nameval_hash == entry->ete_nameval_hash && 616 | name_len == entry->ete_name_len && 617 | input->val_len == entry->ete_val_len && 618 | 0 == memcmp(name, ETE_NAME(entry), name_len) && 619 | 0 == memcmp(val_ptr, ETE_VALUE(entry), input->val_len)) 620 | { 621 | *val_matched = 1; 622 | return henc_calc_table_id(enc, entry); 623 | } 624 | 625 | /* Name/value match is not found, look for header: */ 626 | if (input->hpack_index == LSHPACK_HDR_UNKNOWN) 627 | input->hpack_index = lshpack_enc_get_static_name(input); 628 | if (input->hpack_index != LSHPACK_HDR_UNKNOWN) 629 | { 630 | input->flags &= ~LSXPACK_HPACK_VAL_MATCHED; 631 | return input->hpack_index; 632 | } 633 | 634 | /* Search by name only: */ 635 | buckno = BUCKNO(enc->hpe_nbits, input->name_hash); 636 | STAILQ_FOREACH(entry, &enc->hpe_buckets[buckno].by_name, ete_next_name) 637 | if (input->name_hash == entry->ete_name_hash && 638 | input->name_len == entry->ete_name_len && 639 | 0 == memcmp(name, ETE_NAME(entry), name_len)) 640 | { 641 | input->flags &= ~LSXPACK_HPACK_VAL_MATCHED; 642 | return henc_calc_table_id(enc, entry); 643 | } 644 | 645 | return 0; 646 | } 647 | 648 | 649 | #if !LS_HPACK_EMIT_TEST_CODE 650 | static 651 | #endif 652 | unsigned char * 653 | lshpack_enc_enc_int (unsigned char *dst, unsigned char *const end, 654 | uint32_t value, uint8_t prefix_bits) 655 | { 656 | unsigned char *const dst_orig = dst; 657 | 658 | /* This function assumes that at least one byte is available */ 659 | assert(dst < end); 660 | if (value < (uint32_t)(1 << prefix_bits) - 1) 661 | *dst++ |= value; 662 | else 663 | { 664 | *dst++ |= (1 << prefix_bits) - 1; 665 | value -= (1 << prefix_bits) - 1; 666 | while (value >= 128) 667 | { 668 | if (dst < end) 669 | { 670 | *dst++ = (0x80 | value); 671 | value >>= 7; 672 | } 673 | else 674 | return dst_orig; 675 | } 676 | if (dst < end) 677 | *dst++ = value; 678 | else 679 | return dst_orig; 680 | } 681 | return dst; 682 | } 683 | 684 | 685 | /* This whole pragma business has to do with turning off uninitialized warnings. 686 | * We do it for gcc and clang. Other compilers get slightly slower code, where 687 | * unnecessary initialization is performed. 688 | */ 689 | #if __GNUC__ 690 | #pragma GCC diagnostic ignored "-Wunknown-pragmas" 691 | #if __clang__ 692 | #pragma GCC diagnostic ignored "-Wunknown-warning-option" 693 | #endif 694 | #endif 695 | 696 | 697 | int 698 | lshpack_enc_huff_encode (const unsigned char *src, 699 | const unsigned char *const src_end, unsigned char *const dst, int dst_len) 700 | { 701 | unsigned char *p_dst = dst; 702 | unsigned char *dst_end = p_dst + dst_len; 703 | uintptr_t bits; /* OK not to initialize this variable */ 704 | unsigned bits_used = 0, adj; 705 | struct encode_el cur_enc_code; 706 | #if __GNUC__ && (__clang__ || __GNUC__ >= 5) 707 | #pragma GCC diagnostic push 708 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 709 | #pragma GCC diagnostic ignored "-Wuninitialized" 710 | #else 711 | bits = 0; 712 | #endif 713 | #if LS_HPACK_USE_LARGE_TABLES 714 | const struct henc *henc; 715 | uint16_t idx; 716 | 717 | while (src + sizeof(bits) * 8 / 5 + sizeof(idx) < src_end 718 | && p_dst + sizeof(bits) <= dst_end) 719 | { 720 | memcpy(&idx, src, 2); 721 | henc = &hencs[idx]; 722 | src += 2; 723 | while (bits_used + henc->lens < sizeof(bits) * 8) 724 | { 725 | bits <<= henc->lens; 726 | bits |= henc->code; 727 | bits_used += henc->lens; 728 | memcpy(&idx, src, 2); 729 | henc = &hencs[idx]; 730 | src += 2; 731 | } 732 | if (henc->lens < 64) 733 | { 734 | bits <<= sizeof(bits) * 8 - bits_used; 735 | bits_used = henc->lens - (sizeof(bits) * 8 - bits_used); 736 | bits |= henc->code >> bits_used; 737 | #if UINTPTR_MAX == 18446744073709551615ull 738 | *p_dst++ = bits >> 56; 739 | *p_dst++ = bits >> 48; 740 | *p_dst++ = bits >> 40; 741 | *p_dst++ = bits >> 32; 742 | #endif 743 | *p_dst++ = bits >> 24; 744 | *p_dst++ = bits >> 16; 745 | *p_dst++ = bits >> 8; 746 | *p_dst++ = bits; 747 | bits = henc->code; /* OK not to clear high bits */ 748 | } 749 | else 750 | { 751 | src -= 2; 752 | break; 753 | } 754 | } 755 | #endif 756 | 757 | while (src != src_end) 758 | { 759 | cur_enc_code = encode_table[*src++]; 760 | if (bits_used + cur_enc_code.bits < sizeof(bits) * 8) 761 | { 762 | bits <<= cur_enc_code.bits; 763 | bits |= cur_enc_code.code; 764 | bits_used += cur_enc_code.bits; 765 | continue; 766 | } 767 | else if (p_dst + sizeof(bits) <= dst_end) 768 | { 769 | bits <<= sizeof(bits) * 8 - bits_used; 770 | bits_used = cur_enc_code.bits - (sizeof(bits) * 8 - bits_used); 771 | bits |= cur_enc_code.code >> bits_used; 772 | #if UINTPTR_MAX == 18446744073709551615ull 773 | *p_dst++ = bits >> 56; 774 | *p_dst++ = bits >> 48; 775 | *p_dst++ = bits >> 40; 776 | *p_dst++ = bits >> 32; 777 | #endif 778 | *p_dst++ = bits >> 24; 779 | *p_dst++ = bits >> 16; 780 | *p_dst++ = bits >> 8; 781 | *p_dst++ = bits; 782 | bits = cur_enc_code.code; /* OK not to clear high bits */ 783 | } 784 | else 785 | return -1; 786 | } 787 | 788 | adj = bits_used + (-bits_used & 7); /* Round up to 8 */ 789 | if (bits_used && p_dst + (adj >> 3) <= dst_end) 790 | { 791 | bits <<= -bits_used & 7; /* Align to byte boundary */ 792 | bits |= ((1 << (-bits_used & 7)) - 1); /* EOF */ 793 | switch (adj >> 3) 794 | { /* Write out */ 795 | #if UINTPTR_MAX == 18446744073709551615ull 796 | case 8: *p_dst++ = bits >> 56; 797 | FALL_THROUGH; 798 | case 7: *p_dst++ = bits >> 48; 799 | FALL_THROUGH; 800 | case 6: *p_dst++ = bits >> 40; 801 | FALL_THROUGH; 802 | case 5: *p_dst++ = bits >> 32; 803 | FALL_THROUGH; 804 | #endif 805 | case 4: *p_dst++ = bits >> 24; 806 | FALL_THROUGH; 807 | case 3: *p_dst++ = bits >> 16; 808 | FALL_THROUGH; 809 | case 2: *p_dst++ = bits >> 8; 810 | FALL_THROUGH; 811 | default: *p_dst++ = bits; 812 | } 813 | return p_dst - dst; 814 | } 815 | else if (p_dst + (adj >> 3) <= dst_end) 816 | return p_dst - dst; 817 | else 818 | return -1; 819 | #if __GNUC__ && (__clang__ || __GNUC__ >= 5) 820 | #pragma GCC diagnostic pop 821 | #endif 822 | } 823 | 824 | 825 | #if !LS_HPACK_EMIT_TEST_CODE 826 | static 827 | #endif 828 | int 829 | lshpack_enc_enc_str (unsigned char *const dst, size_t dst_len, 830 | const unsigned char *str, unsigned str_len) 831 | { 832 | unsigned char size_buf[4]; 833 | unsigned char *p; 834 | unsigned size_len; 835 | int rc; 836 | 837 | if (dst_len > 1) 838 | /* We guess that the string size fits into a single byte -- meaning 839 | * compressed string of size 126 and smaller -- which is the normal 840 | * case. Thus, we immediately write compressed string to the output 841 | * buffer. If our guess is not correct, we fix it later. 842 | */ 843 | rc = lshpack_enc_huff_encode(str, str + str_len, dst + 1, dst_len - 1); 844 | else if (dst_len == 1) 845 | /* Here, the call can only succeed if the string to encode is empty. */ 846 | rc = 0; 847 | else 848 | return -1; 849 | 850 | /* 851 | * Check if need huffman encoding or not 852 | * Comment: (size_t)rc <= str_len = means if same length, still use 853 | * Huffman 854 | * ^ 855 | */ 856 | if (rc > 0 && (size_t)rc <= str_len) 857 | { 858 | if (rc < 127) 859 | { 860 | *dst = 0x80 | rc; 861 | return 1 + rc; 862 | } 863 | size_buf[0] = 0x80; 864 | str_len = rc; 865 | str = dst + 1; 866 | } 867 | else if (str_len <= dst_len - 1) 868 | { 869 | if (str_len < 127) 870 | { 871 | *dst = (unsigned char) str_len; 872 | memcpy(dst + 1, str, str_len); 873 | return 1 + str_len; 874 | } 875 | size_buf[0] = 0x00; 876 | } 877 | else 878 | return -1; 879 | 880 | /* The guess of one-byte size was incorrect. Perform necessary 881 | * adjustments. 882 | */ 883 | p = lshpack_enc_enc_int(size_buf, size_buf + sizeof(size_buf), str_len, 7); 884 | if (p == size_buf) 885 | return -1; 886 | 887 | size_len = p - size_buf; 888 | assert(size_len > 1); 889 | 890 | /* Check if there is enough room in the output buffer for both 891 | * encoded size and the string. 892 | */ 893 | if (size_len + str_len > dst_len) 894 | return -1; 895 | 896 | memmove(dst + size_len, str, str_len); 897 | memcpy(dst, size_buf, size_len); 898 | return size_len + str_len; 899 | } 900 | 901 | 902 | static void 903 | henc_drop_oldest_entry (struct lshpack_enc *enc) 904 | { 905 | struct lshpack_enc_table_entry *entry; 906 | unsigned buckno; 907 | 908 | entry = STAILQ_FIRST(&enc->hpe_all_entries); 909 | assert(entry); 910 | STAILQ_REMOVE_HEAD(&enc->hpe_all_entries, ete_next_all); 911 | buckno = BUCKNO(enc->hpe_nbits, entry->ete_nameval_hash); 912 | assert(entry == STAILQ_FIRST(&enc->hpe_buckets[buckno].by_nameval)); 913 | STAILQ_REMOVE_HEAD(&enc->hpe_buckets[buckno].by_nameval, ete_next_nameval); 914 | buckno = BUCKNO(enc->hpe_nbits, entry->ete_name_hash); 915 | if (entry == STAILQ_FIRST(&enc->hpe_buckets[buckno].by_name)) 916 | STAILQ_REMOVE_HEAD(&enc->hpe_buckets[buckno].by_name, ete_next_name); 917 | 918 | enc->hpe_cur_capacity -= DYNAMIC_ENTRY_OVERHEAD + entry->ete_name_len 919 | + entry->ete_val_len; 920 | --enc->hpe_nelem; 921 | free(entry); 922 | } 923 | 924 | 925 | static void 926 | henc_remove_overflow_entries (struct lshpack_enc *enc) 927 | { 928 | while (enc->hpe_cur_capacity > enc->hpe_max_capacity) 929 | henc_drop_oldest_entry(enc); 930 | } 931 | 932 | 933 | static int 934 | henc_grow_tables (struct lshpack_enc *enc) 935 | { 936 | struct lshpack_double_enc_head *new_buckets, *new[2]; 937 | struct lshpack_enc_table_entry *entry; 938 | unsigned n, old_nbits; 939 | int idx; 940 | 941 | old_nbits = enc->hpe_nbits; 942 | new_buckets = malloc(sizeof(enc->hpe_buckets[0]) 943 | * N_BUCKETS(old_nbits + 1)); 944 | if (!new_buckets) 945 | return -1; 946 | 947 | for (n = 0; n < N_BUCKETS(old_nbits); ++n) 948 | { 949 | new[0] = &new_buckets[n]; 950 | new[1] = &new_buckets[n + N_BUCKETS(old_nbits)]; 951 | STAILQ_INIT(&new[0]->by_name); 952 | STAILQ_INIT(&new[1]->by_name); 953 | STAILQ_INIT(&new[0]->by_nameval); 954 | STAILQ_INIT(&new[1]->by_nameval); 955 | while ((entry = STAILQ_FIRST(&enc->hpe_buckets[n].by_name))) 956 | { 957 | STAILQ_REMOVE_HEAD(&enc->hpe_buckets[n].by_name, ete_next_name); 958 | idx = (BUCKNO(old_nbits + 1, entry->ete_name_hash) 959 | >> old_nbits) & 1; 960 | STAILQ_INSERT_TAIL(&new[idx]->by_name, entry, ete_next_name); 961 | } 962 | while ((entry = STAILQ_FIRST(&enc->hpe_buckets[n].by_nameval))) 963 | { 964 | STAILQ_REMOVE_HEAD(&enc->hpe_buckets[n].by_nameval, 965 | ete_next_nameval); 966 | idx = (BUCKNO(old_nbits + 1, entry->ete_nameval_hash) 967 | >> old_nbits) & 1; 968 | STAILQ_INSERT_TAIL(&new[idx]->by_nameval, entry, 969 | ete_next_nameval); 970 | } 971 | } 972 | 973 | free(enc->hpe_buckets); 974 | enc->hpe_nbits = old_nbits + 1; 975 | enc->hpe_buckets = new_buckets; 976 | return 0; 977 | } 978 | 979 | 980 | #if !LS_HPACK_EMIT_TEST_CODE 981 | static 982 | #endif 983 | int 984 | lshpack_enc_push_entry (struct lshpack_enc *enc, 985 | const struct lsxpack_header *input) 986 | { 987 | unsigned buckno; 988 | struct lshpack_enc_table_entry *entry; 989 | size_t size; 990 | const char *name; 991 | unsigned int name_len; 992 | 993 | if (enc->hpe_nelem >= N_BUCKETS(enc->hpe_nbits) / 2 && 994 | 0 != henc_grow_tables(enc)) 995 | return -1; 996 | name_len = input->name_len; 997 | if (name_len == 0) 998 | { 999 | assert(input->hpack_index != LSHPACK_HDR_UNKNOWN); 1000 | name = static_table[input->hpack_index - 1].name; 1001 | name_len = static_table[input->hpack_index - 1].name_len; 1002 | } 1003 | else 1004 | name = lsxpack_header_get_name(input); 1005 | size = sizeof(*entry) + name_len + input->val_len; 1006 | entry = malloc(size); 1007 | if (!entry) 1008 | return -1; 1009 | 1010 | entry->ete_name_hash = input->name_hash; 1011 | entry->ete_nameval_hash = input->nameval_hash; 1012 | entry->ete_name_len = name_len; 1013 | entry->ete_val_len = input->val_len; 1014 | entry->ete_id = enc->hpe_next_id++; 1015 | memcpy(ETE_NAME(entry), name, name_len); 1016 | memcpy(ETE_VALUE(entry), input->buf + input->val_offset, input->val_len); 1017 | 1018 | STAILQ_INSERT_TAIL(&enc->hpe_all_entries, entry, ete_next_all); 1019 | buckno = BUCKNO(enc->hpe_nbits, input->nameval_hash); 1020 | STAILQ_INSERT_TAIL(&enc->hpe_buckets[buckno].by_nameval, entry, 1021 | ete_next_nameval); 1022 | if (input->hpack_index == LSHPACK_HDR_UNKNOWN) 1023 | { 1024 | buckno = BUCKNO(enc->hpe_nbits, input->name_hash); 1025 | STAILQ_INSERT_TAIL(&enc->hpe_buckets[buckno].by_name, entry, 1026 | ete_next_name); 1027 | } 1028 | enc->hpe_cur_capacity += DYNAMIC_ENTRY_OVERHEAD + name_len 1029 | + input->val_len; 1030 | ++enc->hpe_nelem; 1031 | henc_remove_overflow_entries(enc); 1032 | return 0; 1033 | } 1034 | 1035 | 1036 | static void 1037 | henc_resize_history (struct lshpack_enc *enc) 1038 | { 1039 | uint32_t *hist_buf; 1040 | unsigned hist_size, first, count, i, j; 1041 | 1042 | hist_size = henc_hist_size(enc->hpe_max_capacity); 1043 | 1044 | if (hist_size == enc->hpe_hist_size) 1045 | return; 1046 | 1047 | if (hist_size == 0) 1048 | { 1049 | free(enc->hpe_hist_buf); 1050 | enc->hpe_hist_buf = NULL; 1051 | enc->hpe_hist_size = 0; 1052 | enc->hpe_hist_idx = 0; 1053 | enc->hpe_hist_wrapped = 0; 1054 | return; 1055 | } 1056 | 1057 | hist_buf = malloc(sizeof(hist_buf[0]) * (hist_size + 1)); 1058 | if (!hist_buf) 1059 | return; 1060 | 1061 | if (enc->hpe_hist_wrapped) 1062 | { 1063 | first = (enc->hpe_hist_idx + 1) % enc->hpe_hist_size; 1064 | count = enc->hpe_hist_size; 1065 | } 1066 | else 1067 | { 1068 | first = 0; 1069 | count = enc->hpe_hist_idx; 1070 | } 1071 | for (i = 0, j = 0; count > 0 && j < hist_size; ++i, ++j, --count) 1072 | hist_buf[j] = enc->hpe_hist_buf[ (first + i) % enc->hpe_hist_size ]; 1073 | enc->hpe_hist_size = hist_size; 1074 | enc->hpe_hist_idx = j % hist_size; 1075 | enc->hpe_hist_wrapped = enc->hpe_hist_idx == 0; 1076 | free(enc->hpe_hist_buf); 1077 | enc->hpe_hist_buf = hist_buf; 1078 | } 1079 | 1080 | 1081 | /* Returns true if `nameval_hash' was already in history, false otherwise. */ 1082 | static int 1083 | henc_hist_add (struct lshpack_enc *enc, uint32_t nameval_hash) 1084 | { 1085 | unsigned last; 1086 | uint32_t *p; 1087 | 1088 | if (enc->hpe_hist_wrapped) 1089 | last = enc->hpe_hist_size; 1090 | else 1091 | last = enc->hpe_hist_idx; 1092 | 1093 | enc->hpe_hist_buf[ last ] = nameval_hash; 1094 | for (p = enc->hpe_hist_buf; *p != nameval_hash; ++p) 1095 | ; 1096 | enc->hpe_hist_buf[ enc->hpe_hist_idx ] = nameval_hash; 1097 | enc->hpe_hist_idx = (enc->hpe_hist_idx + 1) % enc->hpe_hist_size; 1098 | enc->hpe_hist_wrapped |= enc->hpe_hist_idx == 0; 1099 | 1100 | return p < enc->hpe_hist_buf + last; 1101 | } 1102 | 1103 | 1104 | unsigned char * 1105 | lshpack_enc_encode (struct lshpack_enc *enc, unsigned char *dst, 1106 | unsigned char *dst_end, lsxpack_header_t *input) 1107 | { 1108 | //indexed_type: 0, Add, 1,: without, 2: never 1109 | static const char indexed_prefix_number[] = {0x40, 0x00, 0x10}; 1110 | unsigned char *const dst_org = dst; 1111 | int rc; 1112 | int val_matched = 0; 1113 | unsigned table_id; 1114 | 1115 | if (dst_end <= dst) 1116 | return dst_org; 1117 | 1118 | if (input->flags & LSXPACK_HPACK_VAL_MATCHED) 1119 | { 1120 | assert(input->hpack_index != LSHPACK_HDR_UNKNOWN); 1121 | assert(input->val_len == static_table[input->hpack_index - 1].val_len); 1122 | assert(memcmp(lsxpack_header_get_value(input), 1123 | static_table[input->hpack_index - 1].val, 1124 | input->val_len) == 0); 1125 | table_id = input->hpack_index; 1126 | val_matched = 1; 1127 | } 1128 | else 1129 | { 1130 | if (input->flags & LSXPACK_NEVER_INDEX) 1131 | input->indexed_type = 2; 1132 | table_id = henc_find_table_id(enc, input, &val_matched); 1133 | if (enc->hpe_hist_buf) 1134 | { 1135 | rc = henc_hist_add(enc, input->nameval_hash); 1136 | if (!rc && enc->hpe_hist_wrapped && input->indexed_type == 0) 1137 | input->indexed_type = 1; 1138 | } 1139 | } 1140 | 1141 | if (table_id > 0) 1142 | { 1143 | if (val_matched) 1144 | { 1145 | // LSXPACK_VAL_MATCHED MUST NOT set for dynamic table 1146 | // otherwise, it may cause trouble when feed the input to a different encoder. 1147 | if (table_id > HPACK_STATIC_TABLE_SIZE) 1148 | assert(!(input->flags & LSXPACK_HPACK_VAL_MATCHED)); 1149 | 1150 | *dst = 0x80; 1151 | dst = lshpack_enc_enc_int(dst, dst_end, table_id, 7); 1152 | /* No need to check return value: we pass it up as-is because 1153 | * the behavior is the same. 1154 | */ 1155 | return dst; 1156 | } 1157 | else 1158 | { 1159 | *dst = indexed_prefix_number[input->indexed_type]; 1160 | dst = lshpack_enc_enc_int(dst, dst_end, table_id, 1161 | ((input->indexed_type == 0) ? 6 : 4)); 1162 | if (dst == dst_org) 1163 | return dst_org; 1164 | } 1165 | } 1166 | else 1167 | { 1168 | assert(input->name_len > 0); 1169 | *dst++ = indexed_prefix_number[input->indexed_type]; 1170 | rc = lshpack_enc_enc_str(dst, dst_end - dst, 1171 | (unsigned char *)lsxpack_header_get_name(input), 1172 | input->name_len); 1173 | if (rc < 0) 1174 | return dst_org; //Failed to enc this header, return unchanged ptr. 1175 | dst += rc; 1176 | } 1177 | 1178 | rc = lshpack_enc_enc_str(dst, dst_end - dst, 1179 | (const unsigned char *)input->buf + input->val_offset, 1180 | input->val_len); 1181 | if (rc < 0) 1182 | return dst_org; //Failed to enc this header, return unchanged ptr. 1183 | dst += rc; 1184 | 1185 | if (input->indexed_type == 0) 1186 | { 1187 | rc = lshpack_enc_push_entry(enc, input); 1188 | if (rc != 0) 1189 | return dst_org; //Failed to enc this header, return unchanged ptr. 1190 | } 1191 | 1192 | return dst; 1193 | } 1194 | 1195 | 1196 | void 1197 | lshpack_enc_set_max_capacity (struct lshpack_enc *enc, unsigned max_capacity) 1198 | { 1199 | enc->hpe_max_capacity = max_capacity; 1200 | henc_remove_overflow_entries(enc); 1201 | if (lshpack_enc_hist_used(enc)) 1202 | henc_resize_history(enc); 1203 | } 1204 | 1205 | #if LS_HPACK_EMIT_TEST_CODE 1206 | void 1207 | lshpack_enc_iter_init (struct lshpack_enc *enc, void **iter) 1208 | { 1209 | *iter = STAILQ_FIRST(&enc->hpe_all_entries); 1210 | } 1211 | 1212 | 1213 | /* Returns 0 if entry is found */ 1214 | int 1215 | lshpack_enc_iter_next (struct lshpack_enc *enc, void **iter, 1216 | struct enc_dyn_table_entry *retval) 1217 | { 1218 | const struct lshpack_enc_table_entry *entry; 1219 | 1220 | entry = *iter; 1221 | if (!entry) 1222 | return -1; 1223 | 1224 | *iter = STAILQ_NEXT(entry, ete_next_all); 1225 | 1226 | retval->name = ETE_NAME(entry); 1227 | retval->value = ETE_VALUE(entry); 1228 | retval->name_len = entry->ete_name_len; 1229 | retval->value_len = entry->ete_val_len; 1230 | retval->entry_id = henc_calc_table_id(enc, entry); 1231 | return 0; 1232 | } 1233 | #endif 1234 | 1235 | 1236 | /* Dynamic table entry: */ 1237 | struct dec_table_entry 1238 | { 1239 | unsigned dte_name_len; 1240 | unsigned dte_val_len; 1241 | #if LSHPACK_DEC_CALC_HASH 1242 | uint32_t dte_name_hash; 1243 | uint32_t dte_nameval_hash; 1244 | enum { 1245 | DTEF_NAME_HASH = LSXPACK_NAME_HASH, 1246 | DTEF_NAMEVAL_HASH = LSXPACK_NAMEVAL_HASH, 1247 | } dte_flags:8; 1248 | #endif 1249 | uint8_t dte_name_idx; 1250 | char dte_buf[]; /* Contains both name and value */ 1251 | }; 1252 | 1253 | #define DTE_NAME(dte) ((dte)->dte_buf) 1254 | #define DTE_VALUE(dte) (&(dte)->dte_buf[(dte)->dte_name_len]) 1255 | 1256 | enum 1257 | { 1258 | HPACK_HUFFMAN_FLAG_ACCEPTED = 0x01, 1259 | HPACK_HUFFMAN_FLAG_SYM = 0x02, 1260 | HPACK_HUFFMAN_FLAG_FAIL = 0x04, 1261 | }; 1262 | 1263 | struct decode_status 1264 | { 1265 | uint8_t state; 1266 | uint8_t eos; 1267 | }; 1268 | 1269 | 1270 | void 1271 | lshpack_dec_init (struct lshpack_dec *dec) 1272 | { 1273 | memset(dec, 0, sizeof(*dec)); 1274 | dec->hpd_max_capacity = INITIAL_DYNAMIC_TABLE_SIZE; 1275 | dec->hpd_cur_max_capacity = INITIAL_DYNAMIC_TABLE_SIZE; 1276 | lshpack_arr_init(&dec->hpd_dyn_table); 1277 | } 1278 | 1279 | 1280 | void 1281 | lshpack_dec_cleanup (struct lshpack_dec *dec) 1282 | { 1283 | uintptr_t val; 1284 | 1285 | while (lshpack_arr_count(&dec->hpd_dyn_table) > 0) 1286 | { 1287 | val = lshpack_arr_pop(&dec->hpd_dyn_table); 1288 | free((struct dec_table_entry *) val); 1289 | } 1290 | lshpack_arr_cleanup(&dec->hpd_dyn_table); 1291 | } 1292 | 1293 | 1294 | /* Maximum number of bytes required to encode a 32-bit integer */ 1295 | #define LSHPACK_UINT32_ENC_SZ 6 1296 | 1297 | 1298 | /* Assumption: we have at least one byte to work with */ 1299 | #if !LS_HPACK_EMIT_TEST_CODE 1300 | static 1301 | #endif 1302 | int 1303 | lshpack_dec_dec_int (const unsigned char **src_p, const unsigned char *src_end, 1304 | unsigned prefix_bits, uint32_t *value_p) 1305 | { 1306 | const unsigned char *const orig_src = *src_p; 1307 | const unsigned char *src; 1308 | unsigned prefix_max, M; 1309 | uint32_t val, B; 1310 | 1311 | src = *src_p; 1312 | 1313 | prefix_max = (1 << prefix_bits) - 1; 1314 | val = *src++; 1315 | val &= prefix_max; 1316 | 1317 | if (val < prefix_max) 1318 | { 1319 | *src_p = src; 1320 | *value_p = val; 1321 | return 0; 1322 | } 1323 | 1324 | M = 0; 1325 | do 1326 | { 1327 | if (src < src_end) 1328 | { 1329 | B = *src++; 1330 | val = val + ((B & 0x7f) << M); 1331 | M += 7; 1332 | } 1333 | else if (src - orig_src < LSHPACK_UINT32_ENC_SZ) 1334 | return -1; 1335 | else 1336 | return -2; 1337 | } 1338 | while (B & 0x80); 1339 | 1340 | if (M <= 28 || (M == 35 && src[-1] <= 0xF && val - (src[-1] << 28) < val)) 1341 | { 1342 | *src_p = src; 1343 | *value_p = val; 1344 | return 0; 1345 | } 1346 | else 1347 | return -2; 1348 | } 1349 | 1350 | 1351 | static void 1352 | hdec_drop_oldest_entry (struct lshpack_dec *dec) 1353 | { 1354 | struct dec_table_entry *entry; 1355 | entry = (void *) lshpack_arr_shift(&dec->hpd_dyn_table); 1356 | dec->hpd_cur_capacity -= DYNAMIC_ENTRY_OVERHEAD + entry->dte_name_len 1357 | + entry->dte_val_len; 1358 | ++dec->hpd_state; 1359 | free(entry); 1360 | } 1361 | 1362 | 1363 | static void 1364 | hdec_remove_overflow_entries (struct lshpack_dec *dec) 1365 | { 1366 | while (dec->hpd_cur_capacity > dec->hpd_cur_max_capacity) 1367 | hdec_drop_oldest_entry(dec); 1368 | } 1369 | 1370 | 1371 | static void 1372 | hdec_update_max_capacity (struct lshpack_dec *dec, uint32_t new_capacity) 1373 | { 1374 | dec->hpd_cur_max_capacity = new_capacity; 1375 | hdec_remove_overflow_entries(dec); 1376 | } 1377 | 1378 | 1379 | void 1380 | lshpack_dec_set_max_capacity (struct lshpack_dec *dec, unsigned max_capacity) 1381 | { 1382 | dec->hpd_max_capacity = max_capacity; 1383 | hdec_update_max_capacity(dec, max_capacity); 1384 | } 1385 | 1386 | 1387 | static unsigned char * 1388 | hdec_huff_dec4bits (uint8_t src_4bits, unsigned char *dst, 1389 | struct decode_status *status) 1390 | { 1391 | const struct decode_el cur_dec_code = 1392 | decode_tables[status->state][src_4bits]; 1393 | if (cur_dec_code.flags & HPACK_HUFFMAN_FLAG_FAIL) { 1394 | return NULL; //failed 1395 | } 1396 | if (cur_dec_code.flags & HPACK_HUFFMAN_FLAG_SYM) 1397 | { 1398 | *dst = cur_dec_code.sym; 1399 | dst++; 1400 | } 1401 | 1402 | status->state = cur_dec_code.state; 1403 | status->eos = ((cur_dec_code.flags & HPACK_HUFFMAN_FLAG_ACCEPTED) != 0); 1404 | return dst; 1405 | } 1406 | 1407 | 1408 | #if !LS_HPACK_USE_LARGE_TABLES 1409 | #define lshpack_dec_huff_decode_full lshpack_dec_huff_decode 1410 | #endif 1411 | 1412 | int 1413 | lshpack_dec_huff_decode_full (const unsigned char *src, int src_len, 1414 | unsigned char *dst, int dst_len) 1415 | { 1416 | const unsigned char *p_src = src; 1417 | const unsigned char *const src_end = src + src_len; 1418 | unsigned char *p_dst = dst; 1419 | unsigned char *dst_end = dst + dst_len; 1420 | struct decode_status status = { 0, 1 }; 1421 | 1422 | while (p_src != src_end) 1423 | { 1424 | if (p_dst == dst_end) 1425 | return LSHPACK_ERR_MORE_BUF; 1426 | if ((p_dst = hdec_huff_dec4bits(*p_src >> 4, p_dst, &status)) 1427 | == NULL) 1428 | return -1; 1429 | if (p_dst == dst_end) 1430 | return LSHPACK_ERR_MORE_BUF; 1431 | if ((p_dst = hdec_huff_dec4bits(*p_src & 0xf, p_dst, &status)) 1432 | == NULL) 1433 | return -1; 1434 | ++p_src; 1435 | } 1436 | 1437 | if (!status.eos) 1438 | return -1; 1439 | 1440 | return p_dst - dst; 1441 | } 1442 | 1443 | 1444 | int 1445 | lshpack_dec_huff_decode (const unsigned char *src, int src_len, 1446 | unsigned char *dst, int dst_len); 1447 | 1448 | 1449 | //reutrn the length in the dst, also update the src 1450 | #if !LS_HPACK_EMIT_TEST_CODE 1451 | static 1452 | #endif 1453 | int 1454 | hdec_dec_str (unsigned char *dst, size_t dst_len, const unsigned char **src, 1455 | const unsigned char *src_end) 1456 | { 1457 | if ((*src) == src_end) 1458 | return 0; 1459 | 1460 | int is_huffman = (*(*src) & 0x80); 1461 | uint32_t len; 1462 | if (0 != lshpack_dec_dec_int(src, src_end, 7, &len)) 1463 | return LSHPACK_ERR_BAD_DATA; //wrong int 1464 | 1465 | int ret = 0; 1466 | if ((uint32_t)(src_end - (*src)) < len) { 1467 | return LSHPACK_ERR_BAD_DATA; //wrong int 1468 | } 1469 | 1470 | if (is_huffman) 1471 | { 1472 | ret = lshpack_dec_huff_decode(*src, len, dst, dst_len); 1473 | if (ret < 0) 1474 | return ret; //Wrong code 1475 | 1476 | (*src) += len; 1477 | } 1478 | else 1479 | { 1480 | if (dst_len < len) 1481 | { 1482 | ret = dst_len - len; 1483 | if (ret > LSHPACK_ERR_MORE_BUF) 1484 | ret = LSHPACK_ERR_MORE_BUF; //dst not enough space 1485 | } 1486 | else 1487 | { 1488 | memcpy(dst, (*src), len); 1489 | (*src) += len; 1490 | ret = len; 1491 | } 1492 | } 1493 | 1494 | return ret; 1495 | } 1496 | 1497 | 1498 | /* hpd_dyn_table is a dynamic array. New entries are pushed onto it, 1499 | * while old entries are shifted from it. 1500 | */ 1501 | static struct dec_table_entry * 1502 | hdec_get_table_entry (struct lshpack_dec *dec, uint32_t index) 1503 | { 1504 | uintptr_t val; 1505 | 1506 | index -= HPACK_STATIC_TABLE_SIZE; 1507 | if (index == 0 || index > lshpack_arr_count(&dec->hpd_dyn_table)) 1508 | return NULL; 1509 | 1510 | index = lshpack_arr_count(&dec->hpd_dyn_table) - index; 1511 | val = lshpack_arr_get(&dec->hpd_dyn_table, index); 1512 | return (struct dec_table_entry *) val; 1513 | } 1514 | 1515 | 1516 | #if !LS_HPACK_EMIT_TEST_CODE 1517 | static 1518 | #endif 1519 | int 1520 | lshpack_dec_push_entry (struct lshpack_dec *dec, 1521 | const struct lsxpack_header *xhdr) 1522 | { 1523 | struct dec_table_entry *entry; 1524 | unsigned name_len, val_len; 1525 | size_t size; 1526 | 1527 | name_len = xhdr->name_len; 1528 | val_len = xhdr->val_len; 1529 | 1530 | size = sizeof(*entry) + name_len + val_len; 1531 | entry = malloc(size); 1532 | if (!entry) 1533 | return -1; 1534 | 1535 | if (0 != lshpack_arr_push(&dec->hpd_dyn_table, (uintptr_t) entry)) 1536 | { 1537 | free(entry); 1538 | return -1; 1539 | } 1540 | ++dec->hpd_state; 1541 | dec->hpd_cur_capacity += DYNAMIC_ENTRY_OVERHEAD + name_len + val_len; 1542 | entry->dte_name_len = name_len; 1543 | entry->dte_val_len = val_len; 1544 | entry->dte_name_idx = xhdr->hpack_index; 1545 | #if LSHPACK_DEC_CALC_HASH 1546 | entry->dte_flags = xhdr->flags & (LSXPACK_NAME_HASH|LSXPACK_NAMEVAL_HASH); 1547 | entry->dte_name_hash = xhdr->name_hash; 1548 | entry->dte_nameval_hash = xhdr->nameval_hash; 1549 | #endif 1550 | memcpy(DTE_NAME(entry), lsxpack_header_get_name(xhdr), name_len); 1551 | memcpy(DTE_VALUE(entry), lsxpack_header_get_value(xhdr), val_len); 1552 | 1553 | hdec_remove_overflow_entries(dec); 1554 | return 0; 1555 | } 1556 | 1557 | 1558 | static int 1559 | lshpack_dec_copy_value (lsxpack_header_t *output, char *dest, const char *val, 1560 | unsigned val_len) 1561 | { 1562 | if (val_len + LSHPACK_DEC_HTTP1X_EXTRA > (unsigned)output->val_len) 1563 | return LSHPACK_ERR_MORE_BUF; 1564 | output->val_offset = output->name_offset + output->name_len 1565 | + LSHPACK_DEC_HTTP1X_EXTRA; 1566 | 1567 | assert(dest == output->buf + output->val_offset); 1568 | output->val_len = val_len; 1569 | memcpy(dest, val, output->val_len); 1570 | dest += output->val_len; 1571 | #if LSHPACK_DEC_HTTP1X_OUTPUT 1572 | *dest++ = '\r'; 1573 | *dest++ = '\n'; 1574 | #endif 1575 | return 0; 1576 | } 1577 | 1578 | 1579 | static int 1580 | lshpack_dec_copy_name (lsxpack_header_t *output, char **dest, const char *name, 1581 | unsigned name_len) 1582 | { 1583 | if (name_len + LSHPACK_DEC_HTTP1X_EXTRA > (unsigned)output->val_len) 1584 | return LSHPACK_ERR_MORE_BUF; 1585 | output->val_len -= name_len + LSHPACK_DEC_HTTP1X_EXTRA; 1586 | output->name_len = name_len; 1587 | memcpy(*dest, name, name_len); 1588 | *dest += name_len; 1589 | #if LSHPACK_DEC_HTTP1X_OUTPUT 1590 | *(*dest)++ = ':'; 1591 | *(*dest)++ = ' '; 1592 | #endif 1593 | return 0; 1594 | } 1595 | 1596 | 1597 | enum 1598 | { 1599 | LSHPACK_ADD_INDEX = 0, 1600 | LSHPACK_NO_INDEX = 1, 1601 | LSHPACK_NEVER_INDEX = 2, 1602 | LSHPACK_VAL_INDEX = 3, 1603 | }; 1604 | 1605 | 1606 | int 1607 | lshpack_dec_decode (struct lshpack_dec *dec, 1608 | const unsigned char **src, const unsigned char *src_end, 1609 | struct lsxpack_header *output) 1610 | { 1611 | struct dec_table_entry *entry; 1612 | uint32_t index, new_capacity; 1613 | int indexed_type, len; 1614 | const unsigned char *s; 1615 | size_t buf_len = output->val_len; 1616 | size_t extra_buf = 0; 1617 | 1618 | if ((*src) == src_end) 1619 | return LSHPACK_ERR_BAD_DATA; 1620 | 1621 | buf_len = output->val_len; 1622 | extra_buf = 0; 1623 | s = *src; 1624 | while ((*s & 0xe0) == 0x20) //001 xxxxx 1625 | { 1626 | if (0 != lshpack_dec_dec_int(&s, src_end, 5, &new_capacity)) 1627 | return LSHPACK_ERR_BAD_DATA; 1628 | if (new_capacity > dec->hpd_max_capacity) 1629 | return LSHPACK_ERR_BAD_DATA; 1630 | hdec_update_max_capacity(dec, new_capacity); 1631 | if (s == src_end) 1632 | return LSHPACK_ERR_BAD_DATA; 1633 | } 1634 | 1635 | /* lshpack_dec_dec_int() sets `index' and advances `src'. If we do not 1636 | * call it, we set `index' and advance `src' ourselves: 1637 | */ 1638 | if (*s & 0x80) //1 xxxxxxx 1639 | { 1640 | if (0 != lshpack_dec_dec_int(&s, src_end, 7, &index)) 1641 | return LSHPACK_ERR_BAD_DATA; 1642 | if (index == 0) 1643 | return LSHPACK_ERR_BAD_DATA; 1644 | indexed_type = LSHPACK_VAL_INDEX; //need to parse value 1645 | } 1646 | else if (*s > 0x40) //01 xxxxxx 1647 | { 1648 | if (0 != lshpack_dec_dec_int(&s, src_end, 6, &index)) 1649 | return LSHPACK_ERR_BAD_DATA; 1650 | 1651 | indexed_type = LSHPACK_ADD_INDEX; 1652 | } 1653 | else if (*s == 0x40) //custmized //0100 0000 1654 | { 1655 | indexed_type = LSHPACK_ADD_INDEX; 1656 | index = LSHPACK_HDR_UNKNOWN; 1657 | ++s; 1658 | } 1659 | 1660 | //Never indexed 1661 | else if (*s == 0x10) //00010000 1662 | { 1663 | indexed_type = LSHPACK_NEVER_INDEX; 1664 | output->flags |= LSXPACK_NEVER_INDEX; 1665 | index = LSHPACK_HDR_UNKNOWN; 1666 | ++s; 1667 | } 1668 | else if ((*s & 0xf0) == 0x10) //0001 xxxx 1669 | { 1670 | if (0 != lshpack_dec_dec_int(&s, src_end, 4, &index)) 1671 | return LSHPACK_ERR_BAD_DATA; 1672 | 1673 | indexed_type = LSHPACK_NEVER_INDEX; 1674 | output->flags |= LSXPACK_NEVER_INDEX; 1675 | } 1676 | 1677 | //without indexed 1678 | else if (*s == 0x00) //0000 0000 1679 | { 1680 | indexed_type = LSHPACK_NO_INDEX; 1681 | index = LSHPACK_HDR_UNKNOWN; 1682 | ++s; 1683 | } 1684 | else // 0000 xxxx 1685 | { 1686 | if (0 != lshpack_dec_dec_int(&s, src_end, 4, &index)) 1687 | return LSHPACK_ERR_BAD_DATA; 1688 | 1689 | indexed_type = LSHPACK_NO_INDEX; 1690 | } 1691 | 1692 | if (index == LSHPACK_HDR_UNKNOWN && s == src_end) 1693 | { 1694 | return LSHPACK_ERR_BAD_DATA; 1695 | } 1696 | 1697 | if (index != LSHPACK_HDR_UNKNOWN && index <= LSHPACK_HDR_WWW_AUTHENTICATE) 1698 | { 1699 | output->hpack_index = index; 1700 | } 1701 | 1702 | char *name = output->buf + output->name_offset; 1703 | if (index > 0) 1704 | { 1705 | if (index <= HPACK_STATIC_TABLE_SIZE) //static table 1706 | { 1707 | if (lshpack_dec_copy_name(output, &name, 1708 | static_table[index - 1].name, 1709 | static_table[index - 1].name_len) == LSHPACK_ERR_MORE_BUF) 1710 | { 1711 | extra_buf = static_table[index - 1].name_len 1712 | + LSHPACK_DEC_HTTP1X_EXTRA; 1713 | goto need_more_buf; 1714 | } 1715 | output->flags |= LSXPACK_NAME_HASH; 1716 | output->name_hash = static_table_name_hash[index - 1]; 1717 | 1718 | if (indexed_type == LSHPACK_VAL_INDEX) 1719 | { 1720 | if (lshpack_dec_copy_value(output, name, 1721 | static_table[index - 1].val, 1722 | static_table[index - 1].val_len) == 0) 1723 | { 1724 | output->flags |= LSXPACK_NAMEVAL_HASH; 1725 | output->nameval_hash = static_table_nameval_hash[index - 1]; 1726 | goto decode_end; 1727 | } 1728 | else 1729 | { 1730 | extra_buf = static_table[index - 1].val_len 1731 | + LSHPACK_DEC_HTTP1X_EXTRA; 1732 | goto need_more_buf; 1733 | } 1734 | } 1735 | } 1736 | else 1737 | { 1738 | entry = hdec_get_table_entry(dec, index); 1739 | if (entry == NULL) 1740 | return LSHPACK_ERR_BAD_DATA; 1741 | if (lshpack_dec_copy_name(output, &name, DTE_NAME(entry), 1742 | entry->dte_name_len) == LSHPACK_ERR_MORE_BUF) 1743 | { 1744 | extra_buf = entry->dte_name_len + LSHPACK_DEC_HTTP1X_EXTRA; 1745 | goto need_more_buf; 1746 | } 1747 | 1748 | if (entry->dte_name_idx) 1749 | output->hpack_index = entry->dte_name_idx; 1750 | else 1751 | output->hpack_index = LSHPACK_HDR_UNKNOWN; 1752 | #if LSHPACK_DEC_CALC_HASH 1753 | output->flags |= entry->dte_flags & DTEF_NAME_HASH; 1754 | output->name_hash = entry->dte_name_hash; 1755 | #endif 1756 | if (indexed_type == LSHPACK_VAL_INDEX) 1757 | { 1758 | if (lshpack_dec_copy_value(output, name, DTE_VALUE(entry), 1759 | entry->dte_val_len) == 0) 1760 | { 1761 | #if LSHPACK_DEC_CALC_HASH 1762 | output->flags |= entry->dte_flags & DTEF_NAMEVAL_HASH; 1763 | output->nameval_hash = entry->dte_nameval_hash; 1764 | #endif 1765 | goto decode_end; 1766 | } 1767 | else 1768 | { 1769 | extra_buf = entry->dte_val_len + LSHPACK_DEC_HTTP1X_EXTRA; 1770 | goto need_more_buf; 1771 | } 1772 | } 1773 | } 1774 | } 1775 | else 1776 | { 1777 | len = hdec_dec_str((unsigned char *)name, output->val_len, 1778 | &s, src_end); 1779 | if (len < 0) 1780 | { 1781 | if (len <= LSHPACK_ERR_MORE_BUF) 1782 | { 1783 | extra_buf = -len; 1784 | goto need_more_buf; 1785 | } 1786 | return len; //error 1787 | } 1788 | if (len > UINT16_MAX) 1789 | return LSHPACK_ERR_TOO_LARGE; 1790 | while(len > 0 && isspace(*(name + len - 1))) 1791 | --len; 1792 | if (len == 0) 1793 | return LSHPACK_ERR_BAD_DATA; 1794 | 1795 | #if LSHPACK_DEC_CALC_HASH 1796 | output->flags |= LSXPACK_NAME_HASH; 1797 | output->name_hash = XXH32(name, (size_t) len, LSHPACK_XXH_SEED); 1798 | #endif 1799 | output->name_len = len; 1800 | name += output->name_len; 1801 | #if LSHPACK_DEC_HTTP1X_OUTPUT 1802 | if (output->name_len + 2 <= output->val_len) 1803 | { 1804 | *name++ = ':'; 1805 | *name++ = ' '; 1806 | } 1807 | else 1808 | { 1809 | extra_buf = 2; 1810 | goto need_more_buf; 1811 | } 1812 | #endif 1813 | output->val_len -= len + LSHPACK_DEC_HTTP1X_EXTRA; 1814 | } 1815 | 1816 | len = hdec_dec_str((unsigned char *)name, output->val_len, &s, src_end); 1817 | if (len < 0) 1818 | { 1819 | if (len <= LSHPACK_ERR_MORE_BUF) 1820 | { 1821 | extra_buf = -len; 1822 | goto need_more_buf; 1823 | } 1824 | return len; //error 1825 | } 1826 | if (len > UINT16_MAX) 1827 | return LSHPACK_ERR_TOO_LARGE; 1828 | #if LSHPACK_DEC_CALC_HASH 1829 | assert(output->flags & LSXPACK_NAME_HASH); 1830 | output->flags |= LSXPACK_NAMEVAL_HASH; 1831 | output->nameval_hash = XXH32(name, (size_t) len, output->name_hash); 1832 | #endif 1833 | #if LSHPACK_DEC_HTTP1X_OUTPUT 1834 | if ((unsigned) len + 2 <= output->val_len) 1835 | memcpy(name + len, "\r\n", 2); 1836 | else 1837 | { 1838 | extra_buf = 2; 1839 | goto need_more_buf; 1840 | } 1841 | #endif 1842 | output->val_offset = output->name_offset + output->name_len 1843 | + LSHPACK_DEC_HTTP1X_EXTRA; 1844 | output->val_len = len; 1845 | 1846 | if (indexed_type == LSHPACK_ADD_INDEX && 1847 | 0 != lshpack_dec_push_entry(dec, output)) 1848 | return LSHPACK_ERR_BAD_DATA; //error 1849 | decode_end: 1850 | *src = s; 1851 | #if LSHPACK_DEC_HTTP1X_OUTPUT 1852 | output->dec_overhead = 4; 1853 | #endif 1854 | return 0; 1855 | need_more_buf: 1856 | buf_len += extra_buf; 1857 | output->val_len = buf_len; 1858 | return LSHPACK_ERR_MORE_BUF; 1859 | } 1860 | 1861 | 1862 | #if LS_HPACK_USE_LARGE_TABLES 1863 | #define SHORTEST_CODE 5 1864 | 1865 | 1866 | /* The decoder is optimized for the common case. Most of the time, we decode 1867 | * data whose encoding is 16 bits or shorter. This lets us use a 64 KB table 1868 | * indexed by two bytes of input and outputs 1, 2, or 3 bytes at a time. 1869 | * 1870 | * In the case a longer code is encoutered, we fall back to the original 1871 | * Huffman decoder that supports all code lengths. 1872 | */ 1873 | int 1874 | lshpack_dec_huff_decode (const unsigned char *src, int src_len, 1875 | unsigned char *dst, int dst_len) 1876 | { 1877 | unsigned char *const orig_dst = dst; 1878 | const unsigned char *const src_end = src + src_len; 1879 | unsigned char *const dst_end = dst + dst_len; 1880 | uintptr_t buf; /* OK not to initialize the buffer */ 1881 | unsigned avail_bits, len; 1882 | struct hdec hdec; 1883 | uint16_t idx; 1884 | int r; 1885 | 1886 | #if __GNUC__ 1887 | #pragma GCC diagnostic push 1888 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 1889 | #pragma GCC diagnostic ignored "-Wuninitialized" 1890 | #else 1891 | buf = 0; 1892 | #endif 1893 | 1894 | avail_bits = 0; 1895 | while (1) 1896 | { 1897 | if (src + sizeof(buf) <= src_end) 1898 | { 1899 | len = (sizeof(buf) * 8 - avail_bits) >> 3; 1900 | avail_bits += len << 3; 1901 | switch (len) 1902 | { 1903 | #if UINTPTR_MAX == 18446744073709551615ull 1904 | case 8: 1905 | buf <<= 8; 1906 | buf |= (uintptr_t) *src++; 1907 | FALL_THROUGH; 1908 | case 7: 1909 | buf <<= 8; 1910 | buf |= (uintptr_t) *src++; 1911 | FALL_THROUGH; 1912 | default: 1913 | buf <<= 48; 1914 | buf |= (uintptr_t) *src++ << 40; 1915 | buf |= (uintptr_t) *src++ << 32; 1916 | buf |= (uintptr_t) *src++ << 24; 1917 | buf |= (uintptr_t) *src++ << 16; 1918 | #else 1919 | FALL_THROUGH; 1920 | case 4: 1921 | buf <<= 8; 1922 | buf |= (uintptr_t) *src++; 1923 | FALL_THROUGH; 1924 | case 3: 1925 | buf <<= 8; 1926 | buf |= (uintptr_t) *src++; 1927 | FALL_THROUGH; 1928 | default: 1929 | buf <<= 16; 1930 | #endif 1931 | buf |= (uintptr_t) *src++ << 8; 1932 | buf |= (uintptr_t) *src++ << 0; 1933 | } 1934 | } 1935 | else if (src < src_end) 1936 | do 1937 | { 1938 | buf <<= 8; 1939 | buf |= (uintptr_t) *src++; 1940 | avail_bits += 8; 1941 | } 1942 | while (src < src_end && avail_bits <= sizeof(buf) * 8 - 8); 1943 | else 1944 | break; /* Normal case terminating condition: out of input */ 1945 | 1946 | if (dst_end - dst >= (ptrdiff_t) (8 * sizeof(buf) / SHORTEST_CODE) 1947 | && avail_bits >= 16) 1948 | { 1949 | /* Fast path: don't check destination bounds */ 1950 | do 1951 | { 1952 | idx = buf >> (avail_bits - 16); 1953 | hdec = hdecs[idx]; 1954 | dst[0] = hdec.out[0]; 1955 | dst[1] = hdec.out[1]; 1956 | dst[2] = hdec.out[2]; 1957 | dst += hdec.lens & 3; 1958 | avail_bits -= hdec.lens >> 2; 1959 | } 1960 | while (avail_bits >= 16 && hdec.lens); 1961 | if (avail_bits < 16) 1962 | continue; 1963 | goto slow_path; 1964 | } 1965 | else 1966 | while (avail_bits >= 16) 1967 | { 1968 | idx = buf >> (avail_bits - 16); 1969 | hdec = hdecs[idx]; 1970 | len = hdec.lens & 3; 1971 | if (len && dst + len <= dst_end) 1972 | { 1973 | switch (len) 1974 | { 1975 | case 3: 1976 | *dst++ = hdec.out[0]; 1977 | *dst++ = hdec.out[1]; 1978 | *dst++ = hdec.out[2]; 1979 | break; 1980 | case 2: 1981 | *dst++ = hdec.out[0]; 1982 | *dst++ = hdec.out[1]; 1983 | break; 1984 | default: 1985 | *dst++ = hdec.out[0]; 1986 | break; 1987 | } 1988 | avail_bits -= hdec.lens >> 2; 1989 | } 1990 | else if (dst + len > dst_end) 1991 | { 1992 | r = dst_end - dst - len; 1993 | if (r > LSHPACK_ERR_MORE_BUF) 1994 | r = LSHPACK_ERR_MORE_BUF; 1995 | return r; 1996 | } 1997 | else 1998 | goto slow_path; 1999 | } 2000 | } 2001 | 2002 | if (avail_bits >= SHORTEST_CODE) 2003 | { 2004 | idx = buf << (16 - avail_bits); 2005 | idx |= (1 << (16 - avail_bits)) - 1; /* EOF */ 2006 | if (idx == 0xFFFF && avail_bits < 8) 2007 | goto end; 2008 | /* If a byte or more of input is left, this mean there is a valid 2009 | * encoding, not just EOF. 2010 | */ 2011 | hdec = hdecs[idx]; 2012 | len = hdec.lens & 3; 2013 | if (((unsigned) hdec.lens >> 2) > avail_bits) 2014 | return -1; 2015 | if (len && dst + len <= dst_end) 2016 | { 2017 | switch (len) 2018 | { 2019 | case 3: 2020 | *dst++ = hdec.out[0]; 2021 | *dst++ = hdec.out[1]; 2022 | *dst++ = hdec.out[2]; 2023 | break; 2024 | case 2: 2025 | *dst++ = hdec.out[0]; 2026 | *dst++ = hdec.out[1]; 2027 | break; 2028 | default: 2029 | *dst++ = hdec.out[0]; 2030 | break; 2031 | } 2032 | avail_bits -= hdec.lens >> 2; 2033 | } 2034 | else if (dst + len > dst_end) 2035 | { 2036 | r = dst_end - dst - len; 2037 | if (r > LSHPACK_ERR_MORE_BUF) 2038 | r = LSHPACK_ERR_MORE_BUF; 2039 | return r; 2040 | } 2041 | else 2042 | /* This must be an invalid code, otherwise it would have fit */ 2043 | return -1; 2044 | } 2045 | 2046 | if (avail_bits > 0) 2047 | { 2048 | if (((1u << avail_bits) - 1) != (buf & ((1u << avail_bits) - 1))) 2049 | return -1; /* Not EOF as expected */ 2050 | } 2051 | #if __GNUC__ 2052 | #pragma GCC diagnostic pop 2053 | #endif 2054 | 2055 | end: 2056 | return dst - orig_dst; 2057 | 2058 | slow_path: 2059 | /* Find previous byte boundary and finish decoding thence. */ 2060 | while ((avail_bits & 7) && dst > orig_dst) 2061 | avail_bits += encode_table[ *--dst ].bits; 2062 | assert((avail_bits & 7) == 0); 2063 | src -= avail_bits >> 3; 2064 | r = lshpack_dec_huff_decode_full(src, src_end - src, dst, dst_end - dst); 2065 | if (r >= 0) 2066 | return dst - orig_dst + r; 2067 | else 2068 | return r; 2069 | } 2070 | #endif 2071 | #if __GNUC__ 2072 | #pragma GCC diagnostic pop /* -Wunknown-pragmas */ 2073 | #endif 2074 | -------------------------------------------------------------------------------- /lshpack.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2018 - 2023 LiteSpeed Technologies Inc 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifndef LITESPEED_HPACK_H 26 | #define LITESPEED_HPACK_H 1 27 | 28 | 29 | #include 30 | #include 31 | #include 32 | #include "lsxpack_header.h" 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #define LSHPACK_MAJOR_VERSION 2 39 | #define LSHPACK_MINOR_VERSION 3 40 | #define LSHPACK_PATCH_VERSION 4 41 | 42 | #define lshpack_strlen_t lsxpack_strlen_t 43 | #define LSHPACK_MAX_STRLEN LSXPACK_MAX_STRLEN 44 | 45 | #ifndef LSHPACK_DEC_HTTP1X_OUTPUT 46 | #define LSHPACK_DEC_HTTP1X_OUTPUT 1 47 | #endif 48 | #ifndef LSHPACK_DEC_CALC_HASH 49 | #define LSHPACK_DEC_CALC_HASH 1 50 | #endif 51 | 52 | struct lshpack_enc; 53 | struct lshpack_dec; 54 | 55 | enum lshpack_static_hdr_idx 56 | { 57 | LSHPACK_HDR_UNKNOWN, 58 | LSHPACK_HDR_AUTHORITY, 59 | LSHPACK_HDR_METHOD_GET, 60 | LSHPACK_HDR_METHOD_POST, 61 | LSHPACK_HDR_PATH, 62 | LSHPACK_HDR_PATH_INDEX_HTML, 63 | LSHPACK_HDR_SCHEME_HTTP, 64 | LSHPACK_HDR_SCHEME_HTTPS, 65 | LSHPACK_HDR_STATUS_200, 66 | LSHPACK_HDR_STATUS_204, 67 | LSHPACK_HDR_STATUS_206, 68 | LSHPACK_HDR_STATUS_304, 69 | LSHPACK_HDR_STATUS_400, 70 | LSHPACK_HDR_STATUS_404, 71 | LSHPACK_HDR_STATUS_500, 72 | LSHPACK_HDR_ACCEPT_CHARSET, 73 | LSHPACK_HDR_ACCEPT_ENCODING, 74 | LSHPACK_HDR_ACCEPT_LANGUAGE, 75 | LSHPACK_HDR_ACCEPT_RANGES, 76 | LSHPACK_HDR_ACCEPT, 77 | LSHPACK_HDR_ACCESS_CONTROL_ALLOW_ORIGIN, 78 | LSHPACK_HDR_AGE, 79 | LSHPACK_HDR_ALLOW, 80 | LSHPACK_HDR_AUTHORIZATION, 81 | LSHPACK_HDR_CACHE_CONTROL, 82 | LSHPACK_HDR_CONTENT_DISPOSITION, 83 | LSHPACK_HDR_CONTENT_ENCODING, 84 | LSHPACK_HDR_CONTENT_LANGUAGE, 85 | LSHPACK_HDR_CONTENT_LENGTH, 86 | LSHPACK_HDR_CONTENT_LOCATION, 87 | LSHPACK_HDR_CONTENT_RANGE, 88 | LSHPACK_HDR_CONTENT_TYPE, 89 | LSHPACK_HDR_COOKIE, 90 | LSHPACK_HDR_DATE, 91 | LSHPACK_HDR_ETAG, 92 | LSHPACK_HDR_EXPECT, 93 | LSHPACK_HDR_EXPIRES, 94 | LSHPACK_HDR_FROM, 95 | LSHPACK_HDR_HOST, 96 | LSHPACK_HDR_IF_MATCH, 97 | LSHPACK_HDR_IF_MODIFIED_SINCE, 98 | LSHPACK_HDR_IF_NONE_MATCH, 99 | LSHPACK_HDR_IF_RANGE, 100 | LSHPACK_HDR_IF_UNMODIFIED_SINCE, 101 | LSHPACK_HDR_LAST_MODIFIED, 102 | LSHPACK_HDR_LINK, 103 | LSHPACK_HDR_LOCATION, 104 | LSHPACK_HDR_MAX_FORWARDS, 105 | LSHPACK_HDR_PROXY_AUTHENTICATE, 106 | LSHPACK_HDR_PROXY_AUTHORIZATION, 107 | LSHPACK_HDR_RANGE, 108 | LSHPACK_HDR_REFERER, 109 | LSHPACK_HDR_REFRESH, 110 | LSHPACK_HDR_RETRY_AFTER, 111 | LSHPACK_HDR_SERVER, 112 | LSHPACK_HDR_SET_COOKIE, 113 | LSHPACK_HDR_STRICT_TRANSPORT_SECURITY, 114 | LSHPACK_HDR_TRANSFER_ENCODING, 115 | LSHPACK_HDR_USER_AGENT, 116 | LSHPACK_HDR_VARY, 117 | LSHPACK_HDR_VIA, 118 | LSHPACK_HDR_WWW_AUTHENTICATE, 119 | LSHPACK_HDR_TOBE_INDEXED = 255 120 | }; 121 | 122 | #define LSHPACK_MAX_INDEX 61 123 | 124 | #define LSHPACK_ERR_MORE_BUF (-3) 125 | #define LSHPACK_ERR_TOO_LARGE (-2) 126 | #define LSHPACK_ERR_BAD_DATA (-1) 127 | #define LSHPACK_OK (0) 128 | 129 | /** 130 | * Initialization routine allocates memory. -1 is returned if memory 131 | * could not be allocated. 0 is returned on success. 132 | */ 133 | int 134 | lshpack_enc_init (struct lshpack_enc *); 135 | 136 | /** 137 | * Clean up HPACK encoder, freeing all allocated memory. 138 | */ 139 | void 140 | lshpack_enc_cleanup (struct lshpack_enc *); 141 | 142 | /** 143 | * @brief Encode one name/value pair 144 | * 145 | * @param[in,out] henc - A pointer to a valid HPACK API struct 146 | * @param[out] dst - A pointer to destination buffer 147 | * @param[out] dst_end - A pointer to end of destination buffer 148 | * @param[in] input - Header to encode 149 | * 150 | * @return The (possibly advanced) dst pointer. If the destination 151 | * pointer was not advanced, an error must have occurred. 152 | */ 153 | unsigned char * 154 | lshpack_enc_encode (struct lshpack_enc *henc, unsigned char *dst, 155 | unsigned char *dst_end, struct lsxpack_header *input); 156 | 157 | void 158 | lshpack_enc_set_max_capacity (struct lshpack_enc *, unsigned); 159 | 160 | /** 161 | * Turn history on or off. Turning history on may fail (malloc), in 162 | * which case -1 is returned. 163 | */ 164 | int 165 | lshpack_enc_use_hist (struct lshpack_enc *, int on); 166 | 167 | /** 168 | * Return true if history is used, false otherwise. By default, 169 | * history is off. 170 | */ 171 | int 172 | lshpack_enc_hist_used (const struct lshpack_enc *); 173 | 174 | /** 175 | * Initialize HPACK decoder structure. 176 | */ 177 | void 178 | lshpack_dec_init (struct lshpack_dec *); 179 | 180 | /** 181 | * Clean up HPACK decoder structure, freeing all allocated memory. 182 | */ 183 | void 184 | lshpack_dec_cleanup (struct lshpack_dec *); 185 | 186 | /* 187 | * Returns 0 on success, a negative value on failure. 188 | * 189 | * If 0 is returned, `src' is advanced. Calling with a zero-length input 190 | * buffer results in an error. 191 | * 192 | * To calculate number of bytes written to the output buffer: 193 | * output->name_len + output->val_len + lshpack_dec_extra_bytes(dec) 194 | */ 195 | int 196 | lshpack_dec_decode (struct lshpack_dec *dec, 197 | const unsigned char **src, const unsigned char *src_end, 198 | struct lsxpack_header *output); 199 | 200 | /* Return number of extra bytes per header */ 201 | #if LSHPACK_DEC_HTTP1X_OUTPUT 202 | #define LSHPACK_DEC_HTTP1X_EXTRA (2) 203 | #define lshpack_dec_extra_bytes(dec_) (4) 204 | #else 205 | #define LSHPACK_DEC_HTTP1X_EXTRA (0) 206 | #define lshpack_dec_extra_bytes(dec_) (0) 207 | #endif 208 | 209 | void 210 | lshpack_dec_set_max_capacity (struct lshpack_dec *, unsigned); 211 | 212 | /* Some internals follow. Struct definitions are exposed to save a malloc. 213 | * These structures are not very complicated. 214 | */ 215 | 216 | #ifdef __OpenBSD__ 217 | #define STAILQ_HEAD SIMPLEQ_HEAD 218 | #define STAILQ_ENTRY SIMPLEQ_ENTRY 219 | #define STAILQ_INIT SIMPLEQ_INIT 220 | #define STAILQ_INSERT_TAIL SIMPLEQ_INSERT_TAIL 221 | #define STAILQ_EMPTY SIMPLEQ_EMPTY 222 | #define STAILQ_FIRST SIMPLEQ_FIRST 223 | #define STAILQ_NEXT SIMPLEQ_NEXT 224 | #define STAILQ_REMOVE_HEAD SIMPLEQ_REMOVE_HEAD 225 | #define STAILQ_FOREACH SIMPLEQ_FOREACH 226 | #endif 227 | 228 | #ifndef STAILQ_FOREACH 229 | #define STAILQ_FOREACH(var, head, field) \ 230 | for((var) = STAILQ_FIRST((head)); \ 231 | (var); \ 232 | (var) = STAILQ_NEXT((var), field)) 233 | #endif 234 | 235 | struct lshpack_enc_table_entry; 236 | 237 | STAILQ_HEAD(lshpack_enc_head, lshpack_enc_table_entry); 238 | struct lshpack_double_enc_head; 239 | 240 | struct lshpack_enc 241 | { 242 | unsigned hpe_cur_capacity; 243 | unsigned hpe_max_capacity; 244 | 245 | /* Each new dynamic table entry gets the next number. It is used to 246 | * calculate the entry's position in the decoder table without having 247 | * to maintain an actual array. 248 | */ 249 | unsigned hpe_next_id; 250 | 251 | /* Dynamic table entries (struct enc_table_entry) live in two hash 252 | * tables: name/value hash table and name hash table. These tables 253 | * are the same size. 254 | */ 255 | unsigned hpe_nelem; 256 | unsigned hpe_nbits; 257 | struct lshpack_enc_head 258 | hpe_all_entries; 259 | struct lshpack_double_enc_head 260 | *hpe_buckets; 261 | 262 | uint32_t *hpe_hist_buf; 263 | unsigned hpe_hist_size, hpe_hist_idx; 264 | int hpe_hist_wrapped; 265 | enum { 266 | LSHPACK_ENC_USE_HIST = 1 << 0, 267 | } hpe_flags; 268 | }; 269 | 270 | struct lshpack_arr 271 | { 272 | unsigned nalloc, 273 | nelem, 274 | off; 275 | uintptr_t *els; 276 | }; 277 | 278 | struct lshpack_dec 279 | { 280 | struct lshpack_arr hpd_dyn_table; 281 | unsigned hpd_max_capacity; /* Maximum set by caller */ 282 | unsigned hpd_cur_max_capacity; /* Adjusted at runtime */ 283 | unsigned hpd_cur_capacity; 284 | unsigned hpd_state; 285 | }; 286 | 287 | /* This function may update hash values and flags */ 288 | unsigned 289 | lshpack_enc_get_stx_tab_id (struct lsxpack_header *); 290 | 291 | #ifdef __cplusplus 292 | } 293 | #endif 294 | 295 | #endif 296 | -------------------------------------------------------------------------------- /lsxpack_header.h: -------------------------------------------------------------------------------- 1 | #ifndef LSXPACK_HEADER_H_v208 2 | #define LSXPACK_HEADER_H_v208 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #ifndef LSXPACK_MAX_STRLEN 13 | #define LSXPACK_MAX_STRLEN UINT16_MAX 14 | #endif 15 | 16 | typedef int32_t lsxpack_offset_t; 17 | #if LSXPACK_MAX_STRLEN == UINT16_MAX 18 | typedef uint16_t lsxpack_strlen_t; 19 | #elif LSXPACK_MAX_STRLEN == UINT32_MAX 20 | typedef uint32_t lsxpack_strlen_t; 21 | #else 22 | #error unexpected LSXPACK_MAX_STRLEN 23 | #endif 24 | 25 | #define LSXPACK_DEL ((char *)NULL) 26 | 27 | enum lsxpack_flag 28 | { 29 | LSXPACK_HPACK_VAL_MATCHED = 1, 30 | LSXPACK_QPACK_IDX = 2, 31 | LSXPACK_APP_IDX = 4, 32 | LSXPACK_NAME_HASH = 8, 33 | LSXPACK_NAMEVAL_HASH = 16, 34 | LSXPACK_VAL_MATCHED = 32, 35 | LSXPACK_NEVER_INDEX = 64, 36 | }; 37 | 38 | /** 39 | * When header are decoded, it should be stored to @buf starting from @name_offset, 40 | * : \r\n 41 | * So, it can be used directly as HTTP/1.1 header. there are 4 extra characters 42 | * added. 43 | * 44 | * limitation: we currently does not support total header size > 64KB. 45 | */ 46 | 47 | struct lsxpack_header 48 | { 49 | char *buf; /* the buffer for headers */ 50 | uint32_t name_hash; /* hash value for name */ 51 | uint32_t nameval_hash; /* hash value for name + value */ 52 | lsxpack_offset_t name_offset; /* the offset for name in the buffer */ 53 | lsxpack_offset_t val_offset; /* the offset for value in the buffer */ 54 | lsxpack_strlen_t name_len; /* the length of name */ 55 | lsxpack_strlen_t val_len; /* the length of value */ 56 | uint16_t chain_next_idx; /* mainly for cookie value chain */ 57 | uint8_t hpack_index; /* HPACK static table index */ 58 | uint8_t qpack_index; /* QPACK static table index */ 59 | uint8_t app_index; /* APP header index */ 60 | enum lsxpack_flag flags:8; /* combination of lsxpack_flag */ 61 | uint8_t indexed_type; /* control to disable index or not */ 62 | uint8_t dec_overhead; /* num of extra bytes written to decoded buffer */ 63 | }; 64 | 65 | typedef struct lsxpack_header lsxpack_header_t; 66 | 67 | 68 | static inline void 69 | lsxpack_header_set_idx(lsxpack_header_t *hdr, int hpack_idx, 70 | const char *val, size_t val_len) 71 | { 72 | memset(hdr, 0, sizeof(*hdr)); 73 | hdr->buf = (char *)val; 74 | hdr->hpack_index = (uint8_t)hpack_idx; 75 | assert(hpack_idx != 0); 76 | assert(val_len <= LSXPACK_MAX_STRLEN); 77 | hdr->val_len = (lsxpack_strlen_t)val_len; 78 | } 79 | 80 | 81 | static inline void 82 | lsxpack_header_set_qpack_idx(lsxpack_header_t *hdr, int qpack_idx, 83 | const char *val, size_t val_len) 84 | { 85 | memset(hdr, 0, sizeof(*hdr)); 86 | hdr->buf = (char *)val; 87 | hdr->qpack_index = (uint8_t)qpack_idx; 88 | assert(qpack_idx != -1); 89 | hdr->flags = LSXPACK_QPACK_IDX; 90 | assert(val_len <= LSXPACK_MAX_STRLEN); 91 | hdr->val_len = (lsxpack_strlen_t)val_len; 92 | } 93 | 94 | 95 | static inline void 96 | lsxpack_header_set_offset(lsxpack_header_t *hdr, const char *buf, 97 | size_t name_offset, size_t name_len, 98 | size_t val_len) 99 | { 100 | memset(hdr, 0, sizeof(*hdr)); 101 | hdr->buf = (char *)buf; 102 | hdr->name_offset = (lsxpack_offset_t)name_offset; 103 | assert(name_len <= LSXPACK_MAX_STRLEN); 104 | hdr->name_len = (lsxpack_strlen_t)name_len; 105 | assert(name_offset + name_len + 2 <= LSXPACK_MAX_STRLEN); 106 | hdr->val_offset = (lsxpack_offset_t)(name_offset + name_len + 2); 107 | assert(val_len <= LSXPACK_MAX_STRLEN); 108 | hdr->val_len = (lsxpack_strlen_t)val_len; 109 | } 110 | 111 | 112 | static inline void 113 | lsxpack_header_set_offset2(lsxpack_header_t *hdr, const char *buf, 114 | size_t name_offset, size_t name_len, 115 | size_t val_offset, size_t val_len) 116 | { 117 | memset(hdr, 0, sizeof(*hdr)); 118 | hdr->buf = (char *)buf; 119 | hdr->name_offset = (lsxpack_offset_t)name_offset; 120 | assert(name_len <= LSXPACK_MAX_STRLEN); 121 | hdr->name_len = (lsxpack_strlen_t)name_len; 122 | assert(val_offset <= LSXPACK_MAX_STRLEN); 123 | hdr->val_offset = (lsxpack_offset_t)val_offset; 124 | assert(val_len <= LSXPACK_MAX_STRLEN); 125 | hdr->val_len = (lsxpack_strlen_t)val_len; 126 | } 127 | 128 | 129 | static inline void 130 | lsxpack_header_prepare_decode(lsxpack_header_t *hdr, 131 | char *out, size_t offset, size_t len) 132 | { 133 | memset(hdr, 0, sizeof(*hdr)); 134 | hdr->buf = out; 135 | assert(offset <= LSXPACK_MAX_STRLEN); 136 | hdr->name_offset = (lsxpack_offset_t)offset; 137 | if (len > LSXPACK_MAX_STRLEN) 138 | hdr->val_len = LSXPACK_MAX_STRLEN; 139 | else 140 | hdr->val_len = (lsxpack_strlen_t)len; 141 | } 142 | 143 | 144 | static inline const char * 145 | lsxpack_header_get_name(const lsxpack_header_t *hdr) 146 | { 147 | return (hdr->name_len)? hdr->buf + hdr->name_offset : NULL; 148 | } 149 | 150 | 151 | static inline const char * 152 | lsxpack_header_get_value(const lsxpack_header_t *hdr) 153 | { return hdr->buf + hdr->val_offset; } 154 | 155 | static inline size_t 156 | lsxpack_header_get_dec_size(const lsxpack_header_t *hdr) 157 | { return hdr->name_len + hdr->val_len + hdr->dec_overhead; } 158 | 159 | static inline void 160 | lsxpack_header_mark_val_changed(lsxpack_header_t *hdr) 161 | { 162 | hdr->flags = (enum lsxpack_flag)(hdr->flags & 163 | ~(LSXPACK_HPACK_VAL_MATCHED|LSXPACK_VAL_MATCHED|LSXPACK_NAMEVAL_HASH)); 164 | } 165 | #ifdef __cplusplus 166 | } 167 | #endif 168 | 169 | #endif //LSXPACK_HEADER_H_v208 170 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ENABLE_TESTING() 2 | 3 | FOREACH(HASH 0 1) 4 | FOREACH(HTTP 0 1) 5 | ADD_EXECUTABLE(test_hpack_hash${HASH}_http${HTTP} test_hpack.c ../lshpack.c ../deps/xxhash/xxhash.c) 6 | SET_TARGET_PROPERTIES(test_hpack_hash${HASH}_http${HTTP} 7 | PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -DLSHPACK_DEC_HTTP1X_OUTPUT=${HTTP} -DLSHPACK_DEC_CALC_HASH=${HASH}") 8 | ADD_TEST(hpack-hash${HASH}-http${HTTP} test_hpack_hash${HASH}_http${HTTP}) 9 | ENDFOREACH(HTTP) 10 | ENDFOREACH(HASH) 11 | 12 | ADD_EXECUTABLE(test_int test_int.c ../deps/xxhash/xxhash.c) 13 | TARGET_LINK_LIBRARIES(test_int ls-hpack) 14 | ADD_TEST(int test_int) 15 | -------------------------------------------------------------------------------- /test/lshpack-test.h: -------------------------------------------------------------------------------- 1 | #ifndef LITESPEED_HPACK_TEST_H 2 | #define LITESPEED_HPACK_TEST_H 1 3 | 4 | #define LSHPACK_XXH_SEED 39378473 5 | 6 | struct lsxpack_header; 7 | 8 | struct enc_dyn_table_entry 9 | { 10 | const char *name, /* Not NUL-terminated */ 11 | *value; /* Not NUL-terminated */ 12 | unsigned name_len, 13 | value_len; 14 | unsigned entry_id; 15 | }; 16 | 17 | unsigned 18 | lshpack_enc_get_static_name (const struct lsxpack_header *); 19 | 20 | unsigned 21 | lshpack_enc_get_static_nameval (const struct lsxpack_header *); 22 | 23 | int 24 | lshpack_enc_push_entry (struct lshpack_enc *enc, const struct lsxpack_header *); 25 | 26 | int 27 | lshpack_enc_enc_str (unsigned char *const dst, size_t dst_len, 28 | const unsigned char *str, unsigned str_len); 29 | 30 | typedef void * enc_iter_t; 31 | 32 | void 33 | lshpack_enc_iter_init (struct lshpack_enc *enc, void **iter); 34 | 35 | /* Returns 0 if entry is found */ 36 | int 37 | lshpack_enc_iter_next (struct lshpack_enc *enc, void **iter, 38 | struct enc_dyn_table_entry *); 39 | 40 | int 41 | lshpack_dec_dec_int (const unsigned char **src, const unsigned char *src_end, 42 | unsigned prefix_bits, uint32_t *value); 43 | int 44 | lshpack_dec_push_entry (struct lshpack_dec *dec, 45 | const struct lsxpack_header *xhdr); 46 | 47 | unsigned char * 48 | lshpack_enc_enc_int (unsigned char *dst, unsigned char *const end, uint32_t value, 49 | uint8_t prefix_bits); 50 | 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /test/test_int.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "lshpack.h" 7 | #include "lshpack-test.h" 8 | 9 | struct int_test 10 | { 11 | int it_lineno; 12 | unsigned it_prefix_bits; 13 | unsigned char it_encoded[20]; 14 | size_t it_enc_sz; 15 | uint32_t it_decoded; 16 | int it_dec_retval; 17 | }; 18 | 19 | static const struct int_test tests[] = 20 | { 21 | 22 | { .it_lineno = __LINE__, 23 | .it_prefix_bits = 7, 24 | .it_encoded = { 0x7F, 0x02, }, 25 | .it_enc_sz = 2, 26 | .it_decoded = 0x81, 27 | .it_dec_retval = 0, 28 | }, 29 | 30 | /* RFC 7541, Appendinx C.1.1 */ 31 | { .it_lineno = __LINE__, 32 | .it_prefix_bits = 5, 33 | .it_encoded = { 0b1010, 0x02, }, 34 | .it_enc_sz = 1, 35 | .it_decoded = 10, 36 | .it_dec_retval = 0, 37 | }, 38 | 39 | /* RFC 7541, Appendinx C.1.2 */ 40 | { .it_lineno = __LINE__, 41 | .it_prefix_bits = 5, 42 | .it_encoded = { 0b11111, 0b10011010, 0b00001010, }, 43 | .it_enc_sz = 3, 44 | .it_decoded = 1337, 45 | .it_dec_retval = 0, 46 | }, 47 | 48 | /* RFC 7541, Appendinx C.1.3 */ 49 | { .it_lineno = __LINE__, 50 | .it_prefix_bits = 8, 51 | .it_encoded = { 0b101010, }, 52 | .it_enc_sz = 1, 53 | .it_decoded = 42, 54 | .it_dec_retval = 0, 55 | }, 56 | 57 | { .it_lineno = __LINE__, 58 | .it_prefix_bits = 7, 59 | .it_encoded = { 0b01111111, 0b10000001, 0b10000010, 0b00000011, }, 60 | .it_enc_sz = 4, 61 | /* 01234560123456 */ 62 | .it_decoded = 0b1100000100000001 + 0b1111111, 63 | .it_dec_retval = 0, 64 | }, 65 | 66 | { .it_lineno = __LINE__, 67 | .it_prefix_bits = 7, 68 | .it_encoded = { 0b01111111, 0b10000001, 0b10000010, 0b10000011, 69 | 0b00000011, }, 70 | .it_enc_sz = 5, 71 | /* 012345601234560123456 */ 72 | .it_decoded = 0b11000001100000100000001 + 0b1111111, 73 | .it_dec_retval = 0, 74 | }, 75 | 76 | { .it_lineno = __LINE__, 77 | .it_prefix_bits = 7, 78 | .it_encoded = { 0b01111111, 0b10000000, 0b11111111, 0b11111111, 79 | 0b11111111, 0b00001111, }, 80 | .it_enc_sz = 6, 81 | .it_decoded = UINT32_MAX, 82 | .it_dec_retval = 0, 83 | }, 84 | 85 | { .it_lineno = __LINE__, 86 | .it_prefix_bits = 7, 87 | /* Same as above, but with extra bit that overflows it */ 88 | /* ----v---- */ 89 | .it_encoded = { 0b01111111, 0b10010000, 0b11111111, 0b11111111, 90 | 0b11111111, 0b00001111, }, 91 | .it_enc_sz = 6, 92 | .it_dec_retval = -2, 93 | }, 94 | 95 | { .it_lineno = __LINE__, 96 | .it_prefix_bits = 7, 97 | .it_encoded = { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 98 | 0xFF, 0xFF, 0xFF, }, 99 | .it_enc_sz = 11, 100 | .it_dec_retval = -2, 101 | }, 102 | 103 | { .it_lineno = __LINE__, 104 | .it_encoded = { 0xFE, }, 105 | .it_enc_sz = 1, 106 | .it_prefix_bits = 4, 107 | .it_dec_retval = 0, 108 | .it_decoded = 0xE, 109 | }, 110 | 111 | { .it_lineno = __LINE__, 112 | .it_encoded = { 0x3F, 0x64, }, 113 | .it_enc_sz = 2, 114 | .it_prefix_bits = 6, 115 | .it_dec_retval = 0, 116 | .it_decoded = 0x3F + 0x64, 117 | }, 118 | 119 | { .it_lineno = __LINE__, 120 | .it_encoded = { 0xFF, }, 121 | .it_enc_sz = 1, 122 | .it_prefix_bits = 4, 123 | .it_dec_retval = -1, /* Ran out of buffer */ 124 | .it_decoded = 0, 125 | }, 126 | 127 | { .it_lineno = __LINE__, 128 | .it_encoded = { 0x87, 0xF0, 0x80, 0x7F, }, 129 | .it_enc_sz = 4, 130 | .it_prefix_bits = 3, 131 | .it_dec_retval = 0, 132 | .it_decoded = 0b111111100000001110111, 133 | }, 134 | 135 | { .it_lineno = __LINE__, 136 | .it_encoded = { 0x87, 0x80, 0x80, 0x80, 0x01, }, 137 | .it_enc_sz = 5, 138 | .it_prefix_bits = 3, 139 | .it_dec_retval = 0, 140 | .it_decoded = 0b1000000000000000000111, 141 | }, 142 | 143 | { .it_lineno = __LINE__, 144 | .it_encoded = { 0x87, 0x80, 0x80, 0x80, 0x01, }, 145 | .it_enc_sz = 4, 146 | .it_prefix_bits = 3, 147 | .it_dec_retval = -1, /* Ran out of buffer */ 148 | .it_decoded = 0, 149 | }, 150 | 151 | { .it_lineno = __LINE__, 152 | .it_encoded = { 0x87, 0x80, 0x80, 0x80, 0x80, 0x01, }, 153 | .it_enc_sz = 6, 154 | .it_prefix_bits = 3, 155 | .it_dec_retval = 0, 156 | .it_decoded = 0b10000000000000000000000000111, 157 | }, 158 | 159 | }; 160 | 161 | int 162 | main (void) 163 | { 164 | const struct int_test *test; 165 | const unsigned char *src; 166 | unsigned char *dst; 167 | unsigned char buf[ sizeof(((struct int_test *) NULL)->it_encoded) ]; 168 | uint32_t val; 169 | size_t sz; 170 | int rv; 171 | 172 | /* Test the decoder */ 173 | for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test) 174 | { 175 | for (sz = 0; sz < test->it_enc_sz - 1; ++sz) 176 | { 177 | src = test->it_encoded; 178 | rv = lshpack_dec_dec_int(&src, src + sz, test->it_prefix_bits, &val); 179 | if (test->it_dec_retval == -2) 180 | assert(-1 == rv || -2 == rv); 181 | else 182 | assert(-1 == rv); 183 | } 184 | src = test->it_encoded; 185 | rv = lshpack_dec_dec_int(&src, src + test->it_enc_sz, 186 | test->it_prefix_bits, &val); 187 | assert(rv == test->it_dec_retval); 188 | if (0 == rv) 189 | assert(val == test->it_decoded); 190 | } 191 | 192 | /* Test the encoder */ 193 | for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test) 194 | { 195 | if (test->it_dec_retval != 0) 196 | continue; 197 | for (sz = 1; sz < test->it_enc_sz; ++sz) 198 | { 199 | dst = lshpack_enc_enc_int(buf, buf + sz, test->it_decoded, 200 | test->it_prefix_bits); 201 | assert(dst == buf); /* Not enough room */ 202 | } 203 | for (; sz <= sizeof(buf); ++sz) 204 | { 205 | buf[0] = '\0'; 206 | dst = lshpack_enc_enc_int(buf, buf + sz, test->it_decoded, 207 | test->it_prefix_bits); 208 | assert(dst - buf == (intptr_t) test->it_enc_sz); 209 | assert((test->it_encoded[0] & ((1 << test->it_prefix_bits) - 1)) 210 | == buf[0]); 211 | if (test->it_enc_sz > 1) 212 | assert(0 == memcmp(buf + 1, test->it_encoded + 1, 213 | test->it_enc_sz - 1)); 214 | } 215 | } 216 | 217 | return 0; 218 | } 219 | --------------------------------------------------------------------------------