g_verify_neg_token_init(unsigned char **buf_in, unsigned int cur_size)
{
	unsigned char *buf = *buf_in;
	unsigned char *endptr = buf + cur_size;
	int seqsize;
	int ret = 0;
	unsigned int bytes;

	/*
	 * Verify this is a NegotiationToken type token
	 * - check for a0(context specific identifier)
	 * - get length and verify that enoughd ata exists
	 */
	if (g_get_tag_and_length(&buf, CONTEXT, cur_size, &bytes) < 0)
		return (G_BAD_TOK_HEADER);

	cur_size = bytes; /* should indicate bytes remaining */

	/*
	 * Verify the next piece, it should identify this as
	 * a strucure of type NegTokenInit.
	 */
	if (*buf++ == SEQUENCE) {
		if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
			return (G_BAD_TOK_HEADER);
		/*
		 * Make sure we have the entire buffer as described
		 */
		if (seqsize > endptr - buf)
			return (G_BAD_TOK_HEADER);
	} else {
		return (G_BAD_TOK_HEADER);
	}

	cur_size = seqsize; /* should indicate bytes remaining */

	/*
	 * Verify that the first blob is a sequence of mechTypes
	 */
	if (*buf++ == CONTEXT) {
		if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
			return (G_BAD_TOK_HEADER);
		/*
		 * Make sure we have the entire buffer as described
		 */
		if (seqsize > endptr - buf)
			return (G_BAD_TOK_HEADER);
	} else {
		return (G_BAD_TOK_HEADER);
	}

	/*
	 * At this point, *buf should be at the beginning of the
	 * DER encoded list of mech types that are to be negotiated.
	 */
	*buf_in = buf;

	return (ret);

}


get_mech_oid(OM_uint32 *minor_status, unsigned char **buff_in, size_t length)
{
	OM_uint32	status;
	gss_OID_desc 	toid;
	gss_OID		mech_out = NULL;
	unsigned char		*start, *end;

	if (length < 1 || **buff_in != MECH_OID)
		return (NULL);

	start = *buff_in;
	end = start + length;

	(*buff_in)++;
	toid.length = *(*buff_in)++;

	if ((*buff_in + toid.length) > end)
		return (NULL);

	toid.elements = *buff_in;
	*buff_in += toid.length;

	status = generic_gss_copy_oid(minor_status, &toid, &mech_out);

	if (status != GSS_S_COMPLETE) {
		map_errcode(minor_status);
		mech_out = NULL;
	}

	return (mech_out);
}

Fix null deref in SPNEGO acceptor [CVE-2014-4344]

When processing a continuation token, acc_ctx_cont was dereferencing
the initial byte of the token without checking the length.  This could
result in a null dereference.

CVE-2014-4344:

In MIT krb5 1.5 and newer, an unauthenticated or partially
authenticated remote attacker can cause a NULL dereference and
application crash during a SPNEGO negotiation by sending an empty
token as the second or later context token from initiator to acceptor.
The attacker must provide at least one valid context token in the
security context negotiation before sending the empty token.  This can
be done by an unauthenticated attacker by forcing SPNEGO to
renegotiate the underlying mechanism, or by using IAKERB to wrap an
unauthenticated AS-REQ as the first token.

    CVSSv2 Vector: AV:N/AC:L/Au:N/C:N/I:N/A:C/E:POC/RL:OF/RC:C

[kaduk@mit.edu: CVE summary, CVSSv2 vector]

ticket: 7970 (new)
subject: NULL dereference in SPNEGO acceptor for continuation tokens [CVE-2014-4344]
target_version: 1.12.2
tags: pullup

#define HARD_ERROR(v) ((v) != GSS_S_COMPLETE && (v) != GSS_S_CONTINUE_NEEDED)

typedef const gss_OID_desc *gss_OID_const;

extern unsigned int gssint_der_length_size(unsigned int);

extern int gssint_get_der_length(unsigned char **, unsigned int,
				 unsigned int*);

extern int gssint_put_der_length(unsigned int, unsigned char **, unsigned int);

static spnego_token_t make_spnego_token(const char *);

static gss_buffer_desc make_err_msg(const char *);

static int g_token_size(gss_OID_const, unsigned int);

static int g_make_token_header(gss_OID_const, unsigned int,
			       unsigned char **, unsigned int);

static int g_verify_token_header(gss_OID_const, unsigned int *,
				 unsigned char **,
				 int, unsigned int);

static int g_verify_neg_token_init(unsigned char **, unsigned int);

static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);

static gss_buffer_t get_input_token(unsigned char **, unsigned int);

static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, unsigned int);

static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);

static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t, gss_cred_usage_t,
				     gss_const_key_value_set_t,
				     gss_cred_id_t *, gss_OID_set *);

static OM_uint32 get_negotiable_mechs(OM_uint32 *, spnego_gss_cred_id_t,
				      gss_cred_usage_t, gss_OID_set *);

static int put_input_token(unsigned char **, gss_buffer_t, unsigned int);

static int put_mech_oid(unsigned char **, gss_OID_const, unsigned int);

static int put_negResult(unsigned char **, OM_uint32, unsigned int);

static OM_uint32
process_mic(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t,
	    gss_buffer_t *, OM_uint32 *, send_token_flag *);

static OM_uint32
handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
	   gss_buffer_t *, OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_new(OM_uint32 *, spnego_gss_cred_id_t, gss_ctx_id_t *,
	     send_token_flag *);

static OM_uint32
init_ctx_nego(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32, gss_OID,
	      gss_buffer_t *, gss_buffer_t *,
	      OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_cont(OM_uint32 *, gss_ctx_id_t *, gss_buffer_t,
	      gss_buffer_t *, gss_buffer_t *,
	      OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
		  gss_OID, gss_buffer_t *, gss_buffer_t *,
		  OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
		   gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
		   gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *,
		   OM_uint32 *, send_token_flag *);


make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx,
			  int negHintsCompat,
			  gss_buffer_t mechListMIC, OM_uint32 req_flags,
			  gss_buffer_t data, send_token_flag sendtoken,
			  gss_buffer_t outbuf)
{
	int ret = 0;
	unsigned int tlen, dataLen = 0;
	unsigned int negTokenInitSize = 0;
	unsigned int negTokenInitSeqSize = 0;
	unsigned int negTokenInitContSize = 0;
	unsigned int rspTokenSize = 0;
	unsigned int mechListTokenSize = 0;
	unsigned int micTokenSize = 0;
	unsigned char *t;
	unsigned char *ptr;

	if (outbuf == GSS_C_NO_BUFFER)
		return (-1);

	outbuf->length = 0;
	outbuf->value = NULL;

	/* calculate the data length */

	/*
	 * 0xa0 [DER LEN] [mechTypes]
	 */
	mechListTokenSize = 1 +
		gssint_der_length_size(spnego_ctx->DER_mechTypes.length) +
		spnego_ctx->DER_mechTypes.length;
	dataLen += mechListTokenSize;

	/*
	 * If a token from gss_init_sec_context exists,
	 * add the length of the token + the ASN.1 overhead
	 */
	if (data != NULL) {
		/*
		 * Encoded in final output as:
		 * 0xa2 [DER LEN] 0x04 [DER LEN] [DATA]
		 * -----s--------|--------s2----------
		 */
		rspTokenSize = 1 +
			gssint_der_length_size(data->length) +
			data->length;
		dataLen += 1 + gssint_der_length_size(rspTokenSize) +
			rspTokenSize;
	}

	if (mechListMIC) {
		/*
		 * Encoded in final output as:
		 * 0xa3 [DER LEN] 0x04 [DER LEN] [DATA]
		 *	--s--     -----tlen------------
		 */
		micTokenSize = 1 +
			gssint_der_length_size(mechListMIC->length) +
			mechListMIC->length;
		dataLen += 1 +
			gssint_der_length_size(micTokenSize) +
			micTokenSize;
	}

	/*
	 * Add size of DER encoding
	 * [ SEQUENCE { MechTypeList | ReqFLags | Token | mechListMIC } ]
	 *   0x30 [DER_LEN] [data]
	 *
	 */
	negTokenInitContSize = dataLen;
	negTokenInitSeqSize = 1 + gssint_der_length_size(dataLen) + dataLen;
	dataLen = negTokenInitSeqSize;

	/*
	 * negTokenInitSize indicates the bytes needed to
	 * hold the ASN.1 encoding of the entire NegTokenInit
	 * SEQUENCE.
	 * 0xa0 [DER_LEN] + data
	 *
	 */
	negTokenInitSize = 1 +
		gssint_der_length_size(negTokenInitSeqSize) +
		negTokenInitSeqSize;

	tlen = g_token_size(gss_mech_spnego, negTokenInitSize);

	t = (unsigned char *) gssalloc_malloc(tlen);

	if (t == NULL) {
		return (-1);
	}

	ptr = t;

	/* create the message */
	if ((ret = g_make_token_header(gss_mech_spnego, negTokenInitSize,
			    &ptr, tlen)))
		goto errout;

	*ptr++ = CONTEXT; /* NegotiationToken identifier */
	if ((ret = gssint_put_der_length(negTokenInitSeqSize, &ptr, tlen)))
		goto errout;

	*ptr++ = SEQUENCE;
	if ((ret = gssint_put_der_length(negTokenInitContSize, &ptr,
					 tlen - (int)(ptr-t))))
		goto errout;

	*ptr++ = CONTEXT | 0x00; /* MechTypeList identifier */
	if ((ret = gssint_put_der_length(spnego_ctx->DER_mechTypes.length,
					 &ptr, tlen - (int)(ptr-t))))
		goto errout;

	/* We already encoded the MechSetList */
	(void) memcpy(ptr, spnego_ctx->DER_mechTypes.value,
		      spnego_ctx->DER_mechTypes.length);

	ptr += spnego_ctx->DER_mechTypes.length;

	if (data != NULL) {
		*ptr++ = CONTEXT | 0x02;
		if ((ret = gssint_put_der_length(rspTokenSize,
				&ptr, tlen - (int)(ptr - t))))
			goto errout;

		if ((ret = put_input_token(&ptr, data,
			tlen - (int)(ptr - t))))
			goto errout;
	}

	if (mechListMIC != GSS_C_NO_BUFFER) {
		*ptr++ = CONTEXT | 0x03;
		if ((ret = gssint_put_der_length(micTokenSize,
				&ptr, tlen - (int)(ptr - t))))
			goto errout;

		if (negHintsCompat) {
			ret = put_neg_hints(&ptr, mechListMIC,
					    tlen - (int)(ptr - t));
			if (ret)
				goto errout;
		} else if ((ret = put_input_token(&ptr, mechListMIC,
				tlen - (int)(ptr - t))))
			goto errout;
	}

errout:
	if (ret != 0) {
		if (t)
			free(t);
		t = NULL;
		tlen = 0;
	}
	outbuf->length = tlen;
	outbuf->value = (void *) t;

	return (ret);
}

