static float compress_symbolic_block_for_partition_1plane(
	const astcenc_config& config,
	const block_size_descriptor& bsd,
	const image_block& blk,
	const error_weight_block& ewb,
	bool only_always,
	float tune_errorval_threshold,
	unsigned int partition_count,
	unsigned int partition_index,
	symbolic_compressed_block& scb,
	compression_working_buffers& tmpbuf
) {
	promise(partition_count > 0);
	promise(config.tune_candidate_limit > 0);
	promise(config.tune_refinement_limit > 0);
	promise(bsd.decimation_mode_count > 0);

	static const int free_bits_for_partition_count[5] {
		0, 115 - 4, 111 - 4 - PARTITION_INDEX_BITS, 108 - 4 - PARTITION_INDEX_BITS, 105 - 4 - PARTITION_INDEX_BITS
	};

	const auto& pi = bsd.get_partition_info(partition_count, partition_index);

	// Compute ideal weights and endpoint colors, with no quantization or decimation
	endpoints_and_weights& ei = tmpbuf.ei1;
	endpoints_and_weights *eix = tmpbuf.eix1;
	compute_ideal_colors_and_weights_1plane(bsd, blk, ewb, pi, ei);

	// Compute ideal weights and endpoint colors for every decimation
	float *dec_weights_ideal_value = tmpbuf.dec_weights_ideal_value;
	float *dec_weights_ideal_sig = tmpbuf.dec_weights_ideal_sig;
	float *dec_weights_quant_uvalue = tmpbuf.dec_weights_quant_uvalue;
	uint8_t *dec_weights_quant_pvalue = tmpbuf.dec_weights_quant_pvalue;

	// For each decimation mode, compute an ideal set of weights with no quantization
	unsigned int max_decimation_modes = only_always ? bsd.always_decimation_mode_count
	                                                : bsd.decimation_mode_count;
	promise(max_decimation_modes > 0);
	for (unsigned int i = 0; i < max_decimation_modes; i++)
	{
		const auto& dm = bsd.get_decimation_mode(i);
		if (dm.maxprec_1plane < 0 || !dm.percentile_hit)
		{
			continue;
		}

		const auto& di = bsd.get_decimation_info(i);

		compute_ideal_weights_for_decimation(
		    ei,
		    eix[i],
		    di,
		    dec_weights_ideal_value + i * BLOCK_MAX_WEIGHTS,
		    dec_weights_ideal_sig + i * BLOCK_MAX_WEIGHTS);
	}

	// Compute maximum colors for the endpoints and ideal weights, then for each endpoint and ideal
	// weight pair, compute the smallest weight that will result in a color value greater than 1
	vfloat4 min_ep(10.0f);
	for (unsigned int i = 0; i < partition_count; i++)
	{
		vfloat4 ep = (vfloat4(1.0f) - ei.ep.endpt0[i]) / (ei.ep.endpt1[i] - ei.ep.endpt0[i]);

		vmask4 use_ep = (ep > vfloat4(0.5f)) & (ep < min_ep);
		min_ep = select(min_ep, ep, use_ep);
	}

	float min_wt_cutoff = hmin_s(min_ep);

	// For each mode, use the angular method to compute a shift
	float weight_low_value[WEIGHTS_MAX_BLOCK_MODES];
	float weight_high_value[WEIGHTS_MAX_BLOCK_MODES];

	compute_angular_endpoints_1plane(
	    config.tune_low_weight_count_limit,
	    only_always, bsd,
	    dec_weights_ideal_value, dec_weights_ideal_sig,
	    weight_low_value, weight_high_value);

	// For each mode (which specifies a decimation and a quantization):
	//     * Compute number of bits needed for the quantized weights
	//     * Generate an optimized set of quantized weights
	//     * Compute quantization errors for the mode

	int qwt_bitcounts[WEIGHTS_MAX_BLOCK_MODES];
	float qwt_errors[WEIGHTS_MAX_BLOCK_MODES];

	for (unsigned int i = 0; i < bsd.block_mode_count; ++i)
	{
		qwt_errors[i] = 1e38f;
	}

	unsigned int max_block_modes = only_always ? bsd.always_block_mode_count
	                                           : bsd.block_mode_count;
	promise(max_block_modes > 0);
	for (unsigned int i = 0; i < max_block_modes; ++i)
	{
		const block_mode& bm = bsd.block_modes[i];
		if (bm.is_dual_plane || !bm.percentile_hit)
		{
			continue;
		}

		if (weight_high_value[i] > 1.02f * min_wt_cutoff)
		{
			weight_high_value[i] = 1.0f;
		}

		int decimation_mode = bm.decimation_mode;
		const auto& di = bsd.get_decimation_info(decimation_mode);

		// Compute weight bitcount for the mode
		unsigned int bits_used_by_weights = get_ise_sequence_bitcount(
		    di.weight_count,
		    bm.get_weight_quant_mode());

		int bitcount = free_bits_for_partition_count[partition_count] - bits_used_by_weights;
		if (bitcount <= 0)
		{
			continue;
		}

		qwt_bitcounts[i] = bitcount;

		// Generate the optimized set of weights for the weight mode
		compute_quantized_weights_for_decimation(
		    di,
		    weight_low_value[i], weight_high_value[i],
		    dec_weights_ideal_value + BLOCK_MAX_WEIGHTS * decimation_mode,
		    dec_weights_quant_uvalue + BLOCK_MAX_WEIGHTS * i,
		    dec_weights_quant_pvalue + BLOCK_MAX_WEIGHTS * i,
		    bm.get_weight_quant_mode());

		// Compute weight quantization errors for the block mode
		qwt_errors[i] = compute_error_of_weight_set_1plane(
		    eix[decimation_mode],
		    di,
		    dec_weights_quant_uvalue + BLOCK_MAX_WEIGHTS * i);
	}

	// Decide the optimal combination of color endpoint encodings and weight encodings
	int partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS];
	int block_mode_index[TUNE_MAX_TRIAL_CANDIDATES];

	quant_method color_quant_level[TUNE_MAX_TRIAL_CANDIDATES];
	quant_method color_quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES];

	unsigned int candidate_count = compute_ideal_endpoint_formats(
	    bsd, pi, blk, ewb, ei.ep, qwt_bitcounts, qwt_errors,
	    config.tune_candidate_limit, partition_format_specifiers, block_mode_index,
	    color_quant_level, color_quant_level_mod);

	// Iterate over the N believed-to-be-best modes to find out which one is actually best
	float best_errorval_in_mode = ERROR_CALC_DEFAULT;
	float best_errorval_in_scb = scb.errorval;

	for (unsigned int i = 0; i < candidate_count; i++)
	{
		TRACE_NODE(node0, "candidate");

		const int bm_packed_index = block_mode_index[i];
		assert(bm_packed_index >= 0 && bm_packed_index < (int)bsd.block_mode_count);
		const block_mode& qw_bm = bsd.block_modes[bm_packed_index];

		int decimation_mode = qw_bm.decimation_mode;
		int weight_quant_mode = qw_bm.quant_mode;
		const auto& di = bsd.get_decimation_info(decimation_mode);
		promise(di.weight_count > 0);

		trace_add_data("weight_x", di.weight_x);
		trace_add_data("weight_y", di.weight_y);
		trace_add_data("weight_z", di.weight_z);
		trace_add_data("weight_quant", weight_quant_mode);

		// Recompute the ideal color endpoints before storing them
		vfloat4 rgbs_colors[BLOCK_MAX_PARTITIONS];
		vfloat4 rgbo_colors[BLOCK_MAX_PARTITIONS];

		symbolic_compressed_block workscb;

		uint8_t* u8_weight_src = dec_weights_quant_pvalue + BLOCK_MAX_WEIGHTS * bm_packed_index;

		for (unsigned int j = 0; j < di.weight_count; j++)
		{
			workscb.weights[j] = u8_weight_src[j];
		}

		for (unsigned int l = 0; l < config.tune_refinement_limit; l++)
		{
			recompute_ideal_colors_1plane(
			    blk, ewb, pi, di,
			    weight_quant_mode, workscb.weights,
			    eix[decimation_mode].ep, rgbs_colors, rgbo_colors);

			// Quantize the chosen color
			for (unsigned int j = 0; j < partition_count; j++)
			{
				workscb.color_formats[j] = pack_color_endpoints(
				    eix[decimation_mode].ep.endpt0[j],
				    eix[decimation_mode].ep.endpt1[j],
				    rgbs_colors[j],
				    rgbo_colors[j],
				    partition_format_specifiers[i][j],
				    workscb.color_values[j],
				    (quant_method)color_quant_level[i]);
			}

			// If all the color endpoint modes are the same, we get a few more bits to store colors;
			// let's see if we can take advantage of this: requantize all the colors and see if the
			// endpoint modes remain the same.
			workscb.color_formats_matched = 0;

			if ((partition_count >= 2 && workscb.color_formats[0] == workscb.color_formats[1]
			    && color_quant_level[i] != color_quant_level_mod[i])
			    && (partition_count == 2 || (workscb.color_formats[0] == workscb.color_formats[2]
			    && (partition_count == 3 || (workscb.color_formats[0] == workscb.color_formats[3])))))
			{
				uint8_t colorvals[BLOCK_MAX_PARTITIONS][12];
				uint8_t color_formats_mod[BLOCK_MAX_PARTITIONS] { 0 };
				for (unsigned int j = 0; j < partition_count; j++)
				{
					color_formats_mod[j] = pack_color_endpoints(
					    eix[decimation_mode].ep.endpt0[j],
					    eix[decimation_mode].ep.endpt1[j],
					    rgbs_colors[j],
					    rgbo_colors[j],
					    partition_format_specifiers[i][j],
					    colorvals[j],
					    (quant_method)color_quant_level_mod[i]);
				}

				if (color_formats_mod[0] == color_formats_mod[1]
				    && (partition_count == 2 || (color_formats_mod[0] == color_formats_mod[2]
				    && (partition_count == 3 || (color_formats_mod[0] == color_formats_mod[3])))))
				{
					workscb.color_formats_matched = 1;
					for (unsigned int j = 0; j < BLOCK_MAX_PARTITIONS; j++)
					{
						for (unsigned int k = 0; k < 8; k++)
						{
							workscb.color_values[j][k] = colorvals[j][k];
						}

						workscb.color_formats[j] = color_formats_mod[j];
					}
				}
			}

			// Store header fields
			workscb.partition_count = static_cast<uint8_t>(partition_count);
			workscb.partition_index = static_cast<uint16_t>(partition_index);
			workscb.plane2_component = -1;
			workscb.quant_mode = workscb.color_formats_matched ? color_quant_level_mod[i] : color_quant_level[i];
			workscb.block_mode = qw_bm.mode_index;
			workscb.block_type = SYM_BTYPE_NONCONST;

			if (workscb.quant_mode < QUANT_6)
			{
				workscb.block_type = SYM_BTYPE_ERROR;
			}

			// Pre-realign test
			if (l == 0)
			{
				float errorval = compute_symbolic_block_difference(config, bsd, workscb, blk, ewb);
				if (errorval == -ERROR_CALC_DEFAULT)
				{
					errorval = -errorval;
					workscb.block_type = SYM_BTYPE_ERROR;
				}

				trace_add_data("error_prerealign", errorval);
				best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);

				// Average refinement improvement is 3.5% per iteration (allow 5%), but the first
				// iteration can help more so we give it a extra 10% leeway. Use this knowledge to
				// drive a heuristic to skip blocks that are unlikely to catch up with the best
				// block we have already.
				unsigned int iters_remaining = config.tune_refinement_limit - l;
				float threshold = (0.05f * static_cast<float>(iters_remaining)) + 1.1f;
				if (errorval > (threshold * best_errorval_in_scb))
				{
					break;
				}

				if (errorval < best_errorval_in_scb)
				{
					best_errorval_in_scb = errorval;
					workscb.errorval = errorval;
					scb = workscb;

					if (errorval < tune_errorval_threshold)
					{
						// Skip remaining candidates - this is "good enough"
						i = candidate_count;
						break;
					}
				}
			}

			// Perform a final pass over the weights to try to improve them.
			bool adjustments = realign_weights(
			    config.profile, bsd, blk, ewb, workscb,
			    workscb.weights, nullptr);

			// Post-realign test
			float errorval = compute_symbolic_block_difference(config, bsd, workscb, blk, ewb);
			if (errorval == -ERROR_CALC_DEFAULT)
			{
				errorval = -errorval;
				workscb.block_type = SYM_BTYPE_ERROR;
			}

			trace_add_data("error_postrealign", errorval);
			best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);

			// Average refinement improvement is 3.5% per iteration, so skip blocks that are
			// unlikely to catch up with the best block we have already. Assume a 5% per step to
			// give benefit of the doubt ...
			unsigned int iters_remaining = config.tune_refinement_limit - 1 - l;
			float threshold = (0.05f * static_cast<float>(iters_remaining)) + 1.0f;
			if (errorval > (threshold * best_errorval_in_scb))
			{
				break;
			}

			if (errorval < best_errorval_in_scb)
			{
				best_errorval_in_scb = errorval;
				workscb.errorval = errorval;
				scb = workscb;

				if (errorval < tune_errorval_threshold)
				{
					// Skip remaining candidates - this is "good enough"
					i = candidate_count;
					break;
				}
			}

			if (!adjustments)
			{
				break;
			}
		}
	}

	return best_errorval_in_mode;
}


static void _sqlite_close(void *db)
{
    sqlite_close((sqlite*)db);
}


static int _sqlite3_rollback_txn(void *db, const sasl_utils_t *utils)
{
    return _sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, 0, NULL, utils);
}


void onFailure(const Http::AsyncClient::Request&, Http::AsyncClient::FailureReason) override {}


