126fa459cSmrg/* Copyright 2013 Google Inc. All Rights Reserved.
226fa459cSmrg
326fa459cSmrg   Distributed under MIT license.
426fa459cSmrg   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
526fa459cSmrg*/
626fa459cSmrg
726fa459cSmrg/* This class models a sequence of literals and a backward reference copy. */
826fa459cSmrg
926fa459cSmrg#ifndef BROTLI_ENC_COMMAND_H_
1026fa459cSmrg#define BROTLI_ENC_COMMAND_H_
1126fa459cSmrg
1226fa459cSmrg#include "../common/constants.h"
1326fa459cSmrg#include "../common/platform.h"
1426fa459cSmrg#include <brotli/types.h>
1526fa459cSmrg#include "./fast_log.h"
1626fa459cSmrg#include "./params.h"
1726fa459cSmrg#include "./prefix.h"
1826fa459cSmrg
1926fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus)
2026fa459cSmrgextern "C" {
2126fa459cSmrg#endif
2226fa459cSmrg
2326fa459cSmrgBROTLI_INTERNAL extern const uint32_t
2426fa459cSmrg    kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
2526fa459cSmrgBROTLI_INTERNAL extern const uint32_t
2626fa459cSmrg    kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
2726fa459cSmrgBROTLI_INTERNAL extern const uint32_t
2826fa459cSmrg    kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
2926fa459cSmrgBROTLI_INTERNAL extern const uint32_t
3026fa459cSmrg    kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
3126fa459cSmrg
3226fa459cSmrgstatic BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
3326fa459cSmrg  if (insertlen < 6) {
3426fa459cSmrg    return (uint16_t)insertlen;
3526fa459cSmrg  } else if (insertlen < 130) {
3626fa459cSmrg    uint32_t nbits = Log2FloorNonZero(insertlen - 2) - 1u;
3726fa459cSmrg    return (uint16_t)((nbits << 1) + ((insertlen - 2) >> nbits) + 2);
3826fa459cSmrg  } else if (insertlen < 2114) {
3926fa459cSmrg    return (uint16_t)(Log2FloorNonZero(insertlen - 66) + 10);
4026fa459cSmrg  } else if (insertlen < 6210) {
4126fa459cSmrg    return 21u;
4226fa459cSmrg  } else if (insertlen < 22594) {
4326fa459cSmrg    return 22u;
4426fa459cSmrg  } else {
4526fa459cSmrg    return 23u;
4626fa459cSmrg  }
4726fa459cSmrg}
4826fa459cSmrg
4926fa459cSmrgstatic BROTLI_INLINE uint16_t GetCopyLengthCode(size_t copylen) {
5026fa459cSmrg  if (copylen < 10) {
5126fa459cSmrg    return (uint16_t)(copylen - 2);
5226fa459cSmrg  } else if (copylen < 134) {
5326fa459cSmrg    uint32_t nbits = Log2FloorNonZero(copylen - 6) - 1u;
5426fa459cSmrg    return (uint16_t)((nbits << 1) + ((copylen - 6) >> nbits) + 4);
5526fa459cSmrg  } else if (copylen < 2118) {
5626fa459cSmrg    return (uint16_t)(Log2FloorNonZero(copylen - 70) + 12);
5726fa459cSmrg  } else {
5826fa459cSmrg    return 23u;
5926fa459cSmrg  }
6026fa459cSmrg}
6126fa459cSmrg
6226fa459cSmrgstatic BROTLI_INLINE uint16_t CombineLengthCodes(
6326fa459cSmrg    uint16_t inscode, uint16_t copycode, BROTLI_BOOL use_last_distance) {
6426fa459cSmrg  uint16_t bits64 =
6526fa459cSmrg      (uint16_t)((copycode & 0x7u) | ((inscode & 0x7u) << 3u));
6626fa459cSmrg  if (use_last_distance && inscode < 8u && copycode < 16u) {
6726fa459cSmrg    return (copycode < 8u) ? bits64 : (bits64 | 64u);
6826fa459cSmrg  } else {
6926fa459cSmrg    /* Specification: 5 Encoding of ... (last table) */
7026fa459cSmrg    /* offset = 2 * index, where index is in range [0..8] */
7126fa459cSmrg    uint32_t offset = 2u * ((copycode >> 3u) + 3u * (inscode >> 3u));
7226fa459cSmrg    /* All values in specification are K * 64,
7326fa459cSmrg       where   K = [2, 3, 6, 4, 5, 8, 7, 9, 10],
7426fa459cSmrg           i + 1 = [1, 2, 3, 4, 5, 6, 7, 8,  9],
7526fa459cSmrg       K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1,  2] = D.
7626fa459cSmrg       All values in D require only 2 bits to encode.
7726fa459cSmrg       Magic constant is shifted 6 bits left, to avoid final multiplication. */
7826fa459cSmrg    offset = (offset << 5u) + 0x40u + ((0x520D40u >> offset) & 0xC0u);
7926fa459cSmrg    return (uint16_t)(offset | bits64);
8026fa459cSmrg  }
8126fa459cSmrg}
8226fa459cSmrg
8326fa459cSmrgstatic BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen,
8426fa459cSmrg                                        BROTLI_BOOL use_last_distance,
8526fa459cSmrg                                        uint16_t* code) {
8626fa459cSmrg  uint16_t inscode = GetInsertLengthCode(insertlen);
8726fa459cSmrg  uint16_t copycode = GetCopyLengthCode(copylen);
8826fa459cSmrg  *code = CombineLengthCodes(inscode, copycode, use_last_distance);
8926fa459cSmrg}
9026fa459cSmrg
9126fa459cSmrgstatic BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
9226fa459cSmrg  return kBrotliInsBase[inscode];
9326fa459cSmrg}
9426fa459cSmrg
9526fa459cSmrgstatic BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
9626fa459cSmrg  return kBrotliInsExtra[inscode];
9726fa459cSmrg}
9826fa459cSmrg
9926fa459cSmrgstatic BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) {
10026fa459cSmrg  return kBrotliCopyBase[copycode];
10126fa459cSmrg}
10226fa459cSmrg
10326fa459cSmrgstatic BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
10426fa459cSmrg  return kBrotliCopyExtra[copycode];
10526fa459cSmrg}
10626fa459cSmrg
10726fa459cSmrgtypedef struct Command {
10826fa459cSmrg  uint32_t insert_len_;
10926fa459cSmrg  /* Stores copy_len in low 25 bits and copy_code - copy_len in high 7 bit. */
11026fa459cSmrg  uint32_t copy_len_;
11126fa459cSmrg  /* Stores distance extra bits. */
11226fa459cSmrg  uint32_t dist_extra_;
11326fa459cSmrg  uint16_t cmd_prefix_;
11426fa459cSmrg  /* Stores distance code in low 10 bits
11526fa459cSmrg     and number of extra bits in high 6 bits. */
11626fa459cSmrg  uint16_t dist_prefix_;
11726fa459cSmrg} Command;
11826fa459cSmrg
11926fa459cSmrg/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */
12026fa459cSmrgstatic BROTLI_INLINE void InitCommand(Command* self,
12126fa459cSmrg    const BrotliDistanceParams* dist, size_t insertlen,
12226fa459cSmrg    size_t copylen, int copylen_code_delta, size_t distance_code) {
12326fa459cSmrg  /* Don't rely on signed int representation, use honest casts. */
12426fa459cSmrg  uint32_t delta = (uint8_t)((int8_t)copylen_code_delta);
12526fa459cSmrg  self->insert_len_ = (uint32_t)insertlen;
12626fa459cSmrg  self->copy_len_ = (uint32_t)(copylen | (delta << 25));
12726fa459cSmrg  /* The distance prefix and extra bits are stored in this Command as if
12826fa459cSmrg     npostfix and ndirect were 0, they are only recomputed later after the
12926fa459cSmrg     clustering if needed. */
13026fa459cSmrg  PrefixEncodeCopyDistance(
13126fa459cSmrg      distance_code, dist->num_direct_distance_codes,
13226fa459cSmrg      dist->distance_postfix_bits, &self->dist_prefix_, &self->dist_extra_);
13326fa459cSmrg  GetLengthCode(
13426fa459cSmrg      insertlen, (size_t)((int)copylen + copylen_code_delta),
13526fa459cSmrg      TO_BROTLI_BOOL((self->dist_prefix_ & 0x3FF) == 0), &self->cmd_prefix_);
13626fa459cSmrg}
13726fa459cSmrg
13826fa459cSmrgstatic BROTLI_INLINE void InitInsertCommand(Command* self, size_t insertlen) {
13926fa459cSmrg  self->insert_len_ = (uint32_t)insertlen;
14026fa459cSmrg  self->copy_len_ = 4 << 25;
14126fa459cSmrg  self->dist_extra_ = 0;
14226fa459cSmrg  self->dist_prefix_ = BROTLI_NUM_DISTANCE_SHORT_CODES;
14326fa459cSmrg  GetLengthCode(insertlen, 4, BROTLI_FALSE, &self->cmd_prefix_);
14426fa459cSmrg}
14526fa459cSmrg
14626fa459cSmrgstatic BROTLI_INLINE uint32_t CommandRestoreDistanceCode(
14726fa459cSmrg    const Command* self, const BrotliDistanceParams* dist) {
14826fa459cSmrg  if ((self->dist_prefix_ & 0x3FFu) <
14926fa459cSmrg      BROTLI_NUM_DISTANCE_SHORT_CODES + dist->num_direct_distance_codes) {
15026fa459cSmrg    return self->dist_prefix_ & 0x3FFu;
15126fa459cSmrg  } else {
15226fa459cSmrg    uint32_t dcode = self->dist_prefix_ & 0x3FFu;
15326fa459cSmrg    uint32_t nbits = self->dist_prefix_ >> 10;
15426fa459cSmrg    uint32_t extra = self->dist_extra_;
15526fa459cSmrg    uint32_t postfix_mask = (1U << dist->distance_postfix_bits) - 1U;
15626fa459cSmrg    uint32_t hcode = (dcode - dist->num_direct_distance_codes -
15726fa459cSmrg        BROTLI_NUM_DISTANCE_SHORT_CODES) >>
15826fa459cSmrg        dist->distance_postfix_bits;
15926fa459cSmrg    uint32_t lcode = (dcode - dist->num_direct_distance_codes -
16026fa459cSmrg        BROTLI_NUM_DISTANCE_SHORT_CODES) & postfix_mask;
16126fa459cSmrg    uint32_t offset = ((2U + (hcode & 1U)) << nbits) - 4U;
16226fa459cSmrg    return ((offset + extra) << dist->distance_postfix_bits) + lcode +
16326fa459cSmrg        dist->num_direct_distance_codes + BROTLI_NUM_DISTANCE_SHORT_CODES;
16426fa459cSmrg  }
16526fa459cSmrg}
16626fa459cSmrg
16726fa459cSmrgstatic BROTLI_INLINE uint32_t CommandDistanceContext(const Command* self) {
16826fa459cSmrg  uint32_t r = self->cmd_prefix_ >> 6;
16926fa459cSmrg  uint32_t c = self->cmd_prefix_ & 7;
17026fa459cSmrg  if ((r == 0 || r == 2 || r == 4 || r == 7) && (c <= 2)) {
17126fa459cSmrg    return c;
17226fa459cSmrg  }
17326fa459cSmrg  return 3;
17426fa459cSmrg}
17526fa459cSmrg
17626fa459cSmrgstatic BROTLI_INLINE uint32_t CommandCopyLen(const Command* self) {
17726fa459cSmrg  return self->copy_len_ & 0x1FFFFFF;
17826fa459cSmrg}
17926fa459cSmrg
18026fa459cSmrgstatic BROTLI_INLINE uint32_t CommandCopyLenCode(const Command* self) {
18126fa459cSmrg  uint32_t modifier = self->copy_len_ >> 25;
18226fa459cSmrg  int32_t delta = (int8_t)((uint8_t)(modifier | ((modifier & 0x40) << 1)));
18326fa459cSmrg  return (uint32_t)((int32_t)(self->copy_len_ & 0x1FFFFFF) + delta);
18426fa459cSmrg}
18526fa459cSmrg
18626fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus)
18726fa459cSmrg}  /* extern "C" */
18826fa459cSmrg#endif
18926fa459cSmrg
19026fa459cSmrg#endif  /* BROTLI_ENC_COMMAND_H_ */
191