1 /*
2  * Copyright (C) 2018 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 #ifndef RIL_MNC_H
18 #define RIL_MNC_H
19 
20 #include <climits>
21 #include <cstdio>
22 #include <string>
23 
24 namespace ril {
25 namespace util {
26 namespace mnc {
27 
28 /**
29  * Decode an MNC with an optional length indicator provided in the most-significant nibble.
30  *
31  * @param mnc an encoded MNC value; if no encoding is provided, then the string is returned
32  *     as a minimum length string representing the provided integer.
33  *
34  * @return string representation of an encoded MNC or an empty string if the MNC is not a valid
35  *     MNC value.
36  */
decode(int mnc)37 static inline std::string decode(int mnc) {
38     if (mnc == INT_MAX || mnc < 0) return "";
39     unsigned umnc = mnc;
40     char mncNumDigits = (umnc >> (sizeof(int) * 8 - 4)) & 0xF;
41 
42     umnc = (umnc << 4) >> 4;
43     if (umnc > 999) return "";
44 
45     char mncStr[4] = {0};
46     switch (mncNumDigits) {
47         case 0:
48             // Legacy MNC report hasn't set the number of digits; preserve current
49             // behavior and make a string of the minimum number of required digits.
50             return std::to_string(umnc);
51 
52         case 2:
53             snprintf(mncStr, sizeof(mncStr), "%03.3u", umnc);
54             return mncStr + 1;
55 
56         case 3:
57             snprintf(mncStr, sizeof(mncStr), "%03.3u", umnc);
58             return mncStr;
59 
60         default:
61             // Error case
62             return "";
63     }
64 
65 }
66 
67 /**
68  * Encode an MNC of the given value and a given number of digits
69  *
70  * @param mnc an MNC value 0-999 or INT_MAX if unknown
71  * @param numDigits the number of MNC digits {2, 3} or 0 if unknown
72  *
73  * @return an encoded MNC with embedded length information
74  */
encode(int mnc,int numDigits)75 static inline int encode(int mnc, int numDigits) {
76     if (mnc > 999 || mnc < 0) return INT_MAX;
77     switch (numDigits) {
78         case 0: // fall through
79         case 2: // fall through
80         case 3:
81             break;
82 
83         default:
84             return INT_MAX;
85     };
86 
87     return (numDigits << (sizeof(int) * 8 - 4)) | mnc;
88 }
89 
90 /**
91  * Encode an MNC of the given value
92  *
93  * @param mnc the string representation of the MNC, with the length equal to the length of the
94  *     provided string.
95  *
96  * @return an encoded MNC with embedded length information
97  */
encode(const std::string & mnc)98 static inline int encode(const std::string & mnc) {
99     return encode(std::stoi(mnc), mnc.length());
100 }
101 
102 // echo -e "#include \"hardware/ril/include/telephony/ril_mnc.h\"\nint main()"\
103 // "{ return ril::util::mnc::test(); }" > ril_test.cpp \
104 // && g++ -o /tmp/ril_test -DTEST_RIL_MNC ril_test.cpp; \
105 // rm ril_test.cpp; /tmp/ril_test && [ $? ] && echo "passed"
106 #ifdef TEST_RIL_MNC
test()107 static int test() {
108     const struct mnc_strings { const char * in; const char * out; } mncs[] = {
109         {"0001",""},
110         {"9999",""},
111         {"0",""},
112         {"9",""},
113         {"123","123"},
114         {"000","000"},
115         {"001","001"},
116         {"011","011"},
117         {"111","111"},
118         {"00","00"},
119         {"01","01"},
120         {"11","11"},
121         {"09","09"},
122         {"099","099"},
123         {"999", "999"}};
124 
125     for (int i=0; i< sizeof(mncs) / sizeof(struct mnc_strings); i++) {
126         if (decode(encode(mncs[i].in)).compare(mncs[i].out)) return 1;
127     }
128 
129     const struct mnc_ints { const int in; const char * out; } legacy_mncs[] = {
130         {INT_MAX, ""},
131         {1, "1"},
132         {11, "11"},
133         {111, "111"},
134         {0, "0"},
135         {9999, ""},
136     };
137 
138     for (int i=0; i < sizeof(legacy_mncs) / sizeof(struct mnc_ints); i++) {
139         if (decode(legacy_mncs[i].in).compare(legacy_mncs[i].out)) return 1;
140     }
141 
142     return 0;
143 }
144 #endif
145 
146 }
147 }
148 }
149 #endif /* !defined(RIL_MNC_H) */
150