1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_codemaker.hxx" 26 27 #include "classfile.hxx" 28 29 #include "codemaker/global.hxx" 30 #include "codemaker/options.hxx" 31 #include "codemaker/unotype.hxx" 32 33 #include "boost/static_assert.hpp" 34 #include "osl/diagnose.h" 35 #include "rtl/string.h" 36 #include "rtl/string.hxx" 37 #include "sal/types.h" 38 39 #include <map> 40 #include <utility> 41 #include <vector> 42 43 using codemaker::javamaker::ClassFile; 44 45 namespace { 46 47 void appendU1(std::vector< unsigned char > & stream, sal_uInt8 data) { 48 stream.push_back(static_cast< unsigned char >(data)); 49 } 50 51 void appendU2(std::vector< unsigned char > & stream, sal_uInt16 data) { 52 stream.push_back(static_cast< unsigned char >(data >> 8)); 53 stream.push_back(static_cast< unsigned char >(data & 0xFF)); 54 } 55 56 void appendU4(std::vector< unsigned char > & stream, sal_uInt32 data) { 57 stream.push_back(static_cast< unsigned char >(data >> 24)); 58 stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF)); 59 stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF)); 60 stream.push_back(static_cast< unsigned char >(data & 0xFF)); 61 } 62 63 void appendU8(std::vector< unsigned char > & stream, sal_uInt64 data) { 64 stream.push_back(static_cast< unsigned char >(data >> 56)); 65 stream.push_back(static_cast< unsigned char >((data >> 48) & 0xFF)); 66 stream.push_back(static_cast< unsigned char >((data >> 40) & 0xFF)); 67 stream.push_back(static_cast< unsigned char >((data >> 32) & 0xFF)); 68 stream.push_back(static_cast< unsigned char >((data >> 24) & 0xFF)); 69 stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF)); 70 stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF)); 71 stream.push_back(static_cast< unsigned char >(data & 0xFF)); 72 } 73 74 void appendStream( 75 std::vector< unsigned char > & stream, 76 std::vector< unsigned char > const & data) 77 { 78 stream.insert(stream.end(), data.begin(), data.end()); 79 } 80 81 void write(FileStream & file, void const * buffer, sal_uInt64 size) { 82 if (!file.write(buffer, size)) { 83 throw CannotDumpException( 84 rtl::OString(RTL_CONSTASCII_STRINGPARAM("Error writing file"))); 85 } 86 } 87 88 void writeU1(FileStream & file, sal_uInt8 data) { 89 unsigned char buf[] = { static_cast< unsigned char >(data) }; 90 write(file, &buf, sizeof buf); 91 } 92 93 void writeU2(FileStream & file, sal_uInt16 data) { 94 unsigned char buf[] = { 95 static_cast< unsigned char >(data >> 8), 96 static_cast< unsigned char >(data & 0xFF) }; 97 write(file, buf, sizeof buf); 98 } 99 100 void writeU4(FileStream & file, sal_uInt32 data) { 101 unsigned char buf[] = { 102 static_cast< unsigned char >(data >> 24), 103 static_cast< unsigned char >((data >> 16) & 0xFF), 104 static_cast< unsigned char >((data >> 8) & 0xFF), 105 static_cast< unsigned char >(data & 0xFF) }; 106 write(file, buf, sizeof buf); 107 } 108 109 void writeStream(FileStream & file, std::vector< unsigned char > const & stream) 110 { 111 std::vector< unsigned char >::size_type n = stream.size(); 112 BOOST_STATIC_ASSERT( 113 sizeof (std::vector< unsigned char >::size_type) 114 <= sizeof (sal_uInt64)); 115 // both unsigned integral, so sizeof is a practically sufficient 116 // approximation of std::numeric_limits<T1>::max() <= 117 // std::numeric_limits<T2>::max() 118 if (n != 0) { 119 write(file, &stream[0], static_cast< sal_uInt64 >(n)); 120 } 121 } 122 123 } 124 125 ClassFile::Code::~Code() {} 126 127 void ClassFile::Code::instrAastore() { 128 // aastore: 129 appendU1(m_code, 0x53); 130 } 131 132 void ClassFile::Code::instrAconstNull() { 133 // aconst_null: 134 appendU1(m_code, 0x01); 135 } 136 137 void ClassFile::Code::instrAnewarray(rtl::OString const & type) { 138 // anewarray <indexbyte1> <indexbyte2>: 139 appendU1(m_code, 0xBD); 140 appendU2(m_code, m_classFile.addClassInfo(type)); 141 } 142 143 void ClassFile::Code::instrAreturn() { 144 // areturn: 145 appendU1(m_code, 0xB0); 146 } 147 148 void ClassFile::Code::instrAthrow() { 149 // athrow: 150 appendU1(m_code, 0xBF); 151 } 152 153 void ClassFile::Code::instrCheckcast(rtl::OString const & type) { 154 // checkcast <indexbyte1> <indexbyte2>: 155 appendU1(m_code, 0xC0); 156 appendU2(m_code, m_classFile.addClassInfo(type)); 157 } 158 159 void ClassFile::Code::instrDup() { 160 // dup: 161 appendU1(m_code, 0x59); 162 } 163 164 void ClassFile::Code::instrGetstatic( 165 rtl::OString const & type, rtl::OString const & name, 166 rtl::OString const & descriptor) 167 { 168 // getstatic <indexbyte1> <indexbyte2>: 169 appendU1(m_code, 0xB2); 170 appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor)); 171 } 172 173 ClassFile::Code::Branch ClassFile::Code::instrIfAcmpne() { 174 // if_acmpne <branchbyte1> <branchbyte2>: 175 Branch branch = m_code.size(); 176 appendU1(m_code, 0xA6); 177 appendU2(m_code, 0); 178 return branch; 179 } 180 181 ClassFile::Code::Branch ClassFile::Code::instrIfeq() { 182 // ifeq <branchbyte1> <branchbyte2>: 183 Branch branch = m_code.size(); 184 appendU1(m_code, 0x99); 185 appendU2(m_code, 0); 186 return branch; 187 } 188 189 ClassFile::Code::Branch ClassFile::Code::instrIfnull() { 190 // ifnull <branchbyte1> <branchbyte2>: 191 Branch branch = m_code.size(); 192 appendU1(m_code, 0xC6); 193 appendU2(m_code, 0); 194 return branch; 195 } 196 197 void ClassFile::Code::instrInstanceof(rtl::OString const & type) { 198 // instanceof <indexbyte1> <indexbyte2>: 199 appendU1(m_code, 0xC1); 200 appendU2(m_code, m_classFile.addClassInfo(type)); 201 } 202 203 void ClassFile::Code::instrInvokeinterface( 204 rtl::OString const & type, rtl::OString const & name, 205 rtl::OString const & descriptor, sal_uInt8 args) 206 { 207 // invokeinterface <indexbyte1> <indexbyte2> <nargs> 0: 208 appendU1(m_code, 0xB9); 209 appendU2( 210 m_code, m_classFile.addInterfaceMethodrefInfo(type, name, descriptor)); 211 appendU1(m_code, args); 212 appendU1(m_code, 0); 213 } 214 215 void ClassFile::Code::instrInvokespecial( 216 rtl::OString const & type, rtl::OString const & name, 217 rtl::OString const & descriptor) 218 { 219 // invokespecial <indexbyte1> <indexbyte2>: 220 appendU1(m_code, 0xB7); 221 appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor)); 222 } 223 224 void ClassFile::Code::instrInvokestatic( 225 rtl::OString const & type, rtl::OString const & name, 226 rtl::OString const & descriptor) 227 { 228 // invokestatic <indexbyte1> <indexbyte2>: 229 appendU1(m_code, 0xB8); 230 appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor)); 231 } 232 233 void ClassFile::Code::instrInvokevirtual( 234 rtl::OString const & type, rtl::OString const & name, 235 rtl::OString const & descriptor) 236 { 237 // invokevirtual <indexbyte1> <indexbyte2>: 238 appendU1(m_code, 0xB6); 239 appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor)); 240 } 241 242 void ClassFile::Code::instrLookupswitch( 243 Code const * defaultBlock, 244 std::list< std::pair< sal_Int32, Code * > > const & blocks) 245 { 246 // lookupswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3> 247 // <defaultbyte4> <npairs1> <npairs2> <npairs3> <npairs4> 248 // <match--offset pairs...>: 249 std::list< std::pair< sal_Int32, Code * > >::size_type size = blocks.size(); 250 if (size > SAL_MAX_INT32) { 251 throw CannotDumpException( 252 rtl::OString( 253 RTL_CONSTASCII_STRINGPARAM( 254 "Lookup-switch too large for Java class file format"))); 255 } 256 Position pos1 = m_code.size(); 257 appendU1(m_code, 0xAB); 258 int pad = (pos1 + 1) % 4; 259 {for (int i = 0; i < pad; ++i) { 260 appendU1(m_code, 0); 261 }} 262 Position pos2 = pos1 + 1 + pad + 8 + blocks.size() * 8; //FIXME: overflow 263 appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); //FIXME: overflow 264 pos2 += defaultBlock->m_code.size(); //FIXME: overflow 265 appendU4(m_code, static_cast< sal_uInt32 >(size)); 266 {for (std::list< std::pair< sal_Int32, Code * > >::const_iterator i( 267 blocks.begin()); 268 i != blocks.end(); ++i) 269 { 270 appendU4(m_code, static_cast< sal_uInt32 >(i->first)); 271 appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); 272 //FIXME: overflow 273 pos2 += i->second->m_code.size(); //FIXME: overflow 274 }} 275 appendStream(m_code, defaultBlock->m_code); 276 {for (std::list< std::pair< sal_Int32, Code * > >::const_iterator i( 277 blocks.begin()); 278 i != blocks.end(); ++i) 279 { 280 appendStream(m_code, i->second->m_code); 281 }} 282 } 283 284 void ClassFile::Code::instrNew(rtl::OString const & type) { 285 // new <indexbyte1> <indexbyte2>: 286 appendU1(m_code, 0xBB); 287 appendU2(m_code, m_classFile.addClassInfo(type)); 288 } 289 290 void ClassFile::Code::instrNewarray(codemaker::UnoType::Sort sort) { 291 OSL_ASSERT( 292 sort >= codemaker::UnoType::SORT_BOOLEAN 293 && sort <= codemaker::UnoType::SORT_CHAR); 294 // newarray <atype>: 295 appendU1(m_code, 0xBC); 296 static sal_uInt8 const atypes[codemaker::UnoType::SORT_CHAR] = { 297 0x04, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x06, 0x07, 0x05 }; 298 appendU1(m_code, atypes[sort - 1]); 299 } 300 301 void ClassFile::Code::instrPop() { 302 // pop: 303 appendU1(m_code, 0x57); 304 } 305 306 void ClassFile::Code::instrPutfield( 307 rtl::OString const & type, rtl::OString const & name, 308 rtl::OString const & descriptor) 309 { 310 // putfield <indexbyte1> <indexbyte2>: 311 appendU1(m_code, 0xB5); 312 appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor)); 313 } 314 315 void ClassFile::Code::instrPutstatic( 316 rtl::OString const & type, rtl::OString const & name, 317 rtl::OString const & descriptor) 318 { 319 // putstatic <indexbyte1> <indexbyte2>: 320 appendU1(m_code, 0xB3); 321 appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor)); 322 } 323 324 void ClassFile::Code::instrReturn() { 325 // return: 326 appendU1(m_code, 0xB1); 327 } 328 329 void ClassFile::Code::instrSwap() { 330 // swap: 331 appendU1(m_code, 0x5F); 332 } 333 334 void ClassFile::Code::instrTableswitch( 335 Code const * defaultBlock, sal_Int32 low, 336 std::list< Code * > const & blocks) 337 { 338 // tableswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3> 339 // <defaultbyte4> <lowbyte1> <lowbyte2> <lowbyte3> <lowbyte4> <highbyte1> 340 // <highbyte2> <highbyte3> <highbyte4> <jump offsets...>: 341 Position pos1 = m_code.size(); 342 appendU1(m_code, 0xAA); 343 int pad = (pos1 + 1) % 4; 344 {for (int i = 0; i < pad; ++i) { 345 appendU1(m_code, 0); 346 }} 347 std::list< Code * >::size_type size = blocks.size(); 348 Position pos2 = pos1 + 1 + pad + 12 + size * 4; //FIXME: overflow 349 sal_uInt32 defaultOffset = static_cast< sal_uInt32 >(pos2 - pos1); 350 //FIXME: overflow 351 appendU4(m_code, defaultOffset); 352 pos2 += defaultBlock->m_code.size(); //FIXME: overflow 353 appendU4(m_code, static_cast< sal_uInt32 >(low)); 354 appendU4(m_code, static_cast< sal_uInt32 >(low + (size - 1))); 355 {for (std::list< Code * >::const_iterator i(blocks.begin()); 356 i != blocks.end(); ++i) 357 { 358 if (*i == 0) { 359 appendU4(m_code, defaultOffset); 360 } else { 361 appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); 362 //FIXME: overflow 363 pos2 += (*i)->m_code.size(); //FIXME: overflow 364 } 365 }} 366 appendStream(m_code, defaultBlock->m_code); 367 {for (std::list< Code * >::const_iterator i(blocks.begin()); 368 i != blocks.end(); ++i) 369 { 370 if (*i != 0) { 371 appendStream(m_code, (*i)->m_code); 372 } 373 }} 374 } 375 376 void ClassFile::Code::loadIntegerConstant(sal_Int32 value) { 377 if (value >= -1 && value <= 5) { 378 // iconst_<i>: 379 appendU1(m_code, static_cast< sal_uInt8 >(0x02 + value + 1)); 380 } else if (value >= -128 && value <= 127) { 381 // bipush <byte>: 382 appendU1(m_code, 0x10); 383 appendU1(m_code, static_cast< sal_uInt8 >(value)); 384 } else if (value >= -32768 && value <= 32767) { 385 // sipush <byte1> <byte2>: 386 appendU1(m_code, 0x11); 387 appendU2(m_code, static_cast< sal_uInt16 >(value)); 388 } else { 389 ldc(m_classFile.addIntegerInfo(value)); 390 } 391 } 392 393 void ClassFile::Code::loadStringConstant(rtl::OString const & value) { 394 ldc(m_classFile.addStringInfo(value)); 395 } 396 397 void ClassFile::Code::loadLocalInteger(sal_uInt16 index) { 398 accessLocal(index, 0x1A, 0x15); // iload_<n>, iload 399 } 400 401 void ClassFile::Code::loadLocalLong(sal_uInt16 index) { 402 accessLocal(index, 0x1E, 0x16); // load_<n>, load 403 } 404 405 void ClassFile::Code::loadLocalFloat(sal_uInt16 index) { 406 accessLocal(index, 0x22, 0x17); // load_<n>, load 407 } 408 409 void ClassFile::Code::loadLocalDouble(sal_uInt16 index) { 410 accessLocal(index, 0x26, 0x18); // load_<n>, load 411 } 412 413 void ClassFile::Code::loadLocalReference(sal_uInt16 index) { 414 accessLocal(index, 0x2A, 0x19); // aload_<n>, aload 415 } 416 417 void ClassFile::Code::storeLocalReference(sal_uInt16 index) { 418 accessLocal(index, 0x4B, 0x3A); // astore_<n>, astore 419 } 420 421 void ClassFile::Code::branchHere(Branch branch) { 422 std::vector< unsigned char >::size_type n = m_code.size(); 423 OSL_ASSERT(n > branch && n - branch <= SAL_MAX_INT16); 424 n -= branch; 425 m_code[branch + 1] = static_cast< sal_uInt8 >(n >> 8); 426 m_code[branch + 2] = static_cast< sal_uInt8 >(n & 0xFF); 427 } 428 429 void ClassFile::Code::addException( 430 Position start, Position end, Position handler, rtl::OString const & type) 431 { 432 OSL_ASSERT(start < end && end <= m_code.size() && handler <= m_code.size()); 433 if (m_exceptionTableLength == SAL_MAX_UINT16) { 434 throw CannotDumpException( 435 rtl::OString( 436 RTL_CONSTASCII_STRINGPARAM( 437 "Too many exception handlers for Java class file format"))); 438 } 439 ++m_exceptionTableLength; 440 appendU2(m_exceptionTable, static_cast< sal_uInt16 >(start)); 441 //FIXME: overflow 442 appendU2(m_exceptionTable, static_cast< sal_uInt16 >(end)); 443 //FIXME: overflow 444 appendU2(m_exceptionTable, static_cast< sal_uInt16 >(handler)); 445 //FIXME: overflow 446 appendU2(m_exceptionTable, m_classFile.addClassInfo(type)); 447 } 448 449 ClassFile::Code::Position ClassFile::Code::getPosition() const { 450 return m_code.size(); 451 } 452 453 ClassFile::Code::Code(ClassFile & classFile): 454 m_classFile(classFile), m_exceptionTableLength(0) 455 {} 456 457 void ClassFile::Code::ldc(sal_uInt16 index) { 458 if (index <= 0xFF) { 459 // ldc <index>: 460 appendU1(m_code, 0x12); 461 appendU1(m_code, static_cast< sal_uInt8 >(index)); 462 } else { 463 // ldc_w <indexbyte1> <indexbyte2>: 464 appendU1(m_code, 0x13); 465 appendU2(m_code, index); 466 } 467 } 468 469 void ClassFile::Code::accessLocal( 470 sal_uInt16 index, sal_uInt8 fastOp, sal_uInt8 normalOp) 471 { 472 if (index <= 3) { 473 // ...load/store_<n>: 474 appendU1(m_code, static_cast< sal_uInt8 >(fastOp + index)); 475 } else if (index <= 0xFF) { 476 // ...load/store <index>: 477 appendU1(m_code, normalOp); 478 appendU1(m_code, static_cast< sal_uInt8 >(index)); 479 } else { 480 // wide ...load/store <indexbyte1> <indexbyte2>: 481 appendU1(m_code, 0xC4); 482 appendU1(m_code, normalOp); 483 appendU2(m_code, index); 484 } 485 } 486 487 ClassFile::ClassFile( 488 AccessFlags accessFlags, rtl::OString const & thisClass, 489 rtl::OString const & superClass, rtl::OString const & signature): 490 m_constantPoolCount(1), m_accessFlags(accessFlags), m_interfacesCount(0), 491 m_fieldsCount(0), m_methodsCount(0), m_attributesCount(0) 492 { 493 m_thisClass = addClassInfo(thisClass); 494 m_superClass = addClassInfo(superClass); 495 if (signature.getLength() != 0) { 496 ++m_attributesCount; 497 appendU2( 498 m_attributes, 499 addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature")))); 500 appendU4(m_attributes, 2); 501 appendU2(m_attributes, addUtf8Info(signature)); 502 } 503 } 504 505 ClassFile::~ClassFile() {} 506 507 ClassFile::Code * ClassFile::newCode() { 508 return new Code(*this); 509 } 510 511 sal_uInt16 ClassFile::addIntegerInfo(sal_Int32 value) { 512 std::map< sal_Int32, sal_uInt16 >::iterator i(m_integerInfos.find(value)); 513 if (i != m_integerInfos.end()) { 514 return i->second; 515 } 516 sal_uInt16 index = nextConstantPoolIndex(1); 517 appendU1(m_constantPool, 3); 518 appendU4(m_constantPool, static_cast< sal_uInt32 >(value)); 519 if (!m_integerInfos.insert( 520 std::map< sal_Int32, sal_uInt16 >::value_type(value, index)).second) 521 { 522 OSL_ASSERT(false); 523 } 524 return index; 525 } 526 527 sal_uInt16 ClassFile::addFloatInfo(float value) { 528 std::map< float, sal_uInt16 >::iterator i(m_floatInfos.find(value)); 529 if (i != m_floatInfos.end()) { 530 return i->second; 531 } 532 sal_uInt16 index = nextConstantPoolIndex(1); 533 appendU1(m_constantPool, 4); 534 union { float floatBytes; sal_uInt32 uint32Bytes; } bytes; 535 bytes.floatBytes = value; 536 appendU4(m_constantPool, bytes.uint32Bytes); 537 if (!m_floatInfos.insert( 538 std::map< float, sal_uInt16 >::value_type(value, index)).second) 539 { 540 OSL_ASSERT(false); 541 } 542 return index; 543 } 544 545 sal_uInt16 ClassFile::addLongInfo(sal_Int64 value) { 546 std::map< sal_Int64, sal_uInt16 >::iterator i(m_longInfos.find(value)); 547 if (i != m_longInfos.end()) { 548 return i->second; 549 } 550 sal_uInt16 index = nextConstantPoolIndex(2); 551 appendU1(m_constantPool, 5); 552 appendU8(m_constantPool, static_cast< sal_uInt64 >(value)); 553 if (!m_longInfos.insert( 554 std::map< sal_Int64, sal_uInt16 >::value_type(value, index)).second) 555 { 556 OSL_ASSERT(false); 557 } 558 return index; 559 } 560 561 sal_uInt16 ClassFile::addDoubleInfo(double value) { 562 std::map< double, sal_uInt16 >::iterator i(m_doubleInfos.find(value)); 563 if (i != m_doubleInfos.end()) { 564 return i->second; 565 } 566 sal_uInt16 index = nextConstantPoolIndex(2); 567 appendU1(m_constantPool, 6); 568 union { double doubleBytes; sal_uInt64 uint64Bytes; } bytes; 569 bytes.doubleBytes = value; 570 appendU8(m_constantPool, bytes.uint64Bytes); 571 if (!m_doubleInfos.insert( 572 std::map< double, sal_uInt16 >::value_type(value, index)).second) 573 { 574 OSL_ASSERT(false); 575 } 576 return index; 577 } 578 579 void ClassFile::addInterface(rtl::OString const & interface) { 580 if (m_interfacesCount == SAL_MAX_UINT16) { 581 throw CannotDumpException( 582 rtl::OString( 583 RTL_CONSTASCII_STRINGPARAM( 584 "Too many interfaces for Java class file format"))); 585 } 586 ++m_interfacesCount; 587 appendU2(m_interfaces, addClassInfo(interface)); 588 } 589 590 void ClassFile::addField( 591 AccessFlags accessFlags, rtl::OString const & name, 592 rtl::OString const & descriptor, sal_uInt16 constantValueIndex, 593 rtl::OString const & signature) 594 { 595 if (m_fieldsCount == SAL_MAX_UINT16) { 596 throw CannotDumpException( 597 rtl::OString( 598 RTL_CONSTASCII_STRINGPARAM( 599 "Too many fields for Java class file format"))); 600 } 601 ++m_fieldsCount; 602 appendU2(m_fields, static_cast< sal_uInt16 >(accessFlags)); 603 appendU2(m_fields, addUtf8Info(name)); 604 appendU2(m_fields, addUtf8Info(descriptor)); 605 appendU2( 606 m_fields, 607 ((constantValueIndex == 0 ? 0 : 1) 608 + (signature.getLength() == 0 ? 0 : 1))); 609 if (constantValueIndex != 0) { 610 appendU2( 611 m_fields, 612 addUtf8Info( 613 rtl::OString(RTL_CONSTASCII_STRINGPARAM("ConstantValue")))); 614 appendU4(m_fields, 2); 615 appendU2(m_fields, constantValueIndex); 616 } 617 appendSignatureAttribute(m_fields, signature); 618 } 619 620 void ClassFile::addMethod( 621 AccessFlags accessFlags, rtl::OString const & name, 622 rtl::OString const & descriptor, Code const * code, 623 std::vector< rtl::OString > const & exceptions, 624 rtl::OString const & signature) 625 { 626 if (m_methodsCount == SAL_MAX_UINT16) { 627 throw CannotDumpException( 628 rtl::OString( 629 RTL_CONSTASCII_STRINGPARAM( 630 "Too many methods for Java class file format"))); 631 } 632 ++m_methodsCount; 633 appendU2(m_methods, static_cast< sal_uInt16 >(accessFlags)); 634 appendU2(m_methods, addUtf8Info(name)); 635 appendU2(m_methods, addUtf8Info(descriptor)); 636 std::vector< rtl::OString >::size_type excs = exceptions.size(); 637 if (excs > SAL_MAX_UINT16) { 638 throw CannotDumpException( 639 rtl::OString( 640 RTL_CONSTASCII_STRINGPARAM( 641 "Too many exception specifications for Java class file" 642 " format"))); 643 } 644 appendU2( 645 m_methods, 646 ((code == 0 ? 0 : 1) + (exceptions.empty() ? 0 : 1) 647 + (signature.getLength() == 0 ? 0 : 1))); 648 if (code != 0) { 649 std::vector< unsigned char >::size_type codeSize = code->m_code.size(); 650 std::vector< unsigned char >::size_type exceptionTableSize 651 = code->m_exceptionTable.size(); 652 if (codeSize > SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2) 653 || (exceptionTableSize 654 > (SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2) 655 - static_cast< sal_uInt32 >(codeSize)))) 656 { 657 throw CannotDumpException( 658 rtl::OString( 659 RTL_CONSTASCII_STRINGPARAM( 660 "Code block is too big for Java class file format"))); 661 } 662 appendU2( 663 m_methods, 664 addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Code")))); 665 appendU4( 666 m_methods, 667 (2 + 2 + 4 + static_cast< sal_uInt32 >(codeSize) + 2 668 + static_cast< sal_uInt32 >(exceptionTableSize) + 2)); 669 appendU2(m_methods, code->m_maxStack); 670 appendU2(m_methods, code->m_maxLocals); 671 appendU4(m_methods, static_cast< sal_uInt32 >(codeSize)); 672 appendStream(m_methods, code->m_code); 673 appendU2(m_methods, code->m_exceptionTableLength); 674 appendStream(m_methods, code->m_exceptionTable); 675 appendU2(m_methods, 0); 676 } 677 if (!exceptions.empty()) { 678 appendU2( 679 m_methods, 680 addUtf8Info( 681 rtl::OString(RTL_CONSTASCII_STRINGPARAM("Exceptions")))); 682 appendU4( 683 m_methods, 684 static_cast< sal_uInt32 >(2 + 2 * static_cast< sal_uInt32 >(excs))); 685 appendU2(m_methods, static_cast< sal_uInt16 >(excs)); 686 for (std::vector< rtl::OString >::const_iterator i(exceptions.begin()); 687 i != exceptions.end(); ++i) 688 { 689 appendU2(m_methods, addClassInfo(*i)); 690 } 691 } 692 appendSignatureAttribute(m_methods, signature); 693 } 694 695 #define CLASSFILE_FMT 49.0 // a classfile format understood by JDK 5/6/7 696 697 void ClassFile::write(FileStream & file) const { 698 writeU4(file, 0xCAFEBABE); 699 writeU2(file, static_cast<sal_uInt16>((CLASSFILE_FMT-(int)CLASSFILE_FMT)*100000)); 700 writeU2(file, static_cast<sal_uInt16>((int)CLASSFILE_FMT)); 701 writeU2(file, m_constantPoolCount); 702 writeStream(file, m_constantPool); 703 writeU2(file, static_cast< sal_uInt16 >(m_accessFlags)); 704 writeU2(file, m_thisClass); 705 writeU2(file, m_superClass); 706 writeU2(file, m_interfacesCount); 707 writeStream(file, m_interfaces); 708 writeU2(file, m_fieldsCount); 709 writeStream(file, m_fields); 710 writeU2(file, m_methodsCount); 711 writeStream(file, m_methods); 712 writeU2(file, m_attributesCount); 713 writeStream(file, m_attributes); 714 } 715 716 sal_uInt16 ClassFile::nextConstantPoolIndex(sal_uInt16 width) { 717 OSL_ASSERT(width == 1 || width == 2); 718 if (m_constantPoolCount > SAL_MAX_UINT16 - width) { 719 throw CannotDumpException( 720 rtl::OString( 721 RTL_CONSTASCII_STRINGPARAM( 722 "Too many constant pool items for Java class file" 723 " format"))); 724 } 725 sal_uInt16 index = m_constantPoolCount; 726 m_constantPoolCount = m_constantPoolCount + width; 727 return index; 728 } 729 730 sal_uInt16 ClassFile::addUtf8Info(rtl::OString const & value) { 731 std::map< rtl::OString, sal_uInt16 >::iterator i(m_utf8Infos.find(value)); 732 if (i != m_utf8Infos.end()) { 733 return i->second; 734 } 735 if (value.getLength() > SAL_MAX_UINT16) { 736 throw CannotDumpException( 737 rtl::OString( 738 RTL_CONSTASCII_STRINGPARAM( 739 "UTF-8 string too long for Java class file format"))); 740 } 741 sal_uInt16 index = nextConstantPoolIndex(1); 742 appendU1(m_constantPool, 1); 743 appendU2(m_constantPool, static_cast< sal_uInt16 >(value.getLength())); 744 for (sal_Int32 j = 0; j < value.getLength(); ++j) { 745 appendU1(m_constantPool, static_cast< sal_uInt8 >(value[j])); 746 } 747 if (!m_utf8Infos.insert( 748 std::map< rtl::OString, sal_uInt16 >::value_type(value, index)). 749 second) 750 { 751 OSL_ASSERT(false); 752 } 753 return index; 754 } 755 756 sal_uInt16 ClassFile::addClassInfo(rtl::OString const & type) { 757 sal_uInt16 nameIndex = addUtf8Info(type); 758 std::map< sal_uInt16, sal_uInt16 >::iterator i( 759 m_classInfos.find(nameIndex)); 760 if (i != m_classInfos.end()) { 761 return i->second; 762 } 763 sal_uInt16 index = nextConstantPoolIndex(1); 764 appendU1(m_constantPool, 7); 765 appendU2(m_constantPool, nameIndex); 766 if (!m_classInfos.insert( 767 std::map< sal_uInt16, sal_uInt16 >::value_type(nameIndex, index)). 768 second) 769 { 770 OSL_ASSERT(false); 771 } 772 return index; 773 } 774 775 sal_uInt16 ClassFile::addStringInfo(rtl::OString const & value) { 776 sal_uInt16 stringIndex = addUtf8Info(value); 777 std::map< sal_uInt16, sal_uInt16 >::iterator i( 778 m_stringInfos.find(stringIndex)); 779 if (i != m_stringInfos.end()) { 780 return i->second; 781 } 782 sal_uInt16 index = nextConstantPoolIndex(1); 783 appendU1(m_constantPool, 8); 784 appendU2(m_constantPool, stringIndex); 785 if (!m_stringInfos.insert( 786 std::map< sal_uInt16, sal_uInt16 >::value_type(stringIndex, index)). 787 second) 788 { 789 OSL_ASSERT(false); 790 } 791 return index; 792 } 793 794 sal_uInt16 ClassFile::addFieldrefInfo( 795 rtl::OString const & type, rtl::OString const & name, 796 rtl::OString const & descriptor) 797 { 798 sal_uInt16 classIndex = addClassInfo(type); 799 sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor); 800 sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16) 801 | nameAndTypeIndex; 802 std::map< sal_uInt32, sal_uInt16 >::iterator i(m_fieldrefInfos.find(key)); 803 if (i != m_fieldrefInfos.end()) { 804 return i->second; 805 } 806 sal_uInt16 index = nextConstantPoolIndex(1); 807 appendU1(m_constantPool, 9); 808 appendU2(m_constantPool, classIndex); 809 appendU2(m_constantPool, nameAndTypeIndex); 810 if (!m_fieldrefInfos.insert( 811 std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second) 812 { 813 OSL_ASSERT(false); 814 } 815 return index; 816 } 817 818 sal_uInt16 ClassFile::addMethodrefInfo( 819 rtl::OString const & type, rtl::OString const & name, 820 rtl::OString const & descriptor) 821 { 822 sal_uInt16 classIndex = addClassInfo(type); 823 sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor); 824 sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16) 825 | nameAndTypeIndex; 826 std::map< sal_uInt32, sal_uInt16 >::iterator i(m_methodrefInfos.find(key)); 827 if (i != m_methodrefInfos.end()) { 828 return i->second; 829 } 830 sal_uInt16 index = nextConstantPoolIndex(1); 831 appendU1(m_constantPool, 10); 832 appendU2(m_constantPool, classIndex); 833 appendU2(m_constantPool, nameAndTypeIndex); 834 if (!m_methodrefInfos.insert( 835 std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second) 836 { 837 OSL_ASSERT(false); 838 } 839 return index; 840 } 841 842 sal_uInt16 ClassFile::addInterfaceMethodrefInfo( 843 rtl::OString const & type, rtl::OString const & name, 844 rtl::OString const & descriptor) 845 { 846 sal_uInt16 classIndex = addClassInfo(type); 847 sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor); 848 sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16) 849 | nameAndTypeIndex; 850 std::map< sal_uInt32, sal_uInt16 >::iterator i( 851 m_interfaceMethodrefInfos.find(key)); 852 if (i != m_interfaceMethodrefInfos.end()) { 853 return i->second; 854 } 855 sal_uInt16 index = nextConstantPoolIndex(1); 856 appendU1(m_constantPool, 11); 857 appendU2(m_constantPool, classIndex); 858 appendU2(m_constantPool, nameAndTypeIndex); 859 if (!m_interfaceMethodrefInfos.insert( 860 std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second) 861 { 862 OSL_ASSERT(false); 863 } 864 return index; 865 } 866 867 sal_uInt16 ClassFile::addNameAndTypeInfo( 868 rtl::OString const & name, rtl::OString const & descriptor) 869 { 870 sal_uInt16 nameIndex = addUtf8Info(name); 871 sal_uInt16 descriptorIndex = addUtf8Info(descriptor); 872 sal_uInt32 key = (static_cast< sal_uInt32 >(nameIndex) << 16) 873 | descriptorIndex; 874 std::map< sal_uInt32, sal_uInt16 >::iterator i( 875 m_nameAndTypeInfos.find(key)); 876 if (i != m_nameAndTypeInfos.end()) { 877 return i->second; 878 } 879 sal_uInt16 index = nextConstantPoolIndex(1); 880 appendU1(m_constantPool, 12); 881 appendU2(m_constantPool, nameIndex); 882 appendU2(m_constantPool, descriptorIndex); 883 if (!m_nameAndTypeInfos.insert( 884 std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second) 885 { 886 OSL_ASSERT(false); 887 } 888 return index; 889 } 890 891 void ClassFile::appendSignatureAttribute( 892 std::vector< unsigned char > & stream, rtl::OString const & signature) 893 { 894 if (signature.getLength() != 0) { 895 appendU2( 896 stream, 897 addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature")))); 898 appendU4(stream, 2); 899 appendU2(stream, addUtf8Info(signature)); 900 } 901 } 902