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 #include <utils/Errors.h>
26
27 namespace aidl::android::hardware::audio::core::internal {
28
29 template <typename T>
30 class XmlConverter {
31 public:
XmlConverter(const std::string & configFilePath,std::function<std::optional<T> (const char *)> readXmlConfig)32 XmlConverter(const std::string& configFilePath,
33 std::function<std::optional<T>(const char*)> readXmlConfig)
34 : XmlConverter(configFilePath,
35 ::android::audio_is_readable_configuration_file(configFilePath.c_str()),
36 readXmlConfig) {}
37
getStatus()38 const ::android::status_t& getStatus() const { return mStatus; }
39
getError()40 const std::string& getError() const { return mErrorMessage; }
41
getXsdcConfig()42 const std::optional<T>& getXsdcConfig() const { return mXsdcConfig; }
43
44 private:
XmlConverter(const std::string & configFilePath,const bool & isReadableConfigFile,const std::function<std::optional<T> (const char *)> & readXmlConfig)45 XmlConverter(const std::string& configFilePath, const bool& isReadableConfigFile,
46 const std::function<std::optional<T>(const char*)>& readXmlConfig)
47 : mXsdcConfig{isReadableConfigFile ? readXmlConfig(configFilePath.c_str()) : std::nullopt},
48 mStatus(mXsdcConfig ? ::android::OK : ::android::NO_INIT),
49 mErrorMessage(generateError(configFilePath, isReadableConfigFile, mStatus)) {}
50
generateError(const std::string & configFilePath,const bool & isReadableConfigFile,const::android::status_t & status)51 static std::string generateError(const std::string& configFilePath,
52 const bool& isReadableConfigFile,
53 const ::android::status_t& status) {
54 std::string errorMessage;
55 if (status != ::android::OK) {
56 if (configFilePath.empty()) {
57 errorMessage = "No audio configuration files found";
58 } else if (!isReadableConfigFile) {
59 errorMessage = std::string("Could not read requested XML config file: \"")
60 .append(configFilePath)
61 .append("\"");
62 } else {
63 errorMessage = std::string("Invalid XML config file: \"")
64 .append(configFilePath)
65 .append("\"");
66 }
67 }
68 return errorMessage;
69 }
70
71 const std::optional<T> mXsdcConfig;
72 const ::android::status_t mStatus;
73 const std::string mErrorMessage;
74 };
75
76 /**
77 * Converts a vector of an xsd wrapper type to a flat vector of the
78 * corresponding AIDL type.
79 *
80 * Wrapper types are used in order to have well-formed xIncludes. In the
81 * example below, Modules is the wrapper type for Module.
82 * <Modules>
83 * <Module> ... </Module>
84 * <Module> ... </Module>
85 * </Modules>
86 */
87 template <typename W, typename X, typename A>
convertWrappedCollectionToAidlUnchecked(const std::vector<W> & xsdcWrapperTypeVec,std::function<const std::vector<X> & (const W &)> getInnerTypeVec,std::function<A (const X &)> convertToAidl)88 std::vector<A> convertWrappedCollectionToAidlUnchecked(
89 const std::vector<W>& xsdcWrapperTypeVec,
90 std::function<const std::vector<X>&(const W&)> getInnerTypeVec,
91 std::function<A(const X&)> convertToAidl) {
92 std::vector<A> resultAidlTypeVec;
93 if (!xsdcWrapperTypeVec.empty()) {
94 /*
95 * xsdcWrapperTypeVec likely only contains one element; that is, it's
96 * likely that all the inner types that we need to convert are inside of
97 * xsdcWrapperTypeVec[0].
98 */
99 resultAidlTypeVec.reserve(getInnerTypeVec(xsdcWrapperTypeVec[0]).size());
100 for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
101 std::transform(getInnerTypeVec(xsdcWrapperType).begin(),
102 getInnerTypeVec(xsdcWrapperType).end(),
103 std::back_inserter(resultAidlTypeVec), convertToAidl);
104 }
105 }
106 return resultAidlTypeVec;
107 }
108
109 template <typename X, typename A>
convertCollectionToAidlUnchecked(const std::vector<X> & xsdcTypeVec,std::function<A (const X &)> itemConversion)110 std::vector<A> convertCollectionToAidlUnchecked(const std::vector<X>& xsdcTypeVec,
111 std::function<A(const X&)> itemConversion) {
112 std::vector<A> resultAidlTypeVec;
113 resultAidlTypeVec.reserve(xsdcTypeVec.size());
114 std::transform(xsdcTypeVec.begin(), xsdcTypeVec.end(), std::back_inserter(resultAidlTypeVec),
115 itemConversion);
116 return resultAidlTypeVec;
117 }
118
119 /**
120 * Generates a map of xsd references, keyed by reference name, given a
121 * vector of wrapper types for the reference.
122 *
123 * Wrapper types are used in order to have well-formed xIncludes. In the
124 * example below, Wrapper is the wrapper type for Reference.
125 * <Wrapper>
126 * <Reference> ... </Reference>
127 * <Reference> ... </Reference>
128 * </Wrapper>
129 */
130 template <typename W, typename R>
generateReferenceMap(const std::vector<W> & xsdcWrapperTypeVec)131 std::unordered_map<std::string, R> generateReferenceMap(const std::vector<W>& xsdcWrapperTypeVec) {
132 std::unordered_map<std::string, R> resultMap;
133 if (!xsdcWrapperTypeVec.empty()) {
134 /*
135 * xsdcWrapperTypeVec likely only contains one element; that is, it's
136 * likely that all the inner types that we need to convert are inside of
137 * xsdcWrapperTypeVec[0].
138 */
139 resultMap.reserve(xsdcWrapperTypeVec[0].getReference().size());
140 for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
141 for (const R& xsdcReference : xsdcWrapperType.getReference()) {
142 resultMap.insert({xsdcReference.getName(), xsdcReference});
143 }
144 }
145 }
146 return resultMap;
147 }
148 } // namespace aidl::android::hardware::audio::core::internal
149