// Copyright 2006 Google Inc. All Rights Reserved.
// Author: agl@imperialviolet.org (Adam Langley)
//
// Copyright (C) 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "jbig2arith.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define u64 uint64_t
#define u32 uint32_t
#define u16 uint16_t
#define u8  uint8_t

// C++ doesn't have C99 restricted pointers, but GCC does allow __restrict__
#if !defined(_WIN32)
#define restrict __restrict__
#else
#define restrict
#endif

// -----------------------------------------------------------------------------
// This the structure for a single state of the adaptive arithmetic compressor
// -----------------------------------------------------------------------------
struct context {
  u16 qe;
  u8 mps, lps;
};

// -----------------------------------------------------------------------------
// And this is the table of states for that adaptive compressor
// -----------------------------------------------------------------------------
struct context ctbl[] = {
  // This is the standard state table from
  // Table E.1 of the standard. The switch has been omitted and
  // those states are included below
#define STATETABLE \
  {0x5601, F( 1), SWITCH(F( 1))},\
  {0x3401, F( 2), F( 6)},\
  {0x1801, F( 3), F( 9)},\
  {0x0ac1, F( 4), F(12)},\
  {0x0521, F( 5), F(29)},\
  {0x0221, F(38), F(33)},\
  {0x5601, F( 7), SWITCH(F( 6))},\
  {0x5401, F( 8), F(14)},\
  {0x4801, F( 9), F(14)},\
  {0x3801, F(10), F(14)},\
  {0x3001, F(11), F(17)},\
  {0x2401, F(12), F(18)},\
  {0x1c01, F(13), F(20)},\
  {0x1601, F(29), F(21)},\
  {0x5601, F(15), SWITCH(F(14))},\
  {0x5401, F(16), F(14)},\
  {0x5101, F(17), F(15)},\
  {0x4801, F(18), F(16)},\
  {0x3801, F(19), F(17)},\
  {0x3401, F(20), F(18)},\
  {0x3001, F(21), F(19)},\
  {0x2801, F(22), F(19)},\
  {0x2401, F(23), F(20)},\
  {0x2201, F(24), F(21)},\
  {0x1c01, F(25), F(22)},\
  {0x1801, F(26), F(23)},\
  {0x1601, F(27), F(24)},\
  {0x1401, F(28), F(25)},\
  {0x1201, F(29), F(26)},\
  {0x1101, F(30), F(27)},\
  {0x0ac1, F(31), F(28)},\
  {0x09c1, F(32), F(29)},\
  {0x08a1, F(33), F(30)},\
  {0x0521, F(34), F(31)},\
  {0x0441, F(35), F(32)},\
  {0x02a1, F(36), F(33)},\
  {0x0221, F(37), F(34)},\
  {0x0141, F(38), F(35)},\
  {0x0111, F(39), F(36)},\
  {0x0085, F(40), F(37)},\
  {0x0049, F(41), F(38)},\
  {0x0025, F(42), F(39)},\
  {0x0015, F(43), F(40)},\
  {0x0009, F(44), F(41)},\
  {0x0005, F(45), F(42)},\
  {0x0001, F(45), F(43)},
#undef F
#define F(x) x
#define SWITCH(x) (x + 46)
  STATETABLE
#undef SWITCH
#undef F

#define F(x) (x + 46)
#define SWITCH(x) ((x) - 46)
  STATETABLE
#undef SWITCH
#undef F
};

#if __GNUC__ >= 4
#define BRANCH_OPT
#endif

// GCC peephole optimisations
#ifdef BRANCH_OPT
#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)
#else
#define likely(x)       x
#define unlikely(x)     x
#endif

// see comments in .h file
void
jbig2enc_init(struct jbig2enc_ctx *ctx) {
  memset(ctx->context, 0, JBIG2_MAX_CTX);
  memset(ctx->intctx, 0, 13 * 512);
  ctx->a = 0x8000;
  ctx->c = 0;
  ctx->ct = 12;
  ctx->bp = -1;
  ctx->b = 0;
  ctx->outbuf_used = 0;
  ctx->outbuf = (u8 *) malloc(JBIG2_OUTPUTBUFFER_SIZE);
  ctx->output_chunks = new std::vector<uint8_t *>;
  ctx->iaidctx = NULL;
}

