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