TEST_F(OAuth2Test, OAuthErrorQueryString) {
  Http::TestRequestHeaderMapImpl request_headers{
      {Http::Headers::get().Path.get(), "/_oauth?error=someerrorcode"},
      {Http::Headers::get().Host.get(), "traffic.example.com"},
      {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get},
  };

  Http::TestResponseHeaderMapImpl response_headers{
      {Http::Headers::get().Status.get(), "401"},
      {Http::Headers::get().ContentLength.get(), "18"}, // unauthorizedBodyMessage()
      {Http::Headers::get().ContentType.get(), "text/plain"},
  };

  EXPECT_CALL(*validator_, setParams(_, _));
  EXPECT_CALL(*validator_, isValid()).WillOnce(Return(false));

  EXPECT_CALL(decoder_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false));
  EXPECT_CALL(decoder_callbacks_, encodeData(_, true));

  EXPECT_EQ(Http::FilterHeadersStatus::StopIteration,
            filter_->decodeHeaders(request_headers, false));

  EXPECT_EQ(scope_.counterFromString("test.oauth_failure").value(), 1);
  EXPECT_EQ(scope_.counterFromString("test.oauth_success").value(), 0);
}


void OAuth2Filter::onGetAccessTokenSuccess(const std::string& access_code,
                                           const std::string& id_token,
                                           const std::string& refresh_token,
                                           std::chrono::seconds expires_in) {
  access_token_ = access_code;
  id_token_ = id_token;
  refresh_token_ = refresh_token;

  const auto new_epoch = time_source_.systemTime() + expires_in;
  new_expires_ = std::to_string(
      std::chrono::duration_cast<std::chrono::seconds>(new_epoch.time_since_epoch()).count());

  finishFlow();
}


TEST_F(OAuth2Test, OAuthTestFullFlowPostWithParameters) {
  // First construct the initial request to the oauth filter with URI parameters.
  Http::TestRequestHeaderMapImpl first_request_headers{
      {Http::Headers::get().Path.get(), "/test?name=admin&level=trace"},
      {Http::Headers::get().Host.get(), "traffic.example.com"},
      {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Post},
      {Http::Headers::get().Scheme.get(), "https"},
  };

  // This is the immediate response - a redirect to the auth cluster.
  Http::TestResponseHeaderMapImpl first_response_headers{
      {Http::Headers::get().Status.get(), "302"},
      {Http::Headers::get().Location.get(),
       "https://auth.example.com/oauth/"
       "authorize/?client_id=" +
           TEST_CLIENT_ID + "&scope=" + TEST_ENCODED_AUTH_SCOPES +
           "&response_type=code&"
           "redirect_uri=https%3A%2F%2Ftraffic.example.com%2F"
           "_oauth&state=https%3A%2F%2Ftraffic.example.com%2Ftest%"
           "3Fname%3Dadmin%26level%3Dtrace"
           "&resource=oauth2-resource&resource=http%3A%2F%2Fexample.com"
           "&resource=https%3A%2F%2Fexample.com"},
  };

  // Fail the validation to trigger the OAuth flow.
  EXPECT_CALL(*validator_, setParams(_, _));
  EXPECT_CALL(*validator_, isValid()).WillOnce(Return(false));

  // Check that the redirect includes the escaped parameter characters, '?', '&' and '='.
  EXPECT_CALL(decoder_callbacks_, encodeHeaders_(HeaderMapEqualRef(&first_response_headers), true));

  // This represents the beginning of the OAuth filter.
  EXPECT_EQ(Http::FilterHeadersStatus::StopIteration,
            filter_->decodeHeaders(first_request_headers, false));

  // This represents the callback request from the authorization server.
  Http::TestRequestHeaderMapImpl second_request_headers{
      {Http::Headers::get().Path.get(), "/_oauth?code=123&state=https%3A%2F%2Ftraffic.example.com%"
                                        "2Ftest%3Fname%3Dadmin%26level%3Dtrace"},
      {Http::Headers::get().Host.get(), "traffic.example.com"},
      {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get},
      {Http::Headers::get().Scheme.get(), "https"},
  };

  // Deliberately fail the HMAC validation check.
  EXPECT_CALL(*validator_, setParams(_, _));
  EXPECT_CALL(*validator_, isValid()).WillOnce(Return(false));

  EXPECT_CALL(*oauth_client_, asyncGetAccessToken("123", TEST_CLIENT_ID, "asdf_client_secret_fdsa",
                                                  "https://traffic.example.com" + TEST_CALLBACK));

  // Invoke the callback logic. As a side effect, state_ will be populated.
  EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndBuffer,
            filter_->decodeHeaders(second_request_headers, false));

  EXPECT_EQ(1, config_->stats().oauth_unauthorized_rq_.value());
  EXPECT_EQ(config_->clusterName(), "auth.example.com");

  // Expected response after the callback & validation is complete - verifying we kept the
  // state and method of the original request, including the query string parameters.
  Http::TestRequestHeaderMapImpl second_response_headers{
      {Http::Headers::get().Status.get(), "302"},
      {Http::Headers::get().SetCookie.get(),
       "OauthHMAC="
       "NWUzNzE5MWQwYTg0ZjA2NjIyMjVjMzk3MzY3MzMyZmE0NjZmMWI2MjI1NWFhNDhkYjQ4NDFlZmRiMTVmMTk0MQ==;"
       "version=1;path=/;Max-Age=;secure;HttpOnly"},
      {Http::Headers::get().SetCookie.get(),
       "OauthExpires=;version=1;path=/;Max-Age=;secure;HttpOnly"},
      {Http::Headers::get().SetCookie.get(), "BearerToken=;version=1;path=/;Max-Age=;secure"},
      {Http::Headers::get().Location.get(),
       "https://traffic.example.com/test?name=admin&level=trace"},
  };

  EXPECT_CALL(decoder_callbacks_,
              encodeHeaders_(HeaderMapEqualRef(&second_response_headers), true));

  filter_->finishFlow();
}


TEST_F(OAuth2Test, OAuthTestCallbackUrlInStateQueryParam) {
  Http::TestRequestHeaderMapImpl request_headers{
      {Http::Headers::get().Host.get(), "traffic.example.com"},
      {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get},
      {Http::Headers::get().Path.get(),
       "/_oauth?code=abcdefxyz123&scope=" + TEST_ENCODED_AUTH_SCOPES +
           "&state=https%3A%2F%2Ftraffic.example.com%2F_oauth"},

      {Http::Headers::get().Cookie.get(), "OauthExpires=123;version=test"},
      {Http::Headers::get().Cookie.get(), "BearerToken=legit_token;version=test"},
      {Http::Headers::get().Cookie.get(),
       "OauthHMAC="
       "ZTRlMzU5N2Q4ZDIwZWE5ZTU5NTg3YTU3YTcxZTU0NDFkMzY1ZTc1NjMyODYyMj"
       "RlNjMxZTJmNTZkYzRmZTM0ZQ====;version=test"},
  };

  Http::TestRequestHeaderMapImpl expected_response_headers{
      {Http::Headers::get().Status.get(), "401"},
      {Http::Headers::get().ContentLength.get(), "18"},
      {Http::Headers::get().ContentType.get(), "text/plain"},
  };

  // Succeed the HMAC validation.
  EXPECT_CALL(*validator_, setParams(_, _));
  EXPECT_CALL(*validator_, isValid()).WillOnce(Return(true));

  std::string legit_token{"legit_token"};
  EXPECT_CALL(*validator_, token()).WillRepeatedly(ReturnRef(legit_token));

  EXPECT_CALL(decoder_callbacks_,
              encodeHeaders_(HeaderMapEqualRef(&expected_response_headers), false));
  EXPECT_EQ(Http::FilterHeadersStatus::StopIteration,
            filter_->decodeHeaders(request_headers, false));

  Http::TestRequestHeaderMapImpl final_request_headers{
      {Http::Headers::get().Host.get(), "traffic.example.com"},
      {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get},
      {Http::Headers::get().Path.get(),
       "/_oauth?code=abcdefxyz123&scope=" + TEST_ENCODED_AUTH_SCOPES +
           "&state=https%3A%2F%2Ftraffic.example.com%2F_oauth"},
      {Http::Headers::get().Cookie.get(), "OauthExpires=123;version=test"},
      {Http::Headers::get().Cookie.get(), "BearerToken=legit_token;version=test"},
      {Http::Headers::get().Cookie.get(),
       "OauthHMAC="
       "ZTRlMzU5N2Q4ZDIwZWE5ZTU5NTg3YTU3YTcxZTU0NDFkMzY1ZTc1NjMyODYyMj"
       "RlNjMxZTJmNTZkYzRmZTM0ZQ====;version=test"},
      {Http::CustomHeaders::get().Authorization.get(), "Bearer legit_token"},
  };

  EXPECT_EQ(request_headers, final_request_headers);
}


int ldb_anr_module_init(const char *version)
{
	LDB_MODULE_CHECK_VERSION(version);
	return ldb_register_module(&ldb_anr_module_ops);
}


JANET_CORE_FN(cfun_array_clear,
              "(array/clear arr)",
              "Empties an array, setting it's count to 0 but does not free the backing capacity. "
              "Returns the modified array.") {
    janet_fixarity(argc, 1);
    JanetArray *array = janet_getarray(argv, 0);
    array->count = 0;
    return argv[0];
}


JANET_CORE_FN(cfun_array_new_filled,
              "(array/new-filled count &opt value)",
              "Creates a new array of `count` elements, all set to `value`, which defaults to nil. Returns the new array.") {
    janet_arity(argc, 1, 2);
    int32_t count = janet_getinteger(argv, 0);
    if (count < 0) janet_panic("expected positive integer");
    Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
    JanetArray *array = janet_array(count);
    for (int32_t i = 0; i < count; i++) {
        array->data[i] = x;
    }
    array->count = count;
    return janet_wrap_array(array);
}


Janet janet_array_pop(JanetArray *array) {
    if (array->count) {
        return array->data[--array->count];
    } else {
        return janet_wrap_nil();
    }
}


JANET_CORE_FN(cfun_array_trim,
              "(array/trim arr)",
              "Set the backing capacity of an array to its current length. Returns the modified array.") {
    janet_fixarity(argc, 1);
    JanetArray *array = janet_getarray(argv, 0);
    if (array->count) {
        if (array->count < array->capacity) {
            Janet *newData = janet_realloc(array->data, array->count * sizeof(Janet));
            if (NULL == newData) {
                JANET_OUT_OF_MEMORY;
            }
            array->data = newData;
            array->capacity = array->count;
        }
    } else {
        array->capacity = 0;
        janet_free(array->data);
        array->data = NULL;
    }
    return argv[0];
}


inline void LocalResponseNormalization(
    const tflite::LocalResponseNormalizationParams& op_params,
    const RuntimeShape& input_shape, const float* input_data,
    const RuntimeShape& output_shape, float* output_data) {
  const int trailing_dim = input_shape.DimensionsCount() - 1;
  const int outer_size =
      MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape);
  const int depth =
      MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim);

  for (int i = 0; i < outer_size; ++i) {
    for (int c = 0; c < depth; ++c) {
      const int begin_input_c = std::max(0, c - op_params.range);
      const int end_input_c = std::min(depth, c + op_params.range);
      float accum = 0.f;
      for (int input_c = begin_input_c; input_c < end_input_c; ++input_c) {
        const float input_val = input_data[i * depth + input_c];
        accum += input_val * input_val;
      }
      const float multiplier =
          std::pow(op_params.bias + op_params.alpha * accum, -op_params.beta);
      output_data[i * depth + c] = input_data[i * depth + c] * multiplier;
    }
  }
}


TEST(GatherNdOpTest, DuplicateIndexingIntoRank3Tensor) {
  GatherNdOpModel m({TensorType_FLOAT32, {3, 2, 3}},
                    {TensorType_INT32, {2, 2}});
  m.SetInput<float>({1.1, -1.2, 1.3, -2.1, 2.2, 2.3,   //
                     3.1, 3.2, -3.3, -4.1, -4.2, 4.3,  //
                     5.1, -5.2, 5.3, 6.1, -6.2, 6.3});
  m.SetPositions<int32_t>({0, 1, 0, 1});
  ASSERT_EQ(m.Invoke(), kTfLiteOk);

  EXPECT_THAT(m.GetOutput<float>(),
              ElementsAreArray({-2.1, 2.2, 2.3, -2.1, 2.2, 2.3}));
}


void Split(const SplitParams& params, const RuntimeShape& input_shape,
           const Scalar* input_data, const RuntimeShape* const* output_shapes,
           Scalar* const* output_data) {
  ruy::profiler::ScopeLabel label("Split");
  const int split_dimensions = input_shape.DimensionsCount();
  int axis = params.axis < 0 ? params.axis + split_dimensions : params.axis;
  int outputs_count = params.num_split;
  TFLITE_DCHECK_LT(axis, split_dimensions);

  int64_t split_size = 0;
  for (int i = 0; i < outputs_count; i++) {
    TFLITE_DCHECK_EQ(output_shapes[i]->DimensionsCount(), split_dimensions);
    for (int j = 0; j < split_dimensions; j++) {
      if (j != axis) {
        MatchingDim(*output_shapes[i], j, input_shape, j);
      }
    }
    split_size += output_shapes[i]->Dims(axis);
  }
  TFLITE_DCHECK_EQ(split_size, input_shape.Dims(axis));
  int64_t outer_size = 1;
  for (int i = 0; i < axis; ++i) {
    outer_size *= input_shape.Dims(i);
  }
  // For all output arrays,
  // FlatSize() = outer_size * Dims(axis) * base_inner_size;
  int64_t base_inner_size = 1;
  for (int i = axis + 1; i < split_dimensions; ++i) {
    base_inner_size *= input_shape.Dims(i);
  }

  const Scalar* input_ptr = input_data;
  for (int k = 0; k < outer_size; k++) {
    for (int i = 0; i < outputs_count; ++i) {
      const int copy_size = output_shapes[i]->Dims(axis) * base_inner_size;
      memcpy(output_data[i] + k * copy_size, input_ptr,
             copy_size * sizeof(Scalar));
      input_ptr += copy_size;
    }
  }
}