// see comments in .h file
void
jbig2enc_reset(struct jbig2enc_ctx *ctx) {
  ctx->a = 0x8000;
  ctx->c = 0;
  ctx->ct = 12;
  ctx->bp = -1;
  ctx->b = 0;
  free(ctx->iaidctx);
  ctx->iaidctx = NULL;
  memset(ctx->context, 0, JBIG2_MAX_CTX);
  memset(ctx->intctx, 0, 13 * 512);
}

// see comments in .h file
void
jbig2enc_flush(struct jbig2enc_ctx *ctx) {
  ctx->outbuf_used = 0;

  for (std::vector<uint8_t *>::iterator i = ctx->output_chunks->begin();
       i != ctx->output_chunks->end(); ++i) {
    free(*i);
  }
  ctx->output_chunks->clear();
  ctx->bp = -1;
}

// see comments in .h file
void
jbig2enc_dealloc(struct jbig2enc_ctx *ctx) {
  for (std::vector<uint8_t *>::iterator i = ctx->output_chunks->begin();
       i != ctx->output_chunks->end(); ++i) {
    free(*i);
  }
  delete ctx->output_chunks;
  free(ctx->outbuf);
  free(ctx->iaidctx);
}

// -----------------------------------------------------------------------------
// Emit a byte from the compressor by appending to the current output buffer.
// If the buffer is full, allocate a new one
// -----------------------------------------------------------------------------
static void inline
emit(struct jbig2enc_ctx *restrict ctx) {
  if (unlikely(ctx->outbuf_used == JBIG2_OUTPUTBUFFER_SIZE)) {
    ctx->output_chunks->push_back(ctx->outbuf);
    ctx->outbuf = (u8 *) malloc(JBIG2_OUTPUTBUFFER_SIZE);
    ctx->outbuf_used = 0;
  }

  ctx->outbuf[ctx->outbuf_used++] = ctx->b;
}

// -----------------------------------------------------------------------------
// The BYTEOUT procedure from the standard
// -----------------------------------------------------------------------------
static void
byteout(struct jbig2enc_ctx *restrict ctx) {
  if (ctx->b == 0xff) goto rblock;

  if (ctx->c < 0x8000000) goto lblock;
  ctx->b += 1;
  if (ctx->b != 0xff) goto lblock;
  ctx->c &= 0x7ffffff;

rblock:
  if (ctx->bp >= 0) {
#ifdef TRACE
    printf("emit %x\n", ctx->b);
#endif
    emit(ctx);
  }
  ctx->b = ctx->c >> 20;
  ctx->bp++;
  ctx->c &= 0xfffff;
  ctx->ct = 7;
  return;

lblock:
  if (ctx->bp >= 0) {
#ifdef TRACE
    printf("emit %x\n", ctx->b);
#endif
    emit(ctx);
  }
  ctx->b = ctx->c >> 19;
  ctx->bp++;
  ctx->c &= 0x7ffff;
  ctx->ct = 8;
  return;
}

// -----------------------------------------------------------------------------
// A merging of the ENCODE, CODELPS and CODEMPS procedures from the standard
// -----------------------------------------------------------------------------
static void
encode_bit(struct jbig2enc_ctx *restrict ctx, u8 *restrict context, u32 ctxnum, u8 d) {
  const u8 i = context[ctxnum];
  const u8 mps = i > 46 ? 1 : 0;
  const u16 qe = ctbl[i].qe;

#ifdef CODER_DEBUGGING
    fprintf(stderr, "B: %d %d %d %d\n", ctxnum, qe, ctx->a, d);
#endif

#ifdef TRACE
  static int ec = 0;
  printf("%d\t%d %d %x %x %x %d %x %d\n", ec++, i, mps, qe, ctx->a, ctx->c, ctx->ct, ctx->b, ctx->bp);
#endif

  if (unlikely(d != mps)) goto codelps;
#ifdef SURPRISE_MAP
  {
  u8 b = static_cast<unsigned char>
    (((static_cast<float>(qe) / 0xac02) * 255));
  write(3, &b, 1);
  }
#endif
  ctx->a -= qe;
  if (unlikely((ctx->a & 0x8000) == 0)) {
    if (unlikely(ctx->a < qe)) {
      ctx->a = qe;
    } else {
      ctx->c += qe;
    }
    context[ctxnum] = ctbl[i].mps;
    goto renorme;
  } else {
    ctx->c += qe;
  }

  return;

codelps:
#ifdef SURPRISE_MAP
  {
  u8 b = static_cast<unsigned char>
    ((1.0f - (static_cast<float>(qe) / 0xac02)) * 255);
  write(3, &b, 1);
  }
#endif
  ctx->a -= qe;
  if (ctx->a < qe) {
    ctx->c += qe;
  } else {
    ctx->a = qe;
  }
  context[ctxnum] = ctbl[i].lps;

renorme:
  do {
    ctx->a <<= 1;
    ctx->c <<= 1;
    ctx->ct -= 1;
    if (unlikely(!ctx->ct)) {
      byteout(ctx);
    }
  } while ((ctx->a & 0x8000) == 0);
}

