blob: 32980265aa10105f5695f246ae9b7d4c424a9dd5 [file] [log] [blame]
Zonr Changc383a502010-10-12 01:52:08 +08001/*
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
zonr6315f762010-10-05 15:35:14 +080017#include "slang_rs_reflect_utils.h"
Ying Wang3f8b44d2010-09-04 01:17:01 -070018
Ying Wang3f8b44d2010-09-04 01:17:01 -070019#include <cstdio>
Mike Lockwoodb1980a22010-09-08 10:20:40 -040020#include <cstring>
Stephen Hinese639eb52010-11-08 19:27:20 -080021#include <string>
Ying Wang3f8b44d2010-09-04 01:17:01 -070022
Zonr Chang8c6d9b22010-10-07 18:01:19 +080023#include "llvm/ADT/StringRef.h"
24
Raphael8d5a2f62011-02-08 00:15:05 -080025#include "os_sep.h"
Zonr Chang8c6d9b22010-10-07 18:01:19 +080026#include "slang_utils.h"
Ying Wang3f8b44d2010-09-04 01:17:01 -070027
28namespace slang {
29
30using std::string;
31
Ying Wangdba31112010-10-07 17:30:38 -070032string RSSlangReflectUtils::GetFileNameStem(const char* fileName) {
33 const char *dot = fileName + strlen(fileName);
34 const char *slash = dot - 1;
35 while (slash >= fileName) {
Raphael8d5a2f62011-02-08 00:15:05 -080036 if (*slash == OS_PATH_SEPARATOR) {
Ying Wangdba31112010-10-07 17:30:38 -070037 break;
38 }
39 if ((*slash == '.') && (*dot == 0)) {
40 dot = slash;
41 }
42 --slash;
43 }
44 ++slash;
45 return string(slash, dot - slash);
46}
47
Ying Wang3f8b44d2010-09-04 01:17:01 -070048string RSSlangReflectUtils::ComputePackagedPath(
zonr6315f762010-10-05 15:35:14 +080049 const char *prefixPath, const char *packageName) {
Ying Wang3f8b44d2010-09-04 01:17:01 -070050 string packaged_path(prefixPath);
zonr6315f762010-10-05 15:35:14 +080051 if (!packaged_path.empty() &&
Raphael8d5a2f62011-02-08 00:15:05 -080052 (packaged_path[packaged_path.length() - 1] != OS_PATH_SEPARATOR)) {
53 packaged_path += OS_PATH_SEPARATOR_STR;
Ying Wang3f8b44d2010-09-04 01:17:01 -070054 }
55 size_t s = packaged_path.length();
56 packaged_path += packageName;
57 while (s < packaged_path.length()) {
58 if (packaged_path[s] == '.') {
Raphael8d5a2f62011-02-08 00:15:05 -080059 packaged_path[s] = OS_PATH_SEPARATOR;
Ying Wang3f8b44d2010-09-04 01:17:01 -070060 }
61 ++s;
62 }
63 return packaged_path;
64}
65
zonr6315f762010-10-05 15:35:14 +080066static string InternalFileNameConvert(const char *rsFileName, bool toLower) {
67 const char *dot = rsFileName + strlen(rsFileName);
68 const char *slash = dot - 1;
Ying Wang3f8b44d2010-09-04 01:17:01 -070069 while (slash >= rsFileName) {
Raphael8d5a2f62011-02-08 00:15:05 -080070 if (*slash == OS_PATH_SEPARATOR) {
Ying Wang3f8b44d2010-09-04 01:17:01 -070071 break;
72 }
73 if ((*slash == '.') && (*dot == 0)) {
74 dot = slash;
75 }
76 --slash;
77 }
78 ++slash;
79 char ret[256];
Ying Wang3f8b44d2010-09-04 01:17:01 -070080 int i = 0;
81 for (; (i < 255) && (slash < dot); ++slash) {
Stephen Hinesd4176402010-09-16 17:14:35 -070082 if (isalnum(*slash) || *slash == '_') {
83 if (toLower) {
84 ret[i] = tolower(*slash);
Ying Wang3f8b44d2010-09-04 01:17:01 -070085 } else {
86 ret[i] = *slash;
87 }
Ying Wang3f8b44d2010-09-04 01:17:01 -070088 ++i;
Ying Wang3f8b44d2010-09-04 01:17:01 -070089 }
90 }
91 ret[i] = 0;
92 return string(ret);
93}
94
95std::string RSSlangReflectUtils::JavaClassNameFromRSFileName(
zonr6315f762010-10-05 15:35:14 +080096 const char *rsFileName) {
Stephen Hinesd4176402010-09-16 17:14:35 -070097 return InternalFileNameConvert(rsFileName, false);
Ying Wang3f8b44d2010-09-04 01:17:01 -070098}
99
100
101std::string RSSlangReflectUtils::BCFileNameFromRSFileName(
zonr6315f762010-10-05 15:35:14 +0800102 const char *rsFileName) {
Stephen Hinesd4176402010-09-16 17:14:35 -0700103 return InternalFileNameConvert(rsFileName, true);
Ying Wang3f8b44d2010-09-04 01:17:01 -0700104}
105
Ying Wang0877f052010-09-09 17:19:33 -0700106static bool GenerateAccessorHeader(
zonr6315f762010-10-05 15:35:14 +0800107 const RSSlangReflectUtils::BitCodeAccessorContext &context, FILE *pfout) {
Ying Wang0877f052010-09-09 17:19:33 -0700108 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);
Ying Wang3f8b44d2010-09-04 01:17:01 -0700113
Ying Wang0877f052010-09-09 17:19:33 -0700114 // add imports here.
115
116 return true;
117}
118
119static bool GenerateAccessorMethodSignature(
zonr6315f762010-10-05 15:35:14 +0800120 const RSSlangReflectUtils::BitCodeAccessorContext &context, FILE *pfout) {
Ying Wang0877f052010-09-09 17:19:33 -0700121 // 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.
129static bool GenerateSegmentMethod(
zonr6315f762010-10-05 15:35:14 +0800130 const char *buff, int blen, int seg_num, FILE *pfout) {
Ying Wang0877f052010-09-09 17:19:33 -0700131
132 fprintf(pfout, " private static byte[] getSegment_%d() {\n", seg_num);
133 fprintf(pfout, " byte[] data = {\n");
134
zonr6315f762010-10-05 15:35:14 +0800135 static const int LINE_BYTE_NUM = 16;
Ying Wang0877f052010-09-09 17:19:33 -0700136 char out_line[LINE_BYTE_NUM*6 + 10];
zonr6315f762010-10-05 15:35:14 +0800137 const char *out_line_end = out_line + sizeof(out_line);
138 char *p = out_line;
Ying Wang0877f052010-09-09 17:19:33 -0700139
140 int write_length = 0;
141 while (write_length < blen) {
zonr6315f762010-10-05 15:35:14 +0800142 p += snprintf(p, out_line_end - p,
143 " %4d,", static_cast<int>(buff[write_length]));
Ying Wang0877f052010-09-09 17:19:33 -0700144 ++write_length;
145 if (((write_length % LINE_BYTE_NUM) == 0)
146 || (write_length == blen)) {
147 fprintf(pfout, " ");
Stephen Hines24f9b092010-10-06 12:58:40 -0700148 fprintf(pfout, "%s", out_line);
Ying Wang0877f052010-09-09 17:19:33 -0700149 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
161static bool GenerateJavaCodeAccessorMethod(
zonr6315f762010-10-05 15:35:14 +0800162 const RSSlangReflectUtils::BitCodeAccessorContext &context, FILE *pfout) {
163 FILE *pfin = fopen(context.bcFileName, "rb");
Ying Wang3f8b44d2010-09-04 01:17:01 -0700164 if (pfin == NULL) {
Ying Wang0877f052010-09-09 17:19:33 -0700165 fprintf(stderr, "Error: could not read file %s\n", context.bcFileName);
Ying Wang3f8b44d2010-09-04 01:17:01 -0700166 return false;
167 }
168
Ying Wang0877f052010-09-09 17:19:33 -0700169 // 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).
zonr6315f762010-10-05 15:35:14 +0800178 static const int SEG_SIZE = 0x2000;
179 char *buff = new char[SEG_SIZE];
Ying Wang0877f052010-09-09 17:19:33 -0700180 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
Stephen Hinese639eb52010-11-08 19:27:20 -0800192 fprintf(pfout, " private static int bitCodeLength = %d;\n\n",
193 total_length);
Ying Wang0877f052010-09-09 17:19:33 -0700194 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
209static bool GenerateAccessorClass(
zonr6315f762010-10-05 15:35:14 +0800210 const RSSlangReflectUtils::BitCodeAccessorContext &context,
211 const char *clazz_name, FILE *pfout) {
Ying Wang0877f052010-09-09 17:19:33 -0700212 // 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;
Ying Wang3f8b44d2010-09-04 01:17:01 -0700228 }
229
Ying Wang0877f052010-09-09 17:19:33 -0700230 // end the class.
231 fprintf(pfout, "}\n");
232
233 return ret;
234}
235
236
237bool RSSlangReflectUtils::GenerateBitCodeAccessor(
zonr6315f762010-10-05 15:35:14 +0800238 const BitCodeAccessorContext &context) {
Ying Wang0877f052010-09-09 17:19:33 -0700239 string output_path = ComputePackagedPath(context.reflectPath,
240 context.packageName);
Zonr Chang8c6d9b22010-10-07 18:01:19 +0800241 if (!SlangUtils::CreateDirectoryWithParents(llvm::StringRef(output_path),
242 NULL)) {
Ying Wang0877f052010-09-09 17:19:33 -0700243 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));
Ying Wang3f8b44d2010-09-04 01:17:01 -0700249 clazz_name += "BitCode";
250 string filename(clazz_name);
251 filename += ".java";
252
253 string output_filename(output_path);
Raphael8d5a2f62011-02-08 00:15:05 -0800254 output_filename += OS_PATH_SEPARATOR_STR;
Ying Wang3f8b44d2010-09-04 01:17:01 -0700255 output_filename += filename;
256 printf("Generating %s ...\n", filename.c_str());
zonr6315f762010-10-05 15:35:14 +0800257 FILE *pfout = fopen(output_filename.c_str(), "w");
Ying Wang3f8b44d2010-09-04 01:17:01 -0700258 if (pfout == NULL) {
Ying Wang0877f052010-09-09 17:19:33 -0700259 fprintf(stderr, "Error: could not write to file %s\n",
260 output_filename.c_str());
Ying Wang3f8b44d2010-09-04 01:17:01 -0700261 return false;
262 }
263
zonr6315f762010-10-05 15:35:14 +0800264 bool ret = GenerateAccessorHeader(context, pfout) &&
265 GenerateAccessorClass(context, clazz_name.c_str(), pfout);
Ying Wang3f8b44d2010-09-04 01:17:01 -0700266
Ying Wang3f8b44d2010-09-04 01:17:01 -0700267 fclose(pfout);
Ying Wang0877f052010-09-09 17:19:33 -0700268 return ret;
Ying Wang3f8b44d2010-09-04 01:17:01 -0700269}
Ying Wang3f8b44d2010-09-04 01:17:01 -0700270}