extern unsigned int gssint_der_length_size(unsigned int);

extern int gssint_get_der_length(unsigned char **, unsigned int,
				 unsigned int*);

extern int gssint_put_der_length(unsigned int, unsigned char **, unsigned int);

static spnego_token_t make_spnego_token(const char *);

static gss_buffer_desc make_err_msg(const char *);

static int g_token_size(gss_OID_const, unsigned int);

static int g_make_token_header(gss_OID_const, unsigned int,
			       unsigned char **, unsigned int);

static int g_verify_token_header(gss_OID_const, unsigned int *,
				 unsigned char **,
				 int, unsigned int);

static int g_verify_neg_token_init(unsigned char **, unsigned int);

static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);

static gss_buffer_t get_input_token(unsigned char **, unsigned int);

static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, unsigned int);

static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);

static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t, gss_cred_usage_t,
				     gss_const_key_value_set_t,
				     gss_cred_id_t *, gss_OID_set *);

static OM_uint32 get_negotiable_mechs(OM_uint32 *, spnego_gss_cred_id_t,
				      gss_cred_usage_t, gss_OID_set *);

static void release_spnego_ctx(spnego_gss_ctx_id_t *);

static void check_spnego_options(spnego_gss_ctx_id_t);

static spnego_gss_ctx_id_t create_spnego_ctx(void);

static int put_mech_set(gss_OID_set mechSet, gss_buffer_t buf);

static int put_input_token(unsigned char **, gss_buffer_t, unsigned int);

static int put_mech_oid(unsigned char **, gss_OID_const, unsigned int);

static int put_negResult(unsigned char **, OM_uint32, unsigned int);

static OM_uint32
process_mic(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t,
	    gss_buffer_t *, OM_uint32 *, send_token_flag *);

static OM_uint32
handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
	   gss_buffer_t *, OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_new(OM_uint32 *, spnego_gss_cred_id_t, gss_ctx_id_t *,
	     send_token_flag *);

static OM_uint32
init_ctx_nego(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32, gss_OID,
	      gss_buffer_t *, gss_buffer_t *,
	      OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_cont(OM_uint32 *, gss_ctx_id_t *, gss_buffer_t,
	      gss_buffer_t *, gss_buffer_t *,
	      OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
		  gss_OID, gss_buffer_t *, gss_buffer_t *,
		  OM_uint32 *, send_token_flag *);


spnego_gss_display_name_ext(OM_uint32 *minor_status,
			    gss_name_t name,
			    gss_OID display_as_name_type,
			    gss_buffer_t display_name)
{
	OM_uint32 ret;
	ret = gss_display_name_ext(minor_status,
				   name,
				   display_as_name_type,
				   display_name);
	return (ret);
}

static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);

static gss_buffer_t get_input_token(unsigned char **, unsigned int);

static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, unsigned int);

static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);

static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t, gss_cred_usage_t,
				     gss_const_key_value_set_t,
				     gss_cred_id_t *, gss_OID_set *);

static OM_uint32 get_negotiable_mechs(OM_uint32 *, spnego_gss_cred_id_t,
				      gss_cred_usage_t, gss_OID_set *);

static int put_mech_set(gss_OID_set mechSet, gss_buffer_t buf);

static int put_input_token(unsigned char **, gss_buffer_t, unsigned int);

static int put_negResult(unsigned char **, OM_uint32, unsigned int);

static OM_uint32
process_mic(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t,
	    gss_buffer_t *, OM_uint32 *, send_token_flag *);

static OM_uint32
handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
	   gss_buffer_t *, OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_new(OM_uint32 *, spnego_gss_cred_id_t, gss_ctx_id_t *,
	     send_token_flag *);

static OM_uint32
init_ctx_nego(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32, gss_OID,
	      gss_buffer_t *, gss_buffer_t *,
	      OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_cont(OM_uint32 *, gss_ctx_id_t *, gss_buffer_t,
	      gss_buffer_t *, gss_buffer_t *,
	      OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
		  gss_OID, gss_buffer_t *, gss_buffer_t *,
		  OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
		   gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
		   gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *,
		   OM_uint32 *, send_token_flag *);

static OM_uint32
acc_ctx_new(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
	    spnego_gss_cred_id_t, gss_buffer_t *,
	    gss_buffer_t *, OM_uint32 *, send_token_flag *);

static OM_uint32
acc_ctx_cont(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
	     gss_buffer_t *, gss_buffer_t *,
	     OM_uint32 *, send_token_flag *);

static OM_uint32
acc_ctx_vfy_oid(OM_uint32 *, spnego_gss_ctx_id_t, gss_OID,
		OM_uint32 *, send_token_flag *);


spnego_gss_get_name_attribute(OM_uint32 *minor_status,
			      gss_name_t name,
			      gss_buffer_t attr,
			      int *authenticated,
			      int *complete,
			      gss_buffer_t value,
			      gss_buffer_t display_value,
			      int *more)
{
	OM_uint32 ret;
	ret = gss_get_name_attribute(minor_status,
				     name,
				     attr,
				     authenticated,
				     complete,
				     value,
				     display_value,
				     more);
	return (ret);
}

extern unsigned int gssint_der_length_size(unsigned int);

extern int gssint_get_der_length(unsigned char **, unsigned int,
				 unsigned int*);

extern int gssint_put_der_length(unsigned int, unsigned char **, unsigned int);

static int g_token_size(gss_OID_const, unsigned int);

static int g_make_token_header(gss_OID_const, unsigned int,
			       unsigned char **, unsigned int);

static int g_verify_token_header(gss_OID_const, unsigned int *,
				 unsigned char **,
				 int, unsigned int);

static int g_verify_neg_token_init(unsigned char **, unsigned int);

static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);

static gss_buffer_t get_input_token(unsigned char **, unsigned int);

static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, unsigned int);

static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);

static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t, gss_cred_usage_t,
				     gss_const_key_value_set_t,
				     gss_cred_id_t *, gss_OID_set *);

static OM_uint32 get_negotiable_mechs(OM_uint32 *, spnego_gss_cred_id_t,
				      gss_cred_usage_t, gss_OID_set *);

static int put_mech_set(gss_OID_set mechSet, gss_buffer_t buf);

static int put_input_token(unsigned char **, gss_buffer_t, unsigned int);

static int put_mech_oid(unsigned char **, gss_OID_const, unsigned int);

static int put_negResult(unsigned char **, OM_uint32, unsigned int);

static OM_uint32
process_mic(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t,
	    gss_buffer_t *, OM_uint32 *, send_token_flag *);

static OM_uint32
handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
	   gss_buffer_t *, OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_new(OM_uint32 *, spnego_gss_cred_id_t, gss_ctx_id_t *,
	     send_token_flag *);

static OM_uint32
init_ctx_nego(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32, gss_OID,
	      gss_buffer_t *, gss_buffer_t *,
	      OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_cont(OM_uint32 *, gss_ctx_id_t *, gss_buffer_t,
	      gss_buffer_t *, gss_buffer_t *,
	      OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
		  gss_OID, gss_buffer_t *, gss_buffer_t *,
		  OM_uint32 *, send_token_flag *);

static OM_uint32
init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
		   gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
		   gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *,
		   OM_uint32 *, send_token_flag *);

static OM_uint32
acc_ctx_new(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
	    spnego_gss_cred_id_t, gss_buffer_t *,
	    gss_buffer_t *, OM_uint32 *, send_token_flag *);


spnego_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
		       gss_qop_t qop_req, gss_iov_buffer_desc *iov,
		       int iov_count)
{
    return gss_get_mic_iov(minor_status, context_handle, qop_req, iov,
			   iov_count);
}


put_mech_oid(unsigned char **buf_out, gss_OID_const mech, unsigned int buflen)
{
	if (buflen < mech->length + 2)
		return (-1);
	*(*buf_out)++ = MECH_OID;
	*(*buf_out)++ = (unsigned char) mech->length;
	memcpy(*buf_out, mech->elements, mech->length);
	*buf_out += mech->length;
	return (0);
}

typedef const gss_OID_desc *gss_OID_const;

extern unsigned int gssint_der_length_size(unsigned int);

extern int gssint_get_der_length(unsigned char **, unsigned int,
				 unsigned int*);