// -----------------------------------------------------------------------------
// The FINALISE procudure from the standard
// -----------------------------------------------------------------------------
static void
encode_final(struct jbig2enc_ctx *restrict ctx) {
  // SETBITS
  const u32 tempc = ctx->c + ctx->a;
  ctx->c |= 0xffff;
  if (ctx->c >= tempc) {
    ctx->c -= 0x8000;
  }

  ctx->c <<= ctx->ct;
  byteout(ctx);
  ctx->c <<= ctx->ct;
  byteout(ctx);
  emit(ctx);
  if (ctx->b != 0xff) {
#ifdef TRACE
    printf("emit 0xff\n");
#endif
    ctx->b = 0xff;
    emit(ctx);
  }
#ifdef TRACE
  printf("emit 0xac\n");
#endif
  ctx->b = 0xac;
  emit(ctx);
}

// see comments in .h file
void
jbig2enc_final(struct jbig2enc_ctx *restrict ctx) {
  encode_final(ctx);
}

// -----------------------------------------------------------------------------
// When encoding integers there are a number of different cases. This structure
// contains all the information for one of those cases
// -----------------------------------------------------------------------------
struct intencrange_s {
  int bot, top;  // the range of numbers for which this is valid
  u8 data, bits; // the bits of data to write first, and the number which are valid
                 // These bits are taken from the bottom of the u8, in reverse order
  u16 delta;     // the amount to subtract from the value before encoding it
  u8 intbits;    // number of bits to use to encode the integer
};

// table for how to encode integers of a given range
static struct intencrange_s intencrange[] = {
  {0,   3,  0, 2, 0, 2},
  {-1, -1,  9, 4, 0, 0},
  {-3, -2,  5, 3, 2, 1},
  {4,  19,  2, 3, 4, 4},
  {-19,-4,  3, 3, 4, 4},
  {20, 83,  6, 4, 20, 6},
  {-83,-20, 7, 4, 20, 6},
  {84, 339, 14,5, 84, 8},
  {-339,-84,15,5, 84, 8},
  {340,4435,30,6, 340, 12},
  {-4435,-340,31,6,340, 12},
  {4436,2000000000,62,6,4436, 32},
  {-2000000000,-4436,63,6,4436, 32}
};

// see comments in .h file
void
jbig2enc_oob(struct jbig2enc_ctx *restrict ctx, int proc) {
  u8 *const context = ctx->intctx[proc];

  encode_bit(ctx, context, 1, 1);
  encode_bit(ctx, context, 3, 0);
  encode_bit(ctx, context, 6, 0);
  encode_bit(ctx, context, 12, 0);
}

// see comments in .h file
void
jbig2enc_int(struct jbig2enc_ctx *restrict ctx, int proc, int value) {
  u8 *const context = ctx->intctx[proc];
  int i;

  if (value > 2000000000 || value < -2000000000) abort();

  u32 prev = 1;

  for (i = 0; ; ++i) {
    if (intencrange[i].bot <= value && intencrange[i].top >= value) break;
  }
  if (value < 0) value = -value;
  value -= intencrange[i].delta;

  u8 data = intencrange[i].data;
  for (int j = 0; j < intencrange[i].bits; ++j) {
    const u8 v = data & 1;
    encode_bit(ctx, context, prev, v);
    data >>= 1;
    if (prev & 0x100) {
      // prev > 256
      prev = (((prev << 1) | v) & 0x1ff) | 0x100;
    } else {
      prev = (prev << 1) | v;
    }
  }

  // move the data in value to the top of the word
  if (intencrange[i].intbits)
    value = (u32)value << (32 - intencrange[i].intbits);
  for (int j = 0; j < intencrange[i].intbits; ++j) {
    const u8 v = (value & 0x80000000) >> 31;
    encode_bit(ctx, context, prev, v);
    // roll the next bit into place
    value = (u32)value << 1;
    if (prev & 0x100) {
      // prev > 256
      prev = (((prev << 1) | v) & 0x1ff) | 0x100;
    } else {
      prev = (prev << 1) | v;
    }
  }
}

