blob: fcbae99778add3a687ef3fea0a8ef7737da7c13e [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef RIL_MNC_H
#define RIL_MNC_H
#include <climits>
#include <cstdio>
#include <string>
namespace ril {
namespace util {
namespace mnc {
/**
* Decode an MNC with an optional length indicator provided in the most-significant nibble.
*
* @param mnc an encoded MNC value; if no encoding is provided, then the string is returned
* as a minimum length string representing the provided integer.
*
* @return string representation of an encoded MNC or an empty string if the MNC is not a valid
* MNC value.
*/
static inline std::string decode(int mnc) {
if (mnc == INT_MAX || mnc < 0) return "";
unsigned umnc = mnc;
char mncNumDigits = (umnc >> (sizeof(int) * 8 - 4)) & 0xF;
umnc = (umnc << 4) >> 4;
if (umnc > 999) return "";
char mncStr[4] = {0};
switch (mncNumDigits) {
case 0:
// Legacy MNC report hasn't set the number of digits; preserve current
// behavior and make a string of the minimum number of required digits.
return std::to_string(umnc);
case 2:
snprintf(mncStr, sizeof(mncStr), "%03.3u", umnc);
return mncStr + 1;
case 3:
snprintf(mncStr, sizeof(mncStr), "%03.3u", umnc);
return mncStr;
default:
// Error case
return "";
}
}
/**
* Encode an MNC of the given value and a given number of digits
*
* @param mnc an MNC value 0-999 or INT_MAX if unknown
* @param numDigits the number of MNC digits {2, 3} or 0 if unknown
*
* @return an encoded MNC with embedded length information
*/
static inline int encode(int mnc, int numDigits) {
if (mnc > 999 || mnc < 0) return INT_MAX;
switch (numDigits) {
case 0: // fall through
case 2: // fall through
case 3:
break;
default:
return INT_MAX;
};
return (numDigits << (sizeof(int) * 8 - 4)) | mnc;
}
/**
* Encode an MNC of the given value
*
* @param mnc the string representation of the MNC, with the length equal to the length of the
* provided string.
*
* @return an encoded MNC with embedded length information
*/
static inline int encode(const std::string & mnc) {
return encode(std::stoi(mnc), mnc.length());
}
// echo -e "#include \"hardware/ril/include/telephony/ril_mnc.h\"\nint main()"\
// "{ return ril::util::mnc::test(); }" > ril_test.cpp \
// && g++ -o /tmp/ril_test -DTEST_RIL_MNC ril_test.cpp; \
// rm ril_test.cpp; /tmp/ril_test && [ $? ] && echo "passed"
#ifdef TEST_RIL_MNC
static int test() {
const struct mnc_strings { const char * in; const char * out; } mncs[] = {
{"0001",""},
{"9999",""},
{"0",""},
{"9",""},
{"123","123"},
{"000","000"},
{"001","001"},
{"011","011"},
{"111","111"},
{"00","00"},
{"01","01"},
{"11","11"},
{"09","09"},
{"099","099"},
{"999", "999"}};
for (int i=0; i< sizeof(mncs) / sizeof(struct mnc_strings); i++) {
if (decode(encode(mncs[i].in)).compare(mncs[i].out)) return 1;
}
const struct mnc_ints { const int in; const char * out; } legacy_mncs[] = {
{INT_MAX, ""},
{1, "1"},
{11, "11"},
{111, "111"},
{0, "0"},
{9999, ""},
};
for (int i=0; i < sizeof(legacy_mncs) / sizeof(struct mnc_ints); i++) {
if (decode(legacy_mncs[i].in).compare(legacy_mncs[i].out)) return 1;
}
return 0;
}
#endif
}
}
}
#endif /* !defined(RIL_MNC_H) */