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 #define __C2_GENERATE_GLOBAL_VARS__ // to be able to implement the methods defined 18 #include <C2Enum.h> 19 #include <util/C2Debug-log.h> 20 #include <util/C2ParamUtils.h> 21 22 #include <utility> 23 #include <vector> 24 25 /** \file 26 * Utilities for parameter handling to be used by Codec2 implementations. 27 */ 28 29 /// \cond INTERNAL 30 31 /* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */ 32 33 static size_t countLeadingUnderscores(C2StringLiteral a) { 34 size_t i = 0; 35 while (a[i] == '_') { 36 ++i; 37 } 38 return i; 39 } 40 41 static size_t countMatching(C2StringLiteral a, const C2String &b) { 42 for (size_t i = 0; i < b.size(); ++i) { 43 if (!a[i] || a[i] != b[i]) { 44 return i; 45 } 46 } 47 return b.size(); 48 } 49 50 // ABCDef => abc-def 51 // ABCD2ef => abcd2-ef // 0 52 // ABCD2Ef => ancd2-ef // -1 53 // AbcDef => abc-def // -1 54 // Abc2Def => abc-2def 55 // Abc2def => abc-2-def 56 // _Yo => _yo 57 // _yo => _yo 58 // C2_yo => c2-yo 59 // C2__yo => c2-yo 60 61 //static 62 C2String _C2EnumUtils::camelCaseToDashed(C2String name) { 63 enum { 64 kNone = '.', 65 kLower = 'a', 66 kUpper = 'A', 67 kDigit = '1', 68 kDash = '-', 69 kUnderscore = '_', 70 } type = kNone; 71 size_t word_start = 0; 72 for (size_t ix = 0; ix < name.size(); ++ix) { 73 C2_LOG(VERBOSE) << name.substr(0, word_start) << "|" 74 << name.substr(word_start, ix - word_start) << "[" 75 << name.substr(ix, 1) << "]" << name.substr(ix + 1) 76 << ": " << (char)type; 77 if (isupper(name[ix])) { 78 if (type == kLower) { 79 name.insert(ix++, 1, '-'); 80 word_start = ix; 81 } 82 name[ix] = tolower(name[ix]); 83 type = kUpper; 84 } else if (islower(name[ix])) { 85 if (type == kDigit && ix > 0) { 86 name.insert(ix++, 1, '-'); 87 word_start = ix; 88 } else if (type == kUpper && ix > word_start + 1) { 89 name.insert(ix++ - 1, 1, '-'); 90 word_start = ix - 1; 91 } 92 type = kLower; 93 } else if (isdigit(name[ix])) { 94 if (type == kLower) { 95 name.insert(ix++, 1, '-'); 96 word_start = ix; 97 } 98 type = kDigit; 99 } else if (name[ix] == '_') { 100 if (type == kDash) { 101 name.erase(ix--, 1); 102 } else if (type != kNone && type != kUnderscore) { 103 name[ix] = '-'; 104 type = kDash; 105 word_start = ix + 1; 106 } else { 107 type = kUnderscore; 108 word_start = ix + 1; 109 } 110 } else { 111 name.resize(ix); 112 } 113 } 114 C2_LOG(VERBOSE) << "=> " << name; 115 return name; 116 } 117 118 //static 119 std::vector<C2String> _C2EnumUtils::sanitizeEnumValueNames( 120 const std::vector<C2StringLiteral> names, 121 C2StringLiteral _prefix) { 122 std::vector<C2String> sanitizedNames; 123 C2String prefix; 124 size_t extraUnderscores = 0; 125 bool first = true; 126 if (_prefix) { 127 extraUnderscores = countLeadingUnderscores(_prefix); 128 prefix = _prefix + extraUnderscores; 129 first = false; 130 C2_LOG(VERBOSE) << "prefix:" << prefix << ", underscores:" << extraUnderscores; 131 } 132 133 // calculate prefix and minimum leading underscores 134 for (C2StringLiteral s : names) { 135 C2_LOG(VERBOSE) << s; 136 size_t underscores = countLeadingUnderscores(s); 137 if (first) { 138 extraUnderscores = underscores; 139 prefix = s + underscores; 140 first = false; 141 } else { 142 size_t matching = countMatching( 143 s + underscores, 144 prefix); 145 prefix.resize(matching); 146 extraUnderscores = std::min(underscores, extraUnderscores); 147 } 148 C2_LOG(VERBOSE) << "prefix:" << prefix << ", underscores:" << extraUnderscores; 149 if (prefix.size() == 0 && extraUnderscores == 0) { 150 break; 151 } 152 } 153 154 // we swallow the first underscore after upper case prefixes 155 bool upperCasePrefix = true; 156 for (size_t i = 0; i < prefix.size(); ++i) { 157 if (islower(prefix[i])) { 158 upperCasePrefix = false; 159 break; 160 } 161 } 162 163 for (C2StringLiteral s : names) { 164 size_t underscores = countLeadingUnderscores(s); 165 C2String sanitized = C2String(s, underscores - extraUnderscores); 166 sanitized.append(s + prefix.size() + underscores + 167 (upperCasePrefix && s[prefix.size() + underscores] == '_')); 168 sanitizedNames.push_back(camelCaseToDashed(sanitized)); 169 } 170 171 for (C2String s : sanitizedNames) { 172 C2_LOG(VERBOSE) << s; 173 } 174 175 return sanitizedNames; 176 } 177 178 //static 179 std::vector<C2String> _C2EnumUtils::parseEnumValuesFromString(C2StringLiteral value) { 180 std::vector<C2String> foundNames; 181 size_t pos = 0, len = strlen(value); 182 do { 183 size_t endPos = strcspn(value + pos, " ,=") + pos; 184 if (endPos > pos) { 185 foundNames.emplace_back(value + pos, endPos - pos); 186 } 187 if (value[endPos] && value[endPos] != ',') { 188 endPos += strcspn(value + endPos, ","); 189 } 190 pos = strspn(value + endPos, " ,") + endPos; 191 } while (pos < len); 192 return foundNames; 193 } 194 195 /// safe(r) parsing from parameter blob 196 //static 197 C2Param *C2ParamUtils::ParseFirst(const uint8_t *blob, size_t size) { 198 // _mSize must fit into size, but really C2Param must also to be a valid param 199 if (size < sizeof(C2Param)) { 200 return nullptr; 201 } 202 // _mSize must match length 203 C2Param *param = (C2Param*)blob; 204 if (param->size() > size) { 205 return nullptr; 206 } 207 return param; 208 } 209 210