update credits
[LibreOffice.git] / codemaker / source / javamaker / classfile.cxx
blobc427e96952ae40a9b25bfb762f8ffdf0518ff2f4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "classfile.hxx"
23 #include "codemaker/global.hxx"
24 #include "codemaker/options.hxx"
25 #include "codemaker/unotype.hxx"
27 #include "boost/static_assert.hpp"
28 #include "osl/diagnose.h"
29 #include "rtl/string.h"
30 #include "rtl/string.hxx"
31 #include "sal/types.h"
33 #include <map>
34 #include <utility>
35 #include <vector>
37 using codemaker::javamaker::ClassFile;
39 namespace {
41 void appendU1(std::vector< unsigned char > & stream, sal_uInt8 data) {
42 stream.push_back(static_cast< unsigned char >(data));
45 void appendU2(std::vector< unsigned char > & stream, sal_uInt16 data) {
46 stream.push_back(static_cast< unsigned char >(data >> 8));
47 stream.push_back(static_cast< unsigned char >(data & 0xFF));
50 void appendU4(std::vector< unsigned char > & stream, sal_uInt32 data) {
51 stream.push_back(static_cast< unsigned char >(data >> 24));
52 stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF));
53 stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF));
54 stream.push_back(static_cast< unsigned char >(data & 0xFF));
57 void appendU8(std::vector< unsigned char > & stream, sal_uInt64 data) {
58 stream.push_back(static_cast< unsigned char >(data >> 56));
59 stream.push_back(static_cast< unsigned char >((data >> 48) & 0xFF));
60 stream.push_back(static_cast< unsigned char >((data >> 40) & 0xFF));
61 stream.push_back(static_cast< unsigned char >((data >> 32) & 0xFF));
62 stream.push_back(static_cast< unsigned char >((data >> 24) & 0xFF));
63 stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF));
64 stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF));
65 stream.push_back(static_cast< unsigned char >(data & 0xFF));
68 void appendStream(
69 std::vector< unsigned char > & stream,
70 std::vector< unsigned char > const & data)
72 stream.insert(stream.end(), data.begin(), data.end());
75 void write(FileStream & file, void const * buffer, sal_uInt64 size) {
76 if (!file.write(buffer, size))
77 throw CannotDumpException("Error writing file");
80 void writeU2(FileStream & file, sal_uInt16 data) {
81 unsigned char buf[] = {
82 static_cast< unsigned char >(data >> 8),
83 static_cast< unsigned char >(data & 0xFF) };
84 write(file, buf, sizeof buf);
87 void writeU4(FileStream & file, sal_uInt32 data) {
88 unsigned char buf[] = {
89 static_cast< unsigned char >(data >> 24),
90 static_cast< unsigned char >((data >> 16) & 0xFF),
91 static_cast< unsigned char >((data >> 8) & 0xFF),
92 static_cast< unsigned char >(data & 0xFF) };
93 write(file, buf, sizeof buf);
96 void writeStream(FileStream & file, std::vector< unsigned char > const & stream)
98 std::vector< unsigned char >::size_type n = stream.size();
99 BOOST_STATIC_ASSERT(
100 sizeof (std::vector< unsigned char >::size_type)
101 <= sizeof (sal_uInt64));
102 // both unsigned integral, so sizeof is a practically sufficient
103 // approximation of std::numeric_limits<T1>::max() <=
104 // std::numeric_limits<T2>::max()
105 if (n != 0) {
106 write(file, &stream[0], static_cast< sal_uInt64 >(n));
112 ClassFile::Code::~Code() {}
114 void ClassFile::Code::instrAastore() {
115 // aastore:
116 appendU1(m_code, 0x53);
119 void ClassFile::Code::instrAconstNull() {
120 // aconst_null:
121 appendU1(m_code, 0x01);
124 void ClassFile::Code::instrAnewarray(OString const & type) {
125 // anewarray <indexbyte1> <indexbyte2>:
126 appendU1(m_code, 0xBD);
127 appendU2(m_code, m_classFile.addClassInfo(type));
130 void ClassFile::Code::instrAreturn() {
131 // areturn:
132 appendU1(m_code, 0xB0);
135 void ClassFile::Code::instrAthrow() {
136 // athrow:
137 appendU1(m_code, 0xBF);
140 void ClassFile::Code::instrCheckcast(OString const & type) {
141 // checkcast <indexbyte1> <indexbyte2>:
142 appendU1(m_code, 0xC0);
143 appendU2(m_code, m_classFile.addClassInfo(type));
146 void ClassFile::Code::instrDup() {
147 // dup:
148 appendU1(m_code, 0x59);
151 void ClassFile::Code::instrGetstatic(
152 OString const & type, OString const & name,
153 OString const & descriptor)
155 // getstatic <indexbyte1> <indexbyte2>:
156 appendU1(m_code, 0xB2);
157 appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor));
160 ClassFile::Code::Branch ClassFile::Code::instrIfAcmpne() {
161 // if_acmpne <branchbyte1> <branchbyte2>:
162 Branch branch = m_code.size();
163 appendU1(m_code, 0xA6);
164 appendU2(m_code, 0);
165 return branch;
168 ClassFile::Code::Branch ClassFile::Code::instrIfeq() {
169 // ifeq <branchbyte1> <branchbyte2>:
170 Branch branch = m_code.size();
171 appendU1(m_code, 0x99);
172 appendU2(m_code, 0);
173 return branch;
176 ClassFile::Code::Branch ClassFile::Code::instrIfnull() {
177 // ifnull <branchbyte1> <branchbyte2>:
178 Branch branch = m_code.size();
179 appendU1(m_code, 0xC6);
180 appendU2(m_code, 0);
181 return branch;
184 void ClassFile::Code::instrInstanceof(OString const & type) {
185 // instanceof <indexbyte1> <indexbyte2>:
186 appendU1(m_code, 0xC1);
187 appendU2(m_code, m_classFile.addClassInfo(type));
190 void ClassFile::Code::instrInvokeinterface(
191 OString const & type, OString const & name,
192 OString const & descriptor, sal_uInt8 args)
194 // invokeinterface <indexbyte1> <indexbyte2> <nargs> 0:
195 appendU1(m_code, 0xB9);
196 appendU2(
197 m_code, m_classFile.addInterfaceMethodrefInfo(type, name, descriptor));
198 appendU1(m_code, args);
199 appendU1(m_code, 0);
202 void ClassFile::Code::instrInvokespecial(
203 OString const & type, OString const & name,
204 OString const & descriptor)
206 // invokespecial <indexbyte1> <indexbyte2>:
207 appendU1(m_code, 0xB7);
208 appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor));
211 void ClassFile::Code::instrInvokestatic(
212 OString const & type, OString const & name,
213 OString const & descriptor)
215 // invokestatic <indexbyte1> <indexbyte2>:
216 appendU1(m_code, 0xB8);
217 appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor));
220 void ClassFile::Code::instrInvokevirtual(
221 OString const & type, OString const & name,
222 OString const & descriptor)
224 // invokevirtual <indexbyte1> <indexbyte2>:
225 appendU1(m_code, 0xB6);
226 appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor));
229 void ClassFile::Code::instrLookupswitch(
230 Code const * defaultBlock,
231 std::list< std::pair< sal_Int32, Code * > > const & blocks)
233 // lookupswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3>
234 // <defaultbyte4> <npairs1> <npairs2> <npairs3> <npairs4>
235 // <match--offset pairs...>:
236 std::list< std::pair< sal_Int32, Code * > >::size_type size = blocks.size();
237 if (size > SAL_MAX_INT32) {
238 throw CannotDumpException("Lookup-switch too large for Java class file format");
240 Position pos1 = m_code.size();
241 appendU1(m_code, 0xAB);
242 int pad = (pos1 + 1) % 4;
243 for (int i = 0; i < pad; ++i) {
244 appendU1(m_code, 0);
246 Position pos2 = pos1 + 1 + pad + 8 + blocks.size() * 8; //FIXME: overflow
247 appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); //FIXME: overflow
248 pos2 += defaultBlock->m_code.size(); //FIXME: overflow
249 appendU4(m_code, static_cast< sal_uInt32 >(size));
250 for (std::list< std::pair< sal_Int32, Code * > >::const_iterator i(
251 blocks.begin());
252 i != blocks.end(); ++i)
254 appendU4(m_code, static_cast< sal_uInt32 >(i->first));
255 appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1));
256 //FIXME: overflow
257 pos2 += i->second->m_code.size(); //FIXME: overflow
259 appendStream(m_code, defaultBlock->m_code);
260 for (std::list< std::pair< sal_Int32, Code * > >::const_iterator i(
261 blocks.begin());
262 i != blocks.end(); ++i)
264 appendStream(m_code, i->second->m_code);
268 void ClassFile::Code::instrNew(OString const & type) {
269 // new <indexbyte1> <indexbyte2>:
270 appendU1(m_code, 0xBB);
271 appendU2(m_code, m_classFile.addClassInfo(type));
274 void ClassFile::Code::instrNewarray(codemaker::UnoType::Sort sort) {
275 OSL_ASSERT(
276 sort >= codemaker::UnoType::SORT_BOOLEAN
277 && sort <= codemaker::UnoType::SORT_CHAR);
278 // newarray <atype>:
279 appendU1(m_code, 0xBC);
280 static sal_uInt8 const atypes[codemaker::UnoType::SORT_CHAR] = {
281 0x04, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x06, 0x07, 0x05 };
282 appendU1(m_code, atypes[sort - 1]);
285 void ClassFile::Code::instrPop() {
286 // pop:
287 appendU1(m_code, 0x57);
290 void ClassFile::Code::instrPutfield(
291 OString const & type, OString const & name,
292 OString const & descriptor)
294 // putfield <indexbyte1> <indexbyte2>:
295 appendU1(m_code, 0xB5);
296 appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor));
299 void ClassFile::Code::instrPutstatic(
300 OString const & type, OString const & name,
301 OString const & descriptor)
303 // putstatic <indexbyte1> <indexbyte2>:
304 appendU1(m_code, 0xB3);
305 appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor));
308 void ClassFile::Code::instrReturn() {
309 // return:
310 appendU1(m_code, 0xB1);
313 void ClassFile::Code::instrSwap() {
314 // swap:
315 appendU1(m_code, 0x5F);
318 void ClassFile::Code::instrTableswitch(
319 Code const * defaultBlock, sal_Int32 low,
320 std::list< Code * > const & blocks)
322 // tableswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3>
323 // <defaultbyte4> <lowbyte1> <lowbyte2> <lowbyte3> <lowbyte4> <highbyte1>
324 // <highbyte2> <highbyte3> <highbyte4> <jump offsets...>:
325 Position pos1 = m_code.size();
326 appendU1(m_code, 0xAA);
327 int pad = (pos1 + 1) % 4;
328 for (int i = 0; i < pad; ++i) {
329 appendU1(m_code, 0);
331 std::list< Code * >::size_type size = blocks.size();
332 Position pos2 = pos1 + 1 + pad + 12 + size * 4; //FIXME: overflow
333 sal_uInt32 defaultOffset = static_cast< sal_uInt32 >(pos2 - pos1);
334 //FIXME: overflow
335 appendU4(m_code, defaultOffset);
336 pos2 += defaultBlock->m_code.size(); //FIXME: overflow
337 appendU4(m_code, static_cast< sal_uInt32 >(low));
338 appendU4(m_code, static_cast< sal_uInt32 >(low + (size - 1)));
339 for (std::list< Code * >::const_iterator i(blocks.begin());
340 i != blocks.end(); ++i)
342 if (*i == 0) {
343 appendU4(m_code, defaultOffset);
344 } else {
345 appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1));
346 //FIXME: overflow
347 pos2 += (*i)->m_code.size(); //FIXME: overflow
350 appendStream(m_code, defaultBlock->m_code);
351 for (std::list< Code * >::const_iterator i(blocks.begin());
352 i != blocks.end(); ++i)
354 if (*i != 0) {
355 appendStream(m_code, (*i)->m_code);
360 void ClassFile::Code::loadIntegerConstant(sal_Int32 value) {
361 if (value >= -1 && value <= 5) {
362 // iconst_<i>:
363 appendU1(m_code, static_cast< sal_uInt8 >(0x02 + value + 1));
364 } else if (value >= -128 && value <= 127) {
365 // bipush <byte>:
366 appendU1(m_code, 0x10);
367 appendU1(m_code, static_cast< sal_uInt8 >(value));
368 } else if (value >= -32768 && value <= 32767) {
369 // sipush <byte1> <byte2>:
370 appendU1(m_code, 0x11);
371 appendU2(m_code, static_cast< sal_uInt16 >(value));
372 } else {
373 ldc(m_classFile.addIntegerInfo(value));
377 void ClassFile::Code::loadStringConstant(OString const & value) {
378 ldc(m_classFile.addStringInfo(value));
381 void ClassFile::Code::loadLocalInteger(sal_uInt16 index) {
382 accessLocal(index, 0x1A, 0x15); // iload_<n>, iload
385 void ClassFile::Code::loadLocalLong(sal_uInt16 index) {
386 accessLocal(index, 0x1E, 0x16); // load_<n>, load
389 void ClassFile::Code::loadLocalFloat(sal_uInt16 index) {
390 accessLocal(index, 0x22, 0x17); // load_<n>, load
393 void ClassFile::Code::loadLocalDouble(sal_uInt16 index) {
394 accessLocal(index, 0x26, 0x18); // load_<n>, load
397 void ClassFile::Code::loadLocalReference(sal_uInt16 index) {
398 accessLocal(index, 0x2A, 0x19); // aload_<n>, aload
401 void ClassFile::Code::storeLocalReference(sal_uInt16 index) {
402 accessLocal(index, 0x4B, 0x3A); // astore_<n>, astore
405 void ClassFile::Code::branchHere(Branch branch) {
406 std::vector< unsigned char >::size_type n = m_code.size();
407 OSL_ASSERT(n > branch && n - branch <= SAL_MAX_INT16);
408 n -= branch;
409 m_code[branch + 1] = static_cast< sal_uInt8 >(n >> 8);
410 m_code[branch + 2] = static_cast< sal_uInt8 >(n & 0xFF);
413 void ClassFile::Code::addException(
414 Position start, Position end, Position handler, OString const & type)
416 OSL_ASSERT(start < end && end <= m_code.size() && handler <= m_code.size());
417 if (m_exceptionTableLength == SAL_MAX_UINT16) {
418 throw CannotDumpException("Too many exception handlers for Java class file format");
420 ++m_exceptionTableLength;
421 appendU2(m_exceptionTable, static_cast< sal_uInt16 >(start));
422 //FIXME: overflow
423 appendU2(m_exceptionTable, static_cast< sal_uInt16 >(end));
424 //FIXME: overflow
425 appendU2(m_exceptionTable, static_cast< sal_uInt16 >(handler));
426 //FIXME: overflow
427 appendU2(m_exceptionTable, m_classFile.addClassInfo(type));
430 ClassFile::Code::Position ClassFile::Code::getPosition() const {
431 return m_code.size();
434 ClassFile::Code::Code(ClassFile & classFile):
435 m_classFile(classFile), m_exceptionTableLength(0)
438 void ClassFile::Code::ldc(sal_uInt16 index) {
439 if (index <= 0xFF) {
440 // ldc <index>:
441 appendU1(m_code, 0x12);
442 appendU1(m_code, static_cast< sal_uInt8 >(index));
443 } else {
444 // ldc_w <indexbyte1> <indexbyte2>:
445 appendU1(m_code, 0x13);
446 appendU2(m_code, index);
450 void ClassFile::Code::accessLocal(
451 sal_uInt16 index, sal_uInt8 fastOp, sal_uInt8 normalOp)
453 if (index <= 3) {
454 // ...load/store_<n>:
455 appendU1(m_code, static_cast< sal_uInt8 >(fastOp + index));
456 } else if (index <= 0xFF) {
457 // ...load/store <index>:
458 appendU1(m_code, normalOp);
459 appendU1(m_code, static_cast< sal_uInt8 >(index));
460 } else {
461 // wide ...load/store <indexbyte1> <indexbyte2>:
462 appendU1(m_code, 0xC4);
463 appendU1(m_code, normalOp);
464 appendU2(m_code, index);
468 ClassFile::ClassFile(
469 AccessFlags accessFlags, OString const & thisClass,
470 OString const & superClass, OString const & signature):
471 m_constantPoolCount(1), m_accessFlags(accessFlags), m_interfacesCount(0),
472 m_fieldsCount(0), m_methodsCount(0), m_attributesCount(0)
474 m_thisClass = addClassInfo(thisClass);
475 m_superClass = addClassInfo(superClass);
476 if (!signature.isEmpty()) {
477 ++m_attributesCount;
478 appendU2(m_attributes, addUtf8Info("Signature"));
479 appendU4(m_attributes, 2);
480 appendU2(m_attributes, addUtf8Info(signature));
484 ClassFile::~ClassFile() {}
486 ClassFile::Code * ClassFile::newCode() {
487 return new Code(*this);
490 sal_uInt16 ClassFile::addIntegerInfo(sal_Int32 value) {
491 std::map< sal_Int32, sal_uInt16 >::iterator i(m_integerInfos.find(value));
492 if (i != m_integerInfos.end()) {
493 return i->second;
495 sal_uInt16 index = nextConstantPoolIndex(1);
496 appendU1(m_constantPool, 3);
497 appendU4(m_constantPool, static_cast< sal_uInt32 >(value));
498 if (!m_integerInfos.insert(
499 std::map< sal_Int32, sal_uInt16 >::value_type(value, index)).second)
501 OSL_ASSERT(false);
503 return index;
506 sal_uInt16 ClassFile::addFloatInfo(float value) {
507 std::map< float, sal_uInt16 >::iterator i(m_floatInfos.find(value));
508 if (i != m_floatInfos.end()) {
509 return i->second;
511 sal_uInt16 index = nextConstantPoolIndex(1);
512 appendU1(m_constantPool, 4);
513 union { float floatBytes; sal_uInt32 uint32Bytes; } bytes;
514 bytes.floatBytes = value;
515 appendU4(m_constantPool, bytes.uint32Bytes);
516 if (!m_floatInfos.insert(
517 std::map< float, sal_uInt16 >::value_type(value, index)).second)
519 OSL_ASSERT(false);
521 return index;
524 sal_uInt16 ClassFile::addLongInfo(sal_Int64 value) {
525 std::map< sal_Int64, sal_uInt16 >::iterator i(m_longInfos.find(value));
526 if (i != m_longInfos.end()) {
527 return i->second;
529 sal_uInt16 index = nextConstantPoolIndex(2);
530 appendU1(m_constantPool, 5);
531 appendU8(m_constantPool, static_cast< sal_uInt64 >(value));
532 if (!m_longInfos.insert(
533 std::map< sal_Int64, sal_uInt16 >::value_type(value, index)).second)
535 OSL_ASSERT(false);
537 return index;
540 sal_uInt16 ClassFile::addDoubleInfo(double value) {
541 std::map< double, sal_uInt16 >::iterator i(m_doubleInfos.find(value));
542 if (i != m_doubleInfos.end()) {
543 return i->second;
545 sal_uInt16 index = nextConstantPoolIndex(2);
546 appendU1(m_constantPool, 6);
547 union { double doubleBytes; sal_uInt64 uint64Bytes; } bytes;
548 bytes.doubleBytes = value;
549 appendU8(m_constantPool, bytes.uint64Bytes);
550 if (!m_doubleInfos.insert(
551 std::map< double, sal_uInt16 >::value_type(value, index)).second)
553 OSL_ASSERT(false);
555 return index;
558 void ClassFile::addInterface(OString const & interface) {
559 if (m_interfacesCount == SAL_MAX_UINT16) {
560 throw CannotDumpException("Too many interfaces for Java class file format");
562 ++m_interfacesCount;
563 appendU2(m_interfaces, addClassInfo(interface));
566 void ClassFile::addField(
567 AccessFlags accessFlags, OString const & name,
568 OString const & descriptor, sal_uInt16 constantValueIndex,
569 OString const & signature)
571 if (m_fieldsCount == SAL_MAX_UINT16) {
572 throw CannotDumpException("Too many fields for Java class file format");
574 ++m_fieldsCount;
575 appendU2(m_fields, static_cast< sal_uInt16 >(accessFlags));
576 appendU2(m_fields, addUtf8Info(name));
577 appendU2(m_fields, addUtf8Info(descriptor));
578 appendU2(
579 m_fields,
580 ((constantValueIndex == 0 ? 0 : 1)
581 + (signature.isEmpty() ? 0 : 1)));
582 if (constantValueIndex != 0) {
583 appendU2(m_fields, addUtf8Info("ConstantValue"));
584 appendU4(m_fields, 2);
585 appendU2(m_fields, constantValueIndex);
587 appendSignatureAttribute(m_fields, signature);
590 void ClassFile::addMethod(
591 AccessFlags accessFlags, OString const & name,
592 OString const & descriptor, Code const * code,
593 std::vector< OString > const & exceptions,
594 OString const & signature)
596 if (m_methodsCount == SAL_MAX_UINT16) {
597 throw CannotDumpException("Too many methods for Java class file format");
599 ++m_methodsCount;
600 appendU2(m_methods, static_cast< sal_uInt16 >(accessFlags));
601 appendU2(m_methods, addUtf8Info(name));
602 appendU2(m_methods, addUtf8Info(descriptor));
603 std::vector< OString >::size_type excs = exceptions.size();
604 if (excs > SAL_MAX_UINT16) {
605 throw CannotDumpException("Too many exception specifications for Java class file format");
607 appendU2(
608 m_methods,
609 ((code == 0 ? 0 : 1) + (exceptions.empty() ? 0 : 1)
610 + (signature.isEmpty() ? 0 : 1)));
611 if (code != 0) {
612 std::vector< unsigned char >::size_type codeSize = code->m_code.size();
613 std::vector< unsigned char >::size_type exceptionTableSize
614 = code->m_exceptionTable.size();
615 if (codeSize > SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2)
616 || (exceptionTableSize
617 > (SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2)
618 - static_cast< sal_uInt32 >(codeSize))))
620 throw CannotDumpException("Code block is too big for Java class file format");
622 appendU2(m_methods, addUtf8Info("Code"));
623 appendU4(
624 m_methods,
625 (2 + 2 + 4 + static_cast< sal_uInt32 >(codeSize) + 2
626 + static_cast< sal_uInt32 >(exceptionTableSize) + 2));
627 appendU2(m_methods, code->m_maxStack);
628 appendU2(m_methods, code->m_maxLocals);
629 appendU4(m_methods, static_cast< sal_uInt32 >(codeSize));
630 appendStream(m_methods, code->m_code);
631 appendU2(m_methods, code->m_exceptionTableLength);
632 appendStream(m_methods, code->m_exceptionTable);
633 appendU2(m_methods, 0);
635 if (!exceptions.empty()) {
636 appendU2(m_methods, addUtf8Info("Exceptions"));
637 appendU4(
638 m_methods,
639 static_cast< sal_uInt32 >(2 + 2 * static_cast< sal_uInt32 >(excs)));
640 appendU2(m_methods, static_cast< sal_uInt16 >(excs));
641 for (std::vector< OString >::const_iterator i(exceptions.begin());
642 i != exceptions.end(); ++i)
644 appendU2(m_methods, addClassInfo(*i));
647 appendSignatureAttribute(m_methods, signature);
650 void ClassFile::write(FileStream & file) const {
651 writeU4(file, 0xCAFEBABE);
652 writeU2(file, 0);
653 writeU2(file, 49); // class file version of JRE 1.5
654 writeU2(file, m_constantPoolCount);
655 writeStream(file, m_constantPool);
656 writeU2(file, static_cast< sal_uInt16 >(m_accessFlags));
657 writeU2(file, m_thisClass);
658 writeU2(file, m_superClass);
659 writeU2(file, m_interfacesCount);
660 writeStream(file, m_interfaces);
661 writeU2(file, m_fieldsCount);
662 writeStream(file, m_fields);
663 writeU2(file, m_methodsCount);
664 writeStream(file, m_methods);
665 writeU2(file, m_attributesCount);
666 writeStream(file, m_attributes);
669 sal_uInt16 ClassFile::nextConstantPoolIndex(sal_uInt16 width) {
670 OSL_ASSERT(width == 1 || width == 2);
671 if (m_constantPoolCount > SAL_MAX_UINT16 - width) {
672 throw CannotDumpException("Too many constant pool items for Java class file format");
674 sal_uInt16 index = m_constantPoolCount;
675 m_constantPoolCount = m_constantPoolCount + width;
676 return index;
679 sal_uInt16 ClassFile::addUtf8Info(OString const & value) {
680 std::map< OString, sal_uInt16 >::iterator i(m_utf8Infos.find(value));
681 if (i != m_utf8Infos.end()) {
682 return i->second;
684 if (value.getLength() > SAL_MAX_UINT16) {
685 throw CannotDumpException("UTF-8 string too long for Java class file format");
687 sal_uInt16 index = nextConstantPoolIndex(1);
688 appendU1(m_constantPool, 1);
689 appendU2(m_constantPool, static_cast< sal_uInt16 >(value.getLength()));
690 for (sal_Int32 j = 0; j < value.getLength(); ++j) {
691 appendU1(m_constantPool, static_cast< sal_uInt8 >(value[j]));
693 if (!m_utf8Infos.insert(
694 std::map< OString, sal_uInt16 >::value_type(value, index)).
695 second)
697 OSL_ASSERT(false);
699 return index;
702 sal_uInt16 ClassFile::addClassInfo(OString const & type) {
703 sal_uInt16 nameIndex = addUtf8Info(type);
704 std::map< sal_uInt16, sal_uInt16 >::iterator i(
705 m_classInfos.find(nameIndex));
706 if (i != m_classInfos.end()) {
707 return i->second;
709 sal_uInt16 index = nextConstantPoolIndex(1);
710 appendU1(m_constantPool, 7);
711 appendU2(m_constantPool, nameIndex);
712 if (!m_classInfos.insert(
713 std::map< sal_uInt16, sal_uInt16 >::value_type(nameIndex, index)).
714 second)
716 OSL_ASSERT(false);
718 return index;
721 sal_uInt16 ClassFile::addStringInfo(OString const & value) {
722 sal_uInt16 stringIndex = addUtf8Info(value);
723 std::map< sal_uInt16, sal_uInt16 >::iterator i(
724 m_stringInfos.find(stringIndex));
725 if (i != m_stringInfos.end()) {
726 return i->second;
728 sal_uInt16 index = nextConstantPoolIndex(1);
729 appendU1(m_constantPool, 8);
730 appendU2(m_constantPool, stringIndex);
731 if (!m_stringInfos.insert(
732 std::map< sal_uInt16, sal_uInt16 >::value_type(stringIndex, index)).
733 second)
735 OSL_ASSERT(false);
737 return index;
740 sal_uInt16 ClassFile::addFieldrefInfo(
741 OString const & type, OString const & name,
742 OString const & descriptor)
744 sal_uInt16 classIndex = addClassInfo(type);
745 sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
746 sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
747 | nameAndTypeIndex;
748 std::map< sal_uInt32, sal_uInt16 >::iterator i(m_fieldrefInfos.find(key));
749 if (i != m_fieldrefInfos.end()) {
750 return i->second;
752 sal_uInt16 index = nextConstantPoolIndex(1);
753 appendU1(m_constantPool, 9);
754 appendU2(m_constantPool, classIndex);
755 appendU2(m_constantPool, nameAndTypeIndex);
756 if (!m_fieldrefInfos.insert(
757 std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
759 OSL_ASSERT(false);
761 return index;
764 sal_uInt16 ClassFile::addMethodrefInfo(
765 OString const & type, OString const & name,
766 OString const & descriptor)
768 sal_uInt16 classIndex = addClassInfo(type);
769 sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
770 sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
771 | nameAndTypeIndex;
772 std::map< sal_uInt32, sal_uInt16 >::iterator i(m_methodrefInfos.find(key));
773 if (i != m_methodrefInfos.end()) {
774 return i->second;
776 sal_uInt16 index = nextConstantPoolIndex(1);
777 appendU1(m_constantPool, 10);
778 appendU2(m_constantPool, classIndex);
779 appendU2(m_constantPool, nameAndTypeIndex);
780 if (!m_methodrefInfos.insert(
781 std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
783 OSL_ASSERT(false);
785 return index;
788 sal_uInt16 ClassFile::addInterfaceMethodrefInfo(
789 OString const & type, OString const & name,
790 OString const & descriptor)
792 sal_uInt16 classIndex = addClassInfo(type);
793 sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
794 sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
795 | nameAndTypeIndex;
796 std::map< sal_uInt32, sal_uInt16 >::iterator i(
797 m_interfaceMethodrefInfos.find(key));
798 if (i != m_interfaceMethodrefInfos.end()) {
799 return i->second;
801 sal_uInt16 index = nextConstantPoolIndex(1);
802 appendU1(m_constantPool, 11);
803 appendU2(m_constantPool, classIndex);
804 appendU2(m_constantPool, nameAndTypeIndex);
805 if (!m_interfaceMethodrefInfos.insert(
806 std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
808 OSL_ASSERT(false);
810 return index;
813 sal_uInt16 ClassFile::addNameAndTypeInfo(
814 OString const & name, OString const & descriptor)
816 sal_uInt16 nameIndex = addUtf8Info(name);
817 sal_uInt16 descriptorIndex = addUtf8Info(descriptor);
818 sal_uInt32 key = (static_cast< sal_uInt32 >(nameIndex) << 16)
819 | descriptorIndex;
820 std::map< sal_uInt32, sal_uInt16 >::iterator i(
821 m_nameAndTypeInfos.find(key));
822 if (i != m_nameAndTypeInfos.end()) {
823 return i->second;
825 sal_uInt16 index = nextConstantPoolIndex(1);
826 appendU1(m_constantPool, 12);
827 appendU2(m_constantPool, nameIndex);
828 appendU2(m_constantPool, descriptorIndex);
829 if (!m_nameAndTypeInfos.insert(
830 std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
832 OSL_ASSERT(false);
834 return index;
837 void ClassFile::appendSignatureAttribute(
838 std::vector< unsigned char > & stream, OString const & signature)
840 if (!signature.isEmpty()) {
841 appendU2(stream, addUtf8Info("Signature"));
842 appendU4(stream, 2);
843 appendU2(stream, addUtf8Info(signature));
847 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */