/* Generated from "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod" by precompile.pike running Pike v8.1 release 13
 *
 * Do NOT edit this file.
 */

#undef PRECOMPILE_API_VERSION
#define PRECOMPILE_API_VERSION 6



#undef cmod___CMOD__
#define cmod___CMOD__ 1
#line 1 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
#line 1 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
#line 1 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
#line 3488 "/Users/hww3/devel/pike/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike"







#line 3495 "/Users/hww3/devel/pike/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike"
#line 1 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
#line 1 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
/* -*- c -*-
|| This file is part of Pike. For copyright information see COPYRIGHT.
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
|| for more information.
*/

/*! @module HPack
 *!
 *! Implementation of the HPACK (@rfc{7541@}) header packing standard.
 *!
 *! This is the header packing system that is used in HTTP/2 (@rfc{7540@}).
 */

#include "module.h"
#include "interpret.h"

#include "huffman-tab.h"



#ifndef PIKE_UNUSED_ATTRIBUTE
#define PIKE_UNUSED_ATTRIBUTE
#endif
#define CMOD_MAP_PROGRAM_IDS_DEFINED 1
static int ___cmod_map_program_ids(int id) PIKE_UNUSED_ATTRIBUTE;
#ifndef TYPEOF
/* Compat with older Pikes. */
#define TYPEOF(SVAL)	((SVAL).type)
#define SUBTYPEOF(SVAL)	((SVAL).subtype)
#define SET_SVAL_TYPE(SVAL, TYPE)	(TYPEOF(SVAL) = TYPE)
#define SET_SVAL_SUBTYPE(SVAL, TYPE)	(SUBTYPEOF(SVAL) = TYPE)
#define SET_SVAL(SVAL, TYPE, SUBTYPE, FIELD, EXPR) do {	\
    /* Set the type afterwards to avoid a clobbered	\
     * svalue in case EXPR throws. */			\
    (SVAL).u.FIELD = (EXPR);				\
    SET_SVAL_TYPE((SVAL), (TYPE));			\
    SET_SVAL_SUBTYPE((SVAL), (SUBTYPE));		\
  } while(0)
#endif /* !TYPEOF */
#ifndef PIKE_UNUSED
/* Compat with Pike 7.8 and earlier. */
/* NB: Not strictly correct; PIKE_UNUSED was added the
 *     day after set_program_id_to_id(), but good enough.
 */
#ifndef UNUSED
#define UNUSED(X)	X
#endif
#ifndef set_program_id_to_id
/* NB: Recent Pike 7.8 has a #define that conflicts with
 *     the following declaration.
 */
static void set_program_id_to_id(void*UNUSED(id)){}
#endif
#else /* */
PMOD_EXPORT void set_program_id_to_id( int (*to)(int) );
#endif /* !PIKE_UNUSED */
#if !defined(string_has_null) && !defined(STRING_CONTENT_CHECKED)
/* This symbol was added as a macro in Pike 7.7.20, and is an
 * inline function in Pike 7.9.4 and later, at which time the
 * flag STRING_CONTENT_CHECKED was added.
 */
#define string_has_null(X) (strlen((X)->str)!=(size_t)(X)->len)
#endif


#ifndef DEFAULT_CMOD_STORAGE
#define CMOD_COND_USED
#define DEFAULT_CMOD_STORAGE static
#endif
#ifndef CMOD_COND_USED
# define f_HPack_huffman_decode_fun_num_used 1
# define f_HPack_huffman_encode_fun_num_used 1
#else /* !CMOD_COND_USED */
# undef f_HPack_huffman_decode_fun_num_used
# undef f_HPack_huffman_encode_fun_num_used
#endif /* !CMOD_COND_USED */

#ifdef f_HPack_huffman_encode_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_HPack_huffman_encode_fun_num = -1;

#endif /* f_HPack_huffman_encode_fun_num_used */

#ifdef f_HPack_huffman_decode_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_HPack_huffman_decode_fun_num = -1;

#endif /* f_HPack_huffman_decode_fun_num_used */
#line 19 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
;

#undef ASSERT
#ifdef PIKE_DEBUG
#define ASSERT(X)	do {				\
    if (!(X)) {						\
      Pike_fatal("%s:%d: Assertion failed: %s.\n",	\
		 __FILE__, __LINE__, TOSTR(X));		\
    }							\
  } while(0)
#else
#define ASSERT(X)	0
#endif