inline void Pow(const RuntimeShape& input1_shape, const T* input1_data,
                const RuntimeShape& input2_shape, const T* input2_data,
                const RuntimeShape& output_shape, T* output_data) {
  const int flat_size =
      MatchingFlatSize(input1_shape, input2_shape, output_shape);
  for (int i = 0; i < flat_size; ++i) {
    output_data[i] = std::pow(input1_data[i], input2_data[i]);
  }
}


TEST(GatherNdOpTest, Uint8Int32) {
  GatherNdOpModel m({TensorType_UINT8, {3, 2, 3}}, {TensorType_INT32, {2, 2}});
  m.SetInput<uint8_t>({1, 1, 1, 2, 2, 2,  //
                       3, 3, 3, 4, 4, 4,  //
                       5, 5, 5, 6, 6, 6});
  m.SetPositions<int32_t>({0, 1, 1, 0});
  ASSERT_EQ(m.Invoke(), kTfLiteOk);

  EXPECT_THAT(m.GetOutput<uint8_t>(), ElementsAreArray({2, 2, 2, 3, 3, 3}));
}


TEST(GatherNdOpTest, ErrorOnOutOfBoundsTooLarge) {
  GatherNdOpModel m({TensorType_FLOAT32, {2, 2}}, {TensorType_INT32, {2, 2}});
  m.SetInput<float>({1.1, 1.2, 2.1, 2.2});
  m.SetPositions<int32_t>({0, 0, 2, 0});
  EXPECT_EQ(m.Invoke(), kTfLiteError);
  m.SetPositions<int32_t>({0, 0, 1, 2});
  EXPECT_EQ(m.Invoke(), kTfLiteError);
}


TEST(GatherNdOpTest, SliceIndexingIntoMatrix) {
  GatherNdOpModel m({TensorType_FLOAT32, {2, 2}}, {TensorType_INT32, {2, 1}});
  m.SetInput<float>({1.1, 1.2, 2.1, 2.2});
  m.SetPositions<int32_t>({1, 0});
  ASSERT_EQ(m.Invoke(), kTfLiteOk);

  EXPECT_THAT(m.GetOutput<float>(), ElementsAreArray({2.1, 2.2, 1.1, 1.2}));
}


void Unpack(const UnpackParams& params, const RuntimeShape& input_shape,
            const Scalar* input_data, const RuntimeShape& output_shape,
            Scalar* const* output_datas) {
  ruy::profiler::ScopeLabel label("Unpack");
  const int dimensions = input_shape.DimensionsCount();
  const int outputs_count = params.num_split;

  int outer_size = 1;
  int axis = params.axis;
  if (axis < 0) {
    axis += dimensions;
  }
  TFLITE_DCHECK_GE(axis, 0);
  TFLITE_DCHECK_LT(axis, dimensions);
  for (int i = 0; i < axis; ++i) {
    outer_size *= input_shape.Dims(i);
  }
  int copy_size = 1;
  for (int i = axis + 1; i < dimensions; ++i) {
    copy_size *= input_shape.Dims(i);
  }
  TFLITE_DCHECK_EQ(output_shape.FlatSize(), copy_size * outer_size);

  for (int i = 0; i < outputs_count; ++i) {
    for (int k = 0; k < outer_size; k++) {
      Scalar* output_ptr = output_datas[i] + copy_size * k;
      int loc = k * outputs_count * copy_size + i * copy_size;
      memcpy(output_ptr, input_data + loc, copy_size * sizeof(Scalar));
    }
  }
}


int ldb_msg_append_value(struct ldb_message *msg,
			 const char *attr_name,
			 const struct ldb_val *val,
			 int flags)
{
	return ldb_msg_append_value_impl(msg, attr_name, val, flags, NULL);
}


int tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb,
			  struct sk_buff_head *xmitq)
{
	struct tipc_msg *hdr = buf_msg(skb);
	u32 dnode = msg_destnode(hdr);
	int mtyp = msg_type(hdr);
	u16 acked = msg_bcast_ack(hdr);
	u16 from = acked + 1;
	u16 to = msg_bcgap_to(hdr);
	u16 peers_snd_nxt = to + 1;
	int rc = 0;

	kfree_skb(skb);

	if (!tipc_link_is_up(l) || !l->bc_peer_is_up)
		return 0;

	if (mtyp != STATE_MSG)
		return 0;

	if (dnode == tipc_own_addr(l->net)) {
		rc = tipc_link_bc_ack_rcv(l, acked, to - acked, NULL, xmitq,
					  xmitq);
		l->stats.recv_nacks++;
		return rc;
	}

	/* Msg for other node => suppress own NACK at next sync if applicable */
	if (more(peers_snd_nxt, l->rcv_nxt) && !less(l->rcv_nxt, from))
		l->nack_state = BC_NACK_SND_SUPPRESS;

	return 0;
}


static inline u16 mon_le16_to_cpu(u16 val)
{
	return ntohs((__force __be16)val);
}


int tipc_link_min_win(struct tipc_link *l)
{
	return l->min_win;
}


bool tipc_link_is_up(struct tipc_link *l)
{
	return link_is_up(l);
}


static inline u64 mon_cpu_to_le64(u64 val)
{
	return (__force __u64)cpu_to_be64(val);
}


int tipc_nl_monitor_get_threshold(struct net *net)
{
	struct tipc_net *tn = tipc_net(net);

	return tn->mon_threshold;
}


int tipc_link_mtu(struct tipc_link *l)
{
	return l->mtu;
}


static bool tipc_link_build_bc_proto_msg(struct tipc_link *l, bool bcast,
					 u16 peers_snd_nxt,
					 struct sk_buff_head *xmitq)
{
	struct sk_buff *skb;
	struct tipc_msg *hdr;
	struct sk_buff *dfrd_skb = skb_peek(&l->deferdq);
	u16 ack = l->rcv_nxt - 1;
	u16 gap_to = peers_snd_nxt - 1;

	skb = tipc_msg_create(BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE,
			      0, l->addr, tipc_own_addr(l->net), 0, 0, 0);
	if (!skb)
		return false;
	hdr = buf_msg(skb);
	msg_set_last_bcast(hdr, l->bc_sndlink->snd_nxt - 1);
	msg_set_bcast_ack(hdr, ack);
	msg_set_bcgap_after(hdr, ack);
	if (dfrd_skb)
		gap_to = buf_seqno(dfrd_skb) - 1;
	msg_set_bcgap_to(hdr, gap_to);
	msg_set_non_seq(hdr, bcast);
	__skb_queue_tail(xmitq, skb);
	return true;
}


void tipc_link_set_queue_limits(struct tipc_link *l, u32 min_win, u32 max_win)
{
	int max_bulk = TIPC_MAX_PUBL / (l->mtu / ITEM_SIZE);

	l->min_win = min_win;
	l->ssthresh = max_win;
	l->max_win = max_win;
	l->window = min_win;
	l->backlog[TIPC_LOW_IMPORTANCE].limit      = min_win * 2;
	l->backlog[TIPC_MEDIUM_IMPORTANCE].limit   = min_win * 4;
	l->backlog[TIPC_HIGH_IMPORTANCE].limit     = min_win * 6;
	l->backlog[TIPC_CRITICAL_IMPORTANCE].limit = min_win * 8;
	l->backlog[TIPC_SYSTEM_IMPORTANCE].limit   = max_bulk;
}


void tipc_mon_peer_up(struct net *net, u32 addr, int bearer_id)
{
	struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
	struct tipc_peer *self = get_self(net, bearer_id);
	struct tipc_peer *peer, *head;

	write_lock_bh(&mon->lock);
	peer = get_peer(mon, addr);
	if (!peer && !tipc_mon_add_peer(mon, addr, &peer))
		goto exit;
	peer->is_up = true;
	head = peer_head(peer);
	if (head == self)
		mon_update_local_domain(mon);
	mon_assign_roles(mon, head);
exit:
	write_unlock_bh(&mon->lock);
}


void tipc_mon_reinit_self(struct net *net)
{
	struct tipc_monitor *mon;
	int bearer_id;

	for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
		mon = tipc_monitor(net, bearer_id);
		if (!mon)
			continue;
		write_lock_bh(&mon->lock);
		mon->self->addr = tipc_own_addr(net);
		write_unlock_bh(&mon->lock);
	}
}


GF_Err gf_isom_remove_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber)
{
	GF_Err e;
	GF_TrackBox *trak;

	e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
	if (e) return e;

	trak = gf_isom_get_track_from_file(movie, trackNumber);
	if (!trak || !sampleNumber || (sampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount) )
		return GF_BAD_PARAM;

	//block for hint tracks
	if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;

	e = unpack_track(trak);
	if (e) return e;
	//do NOT change the order DTS, CTS, size chunk

	//remove DTS
	e = stbl_RemoveDTS(trak->Media->information->sampleTable, sampleNumber, 1, trak->Media->mediaHeader->timeScale);
	if (e) return e;
	//remove CTS if any
	if (trak->Media->information->sampleTable->CompositionOffset) {
		e = stbl_RemoveCTS(trak->Media->information->sampleTable, sampleNumber, 1);
		if (e) return e;
	}
	//remove size
	e = stbl_RemoveSize(trak->Media->information->sampleTable, sampleNumber, 1);
	if (e) return e;
	//remove sampleToChunk and chunk
	e = stbl_RemoveChunk(trak->Media->information->sampleTable, sampleNumber, 1);
	if (e) return e;
	//remove sync
	if (trak->Media->information->sampleTable->SyncSample) {
		e = stbl_RemoveRAP(trak->Media->information->sampleTable, sampleNumber);
		if (e) return e;
	}
	//remove sample dep
	if (trak->Media->information->sampleTable->SampleDep) {
		e = stbl_RemoveRedundant(trak->Media->information->sampleTable, sampleNumber, 1);
		if (e) return e;
	}
	//remove shadow
	e = stbl_RemoveShadow(trak->Media->information->sampleTable, sampleNumber);
	if (e) return e;

	//remove padding
	e = stbl_RemovePaddingBits(trak->Media->information->sampleTable, sampleNumber);
	if (e) return e;

	e = stbl_RemoveSubSample(trak->Media->information->sampleTable, sampleNumber);
	if (e) return e;

	e = stbl_RemoveSampleGroup(trak->Media->information->sampleTable, sampleNumber);
	if (e) return e;

	gf_isom_disable_inplace_rewrite(movie);

	gf_isom_meta_track_remove(movie, trak, sampleNumber);

	return SetTrackDuration(trak);
}


GF_Err gf_isom_set_media_subtype(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, u32 new_type)
{
	GF_SampleEntryBox*entry;
	GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
	if (!trak || !sampleDescriptionIndex || !new_type) return GF_BAD_PARAM;

	entry = (GF_SampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex - 1);
	if (!entry) return GF_BAD_PARAM;
	if (entry->type==GF_ISOM_BOX_TYPE_GNRV) {
		((GF_GenericVisualSampleEntryBox *)entry)->EntryType = new_type;
	} else if (entry->type==GF_ISOM_BOX_TYPE_GNRA) {
		((GF_GenericAudioSampleEntryBox *)entry)->EntryType = new_type;
	} else if (entry->type==GF_ISOM_BOX_TYPE_GNRM) {
		((GF_GenericSampleEntryBox *)entry)->EntryType = new_type;
	} else {
		entry->type = new_type;
	}
	return GF_OK;
}


GF_Err gf_isom_set_high_dynamic_range_info(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_MasteringDisplayColourVolumeInfo* mdcv, GF_ContentLightLevelInfo* clli)
{
	GF_Err e;
	GF_TrackBox* trak;
	GF_SampleEntryBox* entry;
	GF_SampleDescriptionBox* stsd;

	e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
	if (e) return e;

	trak = gf_isom_get_track_from_file(movie, trackNumber);
	if (!trak) return GF_BAD_PARAM;

	stsd = trak->Media->information->sampleTable->SampleDescription;
	if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
	if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
		return movie->LastError = GF_BAD_PARAM;
	}
	entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
	//no support for generic sample entries (eg, no MPEG4 descriptor)
	if (entry == NULL) return GF_BAD_PARAM;
	if (!movie->keep_utc)
		trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();

	if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;

	GF_MasteringDisplayColourVolumeBox *mdcvb = (GF_MasteringDisplayColourVolumeBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_MDCV);
	if (mdcv) {
		if (!mdcvb) {
			mdcvb = (GF_MasteringDisplayColourVolumeBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_MDCV);
			if (!mdcvb) return GF_OUT_OF_MEM;
		}
		mdcvb->mdcv = *mdcv;
	} else {
		if (mdcvb) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box *) mdcvb);
	}

	/*clli*/
	GF_ContentLightLevelBox *cllib = (GF_ContentLightLevelBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CLLI);
	if (clli) {
		if (!cllib) {
			cllib = (GF_ContentLightLevelBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_CLLI);
			if (!cllib) return GF_OUT_OF_MEM;
		}
		cllib->clli = *clli;
	} else {
		if (cllib) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box *) cllib);
	}
	return GF_OK;
}


GF_Err gf_isom_reset_alt_brands_ex(GF_ISOFile *movie, Bool leave_empty)
{
	u32 *p;

	if (!movie) return GF_BAD_PARAM;
	if (movie->disable_brand_rewrite) return GF_OK;

#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
	if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
		GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
		if (e) return e;

		e = CheckNoData(movie);
		if (e) return e;
	}
