1/*
2 * Copyright (C) 2016 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#include "ScalarType.h"
18
19#include <hidl-util/Formatter.h>
20
21namespace android {
22
23ScalarType::ScalarType(Kind kind)
24    : mKind(kind) {
25}
26
27const ScalarType *ScalarType::resolveToScalarType() const {
28    return this;
29}
30
31bool ScalarType::isValidEnumStorageType() const {
32    // Only integer types.
33    return mKind >= KIND_INT8 && mKind <= KIND_UINT64;
34}
35
36bool ScalarType::isScalar() const {
37    return true;
38}
39
40bool ScalarType::isElidableType() const {
41    return true;
42}
43
44bool ScalarType::canCheckEquality() const {
45    return true;
46}
47
48std::string ScalarType::typeName() const {
49    return getCppStackType();
50}
51
52std::string ScalarType::getCppType(StorageMode, bool) const {
53    static const char *const kName[] = {
54        "bool",
55        "int8_t",
56        "uint8_t",
57        "int16_t",
58        "uint16_t",
59        "int32_t",
60        "uint32_t",
61        "int64_t",
62        "uint64_t",
63        "float",
64        "double"
65    };
66
67    return kName[mKind];
68}
69
70std::string ScalarType::getJavaType(bool /* forInitializer */) const {
71    static const char *const kName[] = {
72        "boolean",
73        "byte",
74        "byte",
75        "short",
76        "short",
77        "int",
78        "int",
79        "long",
80        "long",
81        "float",
82        "double"
83    };
84
85    return kName[mKind];
86}
87
88std::string ScalarType::getJavaWrapperType() const {
89    static const char *const kName[] = {
90        "Boolean",
91        "Byte",
92        "Byte",
93        "Short",
94        "Short",
95        "Integer",
96        "Integer",
97        "Long",
98        "Long",
99        "Float",
100        "Double"
101    };
102
103    return kName[mKind];
104}
105
106std::string ScalarType::getJavaSuffix() const {
107    static const char *const kSuffix[] = {
108        "Bool",
109        "Int8",
110        "Int8",
111        "Int16",
112        "Int16",
113        "Int32",
114        "Int32",
115        "Int64",
116        "Int64",
117        "Float",
118        "Double"
119    };
120
121    return kSuffix[mKind];
122}
123
124std::string ScalarType::getVtsType() const {
125    return "TYPE_SCALAR";
126}
127
128std::string ScalarType::getVtsScalarType() const {
129    static const char * const kName[] = {
130            "bool_t",
131            "int8_t",
132            "uint8_t",
133            "int16_t",
134            "uint16_t",
135            "int32_t",
136            "uint32_t",
137            "int64_t",
138            "uint64_t",
139            "float_t",
140            "double_t"
141    };
142
143    return kName[mKind];
144}
145
146void ScalarType::emitReaderWriter(
147        Formatter &out,
148        const std::string &name,
149        const std::string &parcelObj,
150        bool parcelObjIsPointer,
151        bool isReader,
152        ErrorMode mode) const {
153    emitReaderWriterWithCast(
154            out,
155            name,
156            parcelObj,
157            parcelObjIsPointer,
158            isReader,
159            mode,
160            false /* needsCast */);
161}
162
163void ScalarType::emitReaderWriterWithCast(
164        Formatter &out,
165        const std::string &name,
166        const std::string &parcelObj,
167        bool parcelObjIsPointer,
168        bool isReader,
169        ErrorMode mode,
170        bool needsCast) const {
171    static const char *const kSuffix[] = {
172        "Bool",
173        "Int8",
174        "Uint8",
175        "Int16",
176        "Uint16",
177        "Int32",
178        "Uint32",
179        "Int64",
180        "Uint64",
181        "Float",
182        "Double"
183    };
184
185    const std::string parcelObjDeref =
186        parcelObj + (parcelObjIsPointer ? "->" : ".");
187
188    out << "_hidl_err = "
189        << parcelObjDeref
190        << (isReader ? "read" : "write")
191        << kSuffix[mKind]
192        << "(";
193
194    if (needsCast) {
195        out << "("
196            << getCppStackType()
197            << (isReader ? " *)" : ")");
198    }
199
200    if (isReader) {
201        out << "&";
202    }
203
204    out << name
205        << ");\n";
206
207    handleError(out, mode);
208}
209
210void ScalarType::emitHexDump(
211        Formatter &out,
212        const std::string &streamName,
213        const std::string &name) const {
214    out << streamName << " += toHexString(" << name << ");\n";
215}
216
217void ScalarType::emitConvertToJavaHexString(
218        Formatter &out,
219        const std::string &name) const {
220    switch(mKind) {
221        case KIND_BOOL: {
222            out << "((" << name << ") ? \"0x1\" : \"0x0\")";
223            break;
224        }
225        case KIND_INT8:     // fallthrough
226        case KIND_UINT8:    // fallthrough
227        case KIND_INT16:    // fallthrough
228        case KIND_UINT16: {
229            // Because Byte and Short doesn't have toHexString, we have to use Integer.toHexString.
230            out << "Integer.toHexString(" << getJavaWrapperType() << ".toUnsignedInt(("
231                << getJavaType(false /* forInitializer */) << ")(" << name << ")))";
232            break;
233        }
234        case KIND_INT32:    // fallthrough
235        case KIND_UINT32:   // fallthrough
236        case KIND_INT64:    // fallthrough
237        case KIND_UINT64: {
238            out << getJavaWrapperType() << ".toHexString(" << name << ")";
239            break;
240        }
241        case KIND_FLOAT:    // fallthrough
242        case KIND_DOUBLE:   // fallthrough
243        default: {
244            // no hex for floating point numbers.
245            out << name;
246            break;
247        }
248    }
249}
250
251void ScalarType::emitJavaFieldReaderWriter(
252        Formatter &out,
253        size_t /* depth */,
254        const std::string & /* parcelName */,
255        const std::string &blobName,
256        const std::string &fieldName,
257        const std::string &offset,
258        bool isReader) const {
259    if (isReader) {
260        out << fieldName
261            << " = "
262            << blobName
263            << ".get"
264            << getJavaSuffix()
265            << "("
266            << offset
267            << ");\n";
268
269        return;
270    }
271
272    out << blobName
273        << ".put"
274        << getJavaSuffix()
275        << "("
276        << offset
277        << ", "
278        << fieldName
279        << ");\n";
280}
281
282status_t ScalarType::emitVtsTypeDeclarations(Formatter &out) const {
283    out << "type: " << getVtsType() << "\n";
284    out << "scalar_type: \"" << getVtsScalarType() << "\"\n";
285    return OK;
286}
287
288void ScalarType::getAlignmentAndSize(size_t *align, size_t *size) const {
289    static const size_t kAlign[] = {
290        1,  // bool, this is NOT standardized!
291        1,  // int8_t
292        1,  // uint8_t
293        2,  // int16_t
294        2,  // uint16_t
295        4,  // int32_t
296        4,  // uint32_t
297        8,  // int64_t
298        8,  // uint64_t
299        4,  // float
300        8   // double
301    };
302
303    *align = *size = kAlign[mKind];
304}
305
306ScalarType::Kind ScalarType::getKind() const {
307    return mKind;
308}
309
310}  // namespace android
311
312