// see comments in .h file
void
jbig2enc_iaid(struct jbig2enc_ctx *restrict ctx, int symcodelen, int value) {
  if (!ctx->iaidctx) {
    // we've not yet allocated the context index buffer for this
    ctx->iaidctx = (u8 *) malloc(1 << symcodelen);
    memset(ctx->iaidctx, 0, 1 << symcodelen);
  }
  const u32 mask = (1 << (symcodelen + 1)) - 1;

  if (symcodelen)
    value = (u32)value << (32 - symcodelen);  // roll the data to the top of the word
  u32 prev = 1;
  for (int i = 0; i < symcodelen; ++i) {
    const u32 tval = prev & mask;
    const u8 v = (value & 0x80000000) >> 31;
    encode_bit(ctx, ctx->iaidctx, tval, v);
    prev = (prev << 1) | v;
    value = (u32)value << 1;
  }
}

// This is the test input to the coder as given in the standard (H.2)
static const u8 input[] = { 0, 2, 0, 0x51, 0, 0, 0, 0xc0, 0x03, 0x52, 0x87,
  0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0x82, 0xc0, 0x20, 0, 0xfc, 0xd7, 0x9e, 0xf6,
  0xbf, 0x7f, 0xed, 0x90, 0x4f, 0x46, 0xa3, 0xbf } ;

// -----------------------------------------------------------------------------
// This function  is used by jbig2enc_image to fetch values from the image and
// to automatically extend the range of the image on three sides with zero's
// -----------------------------------------------------------------------------
static u8 image_get(const u8 *restrict image, int x, int y, int mx, int my) {
  if (y < 0) return 0;
  if (x >= mx) return 0;
  if (y >= my) return 0;
  return image[mx * y + x];
}

// see comments in .h file
unsigned
jbig2enc_datasize(const struct jbig2enc_ctx *ctx) {
  return JBIG2_OUTPUTBUFFER_SIZE * ctx->output_chunks->size() + ctx->outbuf_used;
}

// see comments in .h file
void
jbig2enc_tobuffer(const struct jbig2enc_ctx *restrict ctx, u8 *restrict buffer) {
  int j = 0;
  for (std::vector<u8 *>::const_iterator i = ctx->output_chunks->begin();
       i != ctx->output_chunks->end(); ++i) {
    memcpy(&buffer[j], *i, JBIG2_OUTPUTBUFFER_SIZE);
    j += JBIG2_OUTPUTBUFFER_SIZE;
  }

  memcpy(&buffer[j], ctx->outbuf, ctx->outbuf_used);
}

// This is the context used for the TPGD bits
#define TPGDCTX 0x9b25

