1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18
19 #include <optional>
20 #include <string>
21 #include <unordered_map>
22
23 #include <media/AidlConversionUtil.h>
24 #include <system/audio_config.h>
25
26 namespace aidl::android::hardware::audio::core::internal {
27
28 template <typename T>
29 class XmlConverter {
30 public:
XmlConverter(const std::string & configFilePath,std::function<std::optional<T> (const char *)> readXmlConfig)31 XmlConverter(const std::string& configFilePath,
32 std::function<std::optional<T>(const char*)> readXmlConfig)
33 : XmlConverter(configFilePath,
34 ::android::audio_is_readable_configuration_file(configFilePath.c_str()),
35 readXmlConfig) {}
36
getStatus()37 const ::android::status_t& getStatus() const { return mStatus; }
38
getError()39 const std::string& getError() const { return mErrorMessage; }
40
getXsdcConfig()41 const std::optional<T>& getXsdcConfig() const { return mXsdcConfig; }
42
43 private:
XmlConverter(const std::string & configFilePath,const bool & isReadableConfigFile,const std::function<std::optional<T> (const char *)> & readXmlConfig)44 XmlConverter(const std::string& configFilePath, const bool& isReadableConfigFile,
45 const std::function<std::optional<T>(const char*)>& readXmlConfig)
46 : mXsdcConfig{isReadableConfigFile ? readXmlConfig(configFilePath.c_str()) : std::nullopt},
47 mStatus(mXsdcConfig ? ::android::OK : ::android::NO_INIT),
48 mErrorMessage(generateError(configFilePath, isReadableConfigFile, mStatus)) {}
49
generateError(const std::string & configFilePath,const bool & isReadableConfigFile,const::android::status_t & status)50 static std::string generateError(const std::string& configFilePath,
51 const bool& isReadableConfigFile,
52 const ::android::status_t& status) {
53 std::string errorMessage;
54 if (status != ::android::OK) {
55 if (configFilePath.empty()) {
56 errorMessage = "No audio configuration files found";
57 } else if (!isReadableConfigFile) {
58 errorMessage = std::string("Could not read requested XML config file: \"")
59 .append(configFilePath)
60 .append("\"");
61 } else {
62 errorMessage = std::string("Invalid XML config file: \"")
63 .append(configFilePath)
64 .append("\"");
65 }
66 }
67 return errorMessage;
68 }
69
70 const std::optional<T> mXsdcConfig;
71 const ::android::status_t mStatus;
72 const std::string mErrorMessage;
73 };
74
75 /**
76 * Converts a vector of an xsd wrapper type to a flat vector of the
77 * corresponding AIDL type.
78 *
79 * Wrapper types are used in order to have well-formed xIncludes. In the
80 * example below, Modules is the wrapper type for Module.
81 * <Modules>
82 * <Module> ... </Module>
83 * <Module> ... </Module>
84 * </Modules>
85 */
86 template <typename W, typename X, typename A>
convertWrappedCollectionToAidl(const std::vector<W> & xsdcWrapperTypeVec,std::function<const std::vector<X> & (const W &)> getInnerTypeVec,std::function<ConversionResult<A> (const X &)> convertToAidl)87 static ConversionResult<std::vector<A>> convertWrappedCollectionToAidl(
88 const std::vector<W>& xsdcWrapperTypeVec,
89 std::function<const std::vector<X>&(const W&)> getInnerTypeVec,
90 std::function<ConversionResult<A>(const X&)> convertToAidl) {
91 std::vector<A> resultAidlTypeVec;
92 if (!xsdcWrapperTypeVec.empty()) {
93 /*
94 * xsdcWrapperTypeVec likely only contains one element; that is, it's
95 * likely that all the inner types that we need to convert are inside of
96 * xsdcWrapperTypeVec[0].
97 */
98 resultAidlTypeVec.reserve(getInnerTypeVec(xsdcWrapperTypeVec[0]).size());
99 for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
100 for (const X& xsdcType : getInnerTypeVec(xsdcWrapperType)) {
101 resultAidlTypeVec.push_back(VALUE_OR_FATAL(convertToAidl(xsdcType)));
102 }
103 }
104 }
105 return resultAidlTypeVec;
106 }
107
108 template <typename X, typename A>
convertCollectionToAidlOptionalValues(const std::vector<X> & xsdcTypeVec,std::function<ConversionResult<A> (const X &)> convertToAidl)109 static ConversionResult<std::vector<std::optional<A>>> convertCollectionToAidlOptionalValues(
110 const std::vector<X>& xsdcTypeVec,
111 std::function<ConversionResult<A>(const X&)> convertToAidl) {
112 std::vector<std::optional<A>> resultAidlTypeVec;
113 resultAidlTypeVec.reserve(xsdcTypeVec.size());
114 for (const X& xsdcType : xsdcTypeVec) {
115 resultAidlTypeVec.push_back(
116 std::optional<A>(std::move(VALUE_OR_FATAL(convertToAidl(xsdcType)))));
117 }
118 return resultAidlTypeVec;
119 }
120
121 template <typename X, typename A>
convertCollectionToAidl(const std::vector<X> & xsdcTypeVec,std::function<ConversionResult<A> (const X &)> convertToAidl)122 static ConversionResult<std::vector<A>> convertCollectionToAidl(
123 const std::vector<X>& xsdcTypeVec,
124 std::function<ConversionResult<A>(const X&)> convertToAidl) {
125 std::vector<A> resultAidlTypeVec;
126 resultAidlTypeVec.reserve(xsdcTypeVec.size());
127 for (const X& xsdcType : xsdcTypeVec) {
128 resultAidlTypeVec.push_back(VALUE_OR_FATAL(convertToAidl(xsdcType)));
129 }
130 return resultAidlTypeVec;
131 }
132
133 /**
134 * Generates a map of xsd references, keyed by reference name, given a
135 * vector of wrapper types for the reference.
136 *
137 * Wrapper types are used in order to have well-formed xIncludes. In the
138 * example below, Wrapper is the wrapper type for Reference.
139 * <Wrapper>
140 * <Reference> ... </Reference>
141 * <Reference> ... </Reference>
142 * </Wrapper>
143 */
144 template <typename W, typename R>
generateReferenceMap(const std::vector<W> & xsdcWrapperTypeVec)145 std::unordered_map<std::string, R> generateReferenceMap(const std::vector<W>& xsdcWrapperTypeVec) {
146 std::unordered_map<std::string, R> resultMap;
147 if (!xsdcWrapperTypeVec.empty()) {
148 /*
149 * xsdcWrapperTypeVec likely only contains one element; that is, it's
150 * likely that all the inner types that we need to convert are inside of
151 * xsdcWrapperTypeVec[0].
152 */
153 resultMap.reserve(xsdcWrapperTypeVec[0].getReference().size());
154 for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
155 for (const R& xsdcReference : xsdcWrapperType.getReference()) {
156 resultMap.insert({xsdcReference.getName(), xsdcReference});
157 }
158 }
159 }
160 return resultMap;
161 }
162 } // namespace aidl::android::hardware::audio::core::internal
163