Home | History | Annotate | Download | only in slang
      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 
     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 
     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 
     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 
     95 std::string RSSlangReflectUtils::JavaClassNameFromRSFileName(
     96     const char *rsFileName) {
     97     return InternalFileNameConvert(rsFileName, false);
     98 }
     99 
    100 
    101 std::string RSSlangReflectUtils::BCFileNameFromRSFileName(
    102     const char *rsFileName) {
    103     return InternalFileNameConvert(rsFileName, true);
    104 }
    105 
    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 
    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.
    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 
    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 
    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 
    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