extern int gssint_put_der_length(unsigned int, unsigned char **, unsigned int);

static spnego_token_t make_spnego_token(const char *);

static gss_buffer_desc make_err_msg(const char *);

static int g_token_size(gss_OID_const, unsigned int);

static int g_make_token_header(gss_OID_const, unsigned int,
			       unsigned char **, unsigned int);

static int g_verify_token_header(gss_OID_const, unsigned int *,
				 unsigned char **,
				 int, unsigned int);

static int g_verify_neg_token_init(unsigned char **, unsigned int);

static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);

static gss_buffer_t get_input_token(unsigned char **, unsigned int);

static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, unsigned int);

static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);

static int put_mech_set(gss_OID_set mechSet, gss_buffer_t buf);

static int put_input_token(unsigned char **, gss_buffer_t, unsigned int);

static int put_mech_oid(unsigned char **, gss_OID_const, unsigned int);

static int put_negResult(unsigned char **, OM_uint32, unsigned int);

static OM_uint32
handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
	   gss_buffer_t *, OM_uint32 *, send_token_flag *);

static int
g_get_tag_and_length(unsigned char **, int, unsigned int, unsigned int *);

static int
make_spnego_tokenInit_msg(spnego_gss_ctx_id_t,
			int,
			gss_buffer_t,
			OM_uint32, gss_buffer_t, send_token_flag,
			gss_buffer_t);

static int
make_spnego_tokenTarg_msg(OM_uint32, gss_OID, gss_buffer_t,
			gss_buffer_t, send_token_flag,
			gss_buffer_t);

static OM_uint32
get_negTokenResp(OM_uint32 *, unsigned char *, unsigned int,
		 OM_uint32 *, gss_OID *, gss_buffer_t *, gss_buffer_t *);

static int
is_kerb_mech(gss_OID oid);

static int make_NegHints(OM_uint32 *, spnego_gss_cred_id_t, gss_buffer_t *);

static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int);

int gss_krb5int_lib_init(void);


GetDataBlock(gif_source_ptr sinfo, U_CHAR *buf)
/* Read a GIF data block, which has a leading count byte */
/* A zero-length block marks the end of a data block sequence */
{
  int count;

  count = ReadByte(sinfo);
  if (count > 0) {
    if (!ReadOK(sinfo->pub.input_file, buf, count))
      ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
  }
  return count;
}

cjpeg: Fix FPE when compressing 0-width GIF

Fixes #493

typedef unsigned char U_CHAR;

#define UCH(x)  ((int)(x))

#define ReadOK(file, buffer, len) \
  (JFREAD(file, buffer, len) == ((size_t)(len)))

#define MAXCOLORMAPSIZE  256    /* max # of colors in a GIF colormap */

#define LM_to_uint(array, offset) \
  ((unsigned int)UCH(array[offset]) + \
   (((unsigned int)UCH(array[offset + 1])) << 8))

#define BitSet(byte, bit)       ((byte) & (bit))

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


GetCode(gif_source_ptr sinfo)
/* Fetch the next code_size bits from the GIF data */
/* We assume code_size is less than 16 */
{
  register int accum;
  int offs, count;

  while (sinfo->cur_bit + sinfo->code_size > sinfo->last_bit) {
    /* Time to reload the buffer */
    /* First time, share code with Clear case */
    if (sinfo->first_time) {
      sinfo->first_time = FALSE;
      return sinfo->clear_code;
    }
    if (sinfo->out_of_blocks) {
      WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);
      return sinfo->end_code;   /* fake something useful */
    }
    /* preserve last two bytes of what we have -- assume code_size <= 16 */
    sinfo->code_buf[0] = sinfo->code_buf[sinfo->last_byte-2];
    sinfo->code_buf[1] = sinfo->code_buf[sinfo->last_byte-1];
    /* Load more bytes; set flag if we reach the terminator block */
    if ((count = GetDataBlock(sinfo, &sinfo->code_buf[2])) == 0) {
      sinfo->out_of_blocks = TRUE;
      WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);
      return sinfo->end_code;   /* fake something useful */
    }
    /* Reset counters */
    sinfo->cur_bit = (sinfo->cur_bit - sinfo->last_bit) + 16;
    sinfo->last_byte = 2 + count;
    sinfo->last_bit = sinfo->last_byte * 8;
  }

  /* Form up next 24 bits in accum */
  offs = sinfo->cur_bit >> 3;   /* byte containing cur_bit */
  accum = UCH(sinfo->code_buf[offs + 2]);
  accum <<= 8;
  accum |= UCH(sinfo->code_buf[offs + 1]);
  accum <<= 8;
  accum |= UCH(sinfo->code_buf[offs]);

  /* Right-align cur_bit in accum, then mask off desired number of bits */
  accum >>= (sinfo->cur_bit & 7);
  sinfo->cur_bit += sinfo->code_size;
  return accum & ((1 << sinfo->code_size) - 1);
}

#define UCH(x)  ((int)(x))

#define ReadOK(file, buffer, len) \
  (JFREAD(file, buffer, len) == ((size_t)(len)))

#define MAXCOLORMAPSIZE  256    /* max # of colors in a GIF colormap */

#define MAX_LZW_BITS     12     /* maximum LZW code size */

#define LM_to_uint(array, offset) \
  ((unsigned int)UCH(array[offset]) + \
   (((unsigned int)UCH(array[offset + 1])) << 8))

#define BitSet(byte, bit)       ((byte) & (bit))

#define INTERLACE       0x40    /* mask for bit signifying interlaced image */

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


finish_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
{
  /* no work */
}

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


InitLZWCode(gif_source_ptr sinfo)
/* Initialize for a series of LZWReadByte (and hence GetCode) calls */
{
  /* GetCode initialization */
  sinfo->last_byte = 2;         /* make safe to "recopy last two bytes" */
  sinfo->code_buf[0] = 0;
  sinfo->code_buf[1] = 0;
  sinfo->last_bit = 0;          /* nothing in the buffer */
  sinfo->cur_bit = 0;           /* force buffer load on first call */
  sinfo->first_time = TRUE;
  sinfo->out_of_blocks = FALSE;

  /* LZWReadByte initialization: */
  /* compute special code values (note that these do not change later) */
  sinfo->clear_code = 1 << sinfo->input_code_size;
  sinfo->end_code = sinfo->clear_code + 1;
  ReInitLZW(sinfo);
}

#define ReadOK(file, buffer, len) \
  (JFREAD(file, buffer, len) == ((size_t)(len)))

#define MAX_LZW_BITS     12     /* maximum LZW code size */

#define INTERLACE       0x40    /* mask for bit signifying interlaced image */

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


SkipDataBlocks(gif_source_ptr sinfo)
/* Skip a series of data blocks, until a block terminator is found */
{
  U_CHAR buf[256];

  while (GetDataBlock(sinfo, buf) > 0)
    /* skip */;
}

typedef unsigned char U_CHAR;

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


LZWReadByte(gif_source_ptr sinfo)
/* Read an LZW-compressed byte */
{
  register int code;            /* current working code */
  int incode;                   /* saves actual input code */

  /* If any codes are stacked from a previously read symbol, return them */
  if (sinfo->sp > sinfo->symbol_stack)
    return (int)(*(--sinfo->sp));

  /* Time to read a new symbol */
  code = GetCode(sinfo);

  if (code == sinfo->clear_code) {
    /* Reinit state, swallow any extra Clear codes, and */
    /* return next code, which is expected to be a raw byte. */
    ReInitLZW(sinfo);
    do {
      code = GetCode(sinfo);
    } while (code == sinfo->clear_code);
    if (code > sinfo->clear_code) { /* make sure it is a raw byte */
      WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);
      code = 0;                 /* use something valid */
    }
    /* make firstcode, oldcode valid! */
    sinfo->firstcode = sinfo->oldcode = code;
    return code;
  }

  if (code == sinfo->end_code) {
    /* Skip the rest of the image, unless GetCode already read terminator */
    if (!sinfo->out_of_blocks) {
      SkipDataBlocks(sinfo);
      sinfo->out_of_blocks = TRUE;
    }
    /* Complain that there's not enough data */
    WARNMS(sinfo->cinfo, JWRN_GIF_ENDCODE);
    /* Pad data with 0's */
    return 0;                   /* fake something usable */
  }

  /* Got normal raw byte or LZW symbol */
  incode = code;                /* save for a moment */

  if (code >= sinfo->max_code) { /* special case for not-yet-defined symbol */
    /* code == max_code is OK; anything bigger is bad data */
    if (code > sinfo->max_code) {
      WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);
      incode = 0;               /* prevent creation of loops in symbol table */
    }
    /* this symbol will be defined as oldcode/firstcode */
    *(sinfo->sp++) = (UINT8)sinfo->firstcode;
    code = sinfo->oldcode;
  }

  /* If it's a symbol, expand it into the stack */
  while (code >= sinfo->clear_code) {
    *(sinfo->sp++) = sinfo->symbol_tail[code]; /* tail is a byte value */
    code = sinfo->symbol_head[code]; /* head is another LZW symbol */
  }
  /* At this point code just represents a raw byte */
  sinfo->firstcode = code;      /* save for possible future use */

  /* If there's room in table... */
  if ((code = sinfo->max_code) < LZW_TABLE_SIZE) {
    /* Define a new symbol = prev sym + head of this sym's expansion */
    sinfo->symbol_head[code] = (UINT16)sinfo->oldcode;
    sinfo->symbol_tail[code] = (UINT8)sinfo->firstcode;
    sinfo->max_code++;
    /* Is it time to increase code_size? */
    if (sinfo->max_code >= sinfo->limit_code &&
        sinfo->code_size < MAX_LZW_BITS) {
      sinfo->code_size++;
      sinfo->limit_code <<= 1;  /* keep equal to 2^code_size */
    }
  }

  sinfo->oldcode = incode;      /* save last input symbol for future use */
  return sinfo->firstcode;      /* return first byte of symbol's expansion */
}

