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