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