#define UCH(x)  ((int)(x))

#define MAX_LZW_BITS     12     /* maximum LZW code size */

#define LZW_TABLE_SIZE   (1 << MAX_LZW_BITS) /* # of possible LZW symbols */

#define LM_to_uint(array, offset) \
  ((unsigned int)UCH(array[offset]) + \
   (((unsigned int)UCH(array[offset + 1])) << 8))

#define BitSet(byte, bit)       ((byte) & (bit))

#define INTERLACE       0x40    /* mask for bit signifying interlaced image */

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


ReadColorMap(gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap)
/* Read a GIF colormap */
{
  int i;

  for (i = 0; i < cmaplen; i++) {
#if BITS_IN_JSAMPLE == 8
#define UPSCALE(x)  (x)
#else
#define UPSCALE(x)  ((x) << (BITS_IN_JSAMPLE - 8))
#endif
    cmap[CM_RED][i]   = (JSAMPLE)UPSCALE(ReadByte(sinfo));
    cmap[CM_GREEN][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo));
    cmap[CM_BLUE][i]  = (JSAMPLE)UPSCALE(ReadByte(sinfo));
  }
}

#define UCH(x)  ((int)(x))

#define ReadOK(file, buffer, len) \
  (JFREAD(file, buffer, len) == ((size_t)(len)))

#define MAXCOLORMAPSIZE  256    /* max # of colors in a GIF colormap */

#define NUMCOLORS        3      /* # of colors */

#define CM_RED           0      /* color component numbers */

#define CM_GREEN         1

#define CM_BLUE          2

#define MAX_LZW_BITS     12     /* maximum LZW code size */

#define LZW_TABLE_SIZE   (1 << MAX_LZW_BITS) /* # of possible LZW symbols */

#define LM_to_uint(array, offset) \
  ((unsigned int)UCH(array[offset]) + \
   (((unsigned int)UCH(array[offset + 1])) << 8))

#define BitSet(byte, bit)       ((byte) & (bit))

#define INTERLACE       0x40    /* mask for bit signifying interlaced image */

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
{
  gif_source_ptr source = (gif_source_ptr)sinfo;
  U_CHAR hdrbuf[10];            /* workspace for reading control blocks */
  unsigned int width, height;   /* image dimensions */
  int colormaplen, aspectRatio;
  int c;

  /* Read and verify GIF Header */
  if (!ReadOK(source->pub.input_file, hdrbuf, 6))
    ERREXIT(cinfo, JERR_GIF_NOT);
  if (hdrbuf[0] != 'G' || hdrbuf[1] != 'I' || hdrbuf[2] != 'F')
    ERREXIT(cinfo, JERR_GIF_NOT);
  /* Check for expected version numbers.
   * If unknown version, give warning and try to process anyway;
   * this is per recommendation in GIF89a standard.
   */
  if ((hdrbuf[3] != '8' || hdrbuf[4] != '7' || hdrbuf[5] != 'a') &&
      (hdrbuf[3] != '8' || hdrbuf[4] != '9' || hdrbuf[5] != 'a'))
    TRACEMS3(cinfo, 1, JTRC_GIF_BADVERSION, hdrbuf[3], hdrbuf[4], hdrbuf[5]);

  /* Read and decipher Logical Screen Descriptor */
  if (!ReadOK(source->pub.input_file, hdrbuf, 7))
    ERREXIT(cinfo, JERR_INPUT_EOF);
  width = LM_to_uint(hdrbuf, 0);
  height = LM_to_uint(hdrbuf, 2);
  if (width == 0 || height == 0)
    ERREXIT(cinfo, JERR_GIF_EMPTY);
  /* we ignore the color resolution, sort flag, and background color index */
  aspectRatio = UCH(hdrbuf[6]);
  if (aspectRatio != 0 && aspectRatio != 49)
    TRACEMS(cinfo, 1, JTRC_GIF_NONSQUARE);

  /* Allocate space to store the colormap */
  source->colormap = (*cinfo->mem->alloc_sarray)
    ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)MAXCOLORMAPSIZE,
     (JDIMENSION)NUMCOLORS);
  colormaplen = 0;              /* indicate initialization */

  /* Read global colormap if header indicates it is present */
  if (BitSet(hdrbuf[4], COLORMAPFLAG)) {
    colormaplen = 2 << (hdrbuf[4] & 0x07);
    ReadColorMap(source, colormaplen, source->colormap);
  }

  /* Scan until we reach start of desired image.
   * We don't currently support skipping images, but could add it easily.
   */
  for (;;) {
    c = ReadByte(source);

    if (c == ';')               /* GIF terminator?? */
      ERREXIT(cinfo, JERR_GIF_IMAGENOTFOUND);

    if (c == '!') {             /* Extension */
      DoExtension(source);
      continue;
    }

    if (c != ',') {             /* Not an image separator? */
      WARNMS1(cinfo, JWRN_GIF_CHAR, c);
      continue;
    }

    /* Read and decipher Local Image Descriptor */
    if (!ReadOK(source->pub.input_file, hdrbuf, 9))
      ERREXIT(cinfo, JERR_INPUT_EOF);
    /* we ignore top/left position info, also sort flag */
    width = LM_to_uint(hdrbuf, 4);
    height = LM_to_uint(hdrbuf, 6);
    if (width == 0 || height == 0)
      ERREXIT(cinfo, JERR_GIF_EMPTY);
    source->is_interlaced = (BitSet(hdrbuf[8], INTERLACE) != 0);

    /* Read local colormap if header indicates it is present */
    /* Note: if we wanted to support skipping images, */
    /* we'd need to skip rather than read colormap for ignored images */
    if (BitSet(hdrbuf[8], COLORMAPFLAG)) {
      colormaplen = 2 << (hdrbuf[8] & 0x07);
      ReadColorMap(source, colormaplen, source->colormap);
    }

    source->input_code_size = ReadByte(source); /* get min-code-size byte */
    if (source->input_code_size < 2 || source->input_code_size > 8)
      ERREXIT1(cinfo, JERR_GIF_CODESIZE, source->input_code_size);

    /* Reached desired image, so break out of loop */
    /* If we wanted to skip this image, */
    /* we'd call SkipDataBlocks and then continue the loop */
    break;
  }

  /* Prepare to read selected image: first initialize LZW decompressor */
  source->symbol_head = (UINT16 *)
    (*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                LZW_TABLE_SIZE * sizeof(UINT16));
  source->symbol_tail = (UINT8 *)
    (*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                LZW_TABLE_SIZE * sizeof(UINT8));
  source->symbol_stack = (UINT8 *)
    (*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                LZW_TABLE_SIZE * sizeof(UINT8));
  InitLZWCode(source);

  /*
   * If image is interlaced, we read it into a full-size sample array,
   * decompressing as we go; then get_interlaced_row selects rows from the
   * sample array in the proper order.
   */
  if (source->is_interlaced) {
    /* We request the virtual array now, but can't access it until virtual
     * arrays have been allocated.  Hence, the actual work of reading the
     * image is postponed until the first call to get_pixel_rows.
     */
    source->interlaced_image = (*cinfo->mem->request_virt_sarray)
      ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
       (JDIMENSION)width, (JDIMENSION)height, (JDIMENSION)1);
    if (cinfo->progress != NULL) {
      cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
      progress->total_extra_passes++; /* count file input as separate pass */
    }
    source->pub.get_pixel_rows = load_interlaced_image;
  } else {
    source->pub.get_pixel_rows = get_pixel_rows;
  }

  /* Create compressor input buffer. */
  source->pub.buffer = (*cinfo->mem->alloc_sarray)
    ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)width * NUMCOLORS,
     (JDIMENSION)1);
  source->pub.buffer_height = 1;

  /* Pad colormap for safety. */
  for (c = colormaplen; c < source->clear_code; c++) {
    source->colormap[CM_RED][c]   =
    source->colormap[CM_GREEN][c] =
    source->colormap[CM_BLUE][c]  = CENTERJSAMPLE;
  }

  /* Return info about the image. */
  cinfo->in_color_space = JCS_RGB;
  cinfo->input_components = NUMCOLORS;
  cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
  cinfo->image_width = width;
  cinfo->image_height = height;

  TRACEMS3(cinfo, 1, JTRC_GIF, width, height, colormaplen);
}

typedef unsigned char U_CHAR;

#define UCH(x)  ((int)(x))

#define ReadOK(file, buffer, len) \
  (JFREAD(file, buffer, len) == ((size_t)(len)))

#define MAXCOLORMAPSIZE  256    /* max # of colors in a GIF colormap */

#define NUMCOLORS        3      /* # of colors */

#define CM_RED           0      /* color component numbers */

#define CM_GREEN         1

#define CM_BLUE          2

#define MAX_LZW_BITS     12     /* maximum LZW code size */

#define LZW_TABLE_SIZE   (1 << MAX_LZW_BITS) /* # of possible LZW symbols */

#define LM_to_uint(array, offset) \
  ((unsigned int)UCH(array[offset]) + \
   (((unsigned int)UCH(array[offset + 1])) << 8))

#define BitSet(byte, bit)       ((byte) & (bit))

