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