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>
convertCollectionToAidl(const std::vector<X> & xsdcTypeVec,std::function<ConversionResult<A> (const X &)> convertToAidl)109 static ConversionResult<std::vector<A>> convertCollectionToAidl(
110 const std::vector<X>& xsdcTypeVec,
111 std::function<ConversionResult<A>(const X&)> convertToAidl) {
112 std::vector<A> resultAidlTypeVec;
113 resultAidlTypeVec.reserve(xsdcTypeVec.size());
114 for (const X& xsdcType : xsdcTypeVec) {
115 resultAidlTypeVec.push_back(VALUE_OR_FATAL(convertToAidl(xsdcType)));
116 }
117 return resultAidlTypeVec;
118 }
119
120 /**
121 * Generates a map of xsd references, keyed by reference name, given a
122 * vector of wrapper types for the reference.
123 *
124 * Wrapper types are used in order to have well-formed xIncludes. In the
125 * example below, Wrapper is the wrapper type for Reference.
126 * <Wrapper>
127 * <Reference> ... </Reference>
128 * <Reference> ... </Reference>
129 * </Wrapper>
130 */
131 template <typename W, typename R>
generateReferenceMap(const std::vector<W> & xsdcWrapperTypeVec)132 std::unordered_map<std::string, R> generateReferenceMap(const std::vector<W>& xsdcWrapperTypeVec) {
133 std::unordered_map<std::string, R> resultMap;
134 if (!xsdcWrapperTypeVec.empty()) {
135 /*
136 * xsdcWrapperTypeVec likely only contains one element; that is, it's
137 * likely that all the inner types that we need to convert are inside of
138 * xsdcWrapperTypeVec[0].
139 */
140 resultMap.reserve(xsdcWrapperTypeVec[0].getReference().size());
141 for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
142 for (const R& xsdcReference : xsdcWrapperType.getReference()) {
143 resultMap.insert({xsdcReference.getName(), xsdcReference});
144 }
145 }
146 }
147 return resultMap;
148 }
149 } // namespace aidl::android::hardware::audio::core::internal
150