#endif

	if (!movie->brand) {
		movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
		if (!movie->brand) return GF_OUT_OF_MEM;
		gf_list_add(movie->TopBoxes, movie->brand);
	}
	gf_free(movie->brand->altBrand);
	if (leave_empty) {
		movie->brand->altCount = 0;
		movie->brand->altBrand = NULL;
	} else {
		p = (u32*)gf_malloc(sizeof(u32));
		if (!p) return GF_OUT_OF_MEM;
		p[0] = movie->brand->majorBrand;
		movie->brand->altCount = 1;
		movie->brand->altBrand = p;
	}
	return GF_OK;
}


static void prov_failed(uint8_t err)
{
	BT_DBG("%u", err);
	link.cb->error(&pb_adv, link.cb_data, err);
	atomic_set_bit(link.flags, ADV_LINK_INVALID);
}


static void reset_adv_link(void)
{
	BT_DBG("");
	prov_clear_tx();

	/* If this fails, the work handler will exit early on the LINK_ACTIVE
	 * check.
	 */
	(void)k_work_cancel_delayable(&link.prot_timer);

	if (atomic_test_bit(link.flags, ADV_PROVISIONER)) {
		/* Clear everything except the retransmit and protocol timer
		 * delayed work objects.
		 */
		(void)memset(&link, 0, offsetof(struct pb_adv, tx.retransmit));
		link.rx.id = XACT_ID_NVAL;
	} else {
		/* Accept another provisioning attempt */
		link.id = 0;
		atomic_clear(link.flags);
		link.rx.id = XACT_ID_MAX;
		link.tx.id = XACT_ID_NVAL;
	}

	link.tx.pending_ack = XACT_ID_NVAL;
	link.rx.buf = &rx_buf;
	net_buf_simple_reset(link.rx.buf);
}


static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile)
{
    int ret = 0;
    int layno, reslevelno, compno, precno, ok_reslevel;
    int x, y;

    s->bit_index = 8;
    switch (tile->codsty[0].prog_order) {
    case JPEG2000_PGOD_RLCP:
        avpriv_request_sample(s->avctx, "Progression order RLCP");

    case JPEG2000_PGOD_LRCP:
        for (layno = 0; layno < tile->codsty[0].nlayers; layno++) {
            ok_reslevel = 1;
            for (reslevelno = 0; ok_reslevel; reslevelno++) {
                ok_reslevel = 0;
                for (compno = 0; compno < s->ncomponents; compno++) {
                    Jpeg2000CodingStyle *codsty = tile->codsty + compno;
                    Jpeg2000QuantStyle *qntsty  = tile->qntsty + compno;
                    if (reslevelno < codsty->nreslevels) {
                        Jpeg2000ResLevel *rlevel = tile->comp[compno].reslevel +
                                                reslevelno;
                        ok_reslevel = 1;
                        for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++)
                            if ((ret = jpeg2000_decode_packet(s,
                                                              codsty, rlevel,
                                                              precno, layno,
                                                              qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
                                                              qntsty->nguardbits)) < 0)
                                return ret;
                    }
                }
            }
        }
        break;

    case JPEG2000_PGOD_CPRL:
        for (compno = 0; compno < s->ncomponents; compno++) {
            Jpeg2000CodingStyle *codsty = tile->codsty + compno;
            Jpeg2000QuantStyle *qntsty  = tile->qntsty + compno;

            /* Set bit stream buffer address according to tile-part.
             * For DCinema one tile-part per component, so can be
             * indexed by component. */
            s->g = tile->tile_part[compno].tpg;

            /* Position loop (y axis)
             * TODO: Automate computing of step 256.
             * Fixed here, but to be computed before entering here. */
            for (y = 0; y < s->height; y += 256) {
                /* Position loop (y axis)
                 * TODO: automate computing of step 256.
                 * Fixed here, but to be computed before entering here. */
                for (x = 0; x < s->width; x += 256) {
                    for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++) {
                        uint16_t prcx, prcy;
                        uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; //  ==> N_L - r
                        Jpeg2000ResLevel *rlevel = tile->comp[compno].reslevel + reslevelno;

                        if (!((y % (1 << (rlevel->log2_prec_height + reducedresno)) == 0) ||
                              (y == 0))) // TODO: 2nd condition simplified as try0 always =0 for dcinema
                            continue;

                        if (!((x % (1 << (rlevel->log2_prec_width + reducedresno)) == 0) ||
                              (x == 0))) // TODO: 2nd condition simplified as try0 always =0 for dcinema
                            continue;

                        // check if a precinct exists
                        prcx   = ff_jpeg2000_ceildivpow2(x, reducedresno) >> rlevel->log2_prec_width;
                        prcy   = ff_jpeg2000_ceildivpow2(y, reducedresno) >> rlevel->log2_prec_height;
                        precno = prcx + rlevel->num_precincts_x * prcy;

                        if (prcx >= rlevel->num_precincts_x || prcy >= rlevel->num_precincts_y)
                            return AVERROR_PATCHWELCOME;

                        for (layno = 0; layno < tile->codsty[0].nlayers; layno++) {
                            if ((ret = jpeg2000_decode_packet(s, codsty, rlevel,
                                                              precno, layno,
                                                              qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
                                                              qntsty->nguardbits)) < 0)
                                return ret;
                        }
                    }
                }
            }
        }
        break;

    case JPEG2000_PGOD_RPCL:
        avpriv_request_sample(s->avctx, "Progression order RPCL");
        ret = AVERROR_PATCHWELCOME;
        break;

    case JPEG2000_PGOD_PCRL:
        avpriv_request_sample(s->avctx, "Progression order PCRL");
        ret = AVERROR_PATCHWELCOME;
        break;

    default:
        break;
    }

    /* EOC marker reached */
    bytestream2_skip(&s->g, 2);

    return ret;
}


TPM2B_Marshal(TPM2B *source, UINT32 maxSize, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    assert(source->size <= maxSize); // libtpms added
    written += UINT16_Marshal(&(source->size), buffer, size);
    written += Array_Marshal(source->buffer, source->size, buffer, size);
    return written;
}


UINT64_Marshal(UINT64 *source, BYTE **buffer, INT32 *size)
{
    if (buffer != NULL) {
	if ((size == NULL) || ((UINT32)*size >= sizeof(UINT64))) {

	    (*buffer)[0] = (BYTE)((*source >> 56) & 0xff);
	    (*buffer)[1] = (BYTE)((*source >> 48) & 0xff);
	    (*buffer)[2] = (BYTE)((*source >> 40) & 0xff);
	    (*buffer)[3] = (BYTE)((*source >> 32) & 0xff);
	    (*buffer)[4] = (BYTE)((*source >> 24) & 0xff);
	    (*buffer)[5] = (BYTE)((*source >> 16) & 0xff);
	    (*buffer)[6] = (BYTE)((*source >>  8) & 0xff);
	    (*buffer)[7] = (BYTE)((*source >>  0) & 0xff);
	    *buffer += sizeof(UINT64);

	    if (size != NULL) {
		*size -= sizeof(UINT64);
	    }
	}
	else {
	    pAssert(FALSE);
	}
    }
    return sizeof(UINT64);
}


TPMI_RH_NV_INDEX_Marshal(TPMI_RH_NV_INDEX *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += TPM_HANDLE_Marshal(source, buffer, size);
    return written;
}


TPMU_HA_Marshal(TPMU_HA *source, BYTE **buffer, INT32 *size, UINT32 selector)
{
    UINT16 written = 0;

    switch (selector) {
#if ALG_SHA1
      case TPM_ALG_SHA1:
	written += Array_Marshal(&source->sha1[0], SHA1_DIGEST_SIZE, buffer, size);
	break;
#endif
#if ALG_SHA256
      case TPM_ALG_SHA256:
	written += Array_Marshal(&source->sha256[0], SHA256_DIGEST_SIZE, buffer, size);
	break;
#endif
#if ALG_SHA384
      case TPM_ALG_SHA384:
	written += Array_Marshal(&source->sha384[0], SHA384_DIGEST_SIZE, buffer, size);
	break;
#endif
#if ALG_SHA512
      case TPM_ALG_SHA512:
	written += Array_Marshal(&source->sha512[0], SHA512_DIGEST_SIZE, buffer, size);
	break;
#endif
#if ALG_SM3_256
      case TPM_ALG_SM3_256:
	written += Array_Marshal(&source->sm3_256[0], SM3_256_DIGEST_SIZE, buffer, size);
	break;
#endif
      case TPM_ALG_NULL:
	break;
      default:
	pAssert(FALSE);
    }
    return written;
}


TPMS_TIME_INFO_Marshal(TPMS_TIME_INFO *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;

    written += UINT64_Marshal(&source->time, buffer, size);
    written += TPMS_CLOCK_INFO_Marshal(&source->clockInfo, buffer, size);
    return written;
}


TPMS_SIG_SCHEME_RSASSA_Marshal(TPMS_SIG_SCHEME_RSASSA *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += TPMS_SCHEME_HASH_Marshal(source, buffer, size);
    return written;
}


TPMS_SCHEME_XOR_Marshal(TPMS_SCHEME_XOR *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;

    written += TPMI_ALG_HASH_Marshal(&source->hashAlg, buffer, size);
    written += TPMI_ALG_KDF_Marshal(&source->kdf, buffer, size);
    return written;
}


TPM_ALG_ID_Marshal(TPM_ALG_ID *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += UINT16_Marshal(source, buffer, size);
    return written;
}


TPMI_ALG_RSA_SCHEME_Marshal(TPMI_ALG_RSA_SCHEME *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += TPM_ALG_ID_Marshal(source, buffer, size);
    return written;
}


TPML_TAGGED_PCR_PROPERTY_Marshal(TPML_TAGGED_PCR_PROPERTY *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    UINT32 i;

    written += UINT32_Marshal(&source->count, buffer, size);
    for (i = 0 ; i < source->count ; i++) {
	written += TPMS_TAGGED_PCR_SELECT_Marshal(&source->pcrProperty[i], buffer, size);
    }
    return written;
}


TPMS_KEY_SCHEME_ECDH_Marshal(TPMS_KEY_SCHEME_ECDH *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += TPMS_SCHEME_HASH_Marshal(source, buffer, size);
    return written;
}


TPMU_ASYM_SCHEME_Marshal(TPMU_ASYM_SCHEME  *source, BYTE **buffer, INT32 *size, UINT32 selector)
{
    UINT16 written = 0;

    switch (selector) {
#if ALG_ECDH
      case TPM_ALG_ECDH:
	written += TPMS_KEY_SCHEME_ECDH_Marshal(&source->ecdh, buffer, size);
	break;
#endif
#if ALG_ECMQV
      case TPM_ALG_ECMQV:
	written += TPMS_KEY_SCHEME_ECMQV_Marshal(&source->ecmqv, buffer, size);
	break;
#endif
#if ALG_RSASSA
      case TPM_ALG_RSASSA:
	written += TPMS_SIG_SCHEME_RSASSA_Marshal(&source->rsassa, buffer, size);
	break;
#endif
#if ALG_RSAPSS
      case TPM_ALG_RSAPSS:
	written += TPMS_SIG_SCHEME_RSAPSS_Marshal(&source->rsapss, buffer, size);
	break;
#endif
#if ALG_ECDSA
      case TPM_ALG_ECDSA:
	written += TPMS_SIG_SCHEME_ECDSA_Marshal(&source->ecdsa, buffer, size);
	break;
#endif
#if ALG_ECDAA
      case TPM_ALG_ECDAA:
	written += TPMS_SIG_SCHEME_ECDAA_Marshal(&source->ecdaa, buffer, size);
	break;
#endif
#if ALG_SM2
      case TPM_ALG_SM2:
	written += TPMS_SIG_SCHEME_SM2_Marshal(&source->sm2, buffer, size);
	break;
#endif
#if ALG_ECSCHNORR
      case TPM_ALG_ECSCHNORR:
	written += TPMS_SIG_SCHEME_ECSCHNORR_Marshal(&source->ecschnorr, buffer, size);
	break;
#endif
#if ALG_RSAES
      case TPM_ALG_RSAES:
	written += TPMS_ENC_SCHEME_RSAES_Marshal(&source->rsaes, buffer, size);
	break;
#endif
#if ALG_OAEP
      case TPM_ALG_OAEP:
	written += TPMS_ENC_SCHEME_OAEP_Marshal(&source->oaep, buffer, size);
	break;
#endif
      case TPM_ALG_NULL:
	break;
      default:
	pAssert(FALSE);
    }
    return written;
}


TPM_HANDLE_Marshal(TPM_HANDLE *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += UINT32_Marshal(source, buffer, size);
    return written;
}


TPMI_ALG_HASH_Marshal(TPMI_ALG_HASH *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += TPM_ALG_ID_Marshal(source, buffer, size);
    return written;
}


TPMS_SIGNATURE_ECDSA_Marshal(TPMS_SIGNATURE_ECDSA *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += TPMS_SIGNATURE_ECC_Marshal(source, buffer, size);
    return written;
}


TPMS_NV_CERTIFY_INFO_Marshal(TPMS_NV_CERTIFY_INFO *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;

    written += TPM2B_NAME_Marshal(&source->indexName, buffer, size);
    written += UINT16_Marshal(&source->offset, buffer, size);
    written += TPM2B_MAX_NV_BUFFER_Marshal(&source->nvContents, buffer, size);
    return written;
}


TPM2B_PUBLIC_KEY_RSA_Marshal(TPM2B_PUBLIC_KEY_RSA *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += TPM2B_Marshal(&source->b, sizeof(source->t.buffer), buffer, size); // libtpms changed
    return written;
}


