Move TypeConverter into a shared library

This will be needed for the default implementation of the audio HAL
in TREBLE for parsing supported formats etc. provided by HAL in
a form of string literals.

As a bonus, remove some hand-written type conversions in AudioFlinger
used in dumps.

Example changes in the dump output:

   HAL format: 0x1 (pcm16) ==> HAL format: 0x1 (AUDIO_FORMAT_PCM_16_BIT)
   Processing format: 0x5 (pcmfloat) ==> Processing format: 0x5 (AUDIO_FORMAT_PCM_FLOAT)
   Output device: 0x2 (SPEAKER) ==> Output device: 0x2 (AUDIO_DEVICE_OUT_SPEAKER)
   Input device: 0 (NONE) ==> Input device: 0 (AUDIO_DEVICE_NONE)
   AudioStreamOut: 0x... flags 0x6 (PRIMARY|FAST) ==>
       AudioStreamOut: 0x... flags 0x6 (AUDIO_OUTPUT_FLAG_PRIMARY|AUDIO_OUTPUT_FLAG_FAST)

Test: make & run
Change-Id: I9cde640e6827b7aa6d62e9caade9e738227e299f
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
index ea03a90..63c4d6c 100644
--- a/include/media/AudioParameter.h
+++ b/include/media/AudioParameter.h
@@ -75,7 +75,7 @@
 
     static const char * const valueListSeparator;
 
-    String8 toString();
+    String8 toString() const;
 
     status_t add(const String8& key, const String8& value);
     status_t addInt(const String8& key, const int value);
@@ -83,12 +83,12 @@
 
     status_t remove(const String8& key);
 
-    status_t get(const String8& key, String8& value);
-    status_t getInt(const String8& key, int& value);
-    status_t getFloat(const String8& key, float& value);
-    status_t getAt(size_t index, String8& key, String8& value);
+    status_t get(const String8& key, String8& value) const;
+    status_t getInt(const String8& key, int& value) const;
+    status_t getFloat(const String8& key, float& value) const;
+    status_t getAt(size_t index, String8& key, String8& value) const;
 
-    size_t size() { return mParameters.size(); }
+    size_t size() const { return mParameters.size(); }
 
 private:
     String8 mKeyValuePairs;
