xref: /third_party/alsa-lib/src/topology/decoder.c (revision d5ac70f0)
1d5ac70f0Sopenharmony_ci/*
2d5ac70f0Sopenharmony_ci  Copyright (c) 2019 Red Hat Inc.
3d5ac70f0Sopenharmony_ci  All rights reserved.
4d5ac70f0Sopenharmony_ci
5d5ac70f0Sopenharmony_ci  This library is free software; you can redistribute it and/or modify
6d5ac70f0Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
7d5ac70f0Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of
8d5ac70f0Sopenharmony_ci  the License, or (at your option) any later version.
9d5ac70f0Sopenharmony_ci
10d5ac70f0Sopenharmony_ci  This program is distributed in the hope that it will be useful,
11d5ac70f0Sopenharmony_ci  but WITHOUT ANY WARRANTY; without even the implied warranty of
12d5ac70f0Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13d5ac70f0Sopenharmony_ci  GNU Lesser General Public License for more details.
14d5ac70f0Sopenharmony_ci
15d5ac70f0Sopenharmony_ci  Authors: Jaroslav Kysela <perex@perex.cz>
16d5ac70f0Sopenharmony_ci*/
17d5ac70f0Sopenharmony_ci
18d5ac70f0Sopenharmony_ci#include "tplg_local.h"
19d5ac70f0Sopenharmony_ci
20d5ac70f0Sopenharmony_ciint tplg_decode_template(snd_tplg_t *tplg,
21d5ac70f0Sopenharmony_ci			 size_t pos,
22d5ac70f0Sopenharmony_ci			 struct snd_soc_tplg_hdr *hdr,
23d5ac70f0Sopenharmony_ci			 snd_tplg_obj_template_t *t)
24d5ac70f0Sopenharmony_ci{
25d5ac70f0Sopenharmony_ci	int type;
26d5ac70f0Sopenharmony_ci
27d5ac70f0Sopenharmony_ci	type = tplg_get_type(hdr->type);
28d5ac70f0Sopenharmony_ci	tplg_log(tplg, 'D', pos, "template: asoc type %d library type %d",
29d5ac70f0Sopenharmony_ci		 hdr->type, type);
30d5ac70f0Sopenharmony_ci	if (type < 0)
31d5ac70f0Sopenharmony_ci		return type;
32d5ac70f0Sopenharmony_ci
33d5ac70f0Sopenharmony_ci	memset(t, 0, sizeof(*t));
34d5ac70f0Sopenharmony_ci	t->type = type;
35d5ac70f0Sopenharmony_ci	t->index = hdr->index;
36d5ac70f0Sopenharmony_ci	t->version = hdr->version;
37d5ac70f0Sopenharmony_ci	t->vendor_type = hdr->vendor_type;
38d5ac70f0Sopenharmony_ci	tplg_log(tplg, 'D', pos, "template: index %d version %d vendor_type %d",
39d5ac70f0Sopenharmony_ci		 hdr->index, hdr->version, hdr->vendor_type);
40d5ac70f0Sopenharmony_ci	return 0;
41d5ac70f0Sopenharmony_ci}
42d5ac70f0Sopenharmony_ci
43d5ac70f0Sopenharmony_ciint snd_tplg_decode(snd_tplg_t *tplg, void *bin, size_t size, int dflags)
44d5ac70f0Sopenharmony_ci{
45d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_hdr *hdr;
46d5ac70f0Sopenharmony_ci	struct tplg_table *tptr;
47d5ac70f0Sopenharmony_ci	size_t pos;
48d5ac70f0Sopenharmony_ci	void *b = bin;
49d5ac70f0Sopenharmony_ci	unsigned int index;
50d5ac70f0Sopenharmony_ci	int err;
51d5ac70f0Sopenharmony_ci
52d5ac70f0Sopenharmony_ci	if (dflags != 0)
53d5ac70f0Sopenharmony_ci		return -EINVAL;
54d5ac70f0Sopenharmony_ci	if (tplg == NULL || bin == NULL)
55d5ac70f0Sopenharmony_ci		return -EINVAL;
56d5ac70f0Sopenharmony_ci	while (1) {
57d5ac70f0Sopenharmony_ci		pos = b - bin;
58d5ac70f0Sopenharmony_ci		if (size == pos) {
59d5ac70f0Sopenharmony_ci			tplg_log(tplg, 'D', pos, "block: success (total %zd)", size);
60d5ac70f0Sopenharmony_ci			return 0;
61d5ac70f0Sopenharmony_ci		}
62d5ac70f0Sopenharmony_ci		if (size - pos < sizeof(*hdr)) {
63d5ac70f0Sopenharmony_ci			tplg_log(tplg, 'D', pos, "block: small size");
64d5ac70f0Sopenharmony_ci			SNDERR("incomplete header data to decode");
65d5ac70f0Sopenharmony_ci			return -EINVAL;
66d5ac70f0Sopenharmony_ci		}
67d5ac70f0Sopenharmony_ci		hdr = b;
68d5ac70f0Sopenharmony_ci		if (hdr->magic != SND_SOC_TPLG_MAGIC) {
69d5ac70f0Sopenharmony_ci			SNDERR("bad block magic %08x", hdr->magic);
70d5ac70f0Sopenharmony_ci			return -EINVAL;
71d5ac70f0Sopenharmony_ci		}
72d5ac70f0Sopenharmony_ci
73d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'D', pos, "block: abi %d size %d payload size %d",
74d5ac70f0Sopenharmony_ci			 hdr->abi, hdr->size, hdr->payload_size);
75d5ac70f0Sopenharmony_ci		if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) {
76d5ac70f0Sopenharmony_ci			SNDERR("unsupported ABI version %d", hdr->abi);
77d5ac70f0Sopenharmony_ci			return -EINVAL;
78d5ac70f0Sopenharmony_ci		}
79d5ac70f0Sopenharmony_ci		if (hdr->size != sizeof(*hdr)) {
80d5ac70f0Sopenharmony_ci			SNDERR("header size mismatch");
81d5ac70f0Sopenharmony_ci			return -EINVAL;
82d5ac70f0Sopenharmony_ci		}
83d5ac70f0Sopenharmony_ci
84d5ac70f0Sopenharmony_ci		if (size - pos < hdr->size + hdr->payload_size) {
85d5ac70f0Sopenharmony_ci			SNDERR("incomplete payload data to decode");
86d5ac70f0Sopenharmony_ci			return -EINVAL;
87d5ac70f0Sopenharmony_ci		}
88d5ac70f0Sopenharmony_ci
89d5ac70f0Sopenharmony_ci		if (hdr->payload_size < 8) {
90d5ac70f0Sopenharmony_ci			SNDERR("wrong payload size %d", hdr->payload_size);
91d5ac70f0Sopenharmony_ci			return -EINVAL;
92d5ac70f0Sopenharmony_ci		}
93d5ac70f0Sopenharmony_ci
94d5ac70f0Sopenharmony_ci		/* first block must be manifest */
95d5ac70f0Sopenharmony_ci		if (b == bin) {
96d5ac70f0Sopenharmony_ci			if (hdr->type != SND_SOC_TPLG_TYPE_MANIFEST) {
97d5ac70f0Sopenharmony_ci				SNDERR("first block must be manifest (value %d)", hdr->type);
98d5ac70f0Sopenharmony_ci				return -EINVAL;
99d5ac70f0Sopenharmony_ci			}
100d5ac70f0Sopenharmony_ci			err = snd_tplg_set_version(tplg, hdr->version);
101d5ac70f0Sopenharmony_ci			if (err < 0)
102d5ac70f0Sopenharmony_ci				return err;
103d5ac70f0Sopenharmony_ci		}
104d5ac70f0Sopenharmony_ci
105d5ac70f0Sopenharmony_ci		pos += hdr->size;
106d5ac70f0Sopenharmony_ci		for (index = 0; index < tplg_table_items; index++) {
107d5ac70f0Sopenharmony_ci			tptr = &tplg_table[index];
108d5ac70f0Sopenharmony_ci			if (tptr->tsoc == (int)hdr->type)
109d5ac70f0Sopenharmony_ci				break;
110d5ac70f0Sopenharmony_ci		}
111d5ac70f0Sopenharmony_ci		if (index >= tplg_table_items || tptr->decod == NULL) {
112d5ac70f0Sopenharmony_ci			SNDERR("unknown block type %d", hdr->type);
113d5ac70f0Sopenharmony_ci			return -EINVAL;
114d5ac70f0Sopenharmony_ci		}
115d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'D', pos, "block: type %d - %s", hdr->type, tptr->name);
116d5ac70f0Sopenharmony_ci		err = tptr->decod(tplg, pos, hdr, b + hdr->size, hdr->payload_size);
117d5ac70f0Sopenharmony_ci		if (err < 0)
118d5ac70f0Sopenharmony_ci			return err;
119d5ac70f0Sopenharmony_ci		b += hdr->size + hdr->payload_size;
120d5ac70f0Sopenharmony_ci	}
121d5ac70f0Sopenharmony_ci}
122