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