// -----------------------------------------------------------------------------
// This is designed for Leptonica's 1bpp packed format images. Each row is some
// number of 32-bit words. Pixels are in native-byte-order in each word.
// -----------------------------------------------------------------------------
void
jbig2enc_bitimage(struct jbig2enc_ctx *restrict ctx, const u8 *restrict idata,
                  int mx, int my, bool duplicate_line_removal) {
  const u32 *restrict data = (u32 *) idata;
  u8 *const context = ctx->context;
  const unsigned words_per_row = (mx + 31) / 32;
  const unsigned bytes_per_row = words_per_row * 4;

  u8 ltp = 0, sltp = 0;

  for (int y = 0; y < my; ++y) {
    int x = 0;

    // the c* values store the context bits for each row. The template is fixed
    // as template 0 with the floating bits in the default locations.
    u16 c1, c2, c3;
    // the w* values contain words from each of the rows: w1 is from two rows
    // up etc. The next bit to roll onto the context values are kept at the top
    // of these words.
    u32 w1, w2, w3;
    w1 = w2 = w3 = 0;

    if (y >= 2) w1 = data[(y - 2) * words_per_row];
    if (y >= 1) {
      w2 = data[(y - 1) * words_per_row];

      if (duplicate_line_removal) {
        // it's possible that the last row was the same as this row
        if (memcmp(&data[y * words_per_row], &data[(y - 1) * words_per_row],
                   bytes_per_row) == 0) {
          sltp = ltp ^ 1;
          ltp = 1;
        } else {
          sltp = ltp;
          ltp = 0;
        }
      }
    }
    if (duplicate_line_removal) {
      encode_bit(ctx, context, TPGDCTX, sltp);
      if (ltp) continue;
    }
    w3 = data[y * words_per_row];

    // the top three bits are the start of the context c1
    c1 = w1 >> 29;
    c2 = w2 >> 28;
    // and we need to remove the used bits from the w* vars
    w1 <<= 3;
    w2 <<= 4;
    c3 = 0;
    for (x = 0; x < mx; ++x) {
      const u16 tval = (c1 << 11) | (c2 << 4) | c3;
      const u8 v = (w3 & 0x80000000) >> 31;

      //fprintf(stderr, "%d %d %d %d\n", x, y, tval, v);
      encode_bit(ctx, context, tval, v);
      c1 <<= 1;
      c2 <<= 1;
      c3 <<= 1;
      c1 |= (w1 & 0x80000000) >> 31;
      c2 |= (w2 & 0x80000000) >> 31;
      c3 |= v;
      const int m = x % 32;
      if (m == 28 && y >= 2) {
        // need to roll in another word from two lines up
        const unsigned wordno = (x / 32) + 1;
        if (wordno >= words_per_row) {
          w1 = 0;
        } else {
          w1 = data[(y - 2) * words_per_row + wordno];
        }
      } else {
        w1 <<= 1;
      }

      if (m == 27 && y >= 1) {
        // need to roll in another word from the last line
        const unsigned wordno = (x / 32) + 1;
        if (wordno >= words_per_row) {
          w2 = 0;
        } else {
          w2 = data[(y - 1) * words_per_row + wordno];
        }
      } else {
        w2 <<= 1;
      }

      if (m == 31) {
        // need to roll in another word from this line
        const unsigned wordno = (x / 32) + 1;
        if (wordno >= words_per_row) {
          w3 = 0;
        } else {
          w3 = data[y * words_per_row + wordno];
        }
      } else {
        w3 <<= 1;
      }

      c1 &= 31;
      c2 &= 127;
      c3 &= 15;
    }
  }
}

