/* SPDX-License-Identifier: GPL-2.0 */ /** \file wma_common.c Functions used by both the WMA afh and decoder. */ #include #include "para.h" #include "error.h" #include "afh.h" #include "portable_io.h" #include "imdct.h" #include "wma.h" /** * Find the first occurrence of the given pattern. * * \param pattern The pattern to search for. * \param pattern_len The length of the pattern in bytes. * \param buf The buffer to search for the pattern. * \param buf_size The number of bytes in \a buf. * * \return A pointer into \a buf or \p NULL if the pattern was not found. */ const char *search_pattern(const uint8_t *pattern, int pattern_len, const char *buf, int buf_size) { const char *p, *end = buf + buf_size; /* TODO: Use suffix arrays to speed up the search. */ for (p = buf; p + pattern_len < end; p++) { if (memcmp(p, pattern, pattern_len)) continue; PARA_DEBUG_LOG("found %d byte pattern@%d\n", pattern_len, (int)(p - buf)); return p; } PARA_NOTICE_LOG("%d byte pattern not found\n", pattern_len); return NULL; } static int find_file_properties(const char *buf, int len) { const uint8_t pattern[] = {0xa1, 0xdc, 0xab, 0x8c}; const char *p = search_pattern(pattern, sizeof(pattern), buf, len); if (!p) return -E_WMA_NO_GUID; PARA_DEBUG_LOG("found file property guid@%0x\n", (unsigned)(p - buf)); return p - buf + 16; } /* 40 9e 69 f8 4d 5b cf 11 a8 fd 00 80 5f 5c 44 2b */ static int find_audio_stream_info(const char *buf, int len) { const uint8_t pattern[] = {0x40, 0x9e, 0x69, 0xf8}; const char *p = search_pattern(pattern, sizeof(pattern), buf, len); if (!p) return -E_WMA_NO_GUID; PARA_DEBUG_LOG("found audio stream guid@%0x\n", (unsigned)(p - buf)); return p - buf + 16; } static int read_header_len(const char *buf, int len) { uint16_t header_len; if (len < 18) return 0; header_len = read_u16(buf + 16) + 46; PARA_DEBUG_LOG("header_len: %d\n", header_len); return header_len; } /** * Read an asf audio file header. * * \param buf The input buffer. * \param loaded Number of bytes in \a buf. * \param ahi Result pointer. * * \return Negative on errors, zero if more data is needed in order to read the * full header, 1 on success. */ int read_asf_header(const char *buf, int loaded, struct asf_header_info *ahi) { int ret; const char *start; ahi->header_len = read_header_len(buf, loaded); if (ahi->header_len == 0) /* too short to read header len */ return 0; if (ahi->header_len > loaded) /* too short to read header */ return 0; ret = find_audio_stream_info(buf, ahi->header_len); if (ret < 0) return ret; if (ret + 62 > loaded) return 0; ahi->audio_stream_info_start = ret; start = buf + ahi->audio_stream_info_start; ahi->channels = ((uint8_t *)start)[40]; ahi->sample_rate = read_u16(start + 42); PARA_NOTICE_LOG("%d channels, sample rate: %d\n", ahi->channels, ahi->sample_rate); ahi->bit_rate = 8 * read_u16(start + 46); PARA_INFO_LOG("bit rate: %u\n", ahi->bit_rate); ahi->block_align = read_u16(start + 50); PARA_INFO_LOG("block_align: %d\n", ahi->block_align); ahi->flags1 = read_u32(start + 56); ahi->flags2 = read_u16(start + 60); PARA_INFO_LOG("read_asf_header: flags1: %u, flags2: %u\n", ahi->flags1, ahi->flags2); ahi->use_exp_vlc = ahi->flags2 & 0x0001; ahi->use_bit_reservoir = ahi->flags2 & 0x0002; ahi->use_variable_block_len = ahi->flags2 & 0x0004; ret = find_file_properties(buf, ahi->header_len); if (ret < 0) return ret; /* file property header is always 88 bytes (sans GUID) */ if (ret + 88 > loaded) return 0; start = buf + ret; ahi->packet_size = read_u32(start + 76); /* min packet size */ /* we only support fixed packet sizes */ if (ahi->packet_size != read_u32(start + 80)) /* min != max */ return -E_BAD_ASF_FILE_PROPS; if (ahi->packet_size <= ahi->block_align) return -E_BAD_ASF_FILE_PROPS; PARA_INFO_LOG("packet size: %u\n", ahi->packet_size); return 1; } static const uint8_t log2_tab[256] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; /** * Compute the base-2 logarithm. * * \param v The value to compute the logarithm of. * * \return An integer approximation of log2(v). */ __a_const int wma_log2(unsigned int v) { int n = 0; if (v & 0xffff0000) { v >>= 16; n += 16; } if (v & 0xff00) { v >>= 8; n += 8; } return n + log2_tab[v]; }