1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "jni.h" 27 #include "imageDecompressor.hpp" 28 #include "endian.hpp" 29 #ifdef WIN32 30 #include <windows.h> 31 #else 32 #include <dlfcn.h> 33 #endif 34 35 typedef jboolean (JNICALL *ZipInflateFully_t)(void *inBuf, jlong inLen, 36 void *outBuf, jlong outLen, char **pmsg); 37 static ZipInflateFully_t ZipInflateFully = NULL; 38 39 #ifndef WIN32 40 #define JNI_LIB_PREFIX "lib" 41 #ifdef __APPLE__ 42 #define JNI_LIB_SUFFIX ".dylib" 43 #else 44 #define JNI_LIB_SUFFIX ".so" 45 #endif 46 #endif 47 48 /** 49 * Return the address of the entry point named in the zip shared library. 50 * @param name - the name of the entry point 51 * @return the address of the entry point or NULL 52 */ 53 static void* findEntry(const char* name) { 54 void *addr = NULL; 55 #ifdef WIN32 56 HMODULE handle = GetModuleHandle("zip.dll"); 57 if (handle == NULL) { 58 return NULL; 59 } 60 addr = (void*) GetProcAddress(handle, name); 61 return addr; 62 #else 63 addr = dlopen(JNI_LIB_PREFIX "zip" JNI_LIB_SUFFIX, RTLD_GLOBAL|RTLD_LAZY); 64 if (addr == NULL) { 65 return NULL; 66 } 67 addr = dlsym(addr, name); 68 return addr; 69 #endif 70 } 71 72 /* 73 * Initialize the array of decompressors. 74 */ 75 int ImageDecompressor::_decompressors_num = 0; 76 ImageDecompressor** ImageDecompressor::_decompressors = NULL; 77 void ImageDecompressor::image_decompressor_init() { 78 if (_decompressors == NULL) { 79 ZipInflateFully = (ZipInflateFully_t) findEntry("ZIP_InflateFully"); 80 assert(ZipInflateFully != NULL && "ZIP decompressor not found."); 81 _decompressors_num = 2; 82 _decompressors = new ImageDecompressor*[_decompressors_num]; 83 _decompressors[0] = new ZipDecompressor("zip"); 84 _decompressors[1] = new SharedStringDecompressor("compact-cp"); 85 } 86 } 87 88 void ImageDecompressor::image_decompressor_close() { 89 delete[] _decompressors; 90 } 91 92 /* 93 * Locate decompressor. 94 */ 95 ImageDecompressor* ImageDecompressor::get_decompressor(const char * decompressor_name) { 96 image_decompressor_init(); 97 for (int i = 0; i < _decompressors_num; i++) { 98 ImageDecompressor* decompressor = _decompressors[i]; 99 assert(decompressor != NULL && "Decompressors not initialized."); 100 if (strcmp(decompressor->get_name(), decompressor_name) == 0) { 101 return decompressor; 102 } 103 } 104 assert(false && "No decompressor found."); 105 return NULL; 106 } 107 108 /* 109 * Decompression entry point. Called from ImageFileReader::get_resource. 110 */ 111 void ImageDecompressor::decompress_resource(u1* compressed, u1* uncompressed, 112 u4 uncompressed_size, const ImageStrings* strings) { 113 bool has_header = false; 114 u1* decompressed_resource = compressed; 115 u1* compressed_resource = compressed; 116 117 // Resource could have been transformed by a stack of decompressors. 118 // Iterate and decompress resources until there is no more header. 119 do { 120 ResourceHeader _header; 121 memcpy(&_header, compressed_resource, sizeof (ResourceHeader)); 122 has_header = _header._magic == ResourceHeader::resource_header_magic; 123 if (has_header) { 124 // decompressed_resource array contains the result of decompression 125 decompressed_resource = new u1[_header._uncompressed_size]; 126 // Retrieve the decompressor name 127 const char* decompressor_name = strings->get(_header._decompressor_name_offset); 128 assert(decompressor_name && "image decompressor not found"); 129 // Retrieve the decompressor instance 130 ImageDecompressor* decompressor = get_decompressor(decompressor_name); 131 assert(decompressor && "image decompressor not found"); 132 u1* compressed_resource_base = compressed_resource; 133 compressed_resource += ResourceHeader::resource_header_length; 134 // Ask the decompressor to decompress the compressed content 135 decompressor->decompress_resource(compressed_resource, decompressed_resource, 136 &_header, strings); 137 if (compressed_resource_base != compressed) { 138 delete[] compressed_resource_base; 139 } 140 compressed_resource = decompressed_resource; 141 } 142 } while (has_header); 143 memcpy(uncompressed, decompressed_resource, uncompressed_size); 144 delete[] decompressed_resource; 145 } 146 147 // Zip decompressor 148 149 void ZipDecompressor::decompress_resource(u1* data, u1* uncompressed, 150 ResourceHeader* header, const ImageStrings* strings) { 151 char* msg = NULL; 152 jboolean res = ZipDecompressor::decompress(data, header->_size, uncompressed, 153 header->_uncompressed_size, &msg); 154 assert(res && "decompression failed"); 155 } 156 157 jboolean ZipDecompressor::decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg) { 158 return (*ZipInflateFully)(in, inSize, out, outSize, pmsg); 159 } 160 161 // END Zip Decompressor 162 163 // Shared String decompressor 164 165 // array index is the constant pool tag. value is size. 166 // eg: array[5] = 8; means size of long is 8 bytes. 167 const u1 SharedStringDecompressor::sizes[] = { 168 0, 0, 0, 4, 4, 8, 8, 2, 2, 4, 4, 4, 4, 0, 0, 3, 2, 0, 4 169 }; 170 /** 171 * Recreate the class by reconstructing the constant pool. 172 */ 173 void SharedStringDecompressor::decompress_resource(u1* data, 174 u1* uncompressed_resource, 175 ResourceHeader* header, const ImageStrings* strings) { 176 u1* uncompressed_base = uncompressed_resource; 177 u1* data_base = data; 178 int header_size = 8; // magic + major + minor 179 memcpy(uncompressed_resource, data, header_size + 2); //+ cp count 180 uncompressed_resource += header_size + 2; 181 data += header_size; 182 u2 cp_count = Endian::get_java(data); 183 data += 2; 184 for (int i = 1; i < cp_count; i++) { 185 u1 tag = *data; 186 data += 1; 187 switch (tag) { 188 189 case externalized_string: 190 { // String in Strings table 191 *uncompressed_resource = 1; 192 uncompressed_resource += 1; 193 int k = decompress_int(data); 194 const char * string = strings->get(k); 195 int str_length = (int) strlen(string); 196 Endian::set_java(uncompressed_resource, str_length); 197 uncompressed_resource += 2; 198 memcpy(uncompressed_resource, string, str_length); 199 uncompressed_resource += str_length; 200 break; 201 } 202 // Descriptor String has been split and types added to Strings table 203 case externalized_string_descriptor: 204 { 205 *uncompressed_resource = 1; 206 uncompressed_resource += 1; 207 int descriptor_index = decompress_int(data); 208 int indexes_length = decompress_int(data); 209 u1* length_address = uncompressed_resource; 210 uncompressed_resource += 2; 211 int desc_length = 0; 212 const char * desc_string = strings->get(descriptor_index); 213 if (indexes_length > 0) { 214 u1* indexes_base = data; 215 data += indexes_length; 216 char c = *desc_string; 217 do { 218 *uncompressed_resource = c; 219 uncompressed_resource++; 220 desc_length += 1; 221 /* 222 * Every L character is the marker we are looking at in order 223 * to reconstruct the descriptor. Each time an L is found, then 224 * we retrieve the couple token/token at the current index and 225 * add it to the descriptor. 226 * "(L;I)V" and "java/lang","String" couple of tokens, 227 * this becomes "(Ljava/lang/String;I)V" 228 */ 229 if (c == 'L') { 230 int index = decompress_int(indexes_base); 231 const char * pkg = strings->get(index); 232 int str_length = (int) strlen(pkg); 233 // the case where we have a package. 234 // reconstruct the type full name 235 if (str_length > 0) { 236 int len = str_length + 1; 237 char* fullpkg = new char[len]; 238 char* pkg_base = fullpkg; 239 memcpy(fullpkg, pkg, str_length); 240 fullpkg += str_length; 241 *fullpkg = '/'; 242 memcpy(uncompressed_resource, pkg_base, len); 243 uncompressed_resource += len; 244 delete[] pkg_base; 245 desc_length += len; 246 } else { // Empty package 247 // Nothing to do. 248 } 249 int classIndex = decompress_int(indexes_base); 250 const char * clazz = strings->get(classIndex); 251 int clazz_length = (int) strlen(clazz); 252 memcpy(uncompressed_resource, clazz, clazz_length); 253 uncompressed_resource += clazz_length; 254 desc_length += clazz_length; 255 } 256 desc_string += 1; 257 c = *desc_string; 258 } while (c != '\0'); 259 } else { 260 desc_length = (int) strlen(desc_string); 261 memcpy(uncompressed_resource, desc_string, desc_length); 262 uncompressed_resource += desc_length; 263 } 264 Endian::set_java(length_address, desc_length); 265 break; 266 } 267 268 case constant_utf8: 269 { // UTF-8 270 *uncompressed_resource = tag; 271 uncompressed_resource += 1; 272 u2 str_length = Endian::get_java(data); 273 int len = str_length + 2; 274 memcpy(uncompressed_resource, data, len); 275 uncompressed_resource += len; 276 data += len; 277 break; 278 } 279 280 case constant_long: 281 case constant_double: 282 { 283 i++; 284 } 285 default: 286 { 287 *uncompressed_resource = tag; 288 uncompressed_resource += 1; 289 int size = sizes[tag]; 290 memcpy(uncompressed_resource, data, size); 291 uncompressed_resource += size; 292 data += size; 293 } 294 } 295 } 296 u4 remain = header->_size - (int)(data - data_base); 297 u4 computed = (u4)(uncompressed_resource - uncompressed_base) + remain; 298 if (header->_uncompressed_size != computed) 299 printf("Failure, expecting %d but getting %d\n", header->_uncompressed_size, 300 computed); 301 assert(header->_uncompressed_size == computed && 302 "Constant Pool reconstruction failed"); 303 memcpy(uncompressed_resource, data, remain); 304 } 305 306 /* 307 * Decompress integers. Compressed integers are negative. 308 * If positive, the integer is not decompressed. 309 * If negative, length extracted from the first byte, then reconstruct the integer 310 * from the following bytes. 311 * Example of compression: 1 is compressed on 1 byte: 10100001 312 */ 313 int SharedStringDecompressor::decompress_int(unsigned char*& value) { 314 int len = 4; 315 int res = 0; 316 char b1 = *value; 317 if (is_compressed((signed char)b1)) { // compressed 318 len = get_compressed_length(b1); 319 char clearedValue = b1 &= 0x1F; 320 if (len == 1) { 321 res = clearedValue; 322 } else { 323 res = (clearedValue & 0xFF) << 8 * (len - 1); 324 for (int i = 1; i < len; i++) { 325 res |= (value[i]&0xFF) << 8 * (len - i - 1); 326 } 327 } 328 } else { 329 res = (value[0] & 0xFF) << 24 | (value[1]&0xFF) << 16 | 330 (value[2]&0xFF) << 8 | (value[3]&0xFF); 331 } 332 value += len; 333 return res; 334 } 335 // END Shared String decompressor