1 /*
2 * Copyright 2010, 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 "slang_rs_reflect_utils.h"
18
19 #include <cstdio>
20 #include <cstring>
21 #include <string>
22
23 #include "llvm/ADT/StringRef.h"
24
25 #include "os_sep.h"
26 #include "slang_utils.h"
27
28 namespace slang {
29
30 using std::string;
31
GetFileNameStem(const char * fileName)32 string RSSlangReflectUtils::GetFileNameStem(const char* fileName) {
33 const char *dot = fileName + strlen(fileName);
34 const char *slash = dot - 1;
35 while (slash >= fileName) {
36 if (*slash == OS_PATH_SEPARATOR) {
37 break;
38 }
39 if ((*slash == '.') && (*dot == 0)) {
40 dot = slash;
41 }
42 --slash;
43 }
44 ++slash;
45 return string(slash, dot - slash);
46 }
47
ComputePackagedPath(const char * prefixPath,const char * packageName)48 string RSSlangReflectUtils::ComputePackagedPath(
49 const char *prefixPath, const char *packageName) {
50 string packaged_path(prefixPath);
51 if (!packaged_path.empty() &&
52 (packaged_path[packaged_path.length() - 1] != OS_PATH_SEPARATOR)) {
53 packaged_path += OS_PATH_SEPARATOR_STR;
54 }
55 size_t s = packaged_path.length();
56 packaged_path += packageName;
57 while (s < packaged_path.length()) {
58 if (packaged_path[s] == '.') {
59 packaged_path[s] = OS_PATH_SEPARATOR;
60 }
61 ++s;
62 }
63 return packaged_path;
64 }
65
InternalFileNameConvert(const char * rsFileName,bool toLower)66 static string InternalFileNameConvert(const char *rsFileName, bool toLower) {
67 const char *dot = rsFileName + strlen(rsFileName);
68 const char *slash = dot - 1;
69 while (slash >= rsFileName) {
70 if (*slash == OS_PATH_SEPARATOR) {
71 break;
72 }
73 if ((*slash == '.') && (*dot == 0)) {
74 dot = slash;
75 }
76 --slash;
77 }
78 ++slash;
79 char ret[256];
80 int i = 0;
81 for (; (i < 255) && (slash < dot); ++slash) {
82 if (isalnum(*slash) || *slash == '_') {
83 if (toLower) {
84 ret[i] = tolower(*slash);
85 } else {
86 ret[i] = *slash;
87 }
88 ++i;
89 }
90 }
91 ret[i] = 0;
92 return string(ret);
93 }
94
JavaClassNameFromRSFileName(const char * rsFileName)95 std::string RSSlangReflectUtils::JavaClassNameFromRSFileName(
96 const char *rsFileName) {
97 return InternalFileNameConvert(rsFileName, false);
98 }
99
100
BCFileNameFromRSFileName(const char * rsFileName)101 std::string RSSlangReflectUtils::BCFileNameFromRSFileName(
102 const char *rsFileName) {
103 return InternalFileNameConvert(rsFileName, true);
104 }
105
GenerateAccessorHeader(const RSSlangReflectUtils::BitCodeAccessorContext & context,FILE * pfout)106 static bool GenerateAccessorHeader(
107 const RSSlangReflectUtils::BitCodeAccessorContext &context, FILE *pfout) {
108 fprintf(pfout, "/*\n");
109 fprintf(pfout, " * This file is auto-generated. DO NOT MODIFY!\n");
110 fprintf(pfout, " * The source Renderscript file: %s\n", context.rsFileName);
111 fprintf(pfout, " */\n\n");
112 fprintf(pfout, "package %s;\n\n", context.packageName);
113
114 // add imports here.
115
116 return true;
117 }
118
GenerateAccessorMethodSignature(const RSSlangReflectUtils::BitCodeAccessorContext & context,FILE * pfout)119 static bool GenerateAccessorMethodSignature(
120 const RSSlangReflectUtils::BitCodeAccessorContext &context, FILE *pfout) {
121 // the prototype of the accessor method
122 fprintf(pfout, " // return byte array representation of the bitcode.\n");
123 fprintf(pfout, " public static byte[] getBitCode() {\n");
124 return true;
125 }
126
127 // Java method size must not exceed 64k,
128 // so we have to split the bitcode into multiple segments.
GenerateSegmentMethod(const char * buff,int blen,int seg_num,FILE * pfout)129 static bool GenerateSegmentMethod(
130 const char *buff, int blen, int seg_num, FILE *pfout) {
131
132 fprintf(pfout, " private static byte[] getSegment_%d() {\n", seg_num);
133 fprintf(pfout, " byte[] data = {\n");
134
135 static const int LINE_BYTE_NUM = 16;
136 char out_line[LINE_BYTE_NUM*6 + 10];
137 const char *out_line_end = out_line + sizeof(out_line);
138 char *p = out_line;
139
140 int write_length = 0;
141 while (write_length < blen) {
142 p += snprintf(p, out_line_end - p,
143 " %4d,", static_cast<int>(buff[write_length]));
144 ++write_length;
145 if (((write_length % LINE_BYTE_NUM) == 0)
146 || (write_length == blen)) {
147 fprintf(pfout, " ");
148 fprintf(pfout, "%s", out_line);
149 fprintf(pfout, "\n");
150 p = out_line;
151 }
152 }
153
154 fprintf(pfout, " };\n");
155 fprintf(pfout, " return data;\n");
156 fprintf(pfout, " }\n\n");
157
158 return true;
159 }
160
GenerateJavaCodeAccessorMethod(const RSSlangReflectUtils::BitCodeAccessorContext & context,FILE * pfout)161 static bool GenerateJavaCodeAccessorMethod(
162 const RSSlangReflectUtils::BitCodeAccessorContext &context, FILE *pfout) {
163 FILE *pfin = fopen(context.bcFileName, "rb");
164 if (pfin == NULL) {
165 fprintf(stderr, "Error: could not read file %s\n", context.bcFileName);
166 return false;
167 }
168
169 // start the accessor method
170 GenerateAccessorMethodSignature(context, pfout);
171 fprintf(pfout, " return getBitCodeInternal();\n");
172 // end the accessor method
173 fprintf(pfout, " };\n\n");
174
175 // output the data
176 // make sure the generated function for a segment won't break the Javac
177 // size limitation (64K).
178 static const int SEG_SIZE = 0x2000;
179 char *buff = new char[SEG_SIZE];
180 int read_length;
181 int seg_num = 0;
182 int total_length = 0;
183 while ((read_length = fread(buff, 1, SEG_SIZE, pfin)) > 0) {
184 GenerateSegmentMethod(buff, read_length, seg_num, pfout);
185 ++seg_num;
186 total_length += read_length;
187 }
188 delete []buff;
189 fclose(pfin);
190
191 // output the internal accessor method
192 fprintf(pfout, " private static int bitCodeLength = %d;\n\n",
193 total_length);
194 fprintf(pfout, " private static byte[] getBitCodeInternal() {\n");
195 fprintf(pfout, " byte[] bc = new byte[bitCodeLength];\n");
196 fprintf(pfout, " int offset = 0;\n");
197 fprintf(pfout, " byte[] seg;\n");
198 for (int i = 0; i < seg_num; ++i) {
199 fprintf(pfout, " seg = getSegment_%d();\n", i);
200 fprintf(pfout, " System.arraycopy(seg, 0, bc, offset, seg.length);\n");
201 fprintf(pfout, " offset += seg.length;\n");
202 }
203 fprintf(pfout, " return bc;\n");
204 fprintf(pfout, " }\n\n");
205
206 return true;
207 }
208
GenerateAccessorClass(const RSSlangReflectUtils::BitCodeAccessorContext & context,const char * clazz_name,FILE * pfout)209 static bool GenerateAccessorClass(
210 const RSSlangReflectUtils::BitCodeAccessorContext &context,
211 const char *clazz_name, FILE *pfout) {
212 // begin the class.
213 fprintf(pfout, "/**\n");
214 fprintf(pfout, " * @hide\n");
215 fprintf(pfout, " */\n");
216 fprintf(pfout, "public class %s {\n", clazz_name);
217 fprintf(pfout, "\n");
218
219 bool ret = true;
220 switch (context.bcStorage) {
221 case BCST_APK_RESOURCE:
222 break;
223 case BCST_JAVA_CODE:
224 ret = GenerateJavaCodeAccessorMethod(context, pfout);
225 break;
226 default:
227 ret = false;
228 }
229
230 // end the class.
231 fprintf(pfout, "}\n");
232
233 return ret;
234 }
235
236
GenerateBitCodeAccessor(const BitCodeAccessorContext & context)237 bool RSSlangReflectUtils::GenerateBitCodeAccessor(
238 const BitCodeAccessorContext &context) {
239 string output_path = ComputePackagedPath(context.reflectPath,
240 context.packageName);
241 if (!SlangUtils::CreateDirectoryWithParents(llvm::StringRef(output_path),
242 NULL)) {
243 fprintf(stderr, "Error: could not create dir %s\n",
244 output_path.c_str());
245 return false;
246 }
247
248 string clazz_name(JavaClassNameFromRSFileName(context.rsFileName));
249 clazz_name += "BitCode";
250 string filename(clazz_name);
251 filename += ".java";
252
253 string output_filename(output_path);
254 output_filename += OS_PATH_SEPARATOR_STR;
255 output_filename += filename;
256 printf("Generating %s ...\n", filename.c_str());
257 FILE *pfout = fopen(output_filename.c_str(), "w");
258 if (pfout == NULL) {
259 fprintf(stderr, "Error: could not write to file %s\n",
260 output_filename.c_str());
261 return false;
262 }
263
264 bool ret = GenerateAccessorHeader(context, pfout) &&
265 GenerateAccessorClass(context, clazz_name.c_str(), pfout);
266
267 fclose(pfout);
268 return ret;
269 }
270 }
271