aboutsummaryrefslogblamecommitdiffstats
path: root/libfonts_create_transcoding_table.c
blob: ee75bf46a24fee133c4a3d80a571176d84d91d63 (plain) (tree)



























































































































                                                                                                                      
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifndef TEST


static int
set_range(uint32_t low, uint32_t high, uint32_t target, uint32_t target_inc, struct libfonts_transcoding_table *table)
{
	uint32_t i;

	if (low < table->first_valid) {
		if (target != LIBFONTS_UNDEFINED_CHAR)
			return -1;
		low = table->first_valid;
	}

	if (high > table->last_valid) {
		if (target != LIBFONTS_UNDEFINED_CHAR)
			return -1;
		high = table->last_valid;
	}

	i = low;
	do {
		LIBFONTS_LOOKUP_TRANSCODING_TABLE(table, i) = target;
		target += target_inc;
	} while (i++ < high);

	return 0;
}

struct libfonts_transcoding_table *
libfonts_create_transcoding_table(const struct libfonts_encoding *encoding, size_t mapping)
{
	const struct libfonts_encoding_mapping *map;
	size_t size, entry;
	uint16_t size_rows, size_cols;
	uint8_t first_row, first_col;
	struct libfonts_transcoding_table *ret;
	uint32_t i;
	int r;

	if (!encoding ||
	    mapping > encoding->nmappings ||
	    !encoding->mappings ||
	    (encoding->mappings[mapping].nentries && !encoding->mappings[mapping].entries) ||
	    !encoding->size_rows)
		goto einvalid;

	map = &encoding->mappings[mapping];
	size_rows = encoding->size_rows;
	size_cols = encoding->size_cols;
	first_row = encoding->first_index_row;
	first_col = encoding->first_index_col;

#if SIZE_MAX <= UINT32_MAX
	if ((size_t)size_rows - (size_t)first_row > SIZE_MAX / (size_cols ? (size_t)size_cols : 1))
		goto enomem;
#endif
	size = ((size_t)size_rows - (size_t)first_row) * (size_cols ? (size_t)size_cols : 1);
	if (size > (SIZE_MAX - offsetof(struct libfonts_transcoding_table, table)) / sizeof(uint32_t))
		goto enomem;
	ret = malloc(size * sizeof(uint32_t) + offsetof(struct libfonts_transcoding_table, table));
	if (!ret)
		goto enomem;

	ret->first_valid = (uint32_t)first_row;
	ret->last_valid = (uint32_t)size_rows - 1;
	if (size_cols) {
		ret->first_valid <<= 8;
		ret->first_valid |= (uint32_t)first_col;
		ret->last_valid <<= 8;
		ret->last_valid |= (uint32_t)size_cols - 1;
	}

	ret->offset = encoding->size_cols ? (uint32_t)first_row << 8 : (uint32_t)first_col;
	ret->multiplier = (uint32_t)size_cols;

	for (i = ret->first_valid; i <= ret->last_valid; i++)
		LIBFONTS_LOOKUP_TRANSCODING_TABLE(ret, i) = i;

	for (entry = 0; entry < map->nentries; entry++) {
		if (map->entries[entry].type == LIBFONTS_ENCODING_MAPPING_ENTRY_UNDEFINED_RANGE) {
			set_range(map->entries[entry].undefined_range.low_source,
			          map->entries[entry].undefined_range.high_source,
			          LIBFONTS_UNDEFINED_CHAR, 0, ret);

		} else if (map->entries[entry].type == LIBFONTS_ENCODING_MAPPING_ENTRY_REMAPPED_RANGE) {
			r = set_range(map->entries[entry].remapped_range.low_source,
			              map->entries[entry].remapped_range.high_source,
			              map->entries[entry].remapped_range.low_target, 0, ret);
			if (r)
				goto invalid;

		} else {
			goto invalid;
		}
	}

	return ret;

enomem:
	errno = ENOMEM;
	return NULL;

invalid:
	free(ret);
einvalid:
	errno = EINVAL;
	return NULL;
}


#else


int
main(void)
{
	return 0; /* XXX add test */
}


#endif