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