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
countLeadingUnderscores(C2StringLiteral a)33 static size_t countLeadingUnderscores(C2StringLiteral a) {
34 size_t i = 0;
35 while (a[i] == '_') {
36 ++i;
37 }
38 return i;
39 }
40
countMatching(C2StringLiteral a,const C2String & b)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
camelCaseToDashed(C2String name)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
sanitizeEnumValueNames(const std::vector<C2StringLiteral> names,C2StringLiteral _prefix)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
parseEnumValuesFromString(C2StringLiteral value)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
ParseFirst(const uint8_t * blob,size_t size)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