/*! @decl string(8bit) huffman_encode(string(8bit) str)
 *!
 *! Encodes the string @[str] with the static huffman code specified
 *! in @rfc{7541:B@}.
 *!
 *! @param str
 *!   String to encode.
 *!
 *! @returns
 *!   Returns the encoded string.
 *!
 *! @seealso
 *!   @[huffman_decode()].
 */
#define f_HPack_huffman_encode_defined
DEFAULT_CMOD_STORAGE void f_HPack_huffman_encode(INT32 args) {
#line 47 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
struct pike_string * str;
#line 47 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
if(args != 1) wrong_number_of_args_error("huffman_encode",args,1);
#line 47 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
if((TYPEOF(Pike_sp[0-1]) != PIKE_T_STRING) || Pike_sp[0-1].u.string->size_shift) SIMPLE_ARG_TYPE_ERROR("huffman_encode",1,"string(8bit)");
#line 47 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
debug_malloc_pass(str=Pike_sp[0-1].u.string);
{
  unsigned char *inbytes = STR0(str);
  unsigned char *outbytes;
  unsigned INT32 huffbuf = 0;
  unsigned INT32 huffbits = 0;
  size_t total_bits = 0;
  struct pike_string *res;
  ptrdiff_t i;

  for (i = str->len; i--;) {
    total_bits += pack_tab[inbytes[i]].bits;
  }
  res = begin_shared_string((total_bits + 7)>>3);
  outbytes = STR0(res);
  for (i = 0; i < str->len; i++, inbytes++) {
    const struct huffentry *entry = &pack_tab[*inbytes];
    huffbuf |= entry->code >> huffbits;
    huffbits += entry->bits;
    if (huffbits > 7) {
      if (UNLIKELY(huffbits > 32)) {
	/* Buffer overflow. Maximum number of needed bits is 37. */
	*outbytes = huffbuf>>24;
	huffbuf <<= 8;
	huffbits -= 8;
	outbytes++;
	if (huffbits >= entry->bits) {
	  huffbuf |= entry->code >> (huffbits - entry->bits);
	} else {
	  huffbuf |= entry->code << (entry->bits - huffbits);
	}
      }
      while (huffbits > 7) {
	*outbytes = huffbuf>>24;
	huffbuf <<= 8;
	huffbits -= 8;
	outbytes++;
      }
    }
  }
  if (huffbits) {
    /* Pad with the most significant bits of EOS (ie ~0). */
    *outbytes = (huffbuf >> 24) | (0xff >> (huffbits & 7));
    outbytes++;
  }
  ASSERT(outbytes == (STR0(res) + res->len));
  pop_stack();
  push_string(end_shared_string(res));
}

}
#line 97 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
static const struct huffentry *find_huffentry(unsigned INT32 huffbuf)
{
  const struct huffentry *entry;
  unsigned int code = (huffbuf >> 24) & 0xff;
  int low = unpack_index[code];
  int high = unpack_index[code+1];
  while (1) {
    int m = (low + high)>>1;
    if (m == low) break;
    entry = &unpack_tab[m];
    if (entry->code > huffbuf) high = m;
    else low = m;
  }
  if (UNLIKELY(low == 255) && UNLIKELY(huffbuf & 4)) {
    /* Invalid encoding. EOS in stream. */
    return NULL;
  }
  return &unpack_tab[low];
}

/*! @decl string(8bit) huffman_decode(string(8bit) str)
 *!
 *! Decodes the string @[str] encoded with the static huffman code specified
 *! in @rfc{7541:B@}.
 *!
 *! @param str
 *!   String to decode.
 *!
 *! @returns
 *!   Returns the decoded string.
 *!
 *! @seealso
 *!   @[huffman_encode()].
 */