#define INTERLACE       0x40    /* mask for bit signifying interlaced image */

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


get_interlaced_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
{
  gif_source_ptr source = (gif_source_ptr)sinfo;
  register int c;
  register JSAMPROW sptr, ptr;
  register JDIMENSION col;
  register JSAMPARRAY colormap = source->colormap;
  JDIMENSION irow;

  /* Figure out which row of interlaced image is needed, and access it. */
  switch ((int)(source->cur_row_number & 7)) {
  case 0:                       /* first-pass row */
    irow = source->cur_row_number >> 3;
    break;
  case 4:                       /* second-pass row */
    irow = (source->cur_row_number >> 3) + source->pass2_offset;
    break;
  case 2:                       /* third-pass row */
  case 6:
    irow = (source->cur_row_number >> 2) + source->pass3_offset;
    break;
  default:                      /* fourth-pass row */
    irow = (source->cur_row_number >> 1) + source->pass4_offset;
  }
  sptr = *(*cinfo->mem->access_virt_sarray)
    ((j_common_ptr)cinfo, source->interlaced_image, irow, (JDIMENSION)1,
     FALSE);
  /* Scan the row, expand colormap, and output */
  ptr = source->pub.buffer[0];
  for (col = cinfo->image_width; col > 0; col--) {
    c = *sptr++;
    *ptr++ = colormap[CM_RED][c];
    *ptr++ = colormap[CM_GREEN][c];
    *ptr++ = colormap[CM_BLUE][c];
  }
  source->cur_row_number++;     /* for next time */
  return 1;
}

#define UCH(x)  ((int)(x))

#define ReadOK(file, buffer, len) \
  (JFREAD(file, buffer, len) == ((size_t)(len)))

#define MAXCOLORMAPSIZE  256    /* max # of colors in a GIF colormap */

#define CM_RED           0      /* color component numbers */

#define CM_GREEN         1

#define CM_BLUE          2

#define LM_to_uint(array, offset) \
  ((unsigned int)UCH(array[offset]) + \
   (((unsigned int)UCH(array[offset + 1])) << 8))

#define INTERLACE       0x40    /* mask for bit signifying interlaced image */

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


DoExtension(gif_source_ptr sinfo)
/* Process an extension block */
/* Currently we ignore 'em all */
{
  int extlabel;

  /* Read extension label byte */
  extlabel = ReadByte(sinfo);
  TRACEMS1(sinfo->cinfo, 1, JTRC_GIF_EXTENSION, extlabel);
  /* Skip the data block(s) associated with the extension */
  SkipDataBlocks(sinfo);
}

#define UCH(x)  ((int)(x))

#define LM_to_uint(array, offset) \
  ((unsigned int)UCH(array[offset]) + \
   (((unsigned int)UCH(array[offset + 1])) << 8))

#define BitSet(byte, bit)       ((byte) & (bit))

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


load_interlaced_image(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
{
  gif_source_ptr source = (gif_source_ptr)sinfo;
  register JSAMPROW sptr;
  register JDIMENSION col;
  JDIMENSION row;
  cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;

  /* Read the interlaced image into the virtual array we've created. */
  for (row = 0; row < cinfo->image_height; row++) {
    if (progress != NULL) {
      progress->pub.pass_counter = (long)row;
      progress->pub.pass_limit = (long)cinfo->image_height;
      (*progress->pub.progress_monitor) ((j_common_ptr)cinfo);
    }
    sptr = *(*cinfo->mem->access_virt_sarray)
      ((j_common_ptr)cinfo, source->interlaced_image, row, (JDIMENSION)1,
       TRUE);
    for (col = cinfo->image_width; col > 0; col--) {
      *sptr++ = (JSAMPLE)LZWReadByte(source);
    }
  }
  if (progress != NULL)
    progress->completed_extra_passes++;

  /* Replace method pointer so subsequent calls don't come here. */
  source->pub.get_pixel_rows = get_interlaced_row;
  /* Initialize for get_interlaced_row, and perform first call on it. */
  source->cur_row_number = 0;
  source->pass2_offset = (cinfo->image_height + 7) / 8;
  source->pass3_offset = source->pass2_offset + (cinfo->image_height + 3) / 8;
  source->pass4_offset = source->pass3_offset + (cinfo->image_height + 1) / 4;

  return get_interlaced_row(cinfo, sinfo);
}

#define LM_to_uint(array, offset) \
  ((unsigned int)UCH(array[offset]) + \
   (((unsigned int)UCH(array[offset + 1])) << 8))

#define INTERLACE       0x40    /* mask for bit signifying interlaced image */

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


ReadByte(gif_source_ptr sinfo)
/* Read next byte from GIF file */
{
  register FILE *infile = sinfo->pub.input_file;
  register int c;

  if ((c = getc(infile)) == EOF)
    ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
  return c;
}

#define UCH(x)  ((int)(x))

#define ReadOK(file, buffer, len) \
  (JFREAD(file, buffer, len) == ((size_t)(len)))

#define MAXCOLORMAPSIZE  256    /* max # of colors in a GIF colormap */

#define LM_to_uint(array, offset) \
  ((unsigned int)UCH(array[offset]) + \
   (((unsigned int)UCH(array[offset + 1])) << 8))

#define BitSet(byte, bit)       ((byte) & (bit))

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


jinit_read_gif(j_compress_ptr cinfo)
{
  gif_source_ptr source;

  /* Create module interface object */
  source = (gif_source_ptr)
    (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                sizeof(gif_source_struct));
  source->cinfo = cinfo;        /* make back link for subroutines */
  /* Fill in method ptrs, except get_pixel_rows which start_input sets */
  source->pub.start_input = start_input_gif;
  source->pub.finish_input = finish_input_gif;

  return (cjpeg_source_ptr)source;
}

#define INTERLACE       0x40    /* mask for bit signifying interlaced image */

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


get_pixel_rows(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
{
  gif_source_ptr source = (gif_source_ptr)sinfo;
  register int c;
  register JSAMPROW ptr;
  register JDIMENSION col;
  register JSAMPARRAY colormap = source->colormap;

  ptr = source->pub.buffer[0];
  for (col = cinfo->image_width; col > 0; col--) {
    c = LZWReadByte(source);
    *ptr++ = colormap[CM_RED][c];
    *ptr++ = colormap[CM_GREEN][c];
    *ptr++ = colormap[CM_BLUE][c];
  }
  return 1;
}


ReInitLZW(gif_source_ptr sinfo)
/* (Re)initialize LZW state; shared code for startup and Clear processing */
{
  sinfo->code_size = sinfo->input_code_size + 1;
  sinfo->limit_code = sinfo->clear_code << 1;   /* 2^code_size */
  sinfo->max_code = sinfo->clear_code + 2;      /* first unused code value */
  sinfo->sp = sinfo->symbol_stack;              /* init stack to empty */
}

#define MAX_LZW_BITS     12     /* maximum LZW code size */

#define LZW_TABLE_SIZE   (1 << MAX_LZW_BITS) /* # of possible LZW symbols */

#define INTERLACE       0x40    /* mask for bit signifying interlaced image */

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */

typedef struct {
  struct cjpeg_source_struct pub; /* public fields */

  j_compress_ptr cinfo;         /* back link saves passing separate parm */

  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */

  /* State for GetCode and LZWReadByte */
  U_CHAR code_buf[256 + 4];     /* current input data block */
  int last_byte;                /* # of bytes in code_buf */
  int last_bit;                 /* # of bits in code_buf */
  int cur_bit;                  /* next bit index to read */
  boolean first_time;           /* flags first call to GetCode */
  boolean out_of_blocks;        /* TRUE if hit terminator data block */

  int input_code_size;          /* codesize given in GIF file */
  int clear_code, end_code;     /* values for Clear and End codes */

  int code_size;                /* current actual code size */
  int limit_code;               /* 2^code_size */
  int max_code;                 /* first unused code value */

  /* Private state for LZWReadByte */
  int oldcode;                  /* previous LZW symbol */
  int firstcode;                /* first byte of oldcode's expansion */

  /* LZW symbol table and expansion stack */
  UINT16 *symbol_head;          /* => table of prefix symbols */
  UINT8  *symbol_tail;          /* => table of suffix bytes */
  UINT8  *symbol_stack;         /* => stack for symbol expansions */
  UINT8  *sp;                   /* stack pointer */

  /* State for interlaced image processing */
  boolean is_interlaced;        /* TRUE if have interlaced image */
  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
  JDIMENSION cur_row_number;    /* need to know actual row number */
  JDIMENSION pass2_offset;      /* # of pixel rows in pass 1 */
  JDIMENSION pass3_offset;      /* # of pixel rows in passes 1&2 */
  JDIMENSION pass4_offset;      /* # of pixel rows in passes 1,2,3 */
} gif_source_struct;

typedef gif_source_struct *gif_source_ptr;

METHODDEF(JDIMENSION) get_pixel_rows(j_compress_ptr cinfo,
                                     cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) load_interlaced_image(j_compress_ptr cinfo,
                                            cjpeg_source_ptr sinfo);

METHODDEF(JDIMENSION) get_interlaced_row(j_compress_ptr cinfo,
                                         cjpeg_source_ptr sinfo);


exif_entry_dump (ExifEntry *e, unsigned int indent)
{
	char buf[1024];
	char value[1024];
	unsigned int l;

	if (!e)
		return;

	l = MIN(sizeof(buf)-1, 2*indent);
	memset(buf, ' ', l);
	buf[l] = '\0';

	printf ("%sTag: 0x%x ('%s')\n", buf, e->tag,
		exif_tag_get_name_in_ifd (e->tag, exif_entry_get_ifd(e)));
	printf ("%s  Format: %i ('%s')\n", buf, e->format,
		exif_format_get_name (e->format));
	printf ("%s  Components: %i\n", buf, (int) e->components);
	printf ("%s  Size: %i\n", buf, e->size);
	printf ("%s  Value: %s\n", buf, exif_entry_get_value (e, value, sizeof(value)));
}

fixed a incorrect overflow check that could be optimized away.

inspired by:
https://android.googlesource.com/platform/external/libexif/+/8e7345f3bc0bad06ac369d6cbc1124c8ceaf7d4b

https://source.android.com/security/bulletin/2020-11-01

CVE-2020-0452

struct _ExifEntryPrivate
{
	unsigned int ref_count;

	ExifMem *mem;
}

#define CF(entry,target,v,maxlen)					\
{									\
	if (entry->format != target) {					\
		exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA,	\
			_("The tag '%s' contains data of an invalid "	\
			"format ('%s', expected '%s')."),		\
			exif_tag_get_name (entry->tag),			\
			exif_format_get_name (entry->format),		\
			exif_format_get_name (target));			\
		break;							\
	}								\
}

#define CC(entry,target,v,maxlen)					\
{									\
	if (entry->components != target) {				\
		exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA,	\
			_("The tag '%s' contains an invalid number of "	\
			  "components (%i, expected %i)."),		\
			exif_tag_get_name (entry->tag),		\
			(int) entry->components, (int) target);		\
		break;							\
	}								\
}

static const struct {
	ExifTag tag;
	const char *strings[10];
} list[] = {
#ifndef NO_VERBOSE_TAG_DATA
  { EXIF_TAG_PLANAR_CONFIGURATION,
    { N_("Chunky format"), N_("Planar format"), NULL}},
  { EXIF_TAG_SENSING_METHOD,
    { "", N_("Not defined"), N_("One-chip color area sensor"),
      N_("Two-chip color area sensor"), N_("Three-chip color area sensor"),
      N_("Color sequential area sensor"), "", N_("Trilinear sensor"),
      N_("Color sequential linear sensor"), NULL}},
  { EXIF_TAG_ORIENTATION,
    { "", N_("Top-left"), N_("Top-right"), N_("Bottom-right"),
      N_("Bottom-left"), N_("Left-top"), N_("Right-top"),
      N_("Right-bottom"), N_("Left-bottom"), NULL}},
  { EXIF_TAG_YCBCR_POSITIONING,
    { "", N_("Centered"), N_("Co-sited"), NULL}},
  { EXIF_TAG_PHOTOMETRIC_INTERPRETATION,
    { N_("Reversed mono"), N_("Normal mono"), N_("RGB"), N_("Palette"), "",
      N_("CMYK"), N_("YCbCr"), "", N_("CieLAB"), NULL}},
  { EXIF_TAG_CUSTOM_RENDERED,
    { N_("Normal process"), N_("Custom process"), NULL}},
  { EXIF_TAG_EXPOSURE_MODE,
    { N_("Auto exposure"), N_("Manual exposure"), N_("Auto bracket"), NULL}},
  { EXIF_TAG_WHITE_BALANCE,
    { N_("Auto white balance"), N_("Manual white balance"), NULL}},
  { EXIF_TAG_SCENE_CAPTURE_TYPE,
    { N_("Standard"), N_("Landscape"), N_("Portrait"),
      N_("Night scene"), NULL}},
  { EXIF_TAG_GAIN_CONTROL,
    { N_("Normal"), N_("Low gain up"), N_("High gain up"),
      N_("Low gain down"), N_("High gain down"), NULL}},
  { EXIF_TAG_SATURATION,
    { N_("Normal"), N_("Low saturation"), N_("High saturation"), NULL}},
  { EXIF_TAG_CONTRAST , {N_("Normal"), N_("Soft"), N_("Hard"), NULL}},
  { EXIF_TAG_SHARPNESS, {N_("Normal"), N_("Soft"), N_("Hard"), NULL}},
#endif
  { 0, {NULL}}
};


exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen)
{
	unsigned int i, j, k;
	ExifShort v_short, v_short2, v_short3, v_short4;
	ExifByte v_byte;
	ExifRational v_rat;
	ExifSRational v_srat;
	char b[64];
	const char *c;
	ExifByteOrder o;
	double d;
	ExifEntry *entry;
	static const struct {
		char label[5];
		char major, minor;
	} versions[] = {
		{"0110", 1,  1},
		{"0120", 1,  2},
		{"0200", 2,  0},
		{"0210", 2,  1},
		{"0220", 2,  2},
		{"0221", 2, 21},
		{"0230", 2,  3},
		{""    , 0,  0}
	};

	(void) bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);

	if (!e || !e->parent || !e->parent->parent || !maxlen || !val)
		return val;

	/* make sure the returned string is zero terminated */
	/* FIXME: this is inefficient in the case of long buffers and should
	 * instead be taken care of on each write instead. */
	memset (val, 0, maxlen);

	/* We need the byte order */
	o = exif_data_get_byte_order (e->parent->parent);

	/* Sanity check */
	if (e->size != e->components * exif_format_get_size (e->format)) {
		snprintf (val, maxlen, _("Invalid size of entry (%i, "
			"expected %li x %i)."), e->size, e->components,
				exif_format_get_size (e->format));
		return val;
	}

	switch (e->tag) {
	case EXIF_TAG_USER_COMMENT:

		/*
		 * The specification says UNDEFINED, but some
		 * manufacturers don't care and use ASCII. If this is the
		 * case here, only refuse to read it if there is no chance
		 * of finding readable data.
		 */
		if ((e->format != EXIF_FORMAT_ASCII) ||
		    (e->size <= 8) ||
		    ( memcmp (e->data, "ASCII\0\0\0"  , 8) &&
		      memcmp (e->data, "UNICODE\0"    , 8) &&
		      memcmp (e->data, "JIS\0\0\0\0\0", 8) &&
		      memcmp (e->data, "\0\0\0\0\0\0\0\0", 8)))
			CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen);

		/*
		 * Note that, according to the specification (V2.1, p 40),
		 * the user comment field does not have to be
		 * NULL terminated.
		 */
		if ((e->size >= 8) && !memcmp (e->data, "ASCII\0\0\0", 8)) {
			strncpy (val, (char *) e->data + 8, MIN (e->size - 8, maxlen-1));
			break;
		}
		if ((e->size >= 8) && !memcmp (e->data, "UNICODE\0", 8)) {
			strncpy (val, _("Unsupported UNICODE string"), maxlen-1);
		/* FIXME: use iconv to convert into the locale encoding.
		 * EXIF 2.2 implies (but does not say) that this encoding is
		 * UCS-2.
		 */
			break;
		}
		if ((e->size >= 8) && !memcmp (e->data, "JIS\0\0\0\0\0", 8)) {
			strncpy (val, _("Unsupported JIS string"), maxlen-1);
		/* FIXME: use iconv to convert into the locale encoding */
			break;
		}

		/* Check if there is really some information in the tag. */
		for (i = 0; (i < e->size) &&
			    (!e->data[i] || (e->data[i] == ' ')); i++);
		if (i == e->size) break;

		/*
		 * If we reach this point, the tag does not
 		 * comply with the standard but seems to contain data.
		 * Print as much as possible.
		 * Note: make sure we do not overwrite the final \0 at maxlen-1
		 */
		exif_entry_log (e, EXIF_LOG_CODE_DEBUG,
			_("Tag UserComment contains data but is "
			  "against specification."));
 		for (j = 0; (i < e->size) && (j < maxlen-1); i++, j++) {
			exif_entry_log (e, EXIF_LOG_CODE_DEBUG,
				_("Byte at position %i: 0x%02x"), i, e->data[i]);
 			val[j] = isprint (e->data[i]) ? e->data[i] : '.';
		}
		break;

	case EXIF_TAG_EXIF_VERSION:
		CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (e, 4, val, maxlen);
		strncpy (val, _("Unknown Exif Version"), maxlen-1);
		for (i = 0; *versions[i].label; i++) {
			if (!memcmp (e->data, versions[i].label, 4)) {
    				snprintf (val, maxlen,
					_("Exif Version %d.%d"),
					versions[i].major,
					versions[i].minor);
    				break;
			}
		}
		break;
	case EXIF_TAG_FLASH_PIX_VERSION:
		CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (e, 4, val, maxlen);
		if (!memcmp (e->data, "0100", 4))
			strncpy (val, _("FlashPix Version 1.0"), maxlen-1);
		else if (!memcmp (e->data, "0101", 4))
			strncpy (val, _("FlashPix Version 1.01"), maxlen-1);
		else
			strncpy (val, _("Unknown FlashPix Version"), maxlen-1);
		break;
	case EXIF_TAG_COPYRIGHT:
		CF (e, EXIF_FORMAT_ASCII, val, maxlen);

		/*
		 * First part: Photographer.
		 * Some cameras store a string like "   " here. Ignore it.
		 * Remember that a corrupted tag might not be NUL-terminated
		 */
		if (e->size && e->data && match_repeated_char(e->data, ' ', e->size))
			strncpy (val, (char *) e->data, MIN (maxlen-1, e->size));
		else
			strncpy (val, _("[None]"), maxlen-1);
		strncat (val, " ", maxlen-1 - strlen (val));
		strncat (val, _("(Photographer)"), maxlen-1 - strlen (val));

		/* Second part: Editor. */
		strncat (val, " - ", maxlen-1 - strlen (val));
		k = 0;
		if (e->size && e->data) {
			const unsigned char *tagdata = memchr(e->data, 0, e->size);
			if (tagdata++) {
				unsigned int editor_ofs = tagdata - e->data;
				unsigned int remaining = e->size - editor_ofs;
				if (match_repeated_char(tagdata, ' ', remaining)) {
					strncat (val, (const char*)tagdata, MIN (maxlen-1 - strlen (val), remaining));
					++k;
				}
			}
		}
		if (!k)
			strncat (val, _("[None]"), maxlen-1 - strlen (val));
		strncat (val, " ", maxlen-1 - strlen (val));
		strncat (val, _("(Editor)"), maxlen-1 - strlen (val));

		break;
	case EXIF_TAG_FNUMBER:
		CF (e, EXIF_FORMAT_RATIONAL, val, maxlen);
		CC (e, 1, val, maxlen);
		v_rat = exif_get_rational (e->data, o);
		if (!v_rat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		d = (double) v_rat.numerator / (double) v_rat.denominator;
		snprintf (val, maxlen, "f/%.01f", d);
		break;
	case EXIF_TAG_APERTURE_VALUE:
	case EXIF_TAG_MAX_APERTURE_VALUE:
		CF (e, EXIF_FORMAT_RATIONAL, val, maxlen);
		CC (e, 1, val, maxlen);
		v_rat = exif_get_rational (e->data, o);
		if (!v_rat.denominator || (0x80000000 == v_rat.numerator)) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		d = (double) v_rat.numerator / (double) v_rat.denominator;
		snprintf (val, maxlen, _("%.02f EV"), d);
		snprintf (b, sizeof (b), _(" (f/%.01f)"), pow (2, d / 2.));
		strncat (val, b, maxlen-1 - strlen (val));
		break;
	case EXIF_TAG_FOCAL_LENGTH:
		CF (e, EXIF_FORMAT_RATIONAL, val, maxlen);
		CC (e, 1, val, maxlen);
		v_rat = exif_get_rational (e->data, o);
		if (!v_rat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}

		/*
		 * For calculation of the 35mm equivalent,
		 * Minolta cameras need a multiplier that depends on the
		 * camera model.
		 */
		d = 0.;
		entry = exif_content_get_entry (
			e->parent->parent->ifd[EXIF_IFD_0], EXIF_TAG_MAKE);
		if (entry && entry->data && entry->size >= 7 &&
		    !strncmp ((char *)entry->data, "Minolta", 7)) {
			entry = exif_content_get_entry (
					e->parent->parent->ifd[EXIF_IFD_0],
					EXIF_TAG_MODEL);
			if (entry && entry->data && entry->size >= 8) {
				if (!strncmp ((char *)entry->data, "DiMAGE 7", 8))
					d = 3.9;
				else if (!strncmp ((char *)entry->data, "DiMAGE 5", 8))
					d = 4.9;
			}
		}
		if (d)
			snprintf (b, sizeof (b), _(" (35 equivalent: %.0f mm)"),
				  (d * (double) v_rat.numerator /
				       (double) v_rat.denominator));
		else
			b[0] = 0;

		d = (double) v_rat.numerator / (double) v_rat.denominator;
		snprintf (val, maxlen, "%.1f mm", d);
		strncat (val, b, maxlen-1 - strlen (val));
		break;
	case EXIF_TAG_SUBJECT_DISTANCE:
		CF (e, EXIF_FORMAT_RATIONAL, val, maxlen);
		CC (e, 1, val, maxlen);
		v_rat = exif_get_rational (e->data, o);
		if (!v_rat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		d = (double) v_rat.numerator / (double) v_rat.denominator;
		snprintf (val, maxlen, "%.1f m", d);
		break;
	case EXIF_TAG_EXPOSURE_TIME:
		CF (e, EXIF_FORMAT_RATIONAL, val, maxlen);
		CC (e, 1, val, maxlen);
		v_rat = exif_get_rational (e->data, o);
		if (!v_rat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		d = (double) v_rat.numerator / (double) v_rat.denominator;
		if (d < 1 && d)
			snprintf (val, maxlen, _("1/%.0f"), 1. / d);
		else
			snprintf (val, maxlen, "%.0f", d);
		strncat (val, _(" sec."), maxlen-1 - strlen (val));
		break;
	case EXIF_TAG_SHUTTER_SPEED_VALUE:
		CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen);
		CC (e, 1, val, maxlen);
		v_srat = exif_get_srational (e->data, o);
		if (!v_srat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		d = (double) v_srat.numerator / (double) v_srat.denominator;
		snprintf (val, maxlen, _("%.02f EV"), d);
		if (pow (2, d))
			d = 1. / pow (2, d);
		if (d < 1 && d)
		  snprintf (b, sizeof (b), _(" (1/%.0f sec.)"), 1. / d);
		else
		  snprintf (b, sizeof (b), _(" (%.0f sec.)"), d);
		strncat (val, b, maxlen-1 - strlen (val));
		break;
	case EXIF_TAG_BRIGHTNESS_VALUE:
		CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen);
		CC (e, 1, val, maxlen);
		v_srat = exif_get_srational (e->data, o);
		if (!v_srat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		d = (double) v_srat.numerator / (double) v_srat.denominator;
		snprintf (val, maxlen, _("%.02f EV"), d);
		snprintf (b, sizeof (b), _(" (%.02f cd/m^2)"),
			1. / (M_PI * 0.3048 * 0.3048) * pow (2, d));
		strncat (val, b, maxlen-1 - strlen (val));
		break;
	case EXIF_TAG_FILE_SOURCE:
		CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (e, 1, val, maxlen);
		v_byte = e->data[0];
		if (v_byte == 3)
			strncpy (val, _("DSC"), maxlen-1);
		else
			snprintf (val, maxlen, _("Internal error (unknown "
				  "value %i)"), v_byte);
		break;
	case EXIF_TAG_COMPONENTS_CONFIGURATION:
		CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (e, 4, val, maxlen);
		for (i = 0; i < 4; i++) {
			switch (e->data[i]) {
			case 0: c = _("-"); break;
			case 1: c = _("Y"); break;
			case 2: c = _("Cb"); break;
			case 3: c = _("Cr"); break;
			case 4: c = _("R"); break;
			case 5: c = _("G"); break;
			case 6: c = _("B"); break;
			default: c = _("Reserved"); break;
			}
			strncat (val, c, maxlen-1 - strlen (val));
			if (i < 3)
				strncat (val, " ", maxlen-1 - strlen (val));
		}
		break;
	case EXIF_TAG_EXPOSURE_BIAS_VALUE:
		CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen);
		CC (e, 1, val, maxlen);
		v_srat = exif_get_srational (e->data, o);
		if (!v_srat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		d = (double) v_srat.numerator / (double) v_srat.denominator;
		snprintf (val, maxlen, _("%.02f EV"), d);
		break;
	case EXIF_TAG_SCENE_TYPE:
		CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (e, 1, val, maxlen);
		v_byte = e->data[0];
		if (v_byte == 1)
			strncpy (val, _("Directly photographed"), maxlen-1);
		else
			snprintf (val, maxlen, _("Internal error (unknown "
				  "value %i)"), v_byte);
		break;
	case EXIF_TAG_YCBCR_SUB_SAMPLING:
		CF (e, EXIF_FORMAT_SHORT, val, maxlen);
		CC (e, 2, val, maxlen);
		v_short  = exif_get_short (e->data, o);
		v_short2 = exif_get_short (
			e->data + exif_format_get_size (e->format),
			o);
		if ((v_short == 2) && (v_short2 == 1))
			strncpy (val, _("YCbCr4:2:2"), maxlen-1);
		else if ((v_short == 2) && (v_short2 == 2))
			strncpy (val, _("YCbCr4:2:0"), maxlen-1);
		else
			snprintf (val, maxlen, "%u, %u", v_short, v_short2);
		break;
	case EXIF_TAG_SUBJECT_AREA:
		CF (e, EXIF_FORMAT_SHORT, val, maxlen);
		switch (e->components) {
		case 2:
			v_short  = exif_get_short (e->data, o);
			v_short2 = exif_get_short (e->data + 2, o);
			snprintf (val, maxlen, "(x,y) = (%i,%i)",
				  v_short, v_short2);
			break;
		case 3:
			v_short  = exif_get_short (e->data, o);
			v_short2 = exif_get_short (e->data + 2, o);
			v_short3 = exif_get_short (e->data + 4, o);
			snprintf (val, maxlen, _("Within distance %i of "
				"(x,y) = (%i,%i)"), v_short3, v_short,
				v_short2);
			break;
		case 4:
			v_short  = exif_get_short (e->data, o);
			v_short2 = exif_get_short (e->data + 2, o);
			v_short3 = exif_get_short (e->data + 4, o);
			v_short4 = exif_get_short (e->data + 6, o);
			snprintf (val, maxlen, _("Within rectangle "
				"(width %i, height %i) around "
				"(x,y) = (%i,%i)"), v_short3, v_short4,
				v_short, v_short2);
			break;
		default:
			snprintf (val, maxlen, _("Unexpected number "
				"of components (%li, expected 2, 3, or 4)."),
				e->components);
		}
		break;
	case EXIF_TAG_GPS_VERSION_ID:
		/* This is only valid in the GPS IFD */
		CF (e, EXIF_FORMAT_BYTE, val, maxlen);
		CC (e, 4, val, maxlen);
		v_byte = e->data[0];
		snprintf (val, maxlen, "%u", v_byte);
		for (i = 1; i < e->components; i++) {
			v_byte = e->data[i];
			snprintf (b, sizeof (b), ".%u", v_byte);
			strncat (val, b, maxlen-1 - strlen (val));
		}
		break;
	case EXIF_TAG_INTEROPERABILITY_VERSION:
	/* a.k.a. case EXIF_TAG_GPS_LATITUDE: */
		/* This tag occurs in EXIF_IFD_INTEROPERABILITY */
		if (e->format == EXIF_FORMAT_UNDEFINED) {
			strncpy (val, (char *) e->data, MIN (maxlen-1, e->size));
			break;
		}
		/* EXIF_TAG_GPS_LATITUDE is the same numerically as
		 * EXIF_TAG_INTEROPERABILITY_VERSION but in EXIF_IFD_GPS
		 */
		exif_entry_format_value(e, val, maxlen);
		break;
	case EXIF_TAG_GPS_ALTITUDE_REF:
		/* This is only valid in the GPS IFD */
		CF (e, EXIF_FORMAT_BYTE, val, maxlen);
		CC (e, 1, val, maxlen);
		v_byte = e->data[0];
		if (v_byte == 0)
			strncpy (val, _("Sea level"), maxlen-1);
		else if (v_byte == 1)
			strncpy (val, _("Sea level reference"), maxlen-1);
		else
			snprintf (val, maxlen, _("Internal error (unknown "
				  "value %i)"), v_byte);
		break;
	case EXIF_TAG_GPS_TIME_STAMP:
		/* This is only valid in the GPS IFD */
		CF (e, EXIF_FORMAT_RATIONAL, val, maxlen);
		CC (e, 3, val, maxlen);

		v_rat  = exif_get_rational (e->data, o);
		if (!v_rat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		i = v_rat.numerator / v_rat.denominator;

		v_rat = exif_get_rational (e->data +
					     exif_format_get_size (e->format),
					   o);
		if (!v_rat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		j = v_rat.numerator / v_rat.denominator;

		v_rat = exif_get_rational (e->data +
					     2*exif_format_get_size (e->format),
					     o);
		if (!v_rat.denominator) {
			exif_entry_format_value(e, val, maxlen);
			break;
		}
		d = (double) v_rat.numerator / (double) v_rat.denominator;
		snprintf (val, maxlen, "%02u:%02u:%05.2f", i, j, d);
		break;

	case EXIF_TAG_METERING_MODE:
	case EXIF_TAG_COMPRESSION:
	case EXIF_TAG_LIGHT_SOURCE:
	case EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT:
	case EXIF_TAG_RESOLUTION_UNIT:
	case EXIF_TAG_EXPOSURE_PROGRAM:
	case EXIF_TAG_FLASH:
	case EXIF_TAG_SUBJECT_DISTANCE_RANGE:
	case EXIF_TAG_COLOR_SPACE:
		CF (e,EXIF_FORMAT_SHORT, val, maxlen);
		CC (e, 1, val, maxlen);
		v_short = exif_get_short (e->data, o);

		/* Search the tag */
		for (i = 0; list2[i].tag && (list2[i].tag != e->tag); i++);
		if (!list2[i].tag) {
			snprintf (val, maxlen, _("Internal error (unknown "
				  "value %i)"), v_short);
			break;
		}

		/* Find the value */
		for (j = 0; list2[i].elem[j].values[0] &&
			    (list2[i].elem[j].index < v_short); j++);
		if (list2[i].elem[j].index != v_short) {
			snprintf (val, maxlen, _("Internal error (unknown "
				  "value %i)"), v_short);
			break;
		}

		/* Find a short enough value */
		memset (val, 0, maxlen);
		for (k = 0; list2[i].elem[j].values[k]; k++) {
			size_t l = strlen (_(list2[i].elem[j].values[k]));
			if ((maxlen > l) && (strlen (val) < l))
				strncpy (val, _(list2[i].elem[j].values[k]), maxlen-1);
		}
		if (!val[0]) snprintf (val, maxlen, "%i", v_short);

		break;

	case EXIF_TAG_PLANAR_CONFIGURATION:
	case EXIF_TAG_SENSING_METHOD:
	case EXIF_TAG_ORIENTATION:
	case EXIF_TAG_YCBCR_POSITIONING:
	case EXIF_TAG_PHOTOMETRIC_INTERPRETATION:
	case EXIF_TAG_CUSTOM_RENDERED:
	case EXIF_TAG_EXPOSURE_MODE:
	case EXIF_TAG_WHITE_BALANCE:
	case EXIF_TAG_SCENE_CAPTURE_TYPE:
	case EXIF_TAG_GAIN_CONTROL:
	case EXIF_TAG_SATURATION:
	case EXIF_TAG_CONTRAST:
	case EXIF_TAG_SHARPNESS:
		CF (e, EXIF_FORMAT_SHORT, val, maxlen);
		CC (e, 1, val, maxlen);
		v_short = exif_get_short (e->data, o);

		/* Search the tag */
		for (i = 0; list[i].tag && (list[i].tag != e->tag); i++);
		if (!list[i].tag) {
			snprintf (val, maxlen, _("Internal error (unknown "
				  "value %i)"), v_short);
			break;
		}

		/* Find the value */
		for (j = 0; list[i].strings[j] && (j < v_short); j++);
		if (!list[i].strings[j])
			snprintf (val, maxlen, "%i", v_short);
		else if (!*list[i].strings[j])
			snprintf (val, maxlen, _("Unknown value %i"), v_short);
		else
			strncpy (val, _(list[i].strings[j]), maxlen-1);
		break;

	case EXIF_TAG_XP_TITLE:
	case EXIF_TAG_XP_COMMENT:
	case EXIF_TAG_XP_AUTHOR:
	case EXIF_TAG_XP_KEYWORDS:
	case EXIF_TAG_XP_SUBJECT:
	{
		unsigned char *utf16;

		/* Sanity check the size to prevent overflow. Note EXIF files are 64kb at most. */
		if (e->size >= 65536 - sizeof(uint16_t)*2) break;

		/* The tag may not be U+0000-terminated , so make a local
		   U+0000-terminated copy before converting it */
		utf16 = exif_mem_alloc (e->priv->mem, e->size+sizeof(uint16_t)+1);
		if (!utf16) break;
		memcpy(utf16, e->data, e->size);

		/* NUL terminate the string. If the size is odd (which isn't possible
		 * for a valid UTF16 string), then this will overwrite the high byte of
		 * the final half word, plus add a full zero NUL word at the end.
		 */
		utf16[e->size] = 0;
		utf16[e->size+1] = 0;
		utf16[e->size+2] = 0;

		/* Warning! The texts are converted from UTF16 to UTF8 */
		/* FIXME: use iconv to convert into the locale encoding */
		exif_convert_utf16_to_utf8(val, utf16, maxlen);
		exif_mem_free(e->priv->mem, utf16);
		break;
	}

	default:
		/* Use a generic value formatting */
		exif_entry_format_value(e, val, maxlen);
	}

	return val;
}

#define M_PI 3.14159265358979323846

struct _ExifEntryPrivate
{
	unsigned int ref_count;

	ExifMem *mem;
}

#define exif_entry_log(...) do { } while (0)

#define CF(entry,target,v,maxlen)					\
{									\
	if (entry->format != target) {					\
		exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA,	\
			_("The tag '%s' contains data of an invalid "	\
			"format ('%s', expected '%s')."),		\
			exif_tag_get_name (entry->tag),			\
			exif_format_get_name (entry->format),		\
			exif_format_get_name (target));			\
		break;							\
	}								\
}

#define CC(entry,target,v,maxlen)					\
{									\
	if (entry->components != target) {				\
		exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA,	\
			_("The tag '%s' contains an invalid number of "	\
			  "components (%i, expected %i)."),		\
			exif_tag_get_name (entry->tag),		\
			(int) entry->components, (int) target);		\
		break;							\
	}								\
}


iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt,
			   struct iwl_fw_ini_region_cfg *reg, void *range_ptr,
			   int idx)
{
	struct iwl_fw_ini_error_dump_range *range = range_ptr;
	u32 start_addr = iwl_read_umac_prph(fwrt->trans,
					    MON_BUFF_BASE_ADDR_VER2);

	if (start_addr == 0x5a5a5a5a)
		return -EBUSY;

	range->dram_base_addr = cpu_to_le64(start_addr);
	range->range_data_size = cpu_to_le32(fwrt->trans->dbg.fw_mon[idx].size);

	memcpy(range->data, fwrt->trans->dbg.fw_mon[idx].block,
	       fwrt->trans->dbg.fw_mon[idx].size);

	return sizeof(*range) + le32_to_cpu(range->range_data_size);
}

iwlwifi: dbg_ini: fix memory leak in alloc_sgtable

In alloc_sgtable if alloc_page fails, the alocated table should be
released.

Signed-off-by: Navid Emamdoost <navid.emamdoost@gmail.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>

struct iwl_fw_dump_ptrs {
	struct iwl_trans_dump_data *trans_ptr;
	void *fwrt_ptr;
	u32 fwrt_len;
}

struct iwl_prph_range {
	u32 start, end;
}


static u32 iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt,
					  struct iwl_fw_ini_region_cfg *reg)
{
	u32 size = sizeof(struct iwl_fw_ini_monitor_dump) +
		sizeof(struct iwl_fw_ini_error_dump_range);

	if (fwrt->trans->dbg.num_blocks)
		size += fwrt->trans->dbg.fw_mon[0].size;

	return size;
}


static u32 iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt,
					struct iwl_fw_ini_region_cfg *reg)
{
	return 1;
}