Blame src/topology/decoder.c

Packit Service f36a15
/*
Packit Service f36a15
  Copyright (c) 2019 Red Hat Inc.
Packit Service f36a15
  All rights reserved.
Packit Service f36a15
Packit Service f36a15
  This library is free software; you can redistribute it and/or modify
Packit Service f36a15
  it under the terms of the GNU Lesser General Public License as
Packit Service f36a15
  published by the Free Software Foundation; either version 2.1 of
Packit Service f36a15
  the License, or (at your option) any later version.
Packit Service f36a15
Packit Service f36a15
  This program is distributed in the hope that it will be useful,
Packit Service f36a15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f36a15
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f36a15
  GNU Lesser General Public License for more details.
Packit Service f36a15
Packit Service f36a15
  Authors: Jaroslav Kysela <perex@perex.cz>
Packit Service f36a15
*/
Packit Service f36a15
Packit Service f36a15
#include "list.h"
Packit Service f36a15
#include "tplg_local.h"
Packit Service f36a15
Packit Service f36a15
int tplg_decode_template(snd_tplg_t *tplg,
Packit Service f36a15
			 size_t pos,
Packit Service f36a15
			 struct snd_soc_tplg_hdr *hdr,
Packit Service f36a15
			 snd_tplg_obj_template_t *t)
Packit Service f36a15
{
Packit Service f36a15
	int type;
Packit Service f36a15
Packit Service f36a15
	type = tplg_get_type(hdr->type);
Packit Service f36a15
	tplg_log(tplg, 'D', pos, "template: asoc type %d library type %d",
Packit Service f36a15
		 hdr->type, type);
Packit Service f36a15
	if (type < 0)
Packit Service f36a15
		return type;
Packit Service f36a15
Packit Service f36a15
	memset(t, 0, sizeof(*t));
Packit Service f36a15
	t->type = type;
Packit Service f36a15
	t->index = hdr->index;
Packit Service f36a15
	t->version = hdr->version;
Packit Service f36a15
	t->vendor_type = hdr->vendor_type;
Packit Service f36a15
	tplg_log(tplg, 'D', pos, "template: index %d version %d vendor_type %d",
Packit Service f36a15
		 hdr->index, hdr->version, hdr->vendor_type);
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
int snd_tplg_decode(snd_tplg_t *tplg, void *bin, size_t size, int dflags)
Packit Service f36a15
{
Packit Service f36a15
	struct snd_soc_tplg_hdr *hdr;
Packit Service f36a15
	struct tplg_table *tptr;
Packit Service f36a15
	size_t pos;
Packit Service f36a15
	void *b = bin;
Packit Service f36a15
	unsigned int index;
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	if (dflags != 0)
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	if (tplg == NULL || bin == NULL)
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	while (1) {
Packit Service f36a15
		pos = b - bin;
Packit Service f36a15
		if (size == pos) {
Packit Service f36a15
			tplg_log(tplg, 'D', pos, "block: success (total %zd)", size);
Packit Service f36a15
			return 0;
Packit Service f36a15
		}
Packit Service f36a15
		if (size - pos < sizeof(*hdr)) {
Packit Service f36a15
			tplg_log(tplg, 'D', pos, "block: small size");
Packit Service f36a15
			SNDERR("incomplete header data to decode");
Packit Service f36a15
			return -EINVAL;
Packit Service f36a15
		}
Packit Service f36a15
		hdr = b;
Packit Service f36a15
		if (hdr->magic != SND_SOC_TPLG_MAGIC) {
Packit Service f36a15
			SNDERR("bad block magic %08x", hdr->magic);
Packit Service f36a15
			return -EINVAL;
Packit Service f36a15
		}
Packit Service f36a15
Packit Service f36a15
		tplg_log(tplg, 'D', pos, "block: abi %d size %d payload size %d",
Packit Service f36a15
			 hdr->abi, hdr->size, hdr->payload_size);
Packit Service f36a15
		if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) {
Packit Service f36a15
			SNDERR("unsupported ABI version %d", hdr->abi);
Packit Service f36a15
			return -EINVAL;
Packit Service f36a15
		}
Packit Service f36a15
		if (hdr->size != sizeof(*hdr)) {
Packit Service f36a15
			SNDERR("header size mismatch");
Packit Service f36a15
			return -EINVAL;
Packit Service f36a15
		}
Packit Service f36a15
Packit Service f36a15
		if (size - pos < hdr->size + hdr->payload_size) {
Packit Service f36a15
			SNDERR("incomplete payload data to decode");
Packit Service f36a15
			return -EINVAL;
Packit Service f36a15
		}
Packit Service f36a15
Packit Service f36a15
		if (hdr->payload_size < 8) {
Packit Service f36a15
			SNDERR("wrong payload size %d", hdr->payload_size);
Packit Service f36a15
			return -EINVAL;
Packit Service f36a15
		}
Packit Service f36a15
Packit Service f36a15
		/* first block must be manifest */
Packit Service f36a15
		if (b == bin) {
Packit Service f36a15
			if (hdr->type != SND_SOC_TPLG_TYPE_MANIFEST) {
Packit Service f36a15
				SNDERR("first block must be manifest (value %d)", hdr->type);
Packit Service f36a15
				return -EINVAL;
Packit Service f36a15
			}
Packit Service f36a15
			err = snd_tplg_set_version(tplg, hdr->version);
Packit Service f36a15
			if (err < 0)
Packit Service f36a15
				return err;
Packit Service f36a15
		}
Packit Service f36a15
Packit Service f36a15
		pos += hdr->size;
Packit Service f36a15
		for (index = 0; index < tplg_table_items; index++) {
Packit Service f36a15
			tptr = &tplg_table[index];
Packit Service f36a15
			if (tptr->tsoc == (int)hdr->type)
Packit Service f36a15
				break;
Packit Service f36a15
		}
Packit Service f36a15
		if (index >= tplg_table_items || tptr->decod == NULL) {
Packit Service f36a15
			SNDERR("unknown block type %d", hdr->type);
Packit Service f36a15
			return -EINVAL;
Packit Service f36a15
		}
Packit Service f36a15
		tplg_log(tplg, 'D', pos, "block: type %d - %s", hdr->type, tptr->name);
Packit Service f36a15
		err = tptr->decod(tplg, pos, hdr, b + hdr->size, hdr->payload_size);
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
		b += hdr->size + hdr->payload_size;
Packit Service f36a15
	}
Packit Service f36a15
}