#define f_HPack_huffman_decode_defined
DEFAULT_CMOD_STORAGE void f_HPack_huffman_decode(INT32 args) {
#line 131 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
struct pike_string * str;
#line 131 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
if(args != 1) wrong_number_of_args_error("huffman_decode",args,1);
#line 131 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
if((TYPEOF(Pike_sp[0-1]) != PIKE_T_STRING) || Pike_sp[0-1].u.string->size_shift) SIMPLE_ARG_TYPE_ERROR("huffman_decode",1,"string(8bit)");
#line 131 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
debug_malloc_pass(str=Pike_sp[0-1].u.string);
{
  unsigned char *inbytes = STR0(str);
  struct string_builder out;
  unsigned INT_TYPE huffbuf = 0;
  unsigned INT32 huffbits = 0;
  ptrdiff_t i;

  init_string_builder(&out, 0);

  for (i = 0; i < str->len; i++, inbytes++) {
    unsigned INT_TYPE c = *inbytes;
    huffbits += 8;
    huffbuf |= c << ((sizeof(huffbuf)<<3) - huffbits);
    if (huffbits > ((sizeof(huffbuf)-1)<<3)) {
      /* Try to extract some characters. */
      while(1) {
	unsigned INT32 huffkey = huffbuf >> ((sizeof(huffbuf)-4)<<3);
	const struct huffentry *entry = find_huffentry(huffkey);
	if (UNLIKELY(!entry) || (entry->bits > huffbits)) {
	  /* More bits needed. */
	  break;
	}
	ASSERT(entry->code == (huffkey & ~((1<<(32 - entry->bits))-1)));
	string_builder_putchar(&out, entry->sym);
	huffbuf <<= entry->bits;
	huffbits -= entry->bits;
	if (huffbits < 5) break;
      }

#if (SIZEOF_INT_TYPE < 5)
      if (UNLIKELY(huffbits > 24)) {
	/* We need to read more bits than will fit in huffbuf. */
	const struct huffentry *entry;
	unsigned INT32 lostbits = huffbits - 24;
	inbytes++;
	i++;

	if (UNLIKELY(i >= str->len)) break;

	c = *inbytes;
	huffbuf |= c >> lostbits;
	huffbits = 32;
	entry = find_huffentry(huffbuf);
	if (UNLIKELY(!entry)) break;
	ASSERT(entry->code == (huffbuf & ~((1<<(32 - entry->bits))-1)));
	string_builder_putchar(&out, entry->sym);
	huffbits -= entry->bits - lostbits;
	huffbuf = c << (32 - huffbits);
      }
#endif /* SIZEOF_INT_TYPE < 5 */
    }
  }

  while (huffbits) {
    unsigned INT32 huffkey;
    const struct huffentry *entry;
    huffbuf |= ((unsigned INT_TYPE)~0) >> huffbits;
    if (huffbuf == (unsigned INT_TYPE)~0) {
      /* EOS */
      huffbits = 0;
      break;
    }
    if (huffbits < 5) break;
    huffkey = huffbuf >> ((sizeof(huffbuf)-4)<<3);
    entry = find_huffentry(huffkey);
    if (UNLIKELY(!entry) || (entry->bits > huffbits)) {
      /* BAD */
      break;
    }
    ASSERT(entry->code == (huffkey & ~((1<<(32 - entry->bits))-1)));
    string_builder_putchar(&out, entry->sym);
    huffbuf <<= entry->bits;
    huffbits -= entry->bits;
  }
  if (huffbits) {
    /* Invalid encoding. */
    free_string_builder(&out);
    Pike_error("Invalid huffman encoding.\n");
  }

  pop_stack();
  push_string(finish_string_builder(&out));
}

}
/*! @endmodule
 */

#line 219 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
PIKE_MODULE_INIT
{
  
#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
set_program_id_to_id( ___cmod_map_program_ids );

#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */

#ifdef f_HPack_huffman_encode_defined

#ifdef f_HPack_huffman_encode_fun_num_used
  f_HPack_huffman_encode_fun_num =
#endif /* f_HPack_huffman_encode_fun_num_used */
#line 47 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
    ADD_FUNCTION2("huffman_encode", f_HPack_huffman_encode, tFunc(tStr8,tStr8), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_HPack_huffman_encode_defined */

#ifdef f_HPack_huffman_decode_defined

#ifdef f_HPack_huffman_decode_fun_num_used
  f_HPack_huffman_decode_fun_num =
#endif /* f_HPack_huffman_decode_fun_num_used */
#line 131 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
    ADD_FUNCTION2("huffman_decode", f_HPack_huffman_decode, tFunc(tStr8,tStr8), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_HPack_huffman_decode_defined */

#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
set_program_id_to_id( 0 );
#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */
#line 221 "/Users/hww3/devel/pike/src/post_modules/HPack/hpack.cmod"
;
}

PIKE_MODULE_EXIT
{
  ;
}


#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
static int ___cmod_map_program_ids(int id)
{
  if( (id&0x7f000000) != 0x7f000000 ) return id;
  id = id&0x00ffffff;
  return 0;
}
#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */
