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