| /* | |
| * Copyright (C) 2015 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. | |
| */ | |
| #include <algorithm> | |
| #include <iostream> | |
| #include <sstream> | |
| #include "Utilities.h" | |
| using namespace std; | |
| const char LEGAL_NOTICE[] = | |
| "/*\n" | |
| " * Copyright (C) 2016 The Android Open Source Project\n" | |
| " *\n" | |
| " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" | |
| " * you may not use this file except in compliance with the License.\n" | |
| " * You may obtain a copy of the License at\n" | |
| " *\n" | |
| " * http://www.apache.org/licenses/LICENSE-2.0\n" | |
| " *\n" | |
| " * Unless required by applicable law or agreed to in writing, software\n" | |
| " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" | |
| " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" | |
| " * See the License for the specific language governing permissions and\n" | |
| " * limitations under the License.\n" | |
| " */\n\n"; | |
| const char AUTO_GENERATED_WARNING[] = | |
| "Don't edit this file! It is auto-generated by frameworks/rs/api/generate.sh."; | |
| string capitalize(const string& source) { | |
| int length = source.length(); | |
| string result; | |
| bool capitalize = true; | |
| for (int s = 0; s < length; s++) { | |
| if (source[s] == '_') { | |
| capitalize = true; | |
| } else if (capitalize) { | |
| result += toupper(source[s]); | |
| capitalize = false; | |
| } else { | |
| result += source[s]; | |
| } | |
| } | |
| return result; | |
| } | |
| void trimSpaces(string* s) { | |
| const size_t end = s->find_last_not_of(" "); | |
| if (end == string::npos) { | |
| // All spaces | |
| s->erase(); | |
| return; | |
| } else { | |
| s->erase(end + 1); | |
| } | |
| const size_t start = s->find_first_not_of(" "); | |
| if (start > 0) { | |
| s->erase(0, start); | |
| } | |
| } | |
| string stringReplace(string s, string match, string rep) { | |
| while (1) { | |
| // This is not efficient but we don't care, as this program runs very rarely. | |
| size_t p = s.find(match); | |
| if (p == string::npos) break; | |
| s.erase(p, match.size()); | |
| s.insert(p, rep); | |
| } | |
| return s; | |
| } | |
| bool charRemoved(char c, string* s) { | |
| size_t p = s->find(c); | |
| if (p != string::npos) { | |
| s->erase(p, 1); | |
| return true; | |
| } | |
| return false; | |
| } | |
| string stripHtml(const string& html) { | |
| string in = stringReplace(html, "<li>", "- "); | |
| string out; | |
| for (size_t start = 0; start < in.size(); start++) { | |
| size_t lt = in.find('<', start); | |
| if (lt == string::npos) { | |
| out += in.substr(start); | |
| break; | |
| } | |
| out += in.substr(start, lt - start); | |
| if (isalpha(in[lt + 1]) || in[lt + 1] == '/') { | |
| // It's an HTML tag. Search for the end. | |
| start = in.find('>', lt + 1); | |
| if (start == string::npos) { | |
| break; | |
| } | |
| } else { | |
| out += '<'; | |
| } | |
| } | |
| out = stringReplace(out, ">", ">"); | |
| out = stringReplace(out, "<", "<"); | |
| out = stringReplace(out, " ", " "); | |
| out = stringReplace(out, "&", "&"); | |
| return out; | |
| } | |
| string hashString(const string& s) { | |
| long hash = 0; | |
| for (size_t i = 0; i < s.length(); i++) { | |
| hash = hash * 43 + s[i]; | |
| } | |
| stringstream stream; | |
| stream << "0x" << std::hex << hash << "l"; | |
| return stream.str(); | |
| } | |
| bool testAndSet(const string& flag, set<string>* set) { | |
| if (set->find(flag) == set->end()) { | |
| set->insert(flag); | |
| return false; | |
| } | |
| return true; | |
| } | |
| double maxDoubleForInteger(int numberOfIntegerBits, int mantissaSize) { | |
| /* Double has only 52 bits of precision (53 implied). So for longs, we want | |
| * to create smaller values to avoid a round up. Same for floats and halfs. | |
| */ | |
| int lowZeroBits = max(0, numberOfIntegerBits - mantissaSize); | |
| unsigned long l = (0xffffffffffffffff >> (64 - numberOfIntegerBits + lowZeroBits)) | |
| << lowZeroBits; | |
| return (double)l; | |
| } | |
| // Add the value to the stream, prefixed with a ", " if needed. | |
| static void addCommaSeparated(const string& value, ostringstream* stream, bool* needComma) { | |
| if (value.empty()) { | |
| return; | |
| } | |
| if (*needComma) { | |
| *stream << ", "; | |
| } | |
| *stream << value; | |
| *needComma = true; | |
| } | |
| string makeAttributeTag(const string& userAttribute, const string& additionalAttribute, | |
| unsigned int deprecatedApiLevel, const string& deprecatedMessage) { | |
| ostringstream stream; | |
| bool needComma = false; | |
| if (userAttribute[0] == '=') { | |
| /* If starts with an equal, we don't automatically add additionalAttribute. | |
| * This is because of the error we made defining rsUnpackColor8888(). | |
| */ | |
| addCommaSeparated(userAttribute.substr(1), &stream, &needComma); | |
| } else { | |
| addCommaSeparated(userAttribute, &stream, &needComma); | |
| addCommaSeparated(additionalAttribute, &stream, &needComma); | |
| } | |
| if (deprecatedApiLevel > 0) { | |
| stream << "\n#if (defined(RS_VERSION) && (RS_VERSION >= " << deprecatedApiLevel << "))\n"; | |
| addCommaSeparated("deprecated", &stream, &needComma); | |
| if (!deprecatedMessage.empty()) { | |
| // Remove any @ that's used for generating documentation cross references. | |
| string s = deprecatedMessage; | |
| s.erase(std::remove(s.begin(), s.end(), '@'), s.end()); | |
| stream << "(\"" << s << "\")"; | |
| } | |
| stream << "\n#endif\n"; | |
| } | |
| if (stream.tellp() == 0) { | |
| return ""; | |
| } | |
| return " __attribute__((" + stream.str() + "))"; | |
| } | |
| // Opens the stream. Reports an error if it can't. | |
| bool GeneratedFile::start(const string& directory, const string& name) { | |
| const string path = directory + "/" + name; | |
| open(path.c_str(), ios::out | ios::trunc); | |
| if (!is_open()) { | |
| cerr << "Error. Can't open the output file: " << path << "\n"; | |
| return false; | |
| } | |
| return true; | |
| } | |
| void GeneratedFile::writeNotices() { | |
| *this << LEGAL_NOTICE; | |
| *this << "// " << AUTO_GENERATED_WARNING << "\n\n"; | |
| } | |
| void GeneratedFile::increaseIndent() { | |
| mIndent.append(string(TAB_SIZE, ' ')); | |
| } | |
| void GeneratedFile::decreaseIndent() { | |
| mIndent.erase(0, TAB_SIZE); | |
| } |