1 /*
2  * Copyright (C) 2015 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 #include <algorithm>
18 #include <iostream>
19 #include <sstream>
20 
21 #include "Utilities.h"
22 
23 using namespace std;
24 
25 const char LEGAL_NOTICE[] =
26             "/*\n"
27             " * Copyright (C) 2016 The Android Open Source Project\n"
28             " *\n"
29             " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
30             " * you may not use this file except in compliance with the License.\n"
31             " * You may obtain a copy of the License at\n"
32             " *\n"
33             " *      http://www.apache.org/licenses/LICENSE-2.0\n"
34             " *\n"
35             " * Unless required by applicable law or agreed to in writing, software\n"
36             " * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
37             " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
38             " * See the License for the specific language governing permissions and\n"
39             " * limitations under the License.\n"
40             " */\n\n";
41 
42 const char AUTO_GENERATED_WARNING[] =
43             "Don't edit this file!  It is auto-generated by frameworks/rs/api/generate.sh.";
44 
capitalize(const string & source)45 string capitalize(const string& source) {
46     int length = source.length();
47     string result;
48     bool capitalize = true;
49     for (int s = 0; s < length; s++) {
50         if (source[s] == '_') {
51             capitalize = true;
52         } else if (capitalize) {
53             result += toupper(source[s]);
54             capitalize = false;
55         } else {
56             result += source[s];
57         }
58     }
59     return result;
60 }
61 
trimSpaces(string * s)62 void trimSpaces(string* s) {
63     const size_t end = s->find_last_not_of(" ");
64     if (end == string::npos) {
65         // All spaces
66         s->erase();
67         return;
68     } else {
69         s->erase(end + 1);
70     }
71     const size_t start = s->find_first_not_of(" ");
72     if (start > 0) {
73         s->erase(0, start);
74     }
75 }
76 
stringReplace(string s,string match,string rep)77 string stringReplace(string s, string match, string rep) {
78     while (1) {
79         // This is not efficient but we don't care, as this program runs very rarely.
80         size_t p = s.find(match);
81         if (p == string::npos) break;
82 
83         s.erase(p, match.size());
84         s.insert(p, rep);
85     }
86     return s;
87 }
88 
charRemoved(char c,string * s)89 bool charRemoved(char c, string* s) {
90     size_t p = s->find(c);
91     if (p != string::npos) {
92         s->erase(p, 1);
93         return true;
94     }
95     return false;
96 }
97 
stripHtml(const string & html)98 string stripHtml(const string& html) {
99     string in = stringReplace(html, "<li>", "- ");
100     string out;
101     for (size_t start = 0; start < in.size(); start++) {
102         size_t lt = in.find('<', start);
103         if (lt == string::npos) {
104             out += in.substr(start);
105             break;
106         }
107         out += in.substr(start, lt - start);
108         if (isalpha(in[lt + 1]) || in[lt + 1] == '/') {
109             // It's an HTML tag.  Search for the end.
110             start = in.find('>', lt + 1);
111             if (start == string::npos) {
112                 break;
113             }
114         } else {
115             out += '<';
116         }
117     }
118     out = stringReplace(out, "&gt;", ">");
119     out = stringReplace(out, "&lt;", "<");
120     out = stringReplace(out, "&nbsp;", " ");
121     out = stringReplace(out, "&amp;", "&");
122     return out;
123 }
124 
hashString(const string & s)125 string hashString(const string& s) {
126     long hash = 0;
127     for (size_t i = 0; i < s.length(); i++) {
128         hash = hash * 43 + s[i];
129     }
130     stringstream stream;
131     stream << "0x" << std::hex << hash << "l";
132     return stream.str();
133 }
134 
testAndSet(const string & flag,set<string> * set)135 bool testAndSet(const string& flag, set<string>* set) {
136     if (set->find(flag) == set->end()) {
137         set->insert(flag);
138         return false;
139     }
140     return true;
141 }
142 
maxDoubleForInteger(int numberOfIntegerBits,int mantissaSize)143 double maxDoubleForInteger(int numberOfIntegerBits, int mantissaSize) {
144     /* Double has only 52 bits of precision (53 implied). So for longs, we want
145      * to create smaller values to avoid a round up.  Same for floats and halfs.
146      */
147     int lowZeroBits = max(0, numberOfIntegerBits - mantissaSize);
148     uint64_t l = (0xffffffffffffffff >> (64 - numberOfIntegerBits + lowZeroBits))
149                  << lowZeroBits;
150     return (double)l;
151 }
152 
153 // Add the value to the stream, prefixed with a ", " if needed.
addCommaSeparated(const string & value,ostringstream * stream,bool * needComma)154 static void addCommaSeparated(const string& value, ostringstream* stream, bool* needComma) {
155     if (value.empty()) {
156         return;
157     }
158     if (*needComma) {
159         *stream << ", ";
160     }
161     *stream << value;
162     *needComma = true;
163 }
164 
makeAttributeTag(const string & userAttribute,const string & additionalAttribute,unsigned int deprecatedApiLevel,const string & deprecatedMessage)165 string makeAttributeTag(const string& userAttribute, const string& additionalAttribute,
166                         unsigned int deprecatedApiLevel, const string& deprecatedMessage) {
167     ostringstream stream;
168     bool needComma = false;
169     if (userAttribute[0] == '=') {
170         /* If starts with an equal, we don't automatically add additionalAttribute.
171          * This is because of the error we made defining rsUnpackColor8888().
172          */
173         addCommaSeparated(userAttribute.substr(1), &stream, &needComma);
174     } else {
175         addCommaSeparated(userAttribute, &stream, &needComma);
176         addCommaSeparated(additionalAttribute, &stream, &needComma);
177     }
178     if (deprecatedApiLevel > 0) {
179         stream << "\n#if (defined(RS_VERSION) && (RS_VERSION >= " << deprecatedApiLevel << "))\n";
180         addCommaSeparated("deprecated", &stream, &needComma);
181         if (!deprecatedMessage.empty()) {
182             // Remove any @ that's used for generating documentation cross references.
183             string s = deprecatedMessage;
184             s.erase(std::remove(s.begin(), s.end(), '@'), s.end());
185             stream << "(\"" << s << "\")";
186         }
187         stream << "\n#endif\n";
188     }
189     if (stream.tellp() == 0) {
190         return "";
191     }
192     return " __attribute__((" + stream.str() + "))";
193 }
194 
195 // Opens the stream.  Reports an error if it can't.
start(const string & directory,const string & name)196 bool GeneratedFile::start(const string& directory, const string& name) {
197     const string path = directory + "/" + name;
198     open(path.c_str(), ios::out | ios::trunc);
199     if (!is_open()) {
200         cerr << "Error.  Can't open the output file: " << path << "\n";
201         return false;
202     }
203     return true;
204 }
205 
writeNotices()206 void GeneratedFile::writeNotices() {
207     *this << LEGAL_NOTICE;
208     *this << "// " << AUTO_GENERATED_WARNING << "\n\n";
209 }
210 
increaseIndent()211 void GeneratedFile::increaseIndent() {
212     mIndent.append(string(TAB_SIZE, ' '));
213 }
214 
decreaseIndent()215 void GeneratedFile::decreaseIndent() {
216     mIndent.erase(0, TAB_SIZE);
217 }
218