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 
appendU1(std::vector<unsigned char> & stream,sal_uInt8 data)47 void appendU1(std::vector< unsigned char > & stream, sal_uInt8 data) {
48     stream.push_back(static_cast< unsigned char >(data));
49 }
50 
appendU2(std::vector<unsigned char> & stream,sal_uInt16 data)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 
appendU4(std::vector<unsigned char> & stream,sal_uInt32 data)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 
appendU8(std::vector<unsigned char> & stream,sal_uInt64 data)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 
appendStream(std::vector<unsigned char> & stream,std::vector<unsigned char> const & data)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 
write(FileStream & file,void const * buffer,sal_uInt64 size)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 
writeU1(FileStream & file,sal_uInt8 data)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 
writeU2(FileStream & file,sal_uInt16 data)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 
writeU4(FileStream & file,sal_uInt32 data)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 
writeStream(FileStream & file,std::vector<unsigned char> const & stream)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 
~Code()125 ClassFile::Code::~Code() {}
126 
instrAastore()127 void ClassFile::Code::instrAastore() {
128     // aastore:
129     appendU1(m_code, 0x53);
130 }
131 
instrAconstNull()132 void ClassFile::Code::instrAconstNull() {
133     // aconst_null:
134     appendU1(m_code, 0x01);
135 }
136 
instrAnewarray(rtl::OString const & type)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 
instrAreturn()143 void ClassFile::Code::instrAreturn() {
144     // areturn:
145     appendU1(m_code, 0xB0);
146 }
147 
instrAthrow()148 void ClassFile::Code::instrAthrow() {
149     // athrow:
150     appendU1(m_code, 0xBF);
151 }
152 
instrCheckcast(rtl::OString const & type)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 
instrDup()159 void ClassFile::Code::instrDup() {
160     // dup:
161     appendU1(m_code, 0x59);
162 }
163 
instrGetstatic(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor)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 
instrIfAcmpne()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 
instrIfeq()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 
instrIfnull()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 
instrInstanceof(rtl::OString const & type)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 
instrInvokeinterface(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor,sal_uInt8 args)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 
instrInvokespecial(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor)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 
instrInvokestatic(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor)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 
instrInvokevirtual(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor)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 
instrLookupswitch(Code const * defaultBlock,std::list<std::pair<sal_Int32,Code * >> const & blocks)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 
instrNew(rtl::OString const & type)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 
instrNewarray(codemaker::UnoType::Sort sort)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 
instrPop()301 void ClassFile::Code::instrPop() {
302     // pop:
303     appendU1(m_code, 0x57);
304 }
305 
instrPutfield(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor)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 
instrPutstatic(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor)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 
instrReturn()324 void ClassFile::Code::instrReturn() {
325     // return:
326     appendU1(m_code, 0xB1);
327 }
328 
instrSwap()329 void ClassFile::Code::instrSwap() {
330     // swap:
331     appendU1(m_code, 0x5F);
332 }
333 
instrTableswitch(Code const * defaultBlock,sal_Int32 low,std::list<Code * > const & blocks)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 
loadIntegerConstant(sal_Int32 value)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 
loadStringConstant(rtl::OString const & value)393 void ClassFile::Code::loadStringConstant(rtl::OString const & value) {
394     ldc(m_classFile.addStringInfo(value));
395 }
396 
loadLocalInteger(sal_uInt16 index)397 void ClassFile::Code::loadLocalInteger(sal_uInt16 index) {
398     accessLocal(index, 0x1A, 0x15); // iload_<n>, iload
399 }
400 
loadLocalLong(sal_uInt16 index)401 void ClassFile::Code::loadLocalLong(sal_uInt16 index) {
402     accessLocal(index, 0x1E, 0x16); // load_<n>, load
403 }
404 
loadLocalFloat(sal_uInt16 index)405 void ClassFile::Code::loadLocalFloat(sal_uInt16 index) {
406     accessLocal(index, 0x22, 0x17); // load_<n>, load
407 }
408 
loadLocalDouble(sal_uInt16 index)409 void ClassFile::Code::loadLocalDouble(sal_uInt16 index) {
410     accessLocal(index, 0x26, 0x18); // load_<n>, load
411 }
412 
loadLocalReference(sal_uInt16 index)413 void ClassFile::Code::loadLocalReference(sal_uInt16 index) {
414     accessLocal(index, 0x2A, 0x19); // aload_<n>, aload
415 }
416 
storeLocalReference(sal_uInt16 index)417 void ClassFile::Code::storeLocalReference(sal_uInt16 index) {
418     accessLocal(index, 0x4B, 0x3A); // astore_<n>, astore
419 }
420 
branchHere(Branch branch)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 
addException(Position start,Position end,Position handler,rtl::OString const & type)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 
getPosition() const449 ClassFile::Code::Position ClassFile::Code::getPosition() const {
450     return m_code.size();
451 }
452 
Code(ClassFile & classFile)453 ClassFile::Code::Code(ClassFile & classFile):
454     m_classFile(classFile), m_exceptionTableLength(0)
455 {}
456 
ldc(sal_uInt16 index)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 
accessLocal(sal_uInt16 index,sal_uInt8 fastOp,sal_uInt8 normalOp)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 
ClassFile(AccessFlags accessFlags,rtl::OString const & thisClass,rtl::OString const & superClass,rtl::OString const & signature)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.isEmpty() ) {
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 
~ClassFile()505 ClassFile::~ClassFile() {}
506 
newCode()507 ClassFile::Code * ClassFile::newCode() {
508     return new Code(*this);
509 }
510 
addIntegerInfo(sal_Int32 value)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 
addFloatInfo(float value)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 
addLongInfo(sal_Int64 value)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 
addDoubleInfo(double value)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 
addInterface(rtl::OString const & interface)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 
addField(AccessFlags accessFlags,rtl::OString const & name,rtl::OString const & descriptor,sal_uInt16 constantValueIndex,rtl::OString const & signature)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.isEmpty() ? 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 
addMethod(AccessFlags accessFlags,rtl::OString const & name,rtl::OString const & descriptor,Code const * code,std::vector<rtl::OString> const & exceptions,rtl::OString const & signature)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.isEmpty() ? 0 : 1)));
648     if (code != 0) {
649         std::vector< unsigned char >::size_type codeSize = code->m_code.size();
650         std::vector< unsigned char >::size_type exceptionTableSize
651             = code->m_exceptionTable.size();
652         if (codeSize > SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2)
653             || (exceptionTableSize
654                 > (SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2)
655                    - static_cast< sal_uInt32 >(codeSize))))
656         {
657             throw CannotDumpException(
658                 rtl::OString(
659                     RTL_CONSTASCII_STRINGPARAM(
660                         "Code block is too big for Java class file format")));
661         }
662         appendU2(
663             m_methods,
664             addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Code"))));
665         appendU4(
666             m_methods,
667             (2 + 2 + 4 + static_cast< sal_uInt32 >(codeSize) + 2
668              + static_cast< sal_uInt32 >(exceptionTableSize) + 2));
669         appendU2(m_methods, code->m_maxStack);
670         appendU2(m_methods, code->m_maxLocals);
671         appendU4(m_methods, static_cast< sal_uInt32 >(codeSize));
672         appendStream(m_methods, code->m_code);
673         appendU2(m_methods, code->m_exceptionTableLength);
674         appendStream(m_methods, code->m_exceptionTable);
675         appendU2(m_methods, 0);
676     }
677     if (!exceptions.empty()) {
678         appendU2(
679             m_methods,
680             addUtf8Info(
681                 rtl::OString(RTL_CONSTASCII_STRINGPARAM("Exceptions"))));
682         appendU4(
683             m_methods,
684             static_cast< sal_uInt32 >(2 + 2 * static_cast< sal_uInt32 >(excs)));
685         appendU2(m_methods, static_cast< sal_uInt16 >(excs));
686         for (std::vector< rtl::OString >::const_iterator i(exceptions.begin());
687              i != exceptions.end(); ++i)
688         {
689             appendU2(m_methods, addClassInfo(*i));
690         }
691     }
692     appendSignatureAttribute(m_methods, signature);
693 }
694 
695 #define CLASSFILE_FMT 49.0 // a classfile format understood by JDK 5/6/7
696 
write(FileStream & file) const697 void ClassFile::write(FileStream & file) const {
698     writeU4(file, 0xCAFEBABE);
699     writeU2(file, static_cast<sal_uInt16>((CLASSFILE_FMT-(int)CLASSFILE_FMT)*100000));
700     writeU2(file, static_cast<sal_uInt16>((int)CLASSFILE_FMT));
701     writeU2(file, m_constantPoolCount);
702     writeStream(file, m_constantPool);
703     writeU2(file, static_cast< sal_uInt16 >(m_accessFlags));
704     writeU2(file, m_thisClass);
705     writeU2(file, m_superClass);
706     writeU2(file, m_interfacesCount);
707     writeStream(file, m_interfaces);
708     writeU2(file, m_fieldsCount);
709     writeStream(file, m_fields);
710     writeU2(file, m_methodsCount);
711     writeStream(file, m_methods);
712     writeU2(file, m_attributesCount);
713     writeStream(file, m_attributes);
714 }
715 
nextConstantPoolIndex(sal_uInt16 width)716 sal_uInt16 ClassFile::nextConstantPoolIndex(sal_uInt16 width) {
717     OSL_ASSERT(width == 1 || width == 2);
718     if (m_constantPoolCount > SAL_MAX_UINT16 - width) {
719         throw CannotDumpException(
720             rtl::OString(
721                 RTL_CONSTASCII_STRINGPARAM(
722                     "Too many constant pool items for Java class file"
723                     " format")));
724     }
725     sal_uInt16 index = m_constantPoolCount;
726     m_constantPoolCount = m_constantPoolCount + width;
727     return index;
728 }
729 
addUtf8Info(rtl::OString const & value)730 sal_uInt16 ClassFile::addUtf8Info(rtl::OString const & value) {
731     std::map< rtl::OString, sal_uInt16 >::iterator i(m_utf8Infos.find(value));
732     if (i != m_utf8Infos.end()) {
733         return i->second;
734     }
735     if (value.getLength() > SAL_MAX_UINT16) {
736         throw CannotDumpException(
737             rtl::OString(
738                 RTL_CONSTASCII_STRINGPARAM(
739                     "UTF-8 string too long for Java class file format")));
740     }
741     sal_uInt16 index = nextConstantPoolIndex(1);
742     appendU1(m_constantPool, 1);
743     appendU2(m_constantPool, static_cast< sal_uInt16 >(value.getLength()));
744     for (sal_Int32 j = 0; j < value.getLength(); ++j) {
745         appendU1(m_constantPool, static_cast< sal_uInt8 >(value[j]));
746     }
747     if (!m_utf8Infos.insert(
748             std::map< rtl::OString, sal_uInt16 >::value_type(value, index)).
749         second)
750     {
751         OSL_ASSERT(false);
752     }
753     return index;
754 }
755 
addClassInfo(rtl::OString const & type)756 sal_uInt16 ClassFile::addClassInfo(rtl::OString const & type) {
757     sal_uInt16 nameIndex = addUtf8Info(type);
758     std::map< sal_uInt16, sal_uInt16 >::iterator i(
759         m_classInfos.find(nameIndex));
760     if (i != m_classInfos.end()) {
761         return i->second;
762     }
763     sal_uInt16 index = nextConstantPoolIndex(1);
764     appendU1(m_constantPool, 7);
765     appendU2(m_constantPool, nameIndex);
766     if (!m_classInfos.insert(
767             std::map< sal_uInt16, sal_uInt16 >::value_type(nameIndex, index)).
768         second)
769     {
770         OSL_ASSERT(false);
771     }
772     return index;
773 }
774 
addStringInfo(rtl::OString const & value)775 sal_uInt16 ClassFile::addStringInfo(rtl::OString const & value) {
776     sal_uInt16 stringIndex = addUtf8Info(value);
777     std::map< sal_uInt16, sal_uInt16 >::iterator i(
778         m_stringInfos.find(stringIndex));
779     if (i != m_stringInfos.end()) {
780         return i->second;
781     }
782     sal_uInt16 index = nextConstantPoolIndex(1);
783     appendU1(m_constantPool, 8);
784     appendU2(m_constantPool, stringIndex);
785     if (!m_stringInfos.insert(
786             std::map< sal_uInt16, sal_uInt16 >::value_type(stringIndex, index)).
787         second)
788     {
789         OSL_ASSERT(false);
790     }
791     return index;
792 }
793 
addFieldrefInfo(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor)794 sal_uInt16 ClassFile::addFieldrefInfo(
795     rtl::OString const & type, rtl::OString const & name,
796     rtl::OString const & descriptor)
797 {
798     sal_uInt16 classIndex = addClassInfo(type);
799     sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
800     sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
801         | nameAndTypeIndex;
802     std::map< sal_uInt32, sal_uInt16 >::iterator i(m_fieldrefInfos.find(key));
803     if (i != m_fieldrefInfos.end()) {
804         return i->second;
805     }
806     sal_uInt16 index = nextConstantPoolIndex(1);
807     appendU1(m_constantPool, 9);
808     appendU2(m_constantPool, classIndex);
809     appendU2(m_constantPool, nameAndTypeIndex);
810     if (!m_fieldrefInfos.insert(
811             std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
812     {
813         OSL_ASSERT(false);
814     }
815     return index;
816 }
817 
addMethodrefInfo(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor)818 sal_uInt16 ClassFile::addMethodrefInfo(
819     rtl::OString const & type, rtl::OString const & name,
820     rtl::OString const & descriptor)
821 {
822     sal_uInt16 classIndex = addClassInfo(type);
823     sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
824     sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
825         | nameAndTypeIndex;
826     std::map< sal_uInt32, sal_uInt16 >::iterator i(m_methodrefInfos.find(key));
827     if (i != m_methodrefInfos.end()) {
828         return i->second;
829     }
830     sal_uInt16 index = nextConstantPoolIndex(1);
831     appendU1(m_constantPool, 10);
832     appendU2(m_constantPool, classIndex);
833     appendU2(m_constantPool, nameAndTypeIndex);
834     if (!m_methodrefInfos.insert(
835             std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
836     {
837         OSL_ASSERT(false);
838     }
839     return index;
840 }
841 
addInterfaceMethodrefInfo(rtl::OString const & type,rtl::OString const & name,rtl::OString const & descriptor)842 sal_uInt16 ClassFile::addInterfaceMethodrefInfo(
843     rtl::OString const & type, rtl::OString const & name,
844     rtl::OString const & descriptor)
845 {
846     sal_uInt16 classIndex = addClassInfo(type);
847     sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
848     sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
849         | nameAndTypeIndex;
850     std::map< sal_uInt32, sal_uInt16 >::iterator i(
851         m_interfaceMethodrefInfos.find(key));
852     if (i != m_interfaceMethodrefInfos.end()) {
853         return i->second;
854     }
855     sal_uInt16 index = nextConstantPoolIndex(1);
856     appendU1(m_constantPool, 11);
857     appendU2(m_constantPool, classIndex);
858     appendU2(m_constantPool, nameAndTypeIndex);
859     if (!m_interfaceMethodrefInfos.insert(
860             std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
861     {
862         OSL_ASSERT(false);
863     }
864     return index;
865 }
866 
addNameAndTypeInfo(rtl::OString const & name,rtl::OString const & descriptor)867 sal_uInt16 ClassFile::addNameAndTypeInfo(
868     rtl::OString const & name, rtl::OString const & descriptor)
869 {
870     sal_uInt16 nameIndex = addUtf8Info(name);
871     sal_uInt16 descriptorIndex = addUtf8Info(descriptor);
872     sal_uInt32 key = (static_cast< sal_uInt32 >(nameIndex) << 16)
873         | descriptorIndex;
874     std::map< sal_uInt32, sal_uInt16 >::iterator i(
875         m_nameAndTypeInfos.find(key));
876     if (i != m_nameAndTypeInfos.end()) {
877         return i->second;
878     }
879     sal_uInt16 index = nextConstantPoolIndex(1);
880     appendU1(m_constantPool, 12);
881     appendU2(m_constantPool, nameIndex);
882     appendU2(m_constantPool, descriptorIndex);
883     if (!m_nameAndTypeInfos.insert(
884             std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
885     {
886         OSL_ASSERT(false);
887     }
888     return index;
889 }
890 
appendSignatureAttribute(std::vector<unsigned char> & stream,rtl::OString const & signature)891 void ClassFile::appendSignatureAttribute(
892     std::vector< unsigned char > & stream, rtl::OString const & signature)
893 {
894     if ( !signature.isEmpty() ) {
895         appendU2(
896             stream,
897             addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature"))));
898         appendU4(stream, 2);
899         appendU2(stream, addUtf8Info(signature));
900     }
901 }
902