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