blob: 94fb8b0dd3a912d93a394f3c623bf2fd3211aa47 [file] [log] [blame]
zonr6315f762010-10-05 15:35:14 +08001#include "slang_rs_reflect_utils.h"
Ying Wang3f8b44d2010-09-04 01:17:01 -07002
Ying Wang3f8b44d2010-09-04 01:17:01 -07003#include <cstdio>
Mike Lockwoodb1980a22010-09-08 10:20:40 -04004#include <cstring>
Ying Wang3f8b44d2010-09-04 01:17:01 -07005
Zonr Chang8c6d9b22010-10-07 18:01:19 +08006#include "llvm/ADT/StringRef.h"
7
8#include "slang_utils.h"
Ying Wang3f8b44d2010-09-04 01:17:01 -07009
10namespace slang {
11
12using std::string;
13
Ying Wangdba31112010-10-07 17:30:38 -070014string RSSlangReflectUtils::GetFileNameStem(const char* fileName) {
15 const char *dot = fileName + strlen(fileName);
16 const char *slash = dot - 1;
17 while (slash >= fileName) {
18 if (*slash == '/') {
19 break;
20 }
21 if ((*slash == '.') && (*dot == 0)) {
22 dot = slash;
23 }
24 --slash;
25 }
26 ++slash;
27 return string(slash, dot - slash);
28}
29
Ying Wang3f8b44d2010-09-04 01:17:01 -070030string RSSlangReflectUtils::ComputePackagedPath(
zonr6315f762010-10-05 15:35:14 +080031 const char *prefixPath, const char *packageName) {
Ying Wang3f8b44d2010-09-04 01:17:01 -070032 string packaged_path(prefixPath);
zonr6315f762010-10-05 15:35:14 +080033 if (!packaged_path.empty() &&
34 (packaged_path[packaged_path.length() - 1] != '/')) {
Ying Wang3f8b44d2010-09-04 01:17:01 -070035 packaged_path += "/";
36 }
37 size_t s = packaged_path.length();
38 packaged_path += packageName;
39 while (s < packaged_path.length()) {
40 if (packaged_path[s] == '.') {
41 packaged_path[s] = '/';
42 }
43 ++s;
44 }
45 return packaged_path;
46}
47
zonr6315f762010-10-05 15:35:14 +080048static string InternalFileNameConvert(const char *rsFileName, bool toLower) {
49 const char *dot = rsFileName + strlen(rsFileName);
50 const char *slash = dot - 1;
Ying Wang3f8b44d2010-09-04 01:17:01 -070051 while (slash >= rsFileName) {
52 if (*slash == '/') {
53 break;
54 }
55 if ((*slash == '.') && (*dot == 0)) {
56 dot = slash;
57 }
58 --slash;
59 }
60 ++slash;
61 char ret[256];
Ying Wang3f8b44d2010-09-04 01:17:01 -070062 int i = 0;
63 for (; (i < 255) && (slash < dot); ++slash) {
Stephen Hinesd4176402010-09-16 17:14:35 -070064 if (isalnum(*slash) || *slash == '_') {
65 if (toLower) {
66 ret[i] = tolower(*slash);
Ying Wang3f8b44d2010-09-04 01:17:01 -070067 } else {
68 ret[i] = *slash;
69 }
Ying Wang3f8b44d2010-09-04 01:17:01 -070070 ++i;
Ying Wang3f8b44d2010-09-04 01:17:01 -070071 }
72 }
73 ret[i] = 0;
74 return string(ret);
75}
76
77std::string RSSlangReflectUtils::JavaClassNameFromRSFileName(
zonr6315f762010-10-05 15:35:14 +080078 const char *rsFileName) {
Stephen Hinesd4176402010-09-16 17:14:35 -070079 return InternalFileNameConvert(rsFileName, false);
Ying Wang3f8b44d2010-09-04 01:17:01 -070080}
81
82
83std::string RSSlangReflectUtils::BCFileNameFromRSFileName(
zonr6315f762010-10-05 15:35:14 +080084 const char *rsFileName) {
Stephen Hinesd4176402010-09-16 17:14:35 -070085 return InternalFileNameConvert(rsFileName, true);
Ying Wang3f8b44d2010-09-04 01:17:01 -070086}
87
Ying Wang0877f052010-09-09 17:19:33 -070088static bool GenerateAccessorHeader(
zonr6315f762010-10-05 15:35:14 +080089 const RSSlangReflectUtils::BitCodeAccessorContext &context, FILE *pfout) {
Ying Wang0877f052010-09-09 17:19:33 -070090 fprintf(pfout, "/*\n");
91 fprintf(pfout, " * This file is auto-generated. DO NOT MODIFY!\n");
92 fprintf(pfout, " * The source RenderScript file: %s\n", context.rsFileName);
93 fprintf(pfout, " */\n\n");
94 fprintf(pfout, "package %s;\n\n", context.packageName);
Ying Wang3f8b44d2010-09-04 01:17:01 -070095
Ying Wang0877f052010-09-09 17:19:33 -070096 // add imports here.
97
98 return true;
99}
100
101static bool GenerateAccessorMethodSignature(
zonr6315f762010-10-05 15:35:14 +0800102 const RSSlangReflectUtils::BitCodeAccessorContext &context, FILE *pfout) {
Ying Wang0877f052010-09-09 17:19:33 -0700103 // the prototype of the accessor method
104 fprintf(pfout, " // return byte array representation of the bitcode.\n");
105 fprintf(pfout, " public static byte[] getBitCode() {\n");
106 return true;
107}
108
109// Java method size must not exceed 64k,
110// so we have to split the bitcode into multiple segments.
111static bool GenerateSegmentMethod(
zonr6315f762010-10-05 15:35:14 +0800112 const char *buff, int blen, int seg_num, FILE *pfout) {
Ying Wang0877f052010-09-09 17:19:33 -0700113
114 fprintf(pfout, " private static byte[] getSegment_%d() {\n", seg_num);
115 fprintf(pfout, " byte[] data = {\n");
116
zonr6315f762010-10-05 15:35:14 +0800117 static const int LINE_BYTE_NUM = 16;
Ying Wang0877f052010-09-09 17:19:33 -0700118 char out_line[LINE_BYTE_NUM*6 + 10];
zonr6315f762010-10-05 15:35:14 +0800119 const char *out_line_end = out_line + sizeof(out_line);
120 char *p = out_line;
Ying Wang0877f052010-09-09 17:19:33 -0700121
122 int write_length = 0;
123 while (write_length < blen) {
zonr6315f762010-10-05 15:35:14 +0800124 p += snprintf(p, out_line_end - p,
125 " %4d,", static_cast<int>(buff[write_length]));
Ying Wang0877f052010-09-09 17:19:33 -0700126 ++write_length;
127 if (((write_length % LINE_BYTE_NUM) == 0)
128 || (write_length == blen)) {
129 fprintf(pfout, " ");
Stephen Hines24f9b092010-10-06 12:58:40 -0700130 fprintf(pfout, "%s", out_line);
Ying Wang0877f052010-09-09 17:19:33 -0700131 fprintf(pfout, "\n");
132 p = out_line;
133 }
134 }
135
136 fprintf(pfout, " };\n");
137 fprintf(pfout, " return data;\n");
138 fprintf(pfout, " }\n\n");
139
140 return true;
141}
142
143static bool GenerateJavaCodeAccessorMethod(
zonr6315f762010-10-05 15:35:14 +0800144 const RSSlangReflectUtils::BitCodeAccessorContext &context, FILE *pfout) {
145 FILE *pfin = fopen(context.bcFileName, "rb");
Ying Wang3f8b44d2010-09-04 01:17:01 -0700146 if (pfin == NULL) {
Ying Wang0877f052010-09-09 17:19:33 -0700147 fprintf(stderr, "Error: could not read file %s\n", context.bcFileName);
Ying Wang3f8b44d2010-09-04 01:17:01 -0700148 return false;
149 }
150
Ying Wang0877f052010-09-09 17:19:33 -0700151 // start the accessor method
152 GenerateAccessorMethodSignature(context, pfout);
153 fprintf(pfout, " return getBitCodeInternal();\n");
154 // end the accessor method
155 fprintf(pfout, " };\n\n");
156
157 // output the data
158 // make sure the generated function for a segment won't break the Javac
159 // size limitation (64K).
zonr6315f762010-10-05 15:35:14 +0800160 static const int SEG_SIZE = 0x2000;
161 char *buff = new char[SEG_SIZE];
Ying Wang0877f052010-09-09 17:19:33 -0700162 int read_length;
163 int seg_num = 0;
164 int total_length = 0;
165 while ((read_length = fread(buff, 1, SEG_SIZE, pfin)) > 0) {
166 GenerateSegmentMethod(buff, read_length, seg_num, pfout);
167 ++seg_num;
168 total_length += read_length;
169 }
170 delete []buff;
171 fclose(pfin);
172
173 // output the internal accessor method
174 fprintf(pfout, " private static int bitCodeLength = %d;\n\n", total_length);
175 fprintf(pfout, " private static byte[] getBitCodeInternal() {\n");
176 fprintf(pfout, " byte[] bc = new byte[bitCodeLength];\n");
177 fprintf(pfout, " int offset = 0;\n");
178 fprintf(pfout, " byte[] seg;\n");
179 for (int i = 0; i < seg_num; ++i) {
180 fprintf(pfout, " seg = getSegment_%d();\n", i);
181 fprintf(pfout, " System.arraycopy(seg, 0, bc, offset, seg.length);\n");
182 fprintf(pfout, " offset += seg.length;\n");
183 }
184 fprintf(pfout, " return bc;\n");
185 fprintf(pfout, " }\n\n");
186
187 return true;
188}
189
190static bool GenerateAccessorClass(
zonr6315f762010-10-05 15:35:14 +0800191 const RSSlangReflectUtils::BitCodeAccessorContext &context,
192 const char *clazz_name, FILE *pfout) {
Ying Wang0877f052010-09-09 17:19:33 -0700193 // begin the class.
194 fprintf(pfout, "/**\n");
195 fprintf(pfout, " * @hide\n");
196 fprintf(pfout, " */\n");
197 fprintf(pfout, "public class %s {\n", clazz_name);
198 fprintf(pfout, "\n");
199
200 bool ret = true;
201 switch (context.bcStorage) {
202 case BCST_APK_RESOURCE:
203 break;
204 case BCST_JAVA_CODE:
205 ret = GenerateJavaCodeAccessorMethod(context, pfout);
206 break;
207 default:
208 ret = false;
Ying Wang3f8b44d2010-09-04 01:17:01 -0700209 }
210
Ying Wang0877f052010-09-09 17:19:33 -0700211 // end the class.
212 fprintf(pfout, "}\n");
213
214 return ret;
215}
216
217
218bool RSSlangReflectUtils::GenerateBitCodeAccessor(
zonr6315f762010-10-05 15:35:14 +0800219 const BitCodeAccessorContext &context) {
Ying Wang0877f052010-09-09 17:19:33 -0700220 string output_path = ComputePackagedPath(context.reflectPath,
221 context.packageName);
Zonr Chang8c6d9b22010-10-07 18:01:19 +0800222 if (!SlangUtils::CreateDirectoryWithParents(llvm::StringRef(output_path),
223 NULL)) {
Ying Wang0877f052010-09-09 17:19:33 -0700224 fprintf(stderr, "Error: could not create dir %s\n",
225 output_path.c_str());
226 return false;
227 }
228
229 string clazz_name(JavaClassNameFromRSFileName(context.rsFileName));
Ying Wang3f8b44d2010-09-04 01:17:01 -0700230 clazz_name += "BitCode";
231 string filename(clazz_name);
232 filename += ".java";
233
234 string output_filename(output_path);
235 output_filename += "/";
236 output_filename += filename;
237 printf("Generating %s ...\n", filename.c_str());
zonr6315f762010-10-05 15:35:14 +0800238 FILE *pfout = fopen(output_filename.c_str(), "w");
Ying Wang3f8b44d2010-09-04 01:17:01 -0700239 if (pfout == NULL) {
Ying Wang0877f052010-09-09 17:19:33 -0700240 fprintf(stderr, "Error: could not write to file %s\n",
241 output_filename.c_str());
Ying Wang3f8b44d2010-09-04 01:17:01 -0700242 return false;
243 }
244
zonr6315f762010-10-05 15:35:14 +0800245 bool ret = GenerateAccessorHeader(context, pfout) &&
246 GenerateAccessorClass(context, clazz_name.c_str(), pfout);
Ying Wang3f8b44d2010-09-04 01:17:01 -0700247
Ying Wang3f8b44d2010-09-04 01:17:01 -0700248 fclose(pfout);
Ying Wang0877f052010-09-09 17:19:33 -0700249 return ret;
Ying Wang3f8b44d2010-09-04 01:17:01 -0700250}
Ying Wang3f8b44d2010-09-04 01:17:01 -0700251}