diff --git a/include/media/TypeConverter.h b/include/media/TypeConverter.h
new file mode 100644
index 0000000..ffe4c1f
--- /dev/null
+++ b/include/media/TypeConverter.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_TYPE_CONVERTER_H_
+#define ANDROID_TYPE_CONVERTER_H_
+
+#include <string>
+#include <string.h>
+
+#include <system/audio.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+
+#include "convert.h"
+#include "AudioParameter.h"
+
+namespace android {
+
+struct SampleRateTraits
+{
+    typedef uint32_t Type;
+    typedef SortedVector<Type> Collection;
+};
+struct DeviceTraits
+{
+    typedef audio_devices_t Type;
+    typedef Vector<Type> Collection;
+};
+struct OutputDeviceTraits : public DeviceTraits {};
+struct InputDeviceTraits : public DeviceTraits {};
+struct OutputFlagTraits
+{
+    typedef audio_output_flags_t Type;
+    typedef Vector<Type> Collection;
+};
+struct InputFlagTraits
+{
+    typedef audio_input_flags_t Type;
+    typedef Vector<Type> Collection;
+};
+struct FormatTraits
+{
+    typedef audio_format_t Type;
+    typedef Vector<Type> Collection;
+};
+struct ChannelTraits
+{
+    typedef audio_channel_mask_t Type;
+    typedef SortedVector<Type> Collection;
+};
+struct OutputChannelTraits : public ChannelTraits {};
+struct InputChannelTraits : public ChannelTraits {};
+struct ChannelIndexTraits : public ChannelTraits {};
+struct GainModeTraits
+{
+    typedef audio_gain_mode_t Type;
+    typedef Vector<Type> Collection;
+};
+struct StreamTraits
+{
+    typedef audio_stream_type_t Type;
+    typedef Vector<Type> Collection;
+};
+struct AudioModeTraits
+{
+    typedef audio_mode_t Type;
+    typedef Vector<Type> Collection;
+};
+template <typename T>
+struct DefaultTraits
+{
+    typedef T Type;
+    typedef Vector<Type> Collection;
+};
+
+template <class Traits>
+static void collectionFromString(const std::string &str, typename Traits::Collection &collection,
+                                 const char *del = AudioParameter::valueListSeparator)
+{
+    char *literal = strdup(str.c_str());
+    for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+        typename Traits::Type value;
+        if (utilities::convertTo<std::string, typename Traits::Type >(cstr, value)) {
+            collection.add(value);
+        }
+    }
+    free(literal);
+}
+
+template <class Traits>
+class TypeConverter
+{
+public:
+    static bool toString(const typename Traits::Type &value, std::string &str);
+
+    static bool fromString(const std::string &str, typename Traits::Type &result);
+
+    static void collectionFromString(const std::string &str,
+                                     typename Traits::Collection &collection,
+                                     const char *del = AudioParameter::valueListSeparator);
+
+    static uint32_t maskFromString(
+            const std::string &str, const char *del = AudioParameter::valueListSeparator);
+
+    static void maskToString(
+            uint32_t mask, std::string &str, const char *del = AudioParameter::valueListSeparator);
+
+protected:
+    struct Table {
+        const char *literal;
+        typename Traits::Type value;
+    };
+
+    static const Table mTable[];
+};
+
+template <class Traits>
+inline bool TypeConverter<Traits>::toString(const typename Traits::Type &value, std::string &str)
+{
+    for (size_t i = 0; mTable[i].literal; i++) {
+        if (mTable[i].value == value) {
+            str = mTable[i].literal;
+            return true;
+        }
+    }
+    char result[64];
+    snprintf(result, sizeof(result), "Unknown enum value %d", value);
+    str = result;
+    return false;
+}
+
+template <class Traits>
+inline bool TypeConverter<Traits>::fromString(const std::string &str, typename Traits::Type &result)
+{
+    for (size_t i = 0; mTable[i].literal; i++) {
+        if (strcmp(mTable[i].literal, str.c_str()) == 0) {
+            ALOGV("stringToEnum() found %s", mTable[i].literal);
+            result = mTable[i].value;
+            return true;
+        }
+    }
+    return false;
+}
+
+template <class Traits>
+inline void TypeConverter<Traits>::collectionFromString(const std::string &str,
+        typename Traits::Collection &collection,
+        const char *del)
+{
+    char *literal = strdup(str.c_str());
+
+    for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+        typename Traits::Type value;
+        if (fromString(cstr, value)) {
+            collection.add(value);
+        }
+    }
+    free(literal);
+}
+
+template <class Traits>
+inline uint32_t TypeConverter<Traits>::maskFromString(const std::string &str, const char *del)
+{
+    char *literal = strdup(str.c_str());
+    uint32_t value = 0;
+    for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+        typename Traits::Type type;
+        if (fromString(cstr, type)) {
+            value |= static_cast<uint32_t>(type);
+        }
+    }
+    free(literal);
+    return value;
+}
+
+template <class Traits>
+inline void TypeConverter<Traits>::maskToString(uint32_t mask, std::string &str, const char *del)
+{
+    if (mask != 0) {
+        bool first_flag = true;
+        for (size_t i = 0; mTable[i].literal; i++) {
+            if (mTable[i].value != 0 && (mask & mTable[i].value) == mTable[i].value) {
+                if (!first_flag) str += del;
+                first_flag = false;
+                str += mTable[i].literal;
+            }
+        }
+    } else {
+        toString(static_cast<typename Traits::Type>(0), str);
+    }
+}
+
+typedef TypeConverter<OutputDeviceTraits> OutputDeviceConverter;
+typedef TypeConverter<InputDeviceTraits> InputDeviceConverter;
+typedef TypeConverter<OutputFlagTraits> OutputFlagConverter;
+typedef TypeConverter<InputFlagTraits> InputFlagConverter;
+typedef TypeConverter<FormatTraits> FormatConverter;
+typedef TypeConverter<OutputChannelTraits> OutputChannelConverter;
+typedef TypeConverter<InputChannelTraits> InputChannelConverter;
+typedef TypeConverter<ChannelIndexTraits> ChannelIndexConverter;
+typedef TypeConverter<GainModeTraits> GainModeConverter;
+typedef TypeConverter<StreamTraits> StreamTypeConverter;
+typedef TypeConverter<AudioModeTraits> AudioModeConverter;
+
+bool deviceFromString(const std::string& literalDevice, audio_devices_t& device);
+
+bool deviceToString(audio_devices_t device, std::string& literalDevice);
+
+SampleRateTraits::Collection samplingRatesFromString(
+        const std::string &samplingRates, const char *del = AudioParameter::valueListSeparator);
+
+FormatTraits::Collection formatsFromString(
+        const std::string &formats, const char *del = AudioParameter::valueListSeparator);
+
+audio_format_t formatFromString(
+        const std::string &literalFormat, audio_format_t defaultFormat = AUDIO_FORMAT_DEFAULT);
+
+audio_channel_mask_t channelMaskFromString(const std::string &literalChannels);
+
+ChannelTraits::Collection channelMasksFromString(
+        const std::string &channels, const char *del = AudioParameter::valueListSeparator);
+
+InputChannelTraits::Collection inputChannelMasksFromString(
+        const std::string &inChannels, const char *del = AudioParameter::valueListSeparator);
+
+OutputChannelTraits::Collection outputChannelMasksFromString(
+        const std::string &outChannels, const char *del = AudioParameter::valueListSeparator);
+
+}; // namespace android
+
+#endif  /*ANDROID_TYPE_CONVERTER_H_*/
diff --git a/include/media/convert.h b/include/media/convert.h
new file mode 100644
index 0000000..980b5d5
--- /dev/null
+++ b/include/media/convert.h
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <limits>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <stdint.h>
+#include <cmath>
+
+namespace android
+{
+
+namespace utilities
+{
+
+/**
+ * Convert a given source type to a given destination type.
+ *
+ * String conversion to T reads the value of the type T in the given string.
+ * The function does not allow to have white spaces around the value to parse
+ * and tries to parse the whole string, which means that if some bytes were not
+ * read in the string, the function fails.
+ * Hexadecimal representation (ie. numbers starting with 0x) is supported only
+ * for integral types conversions.
+ *
+ * Numeric conversion to string formats the source value to decimal space.
+ *
+ * Vector to vector conversion calls convertTo on each element.
+ *
+ * @tparam srcType source type, default value is string type
+ * @tparam dstType destination type
+ * @param[in] input The source to convert from.
+ * @param[out] result Converted value if success, undefined on failure.
+ *
+ * @return true if conversion was successful, false otherwise.
+ */
+template <typename srcType, typename dstType>
+static inline bool convertTo(const srcType &input, dstType &result);
+
+/* details namespace is here to hide implementation details to header end user. It
+ * is NOT intended to be used outside. */
+namespace details
+{
+
+/** Helper class to limit instantiation of templates */
+template <typename T>
+struct ConversionFromStringAllowed;
+template <typename T>
+struct ConversionToStringAllowed;
+
+/* List of allowed types for conversion */
+template <>
+struct ConversionFromStringAllowed<bool> {};
+template <>
+struct ConversionFromStringAllowed<uint64_t> {};
+template <>
+struct ConversionFromStringAllowed<int64_t> {};
+template <>
+struct ConversionFromStringAllowed<uint32_t> {};
+template <>
+struct ConversionFromStringAllowed<int32_t> {};
+template <>
+struct ConversionFromStringAllowed<uint16_t> {};
+template <>
+struct ConversionFromStringAllowed<int16_t> {};
+template <>
+struct ConversionFromStringAllowed<float> {};
+template <>
+struct ConversionFromStringAllowed<double> {};
+
+template <>
+struct ConversionToStringAllowed<int64_t> {};
+template <>
+struct ConversionToStringAllowed<uint64_t> {};
+template <>
+struct ConversionToStringAllowed<uint32_t> {};
+template <>
+struct ConversionToStringAllowed<int32_t> {};
+template <>
+struct ConversionToStringAllowed<double> {};
+template <>
+struct ConversionToStringAllowed<float> {};
+
+/**
+ * Set the decimal precision to 10 digits.
+ * Note that this setting is aligned with Android Audio Parameter
+ * policy concerning float storage into string.
+ */
+static const uint32_t gFloatPrecision = 10;
+
+template <typename T>
+static inline bool fromString(const std::string &str, T &result)
+{
+    /* Check that conversion to that type is allowed.
+     * If this fails, this means that this template was not intended to be used
+     * with this type, thus that the result is undefined. */
+    ConversionFromStringAllowed<T>();
+
+    if (str.find_first_of(std::string("\r\n\t\v ")) != std::string::npos) {
+        return false;
+    }
+
+    /* Check for a '-' in string. If type is unsigned and a - is found, the
+     * parsing fails. This is made necessary because "-1" is read as 65535 for
+     * uint16_t, for example */
+    if (str.find("-") != std::string::npos
+        && !std::numeric_limits<T>::is_signed) {
+        return false;
+    }
+
+    std::stringstream ss(str);
+
+    /* Sadly, the stream conversion does not handle hexadecimal format, thus
+     * check is done manually */
+    if (str.substr(0, 2) == "0x") {
+        if (std::numeric_limits<T>::is_integer) {
+            ss >> std::hex >> result;
+        } else {
+            /* Conversion undefined for non integers */
+            return false;
+        }
+    } else {
+        ss >> result;
+    }
+
+    return ss.eof() && !ss.fail() && !ss.bad();
+}
+
+template <typename T>
+static inline bool toString(const T &value, std::string &str)
+{
+    /* Check that conversion from that type is allowed.
+     * If this fails, this means that this template was not intended to be used
+     * with this type, thus that the result is undefined. */
+    ConversionToStringAllowed<T>();
+
+    std::stringstream oss;
+    oss.precision(gFloatPrecision);
+    oss << value;
+    str = oss.str();
+    return !oss.fail() && !oss.bad();
+}
+
+template <typename srcType, typename dstType>
+class Converter;
+
+template <typename dstType>
+class Converter<std::string, dstType>
+{
+public:
+    static inline bool run(const std::string &str, dstType &result)
+    {
+        return fromString<dstType>(str, result);
+    }
+};
+
+template <typename srcType>
+class Converter<srcType, std::string>
+{
+public:
+    static inline bool run(const srcType &str, std::string &result)
+    {
+        return toString<srcType>(str, result);
+    }
+};
+
+/** Convert a vector by applying convertTo on each element.
+ *
+ * @tparam SrcElem Type of the src elements.
+ * @tparam DstElem Type of the destination elements.
+ */
+template <typename SrcElem, typename DstElem>
+class Converter<std::vector<SrcElem>, std::vector<DstElem> >
+{
+public:
+    typedef const std::vector<SrcElem> Src;
+    typedef std::vector<DstElem> Dst;
+
+    static inline bool run(Src &src, Dst &dst)
+    {
+        typedef typename Src::const_iterator SrcIt;
+        dst.clear();
+        dst.reserve(src.size());
+        for (SrcIt it = src.begin(); it != src.end(); ++it) {
+            DstElem dstElem;
+            if (not convertTo(*it, dstElem)) {
+                return false;
+            }
+            dst.push_back(dstElem);
+        }
+        return true;
+    }
+};
+
+} // namespace details
+
+template <typename srcType, typename dstType>
+static inline bool convertTo(const srcType &input, dstType &result)
+{
+    return details::Converter<srcType, dstType>::run(input, result);
+}
+
+/**
+ * Specialization for int16_t of convertTo template function.
+ *
+ * This function follows the same paradigm than it's generic version.
+ *
+ * The specific implementation is made necessary because the stlport version of
+ * string streams is bugged and does not fail when giving overflowed values.
+ * This specialisation can be safely removed when stlport behaviour is fixed.
+ *
+ * @param[in]  str    the string to parse.
+ * @param[out] result reference to object where to store the result.
+ *
+ * @return true if conversion was successful, false otherwise.
+ */
+template <>
+inline bool convertTo<std::string, int16_t>(const std::string &str, int16_t &result)
+{
+    int64_t res;
+
+    if (!convertTo<std::string, int64_t>(str, res)) {
+        return false;
+    }
+
+    if (res > std::numeric_limits<int16_t>::max() || res < std::numeric_limits<int16_t>::min()) {
+        return false;
+    }
+
+    result = static_cast<int16_t>(res);
+    return true;
+}
+
+/**
+ * Specialization for float of convertTo template function.
+ *
+ * This function follows the same paradigm than it's generic version and is
+ * based on it but makes furthers checks on the returned value.
+ *
+ * The specific implementation is made necessary because the stlport conversion
+ * from string to float behaves differently than GNU STL: overflow produce
+ * +/-Infinity rather than an error.
+ *
+ * @param[in]  str    the string to parse.
+ * @param[out] result reference to object where to store the result.
+ *
+ * @return true if conversion was successful, false otherwise.
+ */
+template <>
+inline bool convertTo<std::string, float>(const std::string &str, float &result)
+{
+    if (!details::Converter<std::string, float>::run(str, result)) {
+        return false;
+    }
+
+    if (std::abs(result) == std::numeric_limits<float>::infinity() ||
+        result == std::numeric_limits<float>::quiet_NaN()) {
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * Specialization for double of convertTo template function.
+ *
+ * This function follows the same paradigm than it's generic version and is
+ * based on it but makes furthers checks on the returned value.
+ *
+ * The specific implementation is made necessary because the stlport conversion
+ * from string to double behaves differently than GNU STL: overflow produce
+ * +/-Infinity rather than an error.
+ *
+ * @param[in]  str    the string to parse.
+ * @param[out] result reference to object where to store the result.
+ *
+ * @return true if conversion was successful, false otherwise.
+ */
+template <>
+inline bool convertTo<std::string, double>(const std::string &str, double &result)
+{
+    if (!details::Converter<std::string, double>::run(str, result)) {
+        return false;
+    }
+
+    if (std::abs(result) == std::numeric_limits<double>::infinity() ||
+        result == std::numeric_limits<double>::quiet_NaN()) {
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * Specialization for boolean of convertTo template function.
+ *
+ * This function follows the same paradigm than it's generic version.
+ * This function accepts to parse boolean as "0/1" or "false/true" or
+ * "FALSE/TRUE".
+ * The specific implementation is made necessary because the behaviour of
+ * string streams when parsing boolean values is not sufficient to fit our
+ * requirements. Indeed, parsing "true" will correctly parse the value, but the
+ * end of stream is not reached which makes the ss.eof() fails in the generic
+ * implementation.
+ *
+ * @param[in]  str    the string to parse.
+ * @param[out] result reference to object where to store the result.
+ *
+ * @return true if conversion was successful, false otherwise.
+ */
+template <>
+inline bool convertTo<std::string, bool>(const std::string &str, bool &result)
+{
+    if (str == "0" || str == "FALSE" || str == "false") {
+        result = false;
+        return true;
+    }
+
+    if (str == "1" || str == "TRUE" || str == "true") {
+        result = true;
+        return true;
+    }
+
+    return false;
+}
+
+/**
+ * Specialization for boolean to string of convertTo template function.
+ *
+ * This function follows the same paradigm than it's generic version.
+ * This function arbitrarily decides to return "false/true".
+ * It is compatible with the specialization from string to boolean.
+ *
+ * @param[in]  isSet  boolean to convert to a string.
+ * @param[out] result reference to object where to store the result.
+ *
+ * @return true if conversion was successful, false otherwise.
+ */
+template <>
+inline bool convertTo<bool, std::string>(const bool &isSet, std::string &result)
+{
+    result = isSet ? "true" : "false";
+    return true;
+}
+
+/**
+ * Specialization for string to string of convertTo template function.
+ *
+ * This function is a dummy conversion from string to string.
+ * In case of clients using template as well, this implementation avoids adding extra
+ * specialization to bypass the conversion from string to string.
+ *
+ * @param[in]  str    the string to parse.
+ * @param[out] result reference to object where to store the result.
+ *
+ * @return true if conversion was successful, false otherwise.
+ */
+template <>
+inline bool convertTo<std::string, std::string>(const std::string &str, std::string &result)
+{
+    result = str;
+    return true;
+}
+
+} // namespace utilities
+
+} // namespace android