pcm/AudioParser: use std::string_view
This commit is contained in:
src
@ -9,159 +9,117 @@
|
|||||||
#include "AudioParser.hxx"
|
#include "AudioParser.hxx"
|
||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
#include "lib/fmt/RuntimeError.hxx"
|
#include "lib/fmt/RuntimeError.hxx"
|
||||||
|
#include "util/NumberParser.hxx"
|
||||||
|
#include "util/StringCompare.hxx"
|
||||||
|
#include "util/StringSplit.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <string.h>
|
using std::string_view_literals::operator""sv;
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
ParseSampleRate(const char *src, bool mask, const char **endptr_r)
|
ParseSampleRate(std::string_view src, bool mask)
|
||||||
{
|
{
|
||||||
unsigned long value;
|
if (mask && src == "*"sv)
|
||||||
char *endptr;
|
|
||||||
|
|
||||||
if (mask && *src == '*') {
|
|
||||||
*endptr_r = src + 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
value = strtoul(src, &endptr, 10);
|
const auto value = ParseInteger<uint32_t>(src);
|
||||||
if (endptr == src) {
|
if (!value)
|
||||||
throw std::invalid_argument("Failed to parse the sample rate");
|
throw std::invalid_argument("Failed to parse the sample rate");
|
||||||
} else if (!audio_valid_sample_rate(value))
|
|
||||||
throw FmtInvalidArgument("Invalid sample rate: {}", value);
|
|
||||||
|
|
||||||
*endptr_r = endptr;
|
if (!audio_valid_sample_rate(*value))
|
||||||
return value;
|
throw FmtInvalidArgument("Invalid sample rate: {}", *value);
|
||||||
|
|
||||||
|
return *value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SampleFormat
|
static SampleFormat
|
||||||
ParseSampleFormat(const char *src, bool mask, const char **endptr_r)
|
ParseSampleFormat(std::string_view src, bool mask)
|
||||||
{
|
{
|
||||||
unsigned long value;
|
if (mask && src == "*"sv)
|
||||||
char *endptr;
|
|
||||||
SampleFormat sample_format;
|
|
||||||
|
|
||||||
if (mask && *src == '*') {
|
|
||||||
*endptr_r = src + 1;
|
|
||||||
return SampleFormat::UNDEFINED;
|
return SampleFormat::UNDEFINED;
|
||||||
}
|
else if (src == "f"sv)
|
||||||
|
|
||||||
if (*src == 'f') {
|
|
||||||
*endptr_r = src + 1;
|
|
||||||
return SampleFormat::FLOAT;
|
return SampleFormat::FLOAT;
|
||||||
}
|
else if (src == "dsd"sv)
|
||||||
|
|
||||||
if (memcmp(src, "dsd", 3) == 0) {
|
|
||||||
*endptr_r = src + 3;
|
|
||||||
return SampleFormat::DSD;
|
return SampleFormat::DSD;
|
||||||
}
|
else if (src == "8"sv)
|
||||||
|
return SampleFormat::S8;
|
||||||
value = strtoul(src, &endptr, 10);
|
else if (src == "16"sv)
|
||||||
if (endptr == src)
|
return SampleFormat::S16;
|
||||||
throw std::invalid_argument("Failed to parse the sample format");
|
else if (src == "24"sv)
|
||||||
|
return SampleFormat::S24_P32;
|
||||||
switch (value) {
|
else if (src == "24_3"sv)
|
||||||
case 8:
|
|
||||||
sample_format = SampleFormat::S8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 16:
|
|
||||||
sample_format = SampleFormat::S16;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 24:
|
|
||||||
if (memcmp(endptr, "_3", 2) == 0)
|
|
||||||
/* for backwards compatibility */
|
/* for backwards compatibility */
|
||||||
endptr += 2;
|
return SampleFormat::S24_P32;
|
||||||
|
else if (src == "32"sv)
|
||||||
sample_format = SampleFormat::S24_P32;
|
return SampleFormat::S32;
|
||||||
break;
|
else
|
||||||
|
throw FmtInvalidArgument("Invalid sample format: {:?}", src);
|
||||||
case 32:
|
|
||||||
sample_format = SampleFormat::S32;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw FmtInvalidArgument("Invalid sample format: {}", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(audio_valid_sample_format(sample_format));
|
|
||||||
|
|
||||||
*endptr_r = endptr;
|
|
||||||
return sample_format;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t
|
static uint8_t
|
||||||
ParseChannelCount(const char *src, bool mask, const char **endptr_r)
|
ParseChannelCount(std::string_view src, bool mask)
|
||||||
{
|
{
|
||||||
unsigned long value;
|
if (mask && src == "*"sv)
|
||||||
char *endptr;
|
|
||||||
|
|
||||||
if (mask && *src == '*') {
|
|
||||||
*endptr_r = src + 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
value = strtoul(src, &endptr, 10);
|
const auto value = ParseInteger<uint_least8_t>(src);
|
||||||
if (endptr == src)
|
if (!value)
|
||||||
throw std::invalid_argument("Failed to parse the channel count");
|
throw std::invalid_argument("Failed to parse the channel count");
|
||||||
else if (!audio_valid_channel_count(value))
|
else if (!audio_valid_channel_count(*value))
|
||||||
throw FmtInvalidArgument("Invalid channel count: {}", value);
|
throw FmtInvalidArgument("Invalid channel count: {}", *value);
|
||||||
|
|
||||||
*endptr_r = endptr;
|
return *value;
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioFormat
|
AudioFormat
|
||||||
ParseAudioFormat(const char *src, bool mask)
|
ParseAudioFormat(std::string_view src, bool mask)
|
||||||
{
|
{
|
||||||
AudioFormat dest;
|
AudioFormat dest;
|
||||||
dest.Clear();
|
dest.Clear();
|
||||||
|
|
||||||
if (strncmp(src, "dsd", 3) == 0) {
|
if (SkipPrefix(src, "dsd"sv)) {
|
||||||
/* allow format specifications such as "dsd64" which
|
/* allow format specifications such as "dsd64" which
|
||||||
implies the sample rate */
|
implies the sample rate */
|
||||||
|
|
||||||
char *endptr;
|
const auto [dsd_s, channels_s] = Split(src, ':');
|
||||||
auto dsd = strtoul(src + 3, &endptr, 10);
|
if (channels_s.data() == nullptr)
|
||||||
if (endptr > src + 3 && *endptr == ':' &&
|
throw std::invalid_argument("Channel count missing");
|
||||||
dsd >= 32 && dsd <= 4096 && dsd % 2 == 0) {
|
|
||||||
dest.sample_rate = dsd * 44100 / 8;
|
const auto dsd = ParseInteger<uint_least16_t>(dsd_s);
|
||||||
|
if (!dsd)
|
||||||
|
throw std::invalid_argument("Failed to parse the DSD rate");
|
||||||
|
|
||||||
|
if (*dsd < 32 || *dsd > 4096)
|
||||||
|
throw std::invalid_argument("Bad DSD rate");
|
||||||
|
|
||||||
|
dest.sample_rate = *dsd * 44100 / 8;
|
||||||
dest.format = SampleFormat::DSD;
|
dest.format = SampleFormat::DSD;
|
||||||
|
dest.channels = ParseChannelCount(channels_s, mask);
|
||||||
src = endptr + 1;
|
|
||||||
dest.channels = ParseChannelCount(src, mask, &src);
|
|
||||||
if (*src != 0)
|
|
||||||
throw FmtInvalidArgument("Extra data after channel count: {}",
|
|
||||||
src);
|
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* parse sample rate */
|
/* parse sample rate */
|
||||||
|
|
||||||
dest.sample_rate = ParseSampleRate(src, mask, &src);
|
const auto [sample_rate_s, rest1] = Split(src, ':');
|
||||||
|
|
||||||
if (*src++ != ':')
|
dest.sample_rate = ParseSampleRate(sample_rate_s, mask);
|
||||||
throw std::invalid_argument("Sample format missing");
|
|
||||||
|
|
||||||
/* parse sample format */
|
/* parse sample format */
|
||||||
|
|
||||||
dest.format = ParseSampleFormat(src, mask, &src);
|
if (rest1.data() == nullptr)
|
||||||
|
throw std::invalid_argument("Sample format missing");
|
||||||
|
|
||||||
if (*src++ != ':')
|
const auto [format_s, channels_s] = Split(rest1, ':');
|
||||||
throw std::invalid_argument("Channel count missing");
|
|
||||||
|
dest.format = ParseSampleFormat(format_s, mask);
|
||||||
|
|
||||||
/* parse channel count */
|
/* parse channel count */
|
||||||
|
|
||||||
dest.channels = ParseChannelCount(src, mask, &src);
|
if (channels_s.data() == nullptr)
|
||||||
|
throw std::invalid_argument("Channel count missing");
|
||||||
|
|
||||||
if (*src != 0)
|
dest.channels = ParseChannelCount(channels_s, mask);
|
||||||
throw FmtInvalidArgument("Extra data after channel count: {}",
|
|
||||||
src);
|
|
||||||
|
|
||||||
assert(mask
|
assert(mask
|
||||||
? dest.IsMaskValid()
|
? dest.IsMaskValid()
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
* Parser functions for audio related objects.
|
* Parser functions for audio related objects.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MPD_AUDIO_PARSER_HXX
|
#pragma once
|
||||||
#define MPD_AUDIO_PARSER_HXX
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
struct AudioFormat;
|
struct AudioFormat;
|
||||||
|
|
||||||
@ -21,6 +22,4 @@ struct AudioFormat;
|
|||||||
* @param mask if true, then "*" is allowed for any number of items
|
* @param mask if true, then "*" is allowed for any number of items
|
||||||
*/
|
*/
|
||||||
AudioFormat
|
AudioFormat
|
||||||
ParseAudioFormat(const char *src, bool mask);
|
ParseAudioFormat(std::string_view src, bool mask);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -395,8 +395,7 @@ SongFilter::ParseExpression(const char *&s, bool fold_case)
|
|||||||
|
|
||||||
s = StripLeft(s + 2);
|
s = StripLeft(s + 2);
|
||||||
|
|
||||||
const auto value = ParseAudioFormat(ExpectQuoted(s).c_str(),
|
const auto value = ParseAudioFormat(ExpectQuoted(s), mask);
|
||||||
mask);
|
|
||||||
|
|
||||||
if (*s != ')')
|
if (*s != ')')
|
||||||
throw std::runtime_error("')' expected");
|
throw std::runtime_error("')' expected");
|
||||||
|
Reference in New Issue
Block a user