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