void
jbig2enc_refine(struct jbig2enc_ctx *__restrict__ ctx,
                const uint8_t *__restrict__ itempl, int tx, int ty,
                const uint8_t *__restrict__ itarget, int mx, int my,
                int ox, int oy) {
  const u32 *restrict templdata = (u32 *) itempl;
  const u32 *restrict data = (u32 *) itarget;
  u8 *restrict const context = ctx->context;

  static int image_counter = 0;

  image_counter++;

#ifdef SYM_DEBUGGING
  fprintf(stderr, "refine:%d %d %d %d\n", tx, ty, mx, my);
#endif

  const unsigned templwords_per_row = (tx + 31) / 32;
  const unsigned words_per_row = (mx + 31) / 32;

  for (int y = 0; y < my; ++y) {
    int x;
    const int temply = y + oy;
    // the template is fixed to the 13 pixel template with the floating bits in
    // the default locations.
    // we have 5 words of context. The first three are the last, current and
    // next rows of the template. The last two are the last and current rows of
    // the target.
    // To form the 14 bits of content these are packed from the least
    // significant bits rightward.
    u16 c1, c2, c3, c4, c5;
    // the w* values contain words from each of the corresponding rows. The
    // next bit to be part of the context is kept at the top of these words
    u32 w1, w2, w3, w4, w5;
    w1 = w2 = w3 = w4 = w5 = 0;

    if (temply >= 1 && (temply - 1) < ty) w1 = templdata[(temply - 1) * templwords_per_row];
    if (temply >= 0 && temply < ty) w2 = templdata[temply * templwords_per_row];
    if (temply >= -1 && temply + 1 < ty) w3 = templdata[(temply + 1) * templwords_per_row];

    // the x offset prevents a hassel because we are dealing with bits. Thus we
    // restrict it to being {-1, 0, 1}.
    if (y >= 1) w4 = data[(y - 1) * words_per_row];
    w5 = data[y * words_per_row];

    const int shiftoffset = 30 + ox;
    c1 = w1 >> shiftoffset;
    c2 = w2 >> shiftoffset;
    c3 = w3 >> shiftoffset;

    c4 = w4 >> 30;
    c5 = 0;

    // the w* should contain the next bit to be included in the context, in the
    // MSB position. Thus we need to roll the used bits out of the way.
    const int bits_to_trim = 2 - ox;
    w1 <<= bits_to_trim;
    w2 <<= bits_to_trim;
    w3 <<= bits_to_trim;

    w4 <<= 2;

    for (x = 0; x < mx; ++x) {
      const u16 tval = (c1 << 10) | (c2 << 7) | (c3 << 4) | (c4 << 1) | c5;
      const u8 v = w5 >> 31;

#ifdef SYM_DEBUGGING
      fprintf(stderr, "%d %d %d %d\n", x, y, tval, v);
#endif
      encode_bit(ctx, context, tval, v);
      c1 <<= 1;
      c2 <<= 1;
      c3 <<= 1;
      c4 <<= 1;
      c1 |= w1 >> 31;
      c2 |= w2 >> 31;
      c3 |= w3 >> 31;
      c4 |= w4 >> 31;
      c5 = v;

      const int m = x % 32;
      const unsigned wordno = (x / 32) + 1;
      if (m == 29 + ox) {
        // have run out of bits in the w[123] values. Need to get more.

        if (wordno >= templwords_per_row) {
          w1 = w2 = w3 = 0;
        } else {
          if (temply >= 1 && (temply - 1 < ty)) {
            w1 = templdata[(temply - 1) * templwords_per_row + wordno];
          } else {
            w1 = 0;
          }
          if (temply >= 0 && temply < ty) {
            w2 = templdata[temply * templwords_per_row + wordno];
          } else {
            w2 = 0;
          }
          if (temply >= -1 && (temply + 1) < ty) {
            w3 = templdata[(temply + 1) * templwords_per_row + wordno];
          } else {
            w3 = 0;
          }
        }
      } else {
        w1 <<= 1;
        w2 <<= 1;
        w3 <<= 1;
      }

      if (m == 29 && y >= 1) {
        // run out of data from w4
        if (wordno >= words_per_row) {
          w4 = 0;
        } else {
          w4 = data[(y - 1) * words_per_row + wordno];
        }
      } else {
        w4 <<= 1;
      }

      if (m == 31) {
        // run out of data from w5
        if (wordno >= words_per_row) {
          w5 = 0;
        } else {
          w5 = data[y * words_per_row + wordno];
        }
      } else {
        w5 <<= 1;
      }

      c1 &= 7;
      c2 &= 7;
      c3 &= 7;
      c4 &= 7;
    }
  }
}

// see comments in .h file
void
jbig2enc_image(struct jbig2enc_ctx *restrict ctx, const u8 *restrict data,
               int mx, int my, bool duplicate_line_removal) {
  u8 *const context = ctx->context;
  u8 ltp = 0;
  u8 sltp = 0;
  for (int y = 0; y < my; ++y) {
    int x = 0;
    u16 c1 = (image_get(data, x, y - 2, mx, my) << 2) |
             (image_get(data, x + 1, y - 2, mx, my) << 1) |
             (image_get(data, x + 2, y - 2, mx, my));
    u16 c2 = (image_get(data, x, y - 1, mx, my) << 3) |
             (image_get(data, x + 1, y - 1, mx, my) << 2) |
             (image_get(data, x + 2, y - 1, mx, my) << 1) |
             (image_get(data, x + 3, y - 1, mx, my));
    u16 c3 = 0;
    if (y > 0) {
      // it's possible that the last row was the same as this row
      if (memcmp(&data[y * mx], &data[(y - 1) * mx], mx) == 0) {
        sltp = ltp ^ 1;
        ltp = 1;
      } else {
        sltp = ltp;
        ltp = 0;
      }
    }
    if (duplicate_line_removal) {
      encode_bit(ctx, context, TPGDCTX, sltp);
      if (ltp) continue;
    }
    for (x = 0; x < mx; ++x) {
      const u16 tval = (c1 << 11) | (c2 << 4) | c3;
      const u8 v = image_get(data, x, y, mx, my);
      encode_bit(ctx, context, tval, v);
      c1 <<= 1;
      c2 <<= 1;
      c3 <<= 1;
      c1 |= image_get(data, x + 3, y - 2, mx, my);
      c2 |= image_get(data, x + 4, y - 1, mx, my);
      c3 |= v;
      c1 &= 31;
      c2 &= 127;
      c3 &= 15;
    }
  }
}
