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 void ClassFile::write(FileStream & file) const {
696     writeU4(file, 0xCAFEBABE);
697     writeU2(file, 0);
698     writeU2(file, 46);
699     writeU2(file, m_constantPoolCount);
700     writeStream(file, m_constantPool);
701     writeU2(file, static_cast< sal_uInt16 >(m_accessFlags));
702     writeU2(file, m_thisClass);
703     writeU2(file, m_superClass);
704     writeU2(file, m_interfacesCount);
705     writeStream(file, m_interfaces);
706     writeU2(file, m_fieldsCount);
707     writeStream(file, m_fields);
708     writeU2(file, m_methodsCount);
709     writeStream(file, m_methods);
710     writeU2(file, m_attributesCount);
711     writeStream(file, m_attributes);
712 }
713 
714 sal_uInt16 ClassFile::nextConstantPoolIndex(sal_uInt16 width) {
715     OSL_ASSERT(width == 1 || width == 2);
716     if (m_constantPoolCount > SAL_MAX_UINT16 - width) {
717         throw CannotDumpException(
718             rtl::OString(
719                 RTL_CONSTASCII_STRINGPARAM(
720                     "Too many constant pool items for Java class file"
721                     " format")));
722     }
723     sal_uInt16 index = m_constantPoolCount;
724     m_constantPoolCount = m_constantPoolCount + width;
725     return index;
726 }
727 
728 sal_uInt16 ClassFile::addUtf8Info(rtl::OString const & value) {
729     std::map< rtl::OString, sal_uInt16 >::iterator i(m_utf8Infos.find(value));
730     if (i != m_utf8Infos.end()) {
731         return i->second;
732     }
733     if (value.getLength() > SAL_MAX_UINT16) {
734         throw CannotDumpException(
735             rtl::OString(
736                 RTL_CONSTASCII_STRINGPARAM(
737                     "UTF-8 string too long for Java class file format")));
738     }
739     sal_uInt16 index = nextConstantPoolIndex(1);
740     appendU1(m_constantPool, 1);
741     appendU2(m_constantPool, static_cast< sal_uInt16 >(value.getLength()));
742     for (sal_Int32 j = 0; j < value.getLength(); ++j) {
743         appendU1(m_constantPool, static_cast< sal_uInt8 >(value[j]));
744     }
745     if (!m_utf8Infos.insert(
746             std::map< rtl::OString, sal_uInt16 >::value_type(value, index)).
747         second)
748     {
749         OSL_ASSERT(false);
750     }
751     return index;
752 }
753 
754 sal_uInt16 ClassFile::addClassInfo(rtl::OString const & type) {
755     sal_uInt16 nameIndex = addUtf8Info(type);
756     std::map< sal_uInt16, sal_uInt16 >::iterator i(
757         m_classInfos.find(nameIndex));
758     if (i != m_classInfos.end()) {
759         return i->second;
760     }
761     sal_uInt16 index = nextConstantPoolIndex(1);
762     appendU1(m_constantPool, 7);
763     appendU2(m_constantPool, nameIndex);
764     if (!m_classInfos.insert(
765             std::map< sal_uInt16, sal_uInt16 >::value_type(nameIndex, index)).
766         second)
767     {
768         OSL_ASSERT(false);
769     }
770     return index;
771 }
772 
773 sal_uInt16 ClassFile::addStringInfo(rtl::OString const & value) {
774     sal_uInt16 stringIndex = addUtf8Info(value);
775     std::map< sal_uInt16, sal_uInt16 >::iterator i(
776         m_stringInfos.find(stringIndex));
777     if (i != m_stringInfos.end()) {
778         return i->second;
779     }
780     sal_uInt16 index = nextConstantPoolIndex(1);
781     appendU1(m_constantPool, 8);
782     appendU2(m_constantPool, stringIndex);
783     if (!m_stringInfos.insert(
784             std::map< sal_uInt16, sal_uInt16 >::value_type(stringIndex, index)).
785         second)
786     {
787         OSL_ASSERT(false);
788     }
789     return index;
790 }
791 
792 sal_uInt16 ClassFile::addFieldrefInfo(
793     rtl::OString const & type, rtl::OString const & name,
794     rtl::OString const & descriptor)
795 {
796     sal_uInt16 classIndex = addClassInfo(type);
797     sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
798     sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
799         | nameAndTypeIndex;
800     std::map< sal_uInt32, sal_uInt16 >::iterator i(m_fieldrefInfos.find(key));
801     if (i != m_fieldrefInfos.end()) {
802         return i->second;
803     }
804     sal_uInt16 index = nextConstantPoolIndex(1);
805     appendU1(m_constantPool, 9);
806     appendU2(m_constantPool, classIndex);
807     appendU2(m_constantPool, nameAndTypeIndex);
808     if (!m_fieldrefInfos.insert(
809             std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
810     {
811         OSL_ASSERT(false);
812     }
813     return index;
814 }
815 
816 sal_uInt16 ClassFile::addMethodrefInfo(
817     rtl::OString const & type, rtl::OString const & name,
818     rtl::OString const & descriptor)
819 {
820     sal_uInt16 classIndex = addClassInfo(type);
821     sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
822     sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
823         | nameAndTypeIndex;
824     std::map< sal_uInt32, sal_uInt16 >::iterator i(m_methodrefInfos.find(key));
825     if (i != m_methodrefInfos.end()) {
826         return i->second;
827     }
828     sal_uInt16 index = nextConstantPoolIndex(1);
829     appendU1(m_constantPool, 10);
830     appendU2(m_constantPool, classIndex);
831     appendU2(m_constantPool, nameAndTypeIndex);
832     if (!m_methodrefInfos.insert(
833             std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
834     {
835         OSL_ASSERT(false);
836     }
837     return index;
838 }
839 
840 sal_uInt16 ClassFile::addInterfaceMethodrefInfo(
841     rtl::OString const & type, rtl::OString const & name,
842     rtl::OString const & descriptor)
843 {
844     sal_uInt16 classIndex = addClassInfo(type);
845     sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
846     sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
847         | nameAndTypeIndex;
848     std::map< sal_uInt32, sal_uInt16 >::iterator i(
849         m_interfaceMethodrefInfos.find(key));
850     if (i != m_interfaceMethodrefInfos.end()) {
851         return i->second;
852     }
853     sal_uInt16 index = nextConstantPoolIndex(1);
854     appendU1(m_constantPool, 11);
855     appendU2(m_constantPool, classIndex);
856     appendU2(m_constantPool, nameAndTypeIndex);
857     if (!m_interfaceMethodrefInfos.insert(
858             std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
859     {
860         OSL_ASSERT(false);
861     }
862     return index;
863 }
864 
865 sal_uInt16 ClassFile::addNameAndTypeInfo(
866     rtl::OString const & name, rtl::OString const & descriptor)
867 {
868     sal_uInt16 nameIndex = addUtf8Info(name);
869     sal_uInt16 descriptorIndex = addUtf8Info(descriptor);
870     sal_uInt32 key = (static_cast< sal_uInt32 >(nameIndex) << 16)
871         | descriptorIndex;
872     std::map< sal_uInt32, sal_uInt16 >::iterator i(
873         m_nameAndTypeInfos.find(key));
874     if (i != m_nameAndTypeInfos.end()) {
875         return i->second;
876     }
877     sal_uInt16 index = nextConstantPoolIndex(1);
878     appendU1(m_constantPool, 12);
879     appendU2(m_constantPool, nameIndex);
880     appendU2(m_constantPool, descriptorIndex);
881     if (!m_nameAndTypeInfos.insert(
882             std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
883     {
884         OSL_ASSERT(false);
885     }
886     return index;
887 }
888 
889 void ClassFile::appendSignatureAttribute(
890     std::vector< unsigned char > & stream, rtl::OString const & signature)
891 {
892     if (signature.getLength() != 0) {
893         appendU2(
894             stream,
895             addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature"))));
896         appendU4(stream, 2);
897         appendU2(stream, addUtf8Info(signature));
898     }
899 }
900