TPMU_PUBLIC_PARMS_Marshal(TPMU_PUBLIC_PARMS *source, BYTE **buffer, INT32 *size, UINT32 selector)
{
    UINT16 written = 0;

    switch (selector) {
#if ALG_KEYEDHASH
      case TPM_ALG_KEYEDHASH:
	written += TPMS_KEYEDHASH_PARMS_Marshal(&source->keyedHashDetail, buffer, size);
	break;
#endif
#if ALG_SYMCIPHER
      case TPM_ALG_SYMCIPHER:
	written += TPMS_SYMCIPHER_PARMS_Marshal(&source->symDetail, buffer, size);
	break;
#endif
#if ALG_RSA
      case TPM_ALG_RSA:
	written += TPMS_RSA_PARMS_Marshal(&source->rsaDetail, buffer, size);
	break;
#endif
#if ALG_ECC
      case TPM_ALG_ECC:
	written += TPMS_ECC_PARMS_Marshal(&source->eccDetail, buffer, size);
	break;
#endif
      default:
	pAssert(FALSE);
    }
    return written;
}


TPMI_YES_NO_Marshal(TPMI_YES_NO *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += UINT8_Marshal(source, buffer, size);
    return written;
}


TPM2B_ID_OBJECT_Marshal(TPM2B_ID_OBJECT *source, BYTE **buffer, INT32 *size)
{
    UINT16 written = 0;
    written += TPM2B_Marshal(&source->b, sizeof(source->t.credential), buffer, size); // libtpms changed
    return written;
}


	if (s_httpserv) {
		mg_stop(s_httpserv->ctx);
		mg_exit_library();
		free(s_httpserv->civetweb_options);
		free(s_httpserv);
	}


startupServers(void)
{
	DEFiRet;
	rsRetVal localRet, lastErr;
	int iOK;
	int iAll;
	ptcpsrv_t *pSrv;

	iAll = iOK = 0;
	lastErr = RS_RET_ERR;
	pSrv = pSrvRoot;
	while(pSrv != NULL) {
		DBGPRINTF("imptcp: starting up server for port %s, name '%s'\n", pSrv->port, pSrv->pszInputName);
		localRet = startupSrv(pSrv);
		if(localRet == RS_RET_OK)
			iOK++;
		else
			lastErr = localRet;
		++iAll;
		pSrv = pSrv->pNext;
	}

	DBGPRINTF("imptcp: %d out of %d servers started successfully\n", iOK, iAll);
	if(iOK == 0)	/* iff all fails, we report an error */
		iRet = lastErr;

	RETiRet;
}


	if(pvals == NULL) {
		LogError(0, RS_RET_MISSING_CNFPARAMS, "imptcp: error processing module "
				"config parameters [module(...)]");
		ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
	}


createInstance(instanceConf_t **pinst)
{
	instanceConf_t *inst;
	DEFiRet;
	CHKmalloc(inst = malloc(sizeof(instanceConf_t)));
	inst->next = NULL;

	inst->pszBindPort = NULL;
	inst->pszBindAddr = NULL;
	inst->pszBindPath = NULL;
	inst->fileUID = -1;
	inst->fileGID = -1;
	inst->maxFrameSize = 200000;
	inst->fCreateMode = 0644;
	inst->bFailOnPerms = 1;
	inst->bUnlink = 0;
	inst->discardTruncatedMsg = 0;
	inst->flowControl = 1;
	inst->pszBindRuleset = NULL;
	inst->pszInputName = NULL;
	inst->bSuppOctetFram = 1;
	inst->bSPFramingFix = 0;
	inst->bKeepAlive = 0;
	inst->iKeepAliveIntvl = 0;
	inst->iKeepAliveProbes = 0;
	inst->iKeepAliveTime = 0;
	inst->bEmitMsgOnClose = 0;
	inst->bEmitMsgOnOpen = 0;
	inst->dfltTZ = NULL;
	inst->iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
	inst->startRegex = NULL;
	inst->pBindRuleset = NULL;
	inst->ratelimitBurst = 10000; /* arbitrary high limit */
	inst->ratelimitInterval = 0; /* off */
	inst->compressionMode = COMPRESS_SINGLE_MSG;
	inst->multiLine = 0;
	inst->socketBacklog = 5;
	inst->pszLstnPortFileName = NULL;
	inst->iTCPSessMax = -1;

	/* node created, let's add to config */
	if(loadModConf->tail == NULL) {
		loadModConf->tail = loadModConf->root = inst;
	} else {
		loadModConf->tail->next = inst;
		loadModConf->tail = inst;
	}

	*pinst = inst;
finalize_it:
	RETiRet;
}


getPeerNames(prop_t **peerName, prop_t **peerIP, struct sockaddr *pAddr, sbool bUXServer)
{
	int error;
	uchar szIP[NI_MAXHOST+1] = "";
	uchar szHname[NI_MAXHOST+1] = "";
	struct addrinfo hints, *res;
	sbool bMaliciousHName = 0;

	DEFiRet;

	*peerName = NULL;
	*peerIP = NULL;

	if (bUXServer) {
		strncpy((char *) szHname, (char *) glbl.GetLocalHostName(), NI_MAXHOST);
		strncpy((char *) szIP, (char *) glbl.GetLocalHostIP(), NI_MAXHOST);
		szHname[NI_MAXHOST] = '\0';
		szIP[NI_MAXHOST] = '\0';
	} else {
		error = getnameinfo(pAddr, SALEN(pAddr), (char *) szIP, sizeof(szIP), NULL, 0, NI_NUMERICHOST);
		if (error) {
			DBGPRINTF("Malformed from address %s\n", gai_strerror(error));
			strcpy((char *) szHname, "???");
			strcpy((char *) szIP, "???");
			ABORT_FINALIZE(RS_RET_INVALID_HNAME);
		}

		if (!glbl.GetDisableDNS(runConf)) {
			error = getnameinfo(pAddr, SALEN(pAddr), (char *) szHname, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
			if (error == 0) {
				memset(&hints, 0, sizeof(struct addrinfo));
				hints.ai_flags = AI_NUMERICHOST;
				hints.ai_socktype = SOCK_STREAM;
				/* we now do a lookup once again. This one should fail,
				 * because we should not have obtained a non-numeric address. If
				 * we got a numeric one, someone messed with DNS!
				 */
				if (getaddrinfo((char *) szHname, NULL, &hints, &res) == 0) {
					freeaddrinfo(res);
					/* OK, we know we have evil, so let's indicate this to our caller */
					snprintf((char *) szHname, sizeof(szHname), "[MALICIOUS:IP=%s]", szIP);
					DBGPRINTF("Malicious PTR record, IP = \"%s\" HOST = \"%s\"", szIP, szHname);
					bMaliciousHName = 1;
				}
			} else {
				strcpy((char *) szHname, (char *) szIP);
			}
		} else {
			strcpy((char *) szHname, (char *) szIP);
		}
	}

	/* We now have the names, so now let's allocate memory and store them permanently. */
	CHKiRet(prop.Construct(peerName));
	CHKiRet(prop.SetString(*peerName, szHname, ustrlen(szHname)));
	CHKiRet(prop.ConstructFinalize(*peerName));
	CHKiRet(prop.Construct(peerIP));
	CHKiRet(prop.SetString(*peerIP, szIP, ustrlen(szIP)));
	CHKiRet(prop.ConstructFinalize(*peerIP));

finalize_it:
	if(iRet != RS_RET_OK) {
		if(*peerName != NULL)
			prop.Destruct(peerName);
		if(*peerIP != NULL)
			prop.Destruct(peerIP);
	}
	if(bMaliciousHName)
		iRet = RS_RET_MALICIOUS_HNAME;
	RETiRet;
}


	if (runModConf->nOptions) {
		s_httpserv->civetweb_options_count = count;
		for (int i = 0; i < runModConf->nOptions; ++i) {
			*pcivetweb_options = runModConf->options[i].name;
			pcivetweb_options++;
			*pcivetweb_options = runModConf->options[i].val;
			pcivetweb_options++;
		}
	}


static int __init setup_acpi_sci(char *s)
{
	if (!s)
		return -EINVAL;
	if (!strcmp(s, "edge"))
		acpi_sci_flags.trigger = 1;
	else if (!strcmp(s, "level"))
		acpi_sci_flags.trigger = 3;
	else if (!strcmp(s, "high"))
		acpi_sci_flags.polarity = 1;
	else if (!strcmp(s, "low"))
		acpi_sci_flags.polarity = 3;
	else
		return -EINVAL;
	return 0;
}


void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
{
	unsigned int mask = 1 << irq;
	unsigned int old, new;

	/* Real old ELCR mask */
	old = inb(0x4d0) | (inb(0x4d1) << 8);

	/*
	 * If we use ACPI to set PCI irq's, then we should clear ELCR
	 * since we will set it correctly as we enable the PCI irq
	 * routing.
	 */
	new = acpi_noirq ? old : 0;

	/*
	 * Update SCI information in the ELCR, it isn't in the PCI
	 * routing tables..
	 */
	switch (trigger) {
	case 1:		/* Edge - clear */
		new &= ~mask;
		break;
	case 3:		/* Level - set */
		new |= mask;
		break;
	}

	if (old == new)
		return;

	printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
	outb(new, 0x4d0);
	outb(new >> 8, 0x4d1);
}


int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
	struct sock *sk = sock->sk;
	struct net *net = sock_net(sk);

	switch(cmd)
	{
	case SIOCGSTAMP:
		return sock_get_timestamp(sk, (struct timeval __user *)arg);

	case SIOCGSTAMPNS:
		return sock_get_timestampns(sk, (struct timespec __user *)arg);

	case SIOCADDRT:
	case SIOCDELRT:

		return(ipv6_route_ioctl(net, cmd, (void __user *)arg));

	case SIOCSIFADDR:
		return addrconf_add_ifaddr(net, (void __user *) arg);
	case SIOCDIFADDR:
		return addrconf_del_ifaddr(net, (void __user *) arg);
	case SIOCSIFDSTADDR:
		return addrconf_set_dstaddr(net, (void __user *) arg);
	default:
		if (!sk->sk_prot->ioctl)
			return -ENOIOCTLCMD;
		return sk->sk_prot->ioctl(sk, cmd, arg);
	}
	/*NOTREACHED*/
	return(0);
}


unsigned char	*kssl_skip_confound(krb5_enctype etype, unsigned char *a)
	{
	int 		i, conlen;
	size_t		cklen;
	static size_t 	*cksumlens = NULL;
	unsigned char	*test_auth;

	conlen = (etype)? 8: 0;

	if (!cksumlens  &&  !(cksumlens = populate_cksumlens()))  return NULL;
	for (i=0; (cklen = cksumlens[i]) != 0; i++)
		{
		test_auth = a + conlen + cklen;
		if (kssl_test_confound(test_auth))  return test_auth;
		}

	return NULL;
	}


valid_cksumtype(krb5_cksumtype ctype)
        {
        if (!krb5_loaded)
                load_krb5_dll();

        if ( p_valid_cksumtype )
                return(p_valid_cksumtype(ctype));
        else
                return KRB5KRB_ERR_GENERIC;
        }


    kssl_keytab_is_available(KSSL_CTX *kssl_ctx)
{
    krb5_context		krb5context = NULL;
    krb5_keytab 		krb5keytab = NULL;
    krb5_keytab_entry           entry;
    krb5_principal              princ = NULL;
    krb5_error_code  		krb5rc = KRB5KRB_ERR_GENERIC;
    int rc = 0;

    if ((krb5rc = krb5_init_context(&krb5context)))
        return(0);

    /*	kssl_ctx->keytab_file == NULL ==> use Kerberos default
    */
    if (kssl_ctx->keytab_file)
    {
        krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
                                  &krb5keytab);
        if (krb5rc)
            goto exit;
    }
    else
    {
        krb5rc = krb5_kt_default(krb5context,&krb5keytab);
        if (krb5rc)
            goto exit;
    }

    /* the host key we are looking for */
    krb5rc = krb5_sname_to_principal(krb5context, NULL,
                                     kssl_ctx->service_name ? kssl_ctx->service_name: KRB5SVC,
                                     KRB5_NT_SRV_HST, &princ);

    if (krb5rc)
	goto exit;

    krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
                                princ,
                                0 /* IGNORE_VNO */,
                                0 /* IGNORE_ENCTYPE */,
                                &entry);
    if ( krb5rc == KRB5_KT_NOTFOUND ) {
        rc = 1;
        goto exit;
    } else if ( krb5rc )
        goto exit;

    krb5_kt_free_entry(krb5context, &entry);
    rc = 1;

  exit:
    if (krb5keytab)     krb5_kt_close(krb5context, krb5keytab);
    if (princ)          krb5_free_principal(krb5context, princ);
    if (krb5context)	krb5_free_context(krb5context);
    return(rc);
}


krb5_timeofday(krb5_context con, krb5_int32 *timeret)
	{
	if (!krb5_loaded)
		load_krb5_dll();

	if ( p_krb5_timeofday )
		return(p_krb5_timeofday(con,timeret));
	else
		return KRB5KRB_ERR_GENERIC;
	}


kssl_sget_tkt(	/* UPDATE */	KSSL_CTX		*kssl_ctx,
		/* IN     */	krb5_data		*indata,
		/* OUT    */	krb5_ticket_times	*ttimes,
		/* OUT    */	KSSL_ERR		*kssl_err  )
        {
        krb5_error_code			krb5rc = KRB5KRB_ERR_GENERIC;
        static krb5_context		krb5context = NULL;
	static krb5_auth_context	krb5auth_context = NULL;
	krb5_ticket 			*krb5ticket = NULL;
	KRB5_TKTBODY 			*asn1ticket = NULL;
	const unsigned char		*p;
	krb5_keytab 			krb5keytab = NULL;
	krb5_keytab_entry		kt_entry;
	krb5_principal			krb5server;
        krb5_rcache                     rcache = NULL;

	kssl_err_set(kssl_err, 0, "");

	if (!kssl_ctx)
                {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
			"No kssl_ctx defined.\n");
		goto err;
		}

#ifdef KSSL_DEBUG
	printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
#endif	/* KSSL_DEBUG */

	if (!krb5context  &&  (krb5rc = krb5_init_context(&krb5context)))
                {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
                        "krb5_init_context() fails.\n");
		goto err;
		}
	if (krb5auth_context  &&
		(krb5rc = krb5_auth_con_free(krb5context, krb5auth_context)))
                {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
                        "krb5_auth_con_free() fails.\n");
		goto err;
		}
	else  krb5auth_context = NULL;
	if (!krb5auth_context  &&
		(krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context)))
                {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
                        "krb5_auth_con_init() fails.\n");
		goto err;
		}

	if ((krb5rc = krb5_auth_con_getrcache(krb5context, krb5auth_context,
		&rcache)))
		{
 		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
			"krb5_auth_con_getrcache() fails.\n");
 		goto err;
		}

	if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
                (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
                KRB5_NT_SRV_HST, &krb5server)) != 0)
                {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
                        "krb5_sname_to_principal() fails.\n");
		goto err;
		}

	if (rcache == NULL)
                {
                if ((krb5rc = krb5_get_server_rcache(krb5context,
			krb5_princ_component(krb5context, krb5server, 0),
			&rcache)))
                        {
		        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
                                "krb5_get_server_rcache() fails.\n");
                  	goto err;
                        }
                }

        if ((krb5rc = krb5_auth_con_setrcache(krb5context, krb5auth_context, rcache)))
                {
                kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
			"krb5_auth_con_setrcache() fails.\n");
                goto err;
                }

	/*	kssl_ctx->keytab_file == NULL ==> use Kerberos default
	*/
	if (kssl_ctx->keytab_file)
		{
		krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
                        &krb5keytab);
		if (krb5rc)
			{
			kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
				"krb5_kt_resolve() fails.\n");
			goto err;
			}
		}
	else
		{
                krb5rc = krb5_kt_default(krb5context,&krb5keytab);
                if (krb5rc)
			{
			kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
				"krb5_kt_default() fails.\n");
			goto err;
			}
		}

	/*	Actual Kerberos5 krb5_recvauth() has initial conversation here
	**	o	check KRB5_SENDAUTH_BADAUTHVERS
	**		unless KRB5_RECVAUTH_SKIP_VERSION
	**	o	check KRB5_SENDAUTH_BADAPPLVERS
	**	o	send "0" msg if all OK
	*/

	/*  20010411 was using AP_REQ instead of true KerberosWrapper
	**
	**  if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context,
	**			&krb5in_data, krb5server, krb5keytab,
	**			&ap_option, &krb5ticket)) != 0)  { Error }
	*/

	p = (unsigned char *)indata->data;
	if ((asn1ticket = (KRB5_TKTBODY *) d2i_KRB5_TICKET(NULL, &p,
						(long) indata->length)) == NULL)
		{
		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
			"d2i_KRB5_TICKET() ASN.1 decode failure.\n");
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
		}

	/* Was:  krb5rc = krb5_decode_ticket(krb5in_data,&krb5ticket)) != 0) */
	if ((krb5rc = kssl_TKT2tkt(krb5context, asn1ticket, &krb5ticket,
					kssl_err)) != 0)
		{
		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
			"Error converting ASN.1 ticket to krb5_ticket.\n");
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
		}

	if (! krb5_principal_compare(krb5context, krb5server,
						  krb5ticket->server))  {
		krb5rc = KRB5_PRINC_NOMATCH;
		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
			"server principal != ticket principal\n");
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
		}
	if ((krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
			krb5ticket->server, krb5ticket->enc_part.kvno,
			krb5ticket->enc_part.enctype, &kt_entry)) != 0)  {
		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
			"krb5_kt_get_entry() fails with %x.\n", krb5rc);
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
		}
	if ((krb5rc = krb5_decrypt_tkt_part(krb5context, &kt_entry.key,
			krb5ticket)) != 0)  {
		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
			"krb5_decrypt_tkt_part() failed.\n");
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
		}
	else  {
		krb5_kt_free_entry(krb5context, &kt_entry);
#ifdef KSSL_DEBUG
		{
		int i; krb5_address **paddr = krb5ticket->enc_part2->caddrs;
		printf("Decrypted ticket fields:\n");
		printf("\tflags: %X, transit-type: %X",
			krb5ticket->enc_part2->flags,
			krb5ticket->enc_part2->transited.tr_type);
		print_krb5_data("\ttransit-data: ",
			&(krb5ticket->enc_part2->transited.tr_contents));
		printf("\tcaddrs: %p, authdata: %p\n",
			krb5ticket->enc_part2->caddrs,
			krb5ticket->enc_part2->authorization_data);
		if (paddr)
			{
			printf("\tcaddrs:\n");
			for (i=0; paddr[i] != NULL; i++)
				{
				krb5_data d;
				d.length=paddr[i]->length;
				d.data=paddr[i]->contents;
				print_krb5_data("\t\tIP: ", &d);
				}
			}
		printf("\tstart/auth/end times: %d / %d / %d\n",
			krb5ticket->enc_part2->times.starttime,
			krb5ticket->enc_part2->times.authtime,
			krb5ticket->enc_part2->times.endtime);
		}
#endif	/* KSSL_DEBUG */
		}

	krb5rc = KRB5_NO_TKT_SUPPLIED;
	if (!krb5ticket  ||	!krb5ticket->enc_part2  ||
                !krb5ticket->enc_part2->client  ||
                !krb5ticket->enc_part2->client->data  ||
                !krb5ticket->enc_part2->session)
                {
                kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
                        "bad ticket from krb5_rd_req.\n");
		}
	else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
		 &krb5ticket->enc_part2->client->realm,
		 krb5ticket->enc_part2->client->data,
		 krb5ticket->enc_part2->client->length))
                {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
                        "kssl_ctx_setprinc() fails.\n");
		}
	else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session))
                {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
                        "kssl_ctx_setkey() fails.\n");
		}
	else if (krb5ticket->enc_part2->flags & TKT_FLG_INVALID)
                {
		krb5rc = KRB5KRB_AP_ERR_TKT_INVALID;
                kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
                        "invalid ticket from krb5_rd_req.\n");
		}
	else	krb5rc = 0;

	kssl_ctx->enctype	= krb5ticket->enc_part.enctype;
	ttimes->authtime	= krb5ticket->enc_part2->times.authtime;
	ttimes->starttime	= krb5ticket->enc_part2->times.starttime;
	ttimes->endtime 	= krb5ticket->enc_part2->times.endtime;
	ttimes->renew_till	= krb5ticket->enc_part2->times.renew_till;

 err:
#ifdef KSSL_DEBUG
	kssl_ctx_show(kssl_ctx);
#endif	/* KSSL_DEBUG */

	if (asn1ticket) 	KRB5_TICKET_free((KRB5_TICKET *) asn1ticket);
        if (krb5keytab)         krb5_kt_close(krb5context, krb5keytab);
	if (krb5ticket) 	krb5_free_ticket(krb5context, krb5ticket);
	if (krb5server) 	krb5_free_principal(krb5context, krb5server);
	return (krb5rc);
        }


kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
        {
	int 		length;
	krb5_enctype	enctype;
	krb5_octet FAR	*contents = NULL;

	if (!kssl_ctx)  return KSSL_CTX_ERR;

	if (kssl_ctx->key)
                {
		OPENSSL_cleanse(kssl_ctx->key, kssl_ctx->length);
		kssl_free(kssl_ctx->key);
		}

	if (session)
                {

#ifdef KRB5_HEIMDAL
		length = session->keyvalue->length;
		enctype = session->keytype;
		contents = session->keyvalue->contents;
#else
		length = session->length;
		enctype = session->enctype;
		contents = session->contents;
#endif
		kssl_ctx->enctype = enctype;
		kssl_ctx->length  = length;
		}
	else
                {
		kssl_ctx->enctype = ENCTYPE_UNKNOWN;
		kssl_ctx->length  = 0;
		return KSSL_CTX_OK;
		}

	if ((kssl_ctx->key =
                (krb5_octet FAR *) kssl_calloc(1, kssl_ctx->length)) == NULL)
                {
		kssl_ctx->length  = 0;
		return KSSL_CTX_ERR;
		}
	else
		memcpy(kssl_ctx->key, contents, length);

	return KSSL_CTX_OK;
        }


kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
        {
	char	**string;

	if (!kssl_ctx)  return KSSL_CTX_ERR;

	switch (which)
                {
        case KSSL_SERVICE:	string = &kssl_ctx->service_name;	break;
        case KSSL_SERVER:	string = &kssl_ctx->service_host;	break;
        case KSSL_CLIENT:	string = &kssl_ctx->client_princ;	break;
        case KSSL_KEYTAB:	string = &kssl_ctx->keytab_file;	break;
        default:		return KSSL_CTX_ERR;			break;
		}
	if (*string)  kssl_free(*string);

	if (!text)
                {
		*string = '\0';
		return KSSL_CTX_OK;
		}

	if ((*string = kssl_calloc(1, strlen(text) + 1)) == NULL)
		return KSSL_CTX_ERR;
	else
		strcpy(*string, text);

	return KSSL_CTX_OK;
        }


kssl_krb5_init_context(krb5_context * pCO)
	{
	if (!krb5_loaded)
		load_krb5_dll();

	if ( p_krb5_init_context )
		return(p_krb5_init_context(pCO));
	else
		return KRB5KRB_ERR_GENERIC;
	}


load_krb5_dll(void)
	{
	HANDLE hKRB5_32;

	krb5_loaded++;
	hKRB5_32 = LoadLibrary(TEXT("KRB5_32"));
	if (!hKRB5_32)
		return;

	(FARPROC) p_krb5_free_data_contents =
		GetProcAddress( hKRB5_32, "krb5_free_data_contents" );
	(FARPROC) p_krb5_free_context =
		GetProcAddress( hKRB5_32, "krb5_free_context" );
	(FARPROC) p_krb5_auth_con_free =
		GetProcAddress( hKRB5_32, "krb5_auth_con_free" );
	(FARPROC) p_krb5_free_principal =
		GetProcAddress( hKRB5_32, "krb5_free_principal" );
	(FARPROC) p_krb5_mk_req_extended =
		GetProcAddress( hKRB5_32, "krb5_mk_req_extended" );
	(FARPROC) p_krb5_get_credentials =
		GetProcAddress( hKRB5_32, "krb5_get_credentials" );
	(FARPROC) p_krb5_cc_get_principal =
		GetProcAddress( hKRB5_32, "krb5_cc_get_principal" );
	(FARPROC) p_krb5_cc_default =
		GetProcAddress( hKRB5_32, "krb5_cc_default" );
	(FARPROC) p_krb5_sname_to_principal =
		GetProcAddress( hKRB5_32, "krb5_sname_to_principal" );
	(FARPROC) p_krb5_init_context =
		GetProcAddress( hKRB5_32, "krb5_init_context" );
	(FARPROC) p_krb5_free_ticket =
		GetProcAddress( hKRB5_32, "krb5_free_ticket" );
	(FARPROC) p_krb5_rd_req =
		GetProcAddress( hKRB5_32, "krb5_rd_req" );
	(FARPROC) p_krb5_principal_compare =
		GetProcAddress( hKRB5_32, "krb5_principal_compare" );
	(FARPROC) p_krb5_decrypt_tkt_part =
		GetProcAddress( hKRB5_32, "krb5_decrypt_tkt_part" );
	(FARPROC) p_krb5_timeofday =
		GetProcAddress( hKRB5_32, "krb5_timeofday" );
	(FARPROC) p_krb5_rc_default =
		GetProcAddress( hKRB5_32, "krb5_rc_default" );
	(FARPROC) p_krb5_rc_initialize =
		GetProcAddress( hKRB5_32, "krb5_rc_initialize" );
	(FARPROC) p_krb5_rc_get_lifespan =
		GetProcAddress( hKRB5_32, "krb5_rc_get_lifespan" );
	(FARPROC) p_krb5_rc_destroy =
		GetProcAddress( hKRB5_32, "krb5_rc_destroy" );
	(FARPROC) p_krb5_kt_default =
		GetProcAddress( hKRB5_32, "krb5_kt_default" );
	(FARPROC) p_krb5_kt_resolve =
		GetProcAddress( hKRB5_32, "krb5_kt_resolve" );
	(FARPROC) p_krb5_auth_con_init =
		GetProcAddress( hKRB5_32, "krb5_auth_con_init" );
        (FARPROC) p_valid_cksumtype =
                GetProcAddress( hKRB5_32, "valid_cksumtype" );
        (FARPROC) p_krb5_checksum_size =
                GetProcAddress( hKRB5_32, "krb5_checksum_size" );
        (FARPROC) p_krb5_kt_free_entry =
                GetProcAddress( hKRB5_32, "krb5_kt_free_entry" );
        (FARPROC) p_krb5_auth_con_setrcache =
                GetProcAddress( hKRB5_32, "krb5_auth_con_setrcache" );
        (FARPROC) p_krb5_get_server_rcache =
                GetProcAddress( hKRB5_32, "krb5_get_server_rcache" );
        (FARPROC) p_krb5_auth_con_getrcache =
                GetProcAddress( hKRB5_32, "krb5_auth_con_getrcache" );
        (FARPROC) p_krb5_kt_close =
                GetProcAddress( hKRB5_32, "krb5_kt_close" );
        (FARPROC) p_krb5_kt_get_entry =
                GetProcAddress( hKRB5_32, "krb5_kt_get_entry" );
	}


static void write_pack_info_file(FILE *fp)
{
	int i;
	for (i = 0; i < num_pack; i++)
		fprintf(fp, "P %s\n", info[i]->p->pack_name + objdirlen + 6);
	fputc('\n', fp);
}


Bool unRLE_obuf_to_output_SMALL ( DState* s )
{
   UChar k1;

/*    if (s->blockRandomised) { */

/*       while (True) { */
/*          /\* try to finish existing run *\/ */
/*          while (True) { */
/*             if (s->strm->avail_out == 0) return False; */
/*             if (s->state_out_len == 0) break; */
/*             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; */
/* 	       BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); */
/*             s->state_out_len--; */
/*             s->strm->next_out++; */
/*             s->strm->avail_out--; */
/*             s->strm->total_out_lo32++; */
/*             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; */
/*          } */

/*          /\* can a new run be started? *\/ */
/*          if (s->nblock_used == s->save_nblock+1) return False; */

/*          /\* Only caused by corrupt data stream? *\/ */
/*          if (s->nblock_used > s->save_nblock+1) */
/*             return True; */

/*          s->state_out_len = 1; */
/*          s->state_out_ch = s->k0; */
/*          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;  */
/*          k1 ^= BZ_RAND_MASK; s->nblock_used++; */
/*          if (s->nblock_used == s->save_nblock+1) continue; */
/*          if (k1 != s->k0) { s->k0 = k1; continue; }; */

/*          s->state_out_len = 2; */
/*          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;  */
/*          k1 ^= BZ_RAND_MASK; s->nblock_used++; */
/*          if (s->nblock_used == s->save_nblock+1) continue; */
/*          if (k1 != s->k0) { s->k0 = k1; continue; }; */

/*          s->state_out_len = 3; */
/*          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;  */
/*          k1 ^= BZ_RAND_MASK; s->nblock_used++; */
/*          if (s->nblock_used == s->save_nblock+1) continue; */
/*          if (k1 != s->k0) { s->k0 = k1; continue; }; */

/*          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;  */
/*          k1 ^= BZ_RAND_MASK; s->nblock_used++; */
/*          s->state_out_len = ((Int32)k1) + 4; */
/*          BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;  */
/*          s->k0 ^= BZ_RAND_MASK; s->nblock_used++; */
/*       } */

/*    } else */ {

      while (True) {
         /* try to finish existing run */
         while (True) {
            if (s->strm->avail_out == 0) return False;
            if (s->state_out_len == 0) break;
            *(s->strm->next_out) = s->state_out_ch;
	    /* aCaB BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); */
            s->state_out_len--;
            s->strm->next_out++;
            s->strm->avail_out--;
            s->strm->total_out_lo32++;
            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
         }

         /* can a new run be started? */
         if (s->nblock_used == s->save_nblock+1) return False;

         /* Only caused by corrupt data stream? */
         if (s->nblock_used > s->save_nblock+1)
            return True;

         s->state_out_len = 1;
         s->state_out_ch = s->k0;
         BZ_GET_SMALL(k1); s->nblock_used++;
         if (s->nblock_used == s->save_nblock+1) continue;
         if (k1 != s->k0) { s->k0 = k1; continue; };

         s->state_out_len = 2;
         BZ_GET_SMALL(k1); s->nblock_used++;
         if (s->nblock_used == s->save_nblock+1) continue;
         if (k1 != s->k0) { s->k0 = k1; continue; };

         s->state_out_len = 3;
         BZ_GET_SMALL(k1); s->nblock_used++;
         if (s->nblock_used == s->save_nblock+1) continue;
         if (k1 != s->k0) { s->k0 = k1; continue; };

         BZ_GET_SMALL(k1); s->nblock_used++;
         s->state_out_len = ((Int32)k1) + 4;
         BZ_GET_SMALL(s->k0); s->nblock_used++;
      }

   }
}


rsvg_error_cb (void *data, const char *msg, ...)
{
#ifdef G_ENABLE_DEBUG
    va_list args;

    va_start (args, msg);
    vfprintf (stderr, msg, args);
    va_end (args);
#endif
}


_rsvg_node_chars_free (RsvgNode * node)
{
    RsvgNodeChars *self = (RsvgNodeChars *) node;
    g_string_free (self->contents, TRUE);
    _rsvg_node_free (node);
}


_rsvg_node_dont_set_atts (RsvgNode * node, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
}


rsvg_new_filter_primitive_colour_matrix (void)
{
    RsvgFilterPrimitiveColourMatrix *filter;
    filter = g_new (RsvgFilterPrimitiveColourMatrix, 1);
    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_COLOUR_MATRIX);
    filter->super.in = g_string_new ("none");
    filter->super.result = g_string_new ("none");
    filter->super.x.factor = filter->super.y.factor = filter->super.width.factor =
        filter->super.height.factor = 'n';
    filter->KernelMatrix = NULL;
    filter->super.render = &rsvg_filter_primitive_colour_matrix_render;
    filter->super.super.free = &rsvg_filter_primitive_colour_matrix_free;

    filter->super.super.set_atts = rsvg_filter_primitive_colour_matrix_set_atts;
    return (RsvgNode *) filter;
}


pixbuf_get_alpha (GdkPixbuf * pb, RsvgFilterContext * ctx)
{
    guchar *data;
    guchar *pbdata;
    GdkPixbuf *output;

    gsize i, pbsize;

    pbsize = gdk_pixbuf_get_width (pb) * gdk_pixbuf_get_height (pb);

    output = _rsvg_pixbuf_new_cleared (GDK_COLORSPACE_RGB, 1, 8,
                                       gdk_pixbuf_get_width (pb), gdk_pixbuf_get_height (pb));

    data = gdk_pixbuf_get_pixels (output);
    pbdata = gdk_pixbuf_get_pixels (pb);

    for (i = 0; i < pbsize; i++)
        data[i * 4 + ctx->channelmap[3]] = pbdata[i * 4 + ctx->channelmap[3]];

    return output;
}


rsvg_render_free (RsvgRender * render)
{
    render->free (render);
}


_rsvg_cairo_set_shape_antialias (cairo_t * cr, ShapeRenderingProperty aa)
{
    if (SHAPE_RENDERING_AUTO == aa)
        cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT);
    else if (SHAPE_RENDERING_OPTIMIZE_SPEED == aa)
        cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
    else if (SHAPE_RENDERING_CRISP_EDGES == aa)
        cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
    else if (SHAPE_RENDERING_GEOMETRIC_PRECISION == aa)
        cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT);
}


rsvg_node_path_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    const char *klazz = NULL, *id = NULL, *value;
    RsvgNodePath *path = (RsvgNodePath *) self;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "d"))) {
            if (path->d)
                g_free (path->d);
            path->d = g_strdup (value);
        }
        if ((value = rsvg_property_bag_lookup (atts, "class")))
            klazz = value;
        if ((value = rsvg_property_bag_lookup (atts, "id"))) {
            id = value;
            rsvg_defs_register_name (ctx->priv->defs, value, self);
        }

        rsvg_parse_style_attrs (ctx, self->state, "path", klazz, id, atts);
    }
}


rsvg_text_layout_free (RsvgTextLayout * layout)
{
    g_object_unref (layout->layout);
    g_free (layout);
}


rsvg_filter_blend (RsvgFilterPrimitiveBlendMode mode, GdkPixbuf * in, GdkPixbuf * in2,
                   GdkPixbuf * output, RsvgIRect boundarys, int *channelmap)
{
    guchar i;
    gint x, y;
    gint rowstride, rowstride2, rowstrideo, height, width;
    guchar *in_pixels;
    guchar *in2_pixels;
    guchar *output_pixels;
    height = gdk_pixbuf_get_height (in);
    width = gdk_pixbuf_get_width (in);
    rowstride = gdk_pixbuf_get_rowstride (in);
    rowstride2 = gdk_pixbuf_get_rowstride (in2);
    rowstrideo = gdk_pixbuf_get_rowstride (output);

    output_pixels = gdk_pixbuf_get_pixels (output);
    in_pixels = gdk_pixbuf_get_pixels (in);
    in2_pixels = gdk_pixbuf_get_pixels (in2);

    if (boundarys.x0 < 0)
        boundarys.x0 = 0;
    if (boundarys.y0 < 0)
        boundarys.y0 = 0;
    if (boundarys.x1 >= width)
        boundarys.x1 = width;
    if (boundarys.y1 >= height)
        boundarys.y1 = height;

    for (y = boundarys.y0; y < boundarys.y1; y++)
        for (x = boundarys.x0; x < boundarys.x1; x++) {
            double qr, cr, qa, qb, ca, cb, bca, bcb;
            int ch;

            qa = (double) in_pixels[4 * x + y * rowstride + channelmap[3]] / 255.0;
            qb = (double) in2_pixels[4 * x + y * rowstride2 + channelmap[3]] / 255.0;
            qr = 1 - (1 - qa) * (1 - qb);
            cr = 0;
            for (ch = 0; ch < 3; ch++) {
                i = channelmap[ch];
                ca = (double) in_pixels[4 * x + y * rowstride + i] / 255.0;
                cb = (double) in2_pixels[4 * x + y * rowstride2 + i] / 255.0;
                /*these are the ca and cb that are used in the non-standard blend functions */
                bcb = (1 - qa) * cb + ca;
                bca = (1 - qb) * ca + cb;
                switch (mode) {
                case normal:
                    cr = (1 - qa) * cb + ca;
                    break;
                case multiply:
                    cr = (1 - qa) * cb + (1 - qb) * ca + ca * cb;
                    break;
                case screen:
                    cr = cb + ca - ca * cb;
                    break;
                case darken:
                    cr = MIN ((1 - qa) * cb + ca, (1 - qb) * ca + cb);
                    break;
                case lighten:
                    cr = MAX ((1 - qa) * cb + ca, (1 - qb) * ca + cb);
                    break;
                case softlight:
                    if (bcb < 0.5)
                        cr = 2 * bca * bcb + bca * bca * (1 - 2 * bcb);
                    else
                        cr = sqrt (bca) * (2 * bcb - 1) + (2 * bca) * (1 - bcb);
                    break;
                case hardlight:
                    if (cb < 0.5)
                        cr = 2 * bca * bcb;
                    else
                        cr = 1 - 2 * (1 - bca) * (1 - bcb);
                    break;
                case colordodge:
                    if (bcb == 1)
                        cr = 1;
                    else
                        cr = MIN (bca / (1 - bcb), 1);
                    break;
                case colorburn:
                    if (bcb == 0)
                        cr = 0;
                    else
                        cr = MAX (1 - (1 - bca) / bcb, 0);
                    break;
                case overlay:
                    if (bca < 0.5)
                        cr = 2 * bca * bcb;
                    else
                        cr = 1 - 2 * (1 - bca) * (1 - bcb);
                    break;
                case exclusion:
                    cr = bca + bcb - 2 * bca * bcb;
                    break;
                case difference:
                    cr = abs (bca - bcb);
                    break;
                }
                cr *= 255.0;
                if (cr > 255)
                    cr = 255;
                if (cr < 0)
                    cr = 0;
                output_pixels[4 * x + y * rowstrideo + i] = (guchar) cr;

            }
            output_pixels[4 * x + y * rowstrideo + channelmap[3]] = qr * 255.0;
        }
}


rsvg_filter_primitive_merge_node_free (RsvgNode * self)
{
    RsvgFilterPrimitive *upself;
    upself = (RsvgFilterPrimitive *) self;
    g_string_free (upself->in, TRUE);
    _rsvg_node_free (self);
}


rsvg_characters_impl (RsvgHandle * ctx, const xmlChar * ch, int len)
{
    RsvgNodeChars *self;

    if (!ch || !len)
        return;

    if (ctx->priv->currentnode) {
        RsvgNodeType type = RSVG_NODE_TYPE (ctx->priv->currentnode);
        if (type == RSVG_NODE_TYPE_TSPAN ||
            type == RSVG_NODE_TYPE_TEXT) {
            guint i;

            /* find the last CHARS node in the text or tspan node, so that we
               can coalesce the text, and thus avoid screwing up the Pango layouts */
            self = NULL;
            for (i = 0; i < ctx->priv->currentnode->children->len; i++) {
                RsvgNode *node = g_ptr_array_index (ctx->priv->currentnode->children, i);
                if (RSVG_NODE_TYPE (node) == RSVG_NODE_TYPE_CHARS) {
                    self = (RsvgNodeChars*)node;
                }
            }

            if (self != NULL) {
                if (!g_utf8_validate ((char *) ch, len, NULL)) {
                    char *utf8;
                    utf8 = rsvg_make_valid_utf8 ((char *) ch, len);
                    g_string_append (self->contents, utf8);
                    g_free (utf8);
                } else {
                    g_string_append_len (self->contents, (char *)ch, len);
                }

                return;
            }
        }
    }

    self = rsvg_new_node_chars ((char *) ch, len);

    rsvg_defs_register_memory (ctx->priv->defs, (RsvgNode *) self);
    if (ctx->priv->currentnode)
        rsvg_node_group_pack (ctx->priv->currentnode, (RsvgNode *) self);
}


rsvg_filter_primitive_turbulence_render (RsvgFilterPrimitive * self, RsvgFilterContext * ctx)
{
    RsvgFilterPrimitiveTurbulence *upself;
    gint x, y, tileWidth, tileHeight, rowstride, width, height;
    RsvgIRect boundarys;
    guchar *output_pixels;
    GdkPixbuf *output;
    gdouble affine[6];
    GdkPixbuf *in;

    in = rsvg_filter_get_in (self->in, ctx);
    height = gdk_pixbuf_get_height (in);
    width = gdk_pixbuf_get_width (in);
    rowstride = gdk_pixbuf_get_rowstride (in);

    upself = (RsvgFilterPrimitiveTurbulence *) self;
    boundarys = rsvg_filter_primitive_get_bounds (self, ctx);

    tileWidth = (boundarys.x1 - boundarys.x0);
    tileHeight = (boundarys.y1 - boundarys.y0);

    output = _rsvg_pixbuf_new_cleared (GDK_COLORSPACE_RGB, 1, 8, width, height);
    output_pixels = gdk_pixbuf_get_pixels (output);

    _rsvg_affine_invert (affine, ctx->paffine);

    for (y = 0; y < tileHeight; y++) {
        for (x = 0; x < tileWidth; x++) {
            gint i;
            double point[2];
            guchar *pixel;
            point[0] = affine[0] * (x + boundarys.x0) + affine[2] * (y + boundarys.y0) + affine[4];
            point[1] = affine[1] * (x + boundarys.x0) + affine[3] * (y + boundarys.y0) + affine[5];

            pixel = output_pixels + 4 * (x + boundarys.x0) + (y + boundarys.y0) * rowstride;

            for (i = 0; i < 4; i++) {
                double cr;

                cr = feTurbulence_turbulence (upself, i, point, (double) x, (double) y,
                                              (double) tileWidth, (double) tileHeight);

                if (upself->bFractalSum)
                    cr = ((cr * 255.) + 255.) / 2.;
                else
                    cr = (cr * 255.);

                cr = CLAMP (cr, 0., 255.);

                pixel[ctx->channelmap[i]] = (guchar) cr;
            }
            for (i = 0; i < 3; i++)
                pixel[ctx->channelmap[i]] =
                    pixel[ctx->channelmap[i]] * pixel[ctx->channelmap[3]] / 255;

        }
    }

    rsvg_filter_store_result (self->result, output, ctx);

    g_object_unref (in);
    g_object_unref (output);
}


rsvg_get_file_path (const gchar * filename, const gchar * base_uri)
{
    gchar *absolute_filename;

    if (g_file_test (filename, G_FILE_TEST_EXISTS) || g_path_is_absolute (filename)) {
        absolute_filename = g_strdup (filename);
    } else {
        gchar *tmpcdir;
        gchar *base_filename;

        if (base_uri) {
            base_filename = g_filename_from_uri (base_uri, NULL, NULL);
            if (base_filename != NULL) {
                tmpcdir = g_path_get_dirname (base_filename);
                g_free (base_filename);
            } else
                return NULL;
        } else
            tmpcdir = g_get_current_dir ();

        absolute_filename = g_build_filename (tmpcdir, filename, NULL);
        g_free (tmpcdir);
    }

    return absolute_filename;
}


rsvg_handle_close_impl (RsvgHandle * handle, GError ** error)
{
    GError *real_error = NULL;

	handle->priv->is_closed = TRUE;

    handle->priv->error = &real_error;

    if (handle->priv->ctxt != NULL) {
        xmlDocPtr xmlDoc;
        int result;

        xmlDoc = handle->priv->ctxt->myDoc;

        result = xmlParseChunk (handle->priv->ctxt, "", 0, TRUE);
        if (result != 0) {
            rsvg_set_error (error, handle->priv->ctxt);
            xmlFreeParserCtxt (handle->priv->ctxt);
            xmlFreeDoc (xmlDoc);
            return FALSE;
        }

        xmlFreeParserCtxt (handle->priv->ctxt);
        xmlFreeDoc (xmlDoc);
    }

    rsvg_defs_resolve_all (handle->priv->defs);
    handle->priv->finished = TRUE;
    handle->priv->error = NULL;

    if (real_error != NULL) {
        g_propagate_error (error, real_error);
        return FALSE;
    }

    return TRUE;
}


box_blur (GdkPixbuf * in, GdkPixbuf * output, guchar * intermediate, gint kw,
          gint kh, RsvgIRect boundarys, RsvgFilterPrimitiveOutput op)
{
    gint ch;
    gint x, y;
    gint rowstride, height, width;

    guchar *in_pixels;
    guchar *output_pixels;

    gint sum;

    height = gdk_pixbuf_get_height (in);
    width = gdk_pixbuf_get_width (in);

    in_pixels = gdk_pixbuf_get_pixels (in);
    output_pixels = gdk_pixbuf_get_pixels (output);

    rowstride = gdk_pixbuf_get_rowstride (in);

    if (kw > boundarys.x1 - boundarys.x0)
        kw = boundarys.x1 - boundarys.x0;

    if (kh > boundarys.y1 - boundarys.y0)
        kh = boundarys.y1 - boundarys.y0;

    if (kw >= 1) {
        for (ch = 0; ch < 4; ch++) {
            switch (ch) {
            case 0:
                if (!op.Rused)
                    continue;
            case 1:
                if (!op.Gused)
                    continue;
            case 2:
                if (!op.Bused)
                    continue;
            case 3:
                if (!op.Aused)
                    continue;
            }
            for (y = boundarys.y0; y < boundarys.y1; y++) {
                sum = 0;
                for (x = boundarys.x0; x < boundarys.x0 + kw; x++) {
                    sum += (intermediate[x % kw] = in_pixels[4 * x + y * rowstride + ch]);

                    if (x - kw / 2 >= 0 && x - kw / 2 < boundarys.x1)
                        output_pixels[4 * (x - kw / 2) + y * rowstride + ch] = sum / kw;
                }
                for (x = boundarys.x0 + kw; x < boundarys.x1; x++) {
                    sum -= intermediate[x % kw];
                    sum += (intermediate[x % kw] = in_pixels[4 * x + y * rowstride + ch]);
                    output_pixels[4 * (x - kw / 2) + y * rowstride + ch] = sum / kw;
                }
                for (x = boundarys.x1; x < boundarys.x1 + kw; x++) {
                    sum -= intermediate[x % kw];

                    if (x - kw / 2 >= 0 && x - kw / 2 < boundarys.x1)
                        output_pixels[4 * (x - kw / 2) + y * rowstride + ch] = sum / kw;
                }
            }
        }
        in_pixels = output_pixels;
    }

    if (kh >= 1) {
        for (ch = 0; ch < 4; ch++) {
            switch (ch) {
            case 0:
                if (!op.Rused)
                    continue;
            case 1:
                if (!op.Gused)
                    continue;
            case 2:
                if (!op.Bused)
                    continue;
            case 3:
                if (!op.Aused)
                    continue;
            }

            for (x = boundarys.x0; x < boundarys.x1; x++) {
                sum = 0;

                for (y = boundarys.y0; y < boundarys.y0 + kh; y++) {
                    sum += (intermediate[y % kh] = in_pixels[4 * x + y * rowstride + ch]);

                    if (y - kh / 2 >= 0 && y - kh / 2 < boundarys.y1)
                        output_pixels[4 * x + (y - kh / 2) * rowstride + ch] = sum / kh;
                }
                for (; y < boundarys.y1; y++) {
                    sum -= intermediate[y % kh];
                    sum += (intermediate[y % kh] = in_pixels[4 * x + y * rowstride + ch]);
                    output_pixels[4 * x + (y - kh / 2) * rowstride + ch] = sum / kh;
                }
                for (; y < boundarys.y1 + kh; y++) {
                    sum -= intermediate[y % kh];

                    if (y - kh / 2 >= 0 && y - kh / 2 < boundarys.y1)
                        output_pixels[4 * x + (y - kh / 2) * rowstride + ch] = sum / kh;
                }
            }
        }
    }
}


rsvg_pattern_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    RsvgPattern *pattern = (RsvgPattern *) self;
    const char *value;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "id")))
            rsvg_defs_register_name (ctx->priv->defs, value, self);
        if ((value = rsvg_property_bag_lookup (atts, "viewBox"))) {
            pattern->vbox = rsvg_css_parse_vbox (value);
            pattern->hasvbox = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "x"))) {
            pattern->x = _rsvg_css_parse_length (value);
            pattern->hasx = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "y"))) {
            pattern->y = _rsvg_css_parse_length (value);
            pattern->hasy = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "width"))) {
            pattern->width = _rsvg_css_parse_length (value);
            pattern->haswidth = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "height"))) {
            pattern->height = _rsvg_css_parse_length (value);
            pattern->hasheight = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "xlink:href"))) {
            if (self != rsvg_defs_lookup (ctx->priv->defs, value)) {
                /* The (void *) cast is to avoid a GCC warning like:
                 * "warning: dereferencing type-punned pointer will break strict-aliasing rules"
                 * which is wrong for this code. (void *) introduces a compatible
                 * intermediate type in the cast list. */
                rsvg_defs_add_resolver (ctx->priv->defs, (RsvgNode **) (void *) &pattern->fallback,
                                        value);
            }
        }
        if ((value = rsvg_property_bag_lookup (atts, "patternTransform"))) {
            rsvg_parse_transform (pattern->affine, value);
            pattern->hastransform = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "patternUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                pattern->obj_bbox = FALSE;
            else if (!strcmp (value, "objectBoundingBox"))
                pattern->obj_bbox = TRUE;
            pattern->hasbbox = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "patternContentUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                pattern->obj_cbbox = FALSE;
            else if (!strcmp (value, "objectBoundingBox"))
                pattern->obj_cbbox = TRUE;
            pattern->hascbox = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "preserveAspectRatio"))) {
            pattern->preserve_aspect_ratio = rsvg_css_parse_aspect_ratio (value);
            pattern->hasaspect = TRUE;
        }
    }
}


rsvg_filter_primitive_blend_free (RsvgNode * self)
{
    RsvgFilterPrimitiveBlend *upself;
    upself = (RsvgFilterPrimitiveBlend *) self;
    g_string_free (upself->super.result, TRUE);
    g_string_free (upself->super.in, TRUE);
    g_string_free (upself->in2, TRUE);
    _rsvg_node_free (self);
}


rsvg_get_url_string (const char *str)
{
    if (!strncmp (str, "url(", 4)) {
        const char *p = str + 4;
        int ix;

        while (g_ascii_isspace (*p))
            p++;

        for (ix = 0; p[ix]; ix++)
            if (p[ix] == ')')
                return g_strndup (p, ix);
    }
    return NULL;
}


rsvg_acquire_file_resource (const char *filename, const char *base_uri, GError ** error)
{
    GByteArray *array;
    gchar *path;
    gchar *data = NULL;
    gsize length;

    rsvg_return_val_if_fail (filename != NULL, NULL, error);

    path = rsvg_get_file_path (filename, base_uri);
    if (path == NULL)
        return NULL;

    if (!g_file_get_contents (path, &data, &length, error)) {
        g_free (path);
        return NULL;
    }

    array = g_byte_array_new ();

    g_byte_array_append (array, (guint8 *)data, length);
    g_free (data);
    g_free (path);

    return array;
}


rsvg_filter_primitive_diffuse_lighting_render (RsvgFilterPrimitive * self, RsvgFilterContext * ctx)
{
    gint x, y;
    float dy, dx, rawdy, rawdx;
    gdouble z;
    gint rowstride, height, width;
    gdouble factor, surfaceScale;
    vector3 lightcolour, L, N;
    vector3 colour;
    gdouble iaffine[6];
    RsvgNodeLightSource *source = NULL;
    RsvgIRect boundarys;

    guchar *in_pixels;
    guchar *output_pixels;

    RsvgFilterPrimitiveDiffuseLighting *upself;

    GdkPixbuf *output;
    GdkPixbuf *in;
    unsigned int i;

    for (i = 0; i < self->super.children->len; i++) {
        RsvgNode *temp;

        temp = g_ptr_array_index (self->super.children, i);
        if (RSVG_NODE_TYPE (temp) == RSVG_NODE_TYPE_LIGHT_SOURCE) {
            source = (RsvgNodeLightSource *) temp;
        }
    }
    if (source == NULL)
        return;

    upself = (RsvgFilterPrimitiveDiffuseLighting *) self;
    boundarys = rsvg_filter_primitive_get_bounds (self, ctx);

    in = rsvg_filter_get_in (self->in, ctx);
    in_pixels = gdk_pixbuf_get_pixels (in);

    height = gdk_pixbuf_get_height (in);
    width = gdk_pixbuf_get_width (in);

    rowstride = gdk_pixbuf_get_rowstride (in);

    output = _rsvg_pixbuf_new_cleared (GDK_COLORSPACE_RGB, 1, 8, width, height);

    output_pixels = gdk_pixbuf_get_pixels (output);

    colour.x = ((guchar *) (&upself->lightingcolour))[2] / 255.0;
    colour.y = ((guchar *) (&upself->lightingcolour))[1] / 255.0;
    colour.z = ((guchar *) (&upself->lightingcolour))[0] / 255.0;

    surfaceScale = upself->surfaceScale / 255.0;

    if (upself->dy < 0 || upself->dx < 0) {
        dx = 1;
        dy = 1;
        rawdx = 1;
        rawdy = 1;
    } else {
        dx = upself->dx * ctx->paffine[0];
        dy = upself->dy * ctx->paffine[3];
        rawdx = upself->dx;
        rawdy = upself->dy;
    }

    _rsvg_affine_invert (iaffine, ctx->paffine);

    for (y = boundarys.y0; y < boundarys.y1; y++)
        for (x = boundarys.x0; x < boundarys.x1; x++) {
            z = surfaceScale * (double) in_pixels[y * rowstride + x * 4 + ctx->channelmap[3]];
            L = get_light_direction (source, x, y, z, iaffine, ctx->ctx);
            N = get_surface_normal (in_pixels, boundarys, x, y,
                                    dx, dy, rawdx, rawdy, upself->surfaceScale,
                                    rowstride, ctx->channelmap[3]);
            lightcolour = get_light_colour (source, colour, x, y, z, iaffine, ctx->ctx);
            factor = dotproduct (N, L);

            output_pixels[y * rowstride + x * 4 + ctx->channelmap[0]] =
                MAX (0, MIN (255, upself->diffuseConstant * factor * lightcolour.x * 255.0));
            output_pixels[y * rowstride + x * 4 + ctx->channelmap[1]] =
                MAX (0, MIN (255, upself->diffuseConstant * factor * lightcolour.y * 255.0));
            output_pixels[y * rowstride + x * 4 + ctx->channelmap[2]] =
                MAX (0, MIN (255, upself->diffuseConstant * factor * lightcolour.z * 255.0));
            output_pixels[y * rowstride + x * 4 + ctx->channelmap[3]] = 255;
        }

    rsvg_filter_store_result (self->result, output, ctx);

    g_object_unref (in);
    g_object_unref (output);
}