• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }  // namespace slang
271