Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "classfile.hxx"
22 :
23 : #include "codemaker/global.hxx"
24 : #include "codemaker/options.hxx"
25 : #include "codemaker/unotype.hxx"
26 :
27 : #include "boost/static_assert.hpp"
28 : #include "osl/diagnose.h"
29 : #include "rtl/string.h"
30 : #include "rtl/string.hxx"
31 : #include "sal/types.h"
32 :
33 : #include <map>
34 : #include <utility>
35 : #include <vector>
36 :
37 : using codemaker::javamaker::ClassFile;
38 :
39 : namespace {
40 :
41 1649432 : void appendU1(std::vector< unsigned char > & stream, sal_uInt8 data) {
42 1649432 : stream.push_back(static_cast< unsigned char >(data));
43 1649432 : }
44 :
45 291382 : void appendU2(std::vector< unsigned char > & stream, sal_uInt16 data) {
46 291382 : stream.push_back(static_cast< unsigned char >(data >> 8));
47 291382 : stream.push_back(static_cast< unsigned char >(data & 0xFF));
48 291382 : }
49 :
50 22738 : void appendU4(std::vector< unsigned char > & stream, sal_uInt32 data) {
51 22738 : stream.push_back(static_cast< unsigned char >(data >> 24));
52 22738 : stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF));
53 22738 : stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF));
54 22738 : stream.push_back(static_cast< unsigned char >(data & 0xFF));
55 22738 : }
56 :
57 29 : void appendU8(std::vector< unsigned char > & stream, sal_uInt64 data) {
58 29 : stream.push_back(static_cast< unsigned char >(data >> 56));
59 29 : stream.push_back(static_cast< unsigned char >((data >> 48) & 0xFF));
60 29 : stream.push_back(static_cast< unsigned char >((data >> 40) & 0xFF));
61 29 : stream.push_back(static_cast< unsigned char >((data >> 32) & 0xFF));
62 29 : stream.push_back(static_cast< unsigned char >((data >> 24) & 0xFF));
63 29 : stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF));
64 29 : stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF));
65 29 : stream.push_back(static_cast< unsigned char >(data & 0xFF));
66 29 : }
67 :
68 11167 : void appendStream(
69 : std::vector< unsigned char > & stream,
70 : std::vector< unsigned char > const & data)
71 : {
72 11167 : stream.insert(stream.end(), data.begin(), data.end());
73 11167 : }
74 :
75 43858 : void write(FileStream & file, void const * buffer, sal_uInt64 size) {
76 43858 : if (!file.write(buffer, size)) {
77 : throw CannotDumpException(
78 0 : rtl::OString(RTL_CONSTASCII_STRINGPARAM("Error writing file")));
79 : }
80 43858 : }
81 :
82 30770 : void writeU2(FileStream & file, sal_uInt16 data) {
83 : unsigned char buf[] = {
84 : static_cast< unsigned char >(data >> 8),
85 30770 : static_cast< unsigned char >(data & 0xFF) };
86 30770 : write(file, buf, sizeof buf);
87 30770 : }
88 :
89 3077 : void writeU4(FileStream & file, sal_uInt32 data) {
90 : unsigned char buf[] = {
91 : static_cast< unsigned char >(data >> 24),
92 : static_cast< unsigned char >((data >> 16) & 0xFF),
93 : static_cast< unsigned char >((data >> 8) & 0xFF),
94 3077 : static_cast< unsigned char >(data & 0xFF) };
95 3077 : write(file, buf, sizeof buf);
96 3077 : }
97 :
98 15385 : void writeStream(FileStream & file, std::vector< unsigned char > const & stream)
99 : {
100 15385 : std::vector< unsigned char >::size_type n = stream.size();
101 : BOOST_STATIC_ASSERT(
102 : sizeof (std::vector< unsigned char >::size_type)
103 : <= sizeof (sal_uInt64));
104 : // both unsigned integral, so sizeof is a practically sufficient
105 : // approximation of std::numeric_limits<T1>::max() <=
106 : // std::numeric_limits<T2>::max()
107 15385 : if (n != 0) {
108 10011 : write(file, &stream[0], static_cast< sal_uInt64 >(n));
109 : }
110 15385 : }
111 :
112 : }
113 :
114 6332 : ClassFile::Code::~Code() {}
115 :
116 8136 : void ClassFile::Code::instrAastore() {
117 : // aastore:
118 8136 : appendU1(m_code, 0x53);
119 8136 : }
120 :
121 200 : void ClassFile::Code::instrAconstNull() {
122 : // aconst_null:
123 200 : appendU1(m_code, 0x01);
124 200 : }
125 :
126 2262 : void ClassFile::Code::instrAnewarray(rtl::OString const & type) {
127 : // anewarray <indexbyte1> <indexbyte2>:
128 2262 : appendU1(m_code, 0xBD);
129 2262 : appendU2(m_code, m_classFile.addClassInfo(type));
130 2262 : }
131 :
132 2144 : void ClassFile::Code::instrAreturn() {
133 : // areturn:
134 2144 : appendU1(m_code, 0xB0);
135 2144 : }
136 :
137 452 : void ClassFile::Code::instrAthrow() {
138 : // athrow:
139 452 : appendU1(m_code, 0xBF);
140 452 : }
141 :
142 261 : void ClassFile::Code::instrCheckcast(rtl::OString const & type) {
143 : // checkcast <indexbyte1> <indexbyte2>:
144 261 : appendU1(m_code, 0xC0);
145 261 : appendU2(m_code, m_classFile.addClassInfo(type));
146 261 : }
147 :
148 18650 : void ClassFile::Code::instrDup() {
149 : // dup:
150 18650 : appendU1(m_code, 0x59);
151 18650 : }
152 :
153 2013 : void ClassFile::Code::instrGetstatic(
154 : rtl::OString const & type, rtl::OString const & name,
155 : rtl::OString const & descriptor)
156 : {
157 : // getstatic <indexbyte1> <indexbyte2>:
158 2013 : appendU1(m_code, 0xB2);
159 2013 : appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor));
160 2013 : }
161 :
162 11 : ClassFile::Code::Branch ClassFile::Code::instrIfAcmpne() {
163 : // if_acmpne <branchbyte1> <branchbyte2>:
164 11 : Branch branch = m_code.size();
165 11 : appendU1(m_code, 0xA6);
166 11 : appendU2(m_code, 0);
167 11 : return branch;
168 : }
169 :
170 11 : ClassFile::Code::Branch ClassFile::Code::instrIfeq() {
171 : // ifeq <branchbyte1> <branchbyte2>:
172 11 : Branch branch = m_code.size();
173 11 : appendU1(m_code, 0x99);
174 11 : appendU2(m_code, 0);
175 11 : return branch;
176 : }
177 :
178 216 : ClassFile::Code::Branch ClassFile::Code::instrIfnull() {
179 : // ifnull <branchbyte1> <branchbyte2>:
180 216 : Branch branch = m_code.size();
181 216 : appendU1(m_code, 0xC6);
182 216 : appendU2(m_code, 0);
183 216 : return branch;
184 : }
185 :
186 11 : void ClassFile::Code::instrInstanceof(rtl::OString const & type) {
187 : // instanceof <indexbyte1> <indexbyte2>:
188 11 : appendU1(m_code, 0xC1);
189 11 : appendU2(m_code, m_classFile.addClassInfo(type));
190 11 : }
191 :
192 489 : void ClassFile::Code::instrInvokeinterface(
193 : rtl::OString const & type, rtl::OString const & name,
194 : rtl::OString const & descriptor, sal_uInt8 args)
195 : {
196 : // invokeinterface <indexbyte1> <indexbyte2> <nargs> 0:
197 489 : appendU1(m_code, 0xB9);
198 : appendU2(
199 489 : m_code, m_classFile.addInterfaceMethodrefInfo(type, name, descriptor));
200 489 : appendU1(m_code, args);
201 489 : appendU1(m_code, 0);
202 489 : }
203 :
204 11994 : void ClassFile::Code::instrInvokespecial(
205 : rtl::OString const & type, rtl::OString const & name,
206 : rtl::OString const & descriptor)
207 : {
208 : // invokespecial <indexbyte1> <indexbyte2>:
209 11994 : appendU1(m_code, 0xB7);
210 11994 : appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor));
211 11994 : }
212 :
213 455 : void ClassFile::Code::instrInvokestatic(
214 : rtl::OString const & type, rtl::OString const & name,
215 : rtl::OString const & descriptor)
216 : {
217 : // invokestatic <indexbyte1> <indexbyte2>:
218 455 : appendU1(m_code, 0xB8);
219 455 : appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor));
220 455 : }
221 :
222 505 : void ClassFile::Code::instrInvokevirtual(
223 : rtl::OString const & type, rtl::OString const & name,
224 : rtl::OString const & descriptor)
225 : {
226 : // invokevirtual <indexbyte1> <indexbyte2>:
227 505 : appendU1(m_code, 0xB6);
228 505 : appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor));
229 505 : }
230 :
231 1 : void ClassFile::Code::instrLookupswitch(
232 : Code const * defaultBlock,
233 : std::list< std::pair< sal_Int32, Code * > > const & blocks)
234 : {
235 : // lookupswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3>
236 : // <defaultbyte4> <npairs1> <npairs2> <npairs3> <npairs4>
237 : // <match--offset pairs...>:
238 1 : std::list< std::pair< sal_Int32, Code * > >::size_type size = blocks.size();
239 1 : if (size > SAL_MAX_INT32) {
240 : throw CannotDumpException(
241 : rtl::OString(
242 : RTL_CONSTASCII_STRINGPARAM(
243 0 : "Lookup-switch too large for Java class file format")));
244 : }
245 1 : Position pos1 = m_code.size();
246 1 : appendU1(m_code, 0xAB);
247 1 : int pad = (pos1 + 1) % 4;
248 3 : {for (int i = 0; i < pad; ++i) {
249 2 : appendU1(m_code, 0);
250 : }}
251 1 : Position pos2 = pos1 + 1 + pad + 8 + blocks.size() * 8; //FIXME: overflow
252 1 : appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); //FIXME: overflow
253 1 : pos2 += defaultBlock->m_code.size(); //FIXME: overflow
254 1 : appendU4(m_code, static_cast< sal_uInt32 >(size));
255 114 : {for (std::list< std::pair< sal_Int32, Code * > >::const_iterator i(
256 1 : blocks.begin());
257 76 : i != blocks.end(); ++i)
258 : {
259 37 : appendU4(m_code, static_cast< sal_uInt32 >(i->first));
260 37 : appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1));
261 : //FIXME: overflow
262 37 : pos2 += i->second->m_code.size(); //FIXME: overflow
263 : }}
264 1 : appendStream(m_code, defaultBlock->m_code);
265 114 : {for (std::list< std::pair< sal_Int32, Code * > >::const_iterator i(
266 1 : blocks.begin());
267 76 : i != blocks.end(); ++i)
268 : {
269 37 : appendStream(m_code, i->second->m_code);
270 : }}
271 1 : }
272 :
273 10276 : void ClassFile::Code::instrNew(rtl::OString const & type) {
274 : // new <indexbyte1> <indexbyte2>:
275 10276 : appendU1(m_code, 0xBB);
276 10276 : appendU2(m_code, m_classFile.addClassInfo(type));
277 10276 : }
278 :
279 16 : void ClassFile::Code::instrNewarray(codemaker::UnoType::Sort sort) {
280 : OSL_ASSERT(
281 : sort >= codemaker::UnoType::SORT_BOOLEAN
282 : && sort <= codemaker::UnoType::SORT_CHAR);
283 : // newarray <atype>:
284 16 : appendU1(m_code, 0xBC);
285 : static sal_uInt8 const atypes[codemaker::UnoType::SORT_CHAR] = {
286 : 0x04, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x06, 0x07, 0x05 };
287 16 : appendU1(m_code, atypes[sort - 1]);
288 16 : }
289 :
290 216 : void ClassFile::Code::instrPop() {
291 : // pop:
292 216 : appendU1(m_code, 0x57);
293 216 : }
294 :
295 2310 : void ClassFile::Code::instrPutfield(
296 : rtl::OString const & type, rtl::OString const & name,
297 : rtl::OString const & descriptor)
298 : {
299 : // putfield <indexbyte1> <indexbyte2>:
300 2310 : appendU1(m_code, 0xB5);
301 2310 : appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor));
302 2310 : }
303 :
304 3391 : void ClassFile::Code::instrPutstatic(
305 : rtl::OString const & type, rtl::OString const & name,
306 : rtl::OString const & descriptor)
307 : {
308 : // putstatic <indexbyte1> <indexbyte2>:
309 3391 : appendU1(m_code, 0xB3);
310 3391 : appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor));
311 3391 : }
312 :
313 3996 : void ClassFile::Code::instrReturn() {
314 : // return:
315 3996 : appendU1(m_code, 0xB1);
316 3996 : }
317 :
318 11 : void ClassFile::Code::instrSwap() {
319 : // swap:
320 11 : appendU1(m_code, 0x5F);
321 11 : }
322 :
323 191 : void ClassFile::Code::instrTableswitch(
324 : Code const * defaultBlock, sal_Int32 low,
325 : std::list< Code * > const & blocks)
326 : {
327 : // tableswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3>
328 : // <defaultbyte4> <lowbyte1> <lowbyte2> <lowbyte3> <lowbyte4> <highbyte1>
329 : // <highbyte2> <highbyte3> <highbyte4> <jump offsets...>:
330 191 : Position pos1 = m_code.size();
331 191 : appendU1(m_code, 0xAA);
332 191 : int pad = (pos1 + 1) % 4;
333 573 : {for (int i = 0; i < pad; ++i) {
334 382 : appendU1(m_code, 0);
335 : }}
336 191 : std::list< Code * >::size_type size = blocks.size();
337 191 : Position pos2 = pos1 + 1 + pad + 12 + size * 4; //FIXME: overflow
338 191 : sal_uInt32 defaultOffset = static_cast< sal_uInt32 >(pos2 - pos1);
339 : //FIXME: overflow
340 191 : appendU4(m_code, defaultOffset);
341 191 : pos2 += defaultBlock->m_code.size(); //FIXME: overflow
342 191 : appendU4(m_code, static_cast< sal_uInt32 >(low));
343 191 : appendU4(m_code, static_cast< sal_uInt32 >(low + (size - 1)));
344 4386 : {for (std::list< Code * >::const_iterator i(blocks.begin());
345 2924 : i != blocks.end(); ++i)
346 : {
347 1271 : if (*i == 0) {
348 3 : appendU4(m_code, defaultOffset);
349 : } else {
350 1268 : appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1));
351 : //FIXME: overflow
352 1268 : pos2 += (*i)->m_code.size(); //FIXME: overflow
353 : }
354 : }}
355 191 : appendStream(m_code, defaultBlock->m_code);
356 4386 : {for (std::list< Code * >::const_iterator i(blocks.begin());
357 2924 : i != blocks.end(); ++i)
358 : {
359 1271 : if (*i != 0) {
360 1268 : appendStream(m_code, (*i)->m_code);
361 : }
362 : }}
363 191 : }
364 :
365 27577 : void ClassFile::Code::loadIntegerConstant(sal_Int32 value) {
366 27577 : if (value >= -1 && value <= 5) {
367 : // iconst_<i>:
368 22122 : appendU1(m_code, static_cast< sal_uInt8 >(0x02 + value + 1));
369 5455 : } else if (value >= -128 && value <= 127) {
370 : // bipush <byte>:
371 5127 : appendU1(m_code, 0x10);
372 5127 : appendU1(m_code, static_cast< sal_uInt8 >(value));
373 328 : } else if (value >= -32768 && value <= 32767) {
374 : // sipush <byte1> <byte2>:
375 313 : appendU1(m_code, 0x11);
376 313 : appendU2(m_code, static_cast< sal_uInt16 >(value));
377 : } else {
378 15 : ldc(m_classFile.addIntegerInfo(value));
379 : }
380 27577 : }
381 :
382 9621 : void ClassFile::Code::loadStringConstant(rtl::OString const & value) {
383 9621 : ldc(m_classFile.addStringInfo(value));
384 9621 : }
385 :
386 1112 : void ClassFile::Code::loadLocalInteger(sal_uInt16 index) {
387 1112 : accessLocal(index, 0x1A, 0x15); // iload_<n>, iload
388 1112 : }
389 :
390 34 : void ClassFile::Code::loadLocalLong(sal_uInt16 index) {
391 34 : accessLocal(index, 0x1E, 0x16); // load_<n>, load
392 34 : }
393 :
394 18 : void ClassFile::Code::loadLocalFloat(sal_uInt16 index) {
395 18 : accessLocal(index, 0x22, 0x17); // load_<n>, load
396 18 : }
397 :
398 111 : void ClassFile::Code::loadLocalDouble(sal_uInt16 index) {
399 111 : accessLocal(index, 0x26, 0x18); // load_<n>, load
400 111 : }
401 :
402 7532 : void ClassFile::Code::loadLocalReference(sal_uInt16 index) {
403 7532 : accessLocal(index, 0x2A, 0x19); // aload_<n>, aload
404 7532 : }
405 :
406 236 : void ClassFile::Code::storeLocalReference(sal_uInt16 index) {
407 236 : accessLocal(index, 0x4B, 0x3A); // astore_<n>, astore
408 236 : }
409 :
410 238 : void ClassFile::Code::branchHere(Branch branch) {
411 238 : std::vector< unsigned char >::size_type n = m_code.size();
412 : OSL_ASSERT(n > branch && n - branch <= SAL_MAX_INT16);
413 238 : n -= branch;
414 238 : m_code[branch + 1] = static_cast< sal_uInt8 >(n >> 8);
415 238 : m_code[branch + 2] = static_cast< sal_uInt8 >(n & 0xFF);
416 238 : }
417 :
418 244 : void ClassFile::Code::addException(
419 : Position start, Position end, Position handler, rtl::OString const & type)
420 : {
421 : OSL_ASSERT(start < end && end <= m_code.size() && handler <= m_code.size());
422 244 : if (m_exceptionTableLength == SAL_MAX_UINT16) {
423 : throw CannotDumpException(
424 : rtl::OString(
425 : RTL_CONSTASCII_STRINGPARAM(
426 0 : "Too many exception handlers for Java class file format")));
427 : }
428 244 : ++m_exceptionTableLength;
429 244 : appendU2(m_exceptionTable, static_cast< sal_uInt16 >(start));
430 : //FIXME: overflow
431 244 : appendU2(m_exceptionTable, static_cast< sal_uInt16 >(end));
432 : //FIXME: overflow
433 244 : appendU2(m_exceptionTable, static_cast< sal_uInt16 >(handler));
434 : //FIXME: overflow
435 244 : appendU2(m_exceptionTable, m_classFile.addClassInfo(type));
436 244 : }
437 :
438 950 : ClassFile::Code::Position ClassFile::Code::getPosition() const {
439 950 : return m_code.size();
440 : }
441 :
442 6332 : ClassFile::Code::Code(ClassFile & classFile):
443 6332 : m_classFile(classFile), m_exceptionTableLength(0)
444 6332 : {}
445 :
446 9636 : void ClassFile::Code::ldc(sal_uInt16 index) {
447 9636 : if (index <= 0xFF) {
448 : // ldc <index>:
449 9508 : appendU1(m_code, 0x12);
450 9508 : appendU1(m_code, static_cast< sal_uInt8 >(index));
451 : } else {
452 : // ldc_w <indexbyte1> <indexbyte2>:
453 128 : appendU1(m_code, 0x13);
454 128 : appendU2(m_code, index);
455 : }
456 9636 : }
457 :
458 9043 : void ClassFile::Code::accessLocal(
459 : sal_uInt16 index, sal_uInt8 fastOp, sal_uInt8 normalOp)
460 : {
461 9043 : if (index <= 3) {
462 : // ...load/store_<n>:
463 8244 : appendU1(m_code, static_cast< sal_uInt8 >(fastOp + index));
464 799 : } else if (index <= 0xFF) {
465 : // ...load/store <index>:
466 799 : appendU1(m_code, normalOp);
467 799 : appendU1(m_code, static_cast< sal_uInt8 >(index));
468 : } else {
469 : // wide ...load/store <indexbyte1> <indexbyte2>:
470 0 : appendU1(m_code, 0xC4);
471 0 : appendU1(m_code, normalOp);
472 0 : appendU2(m_code, index);
473 : }
474 9043 : }
475 :
476 3077 : ClassFile::ClassFile(
477 : AccessFlags accessFlags, rtl::OString const & thisClass,
478 : rtl::OString const & superClass, rtl::OString const & signature):
479 : m_constantPoolCount(1), m_accessFlags(accessFlags), m_interfacesCount(0),
480 3077 : m_fieldsCount(0), m_methodsCount(0), m_attributesCount(0)
481 : {
482 3077 : m_thisClass = addClassInfo(thisClass);
483 3077 : m_superClass = addClassInfo(superClass);
484 3077 : if (!signature.isEmpty()) {
485 6 : ++m_attributesCount;
486 : appendU2(
487 : m_attributes,
488 6 : addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature"))));
489 6 : appendU4(m_attributes, 2);
490 6 : appendU2(m_attributes, addUtf8Info(signature));
491 : }
492 3077 : }
493 :
494 3077 : ClassFile::~ClassFile() {}
495 :
496 6332 : ClassFile::Code * ClassFile::newCode() {
497 6332 : return new Code(*this);
498 : }
499 :
500 4532 : sal_uInt16 ClassFile::addIntegerInfo(sal_Int32 value) {
501 4532 : std::map< sal_Int32, sal_uInt16 >::iterator i(m_integerInfos.find(value));
502 4532 : if (i != m_integerInfos.end()) {
503 70 : return i->second;
504 : }
505 4462 : sal_uInt16 index = nextConstantPoolIndex(1);
506 4462 : appendU1(m_constantPool, 3);
507 4462 : appendU4(m_constantPool, static_cast< sal_uInt32 >(value));
508 4462 : if (!m_integerInfos.insert(
509 8924 : std::map< sal_Int32, sal_uInt16 >::value_type(value, index)).second)
510 : {
511 : OSL_ASSERT(false);
512 : }
513 4462 : return index;
514 : }
515 :
516 20 : sal_uInt16 ClassFile::addFloatInfo(float value) {
517 20 : std::map< float, sal_uInt16 >::iterator i(m_floatInfos.find(value));
518 20 : if (i != m_floatInfos.end()) {
519 0 : return i->second;
520 : }
521 20 : sal_uInt16 index = nextConstantPoolIndex(1);
522 20 : appendU1(m_constantPool, 4);
523 : union { float floatBytes; sal_uInt32 uint32Bytes; } bytes;
524 20 : bytes.floatBytes = value;
525 20 : appendU4(m_constantPool, bytes.uint32Bytes);
526 20 : if (!m_floatInfos.insert(
527 40 : std::map< float, sal_uInt16 >::value_type(value, index)).second)
528 : {
529 : OSL_ASSERT(false);
530 : }
531 20 : return index;
532 : }
533 :
534 29 : sal_uInt16 ClassFile::addLongInfo(sal_Int64 value) {
535 29 : std::map< sal_Int64, sal_uInt16 >::iterator i(m_longInfos.find(value));
536 29 : if (i != m_longInfos.end()) {
537 0 : return i->second;
538 : }
539 29 : sal_uInt16 index = nextConstantPoolIndex(2);
540 29 : appendU1(m_constantPool, 5);
541 29 : appendU8(m_constantPool, static_cast< sal_uInt64 >(value));
542 29 : if (!m_longInfos.insert(
543 58 : std::map< sal_Int64, sal_uInt16 >::value_type(value, index)).second)
544 : {
545 : OSL_ASSERT(false);
546 : }
547 29 : return index;
548 : }
549 :
550 0 : sal_uInt16 ClassFile::addDoubleInfo(double value) {
551 0 : std::map< double, sal_uInt16 >::iterator i(m_doubleInfos.find(value));
552 0 : if (i != m_doubleInfos.end()) {
553 0 : return i->second;
554 : }
555 0 : sal_uInt16 index = nextConstantPoolIndex(2);
556 0 : appendU1(m_constantPool, 6);
557 : union { double doubleBytes; sal_uInt64 uint64Bytes; } bytes;
558 0 : bytes.doubleBytes = value;
559 0 : appendU8(m_constantPool, bytes.uint64Bytes);
560 0 : if (!m_doubleInfos.insert(
561 0 : std::map< double, sal_uInt16 >::value_type(value, index)).second)
562 : {
563 : OSL_ASSERT(false);
564 : }
565 0 : return index;
566 : }
567 :
568 1839 : void ClassFile::addInterface(rtl::OString const & interface) {
569 1839 : if (m_interfacesCount == SAL_MAX_UINT16) {
570 : throw CannotDumpException(
571 : rtl::OString(
572 : RTL_CONSTASCII_STRINGPARAM(
573 0 : "Too many interfaces for Java class file format")));
574 : }
575 1839 : ++m_interfacesCount;
576 1839 : appendU2(m_interfaces, addClassInfo(interface));
577 1839 : }
578 :
579 9505 : void ClassFile::addField(
580 : AccessFlags accessFlags, rtl::OString const & name,
581 : rtl::OString const & descriptor, sal_uInt16 constantValueIndex,
582 : rtl::OString const & signature)
583 : {
584 9505 : if (m_fieldsCount == SAL_MAX_UINT16) {
585 : throw CannotDumpException(
586 : rtl::OString(
587 : RTL_CONSTASCII_STRINGPARAM(
588 0 : "Too many fields for Java class file format")));
589 : }
590 9505 : ++m_fieldsCount;
591 9505 : appendU2(m_fields, static_cast< sal_uInt16 >(accessFlags));
592 9505 : appendU2(m_fields, addUtf8Info(name));
593 9505 : appendU2(m_fields, addUtf8Info(descriptor));
594 : appendU2(
595 : m_fields,
596 : ((constantValueIndex == 0 ? 0 : 1)
597 9505 : + (signature.isEmpty() ? 0 : 1)));
598 9505 : if (constantValueIndex != 0) {
599 : appendU2(
600 : m_fields,
601 : addUtf8Info(
602 4566 : rtl::OString(RTL_CONSTASCII_STRINGPARAM("ConstantValue"))));
603 4566 : appendU4(m_fields, 2);
604 4566 : appendU2(m_fields, constantValueIndex);
605 : }
606 9505 : appendSignatureAttribute(m_fields, signature);
607 9505 : }
608 :
609 11400 : void ClassFile::addMethod(
610 : AccessFlags accessFlags, rtl::OString const & name,
611 : rtl::OString const & descriptor, Code const * code,
612 : std::vector< rtl::OString > const & exceptions,
613 : rtl::OString const & signature)
614 : {
615 11400 : if (m_methodsCount == SAL_MAX_UINT16) {
616 : throw CannotDumpException(
617 : rtl::OString(
618 : RTL_CONSTASCII_STRINGPARAM(
619 0 : "Too many methods for Java class file format")));
620 : }
621 11400 : ++m_methodsCount;
622 11400 : appendU2(m_methods, static_cast< sal_uInt16 >(accessFlags));
623 11400 : appendU2(m_methods, addUtf8Info(name));
624 11400 : appendU2(m_methods, addUtf8Info(descriptor));
625 11400 : std::vector< rtl::OString >::size_type excs = exceptions.size();
626 11400 : if (excs > SAL_MAX_UINT16) {
627 : throw CannotDumpException(
628 : rtl::OString(
629 : RTL_CONSTASCII_STRINGPARAM(
630 : "Too many exception specifications for Java class file"
631 0 : " format")));
632 : }
633 : appendU2(
634 : m_methods,
635 11400 : ((code == 0 ? 0 : 1) + (exceptions.empty() ? 0 : 1)
636 22800 : + (signature.isEmpty() ? 0 : 1)));
637 11400 : if (code != 0) {
638 4835 : std::vector< unsigned char >::size_type codeSize = code->m_code.size();
639 : std::vector< unsigned char >::size_type exceptionTableSize
640 4835 : = code->m_exceptionTable.size();
641 4835 : if (codeSize > SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2)
642 : || (exceptionTableSize
643 : > (SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2)
644 : - static_cast< sal_uInt32 >(codeSize))))
645 : {
646 : throw CannotDumpException(
647 : rtl::OString(
648 : RTL_CONSTASCII_STRINGPARAM(
649 0 : "Code block is too big for Java class file format")));
650 : }
651 : appendU2(
652 : m_methods,
653 4835 : addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Code"))));
654 : appendU4(
655 : m_methods,
656 : (2 + 2 + 4 + static_cast< sal_uInt32 >(codeSize) + 2
657 4835 : + static_cast< sal_uInt32 >(exceptionTableSize) + 2));
658 4835 : appendU2(m_methods, code->m_maxStack);
659 4835 : appendU2(m_methods, code->m_maxLocals);
660 4835 : appendU4(m_methods, static_cast< sal_uInt32 >(codeSize));
661 4835 : appendStream(m_methods, code->m_code);
662 4835 : appendU2(m_methods, code->m_exceptionTableLength);
663 4835 : appendStream(m_methods, code->m_exceptionTable);
664 4835 : appendU2(m_methods, 0);
665 : }
666 11400 : if (!exceptions.empty()) {
667 : appendU2(
668 : m_methods,
669 : addUtf8Info(
670 2044 : rtl::OString(RTL_CONSTASCII_STRINGPARAM("Exceptions"))));
671 : appendU4(
672 : m_methods,
673 2044 : static_cast< sal_uInt32 >(2 + 2 * static_cast< sal_uInt32 >(excs)));
674 2044 : appendU2(m_methods, static_cast< sal_uInt16 >(excs));
675 14769 : for (std::vector< rtl::OString >::const_iterator i(exceptions.begin());
676 9846 : i != exceptions.end(); ++i)
677 : {
678 2879 : appendU2(m_methods, addClassInfo(*i));
679 : }
680 : }
681 11400 : appendSignatureAttribute(m_methods, signature);
682 11400 : }
683 :
684 3077 : void ClassFile::write(FileStream & file) const {
685 3077 : writeU4(file, 0xCAFEBABE);
686 3077 : writeU2(file, 0);
687 3077 : writeU2(file, 49); // class file version of JRE 1.5
688 3077 : writeU2(file, m_constantPoolCount);
689 3077 : writeStream(file, m_constantPool);
690 3077 : writeU2(file, static_cast< sal_uInt16 >(m_accessFlags));
691 3077 : writeU2(file, m_thisClass);
692 3077 : writeU2(file, m_superClass);
693 3077 : writeU2(file, m_interfacesCount);
694 3077 : writeStream(file, m_interfaces);
695 3077 : writeU2(file, m_fieldsCount);
696 3077 : writeStream(file, m_fields);
697 3077 : writeU2(file, m_methodsCount);
698 3077 : writeStream(file, m_methods);
699 3077 : writeU2(file, m_attributesCount);
700 3077 : writeStream(file, m_attributes);
701 3077 : }
702 :
703 112718 : sal_uInt16 ClassFile::nextConstantPoolIndex(sal_uInt16 width) {
704 : OSL_ASSERT(width == 1 || width == 2);
705 112718 : if (m_constantPoolCount > SAL_MAX_UINT16 - width) {
706 : throw CannotDumpException(
707 : rtl::OString(
708 : RTL_CONSTASCII_STRINGPARAM(
709 : "Too many constant pool items for Java class file"
710 0 : " format")));
711 : }
712 112718 : sal_uInt16 index = m_constantPoolCount;
713 112718 : m_constantPoolCount = m_constantPoolCount + width;
714 112718 : return index;
715 : }
716 :
717 150385 : sal_uInt16 ClassFile::addUtf8Info(rtl::OString const & value) {
718 150385 : std::map< rtl::OString, sal_uInt16 >::iterator i(m_utf8Infos.find(value));
719 150385 : if (i != m_utf8Infos.end()) {
720 88722 : return i->second;
721 : }
722 61663 : if (value.getLength() > SAL_MAX_UINT16) {
723 : throw CannotDumpException(
724 : rtl::OString(
725 : RTL_CONSTASCII_STRINGPARAM(
726 0 : "UTF-8 string too long for Java class file format")));
727 : }
728 61663 : sal_uInt16 index = nextConstantPoolIndex(1);
729 61663 : appendU1(m_constantPool, 1);
730 61663 : appendU2(m_constantPool, static_cast< sal_uInt16 >(value.getLength()));
731 1467106 : for (sal_Int32 j = 0; j < value.getLength(); ++j) {
732 1405443 : appendU1(m_constantPool, static_cast< sal_uInt8 >(value[j]));
733 : }
734 61663 : if (!m_utf8Infos.insert(
735 123326 : std::map< rtl::OString, sal_uInt16 >::value_type(value, index)).
736 123326 : second)
737 : {
738 : OSL_ASSERT(false);
739 : }
740 61663 : return index;
741 : }
742 :
743 45083 : sal_uInt16 ClassFile::addClassInfo(rtl::OString const & type) {
744 45083 : sal_uInt16 nameIndex = addUtf8Info(type);
745 : std::map< sal_uInt16, sal_uInt16 >::iterator i(
746 45083 : m_classInfos.find(nameIndex));
747 45083 : if (i != m_classInfos.end()) {
748 29262 : return i->second;
749 : }
750 15821 : sal_uInt16 index = nextConstantPoolIndex(1);
751 15821 : appendU1(m_constantPool, 7);
752 15821 : appendU2(m_constantPool, nameIndex);
753 15821 : if (!m_classInfos.insert(
754 31642 : std::map< sal_uInt16, sal_uInt16 >::value_type(nameIndex, index)).
755 31642 : second)
756 : {
757 : OSL_ASSERT(false);
758 : }
759 15821 : return index;
760 : }
761 :
762 9621 : sal_uInt16 ClassFile::addStringInfo(rtl::OString const & value) {
763 9621 : sal_uInt16 stringIndex = addUtf8Info(value);
764 : std::map< sal_uInt16, sal_uInt16 >::iterator i(
765 9621 : m_stringInfos.find(stringIndex));
766 9621 : if (i != m_stringInfos.end()) {
767 606 : return i->second;
768 : }
769 9015 : sal_uInt16 index = nextConstantPoolIndex(1);
770 9015 : appendU1(m_constantPool, 8);
771 9015 : appendU2(m_constantPool, stringIndex);
772 9015 : if (!m_stringInfos.insert(
773 18030 : std::map< sal_uInt16, sal_uInt16 >::value_type(stringIndex, index)).
774 18030 : second)
775 : {
776 : OSL_ASSERT(false);
777 : }
778 9015 : return index;
779 : }
780 :
781 7714 : sal_uInt16 ClassFile::addFieldrefInfo(
782 : rtl::OString const & type, rtl::OString const & name,
783 : rtl::OString const & descriptor)
784 : {
785 7714 : sal_uInt16 classIndex = addClassInfo(type);
786 7714 : sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
787 : sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
788 7714 : | nameAndTypeIndex;
789 7714 : std::map< sal_uInt32, sal_uInt16 >::iterator i(m_fieldrefInfos.find(key));
790 7714 : if (i != m_fieldrefInfos.end()) {
791 2407 : return i->second;
792 : }
793 5307 : sal_uInt16 index = nextConstantPoolIndex(1);
794 5307 : appendU1(m_constantPool, 9);
795 5307 : appendU2(m_constantPool, classIndex);
796 5307 : appendU2(m_constantPool, nameAndTypeIndex);
797 5307 : if (!m_fieldrefInfos.insert(
798 10614 : std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
799 : {
800 : OSL_ASSERT(false);
801 : }
802 5307 : return index;
803 : }
804 :
805 12954 : sal_uInt16 ClassFile::addMethodrefInfo(
806 : rtl::OString const & type, rtl::OString const & name,
807 : rtl::OString const & descriptor)
808 : {
809 12954 : sal_uInt16 classIndex = addClassInfo(type);
810 12954 : sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
811 : sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
812 12954 : | nameAndTypeIndex;
813 12954 : std::map< sal_uInt32, sal_uInt16 >::iterator i(m_methodrefInfos.find(key));
814 12954 : if (i != m_methodrefInfos.end()) {
815 7672 : return i->second;
816 : }
817 5282 : sal_uInt16 index = nextConstantPoolIndex(1);
818 5282 : appendU1(m_constantPool, 10);
819 5282 : appendU2(m_constantPool, classIndex);
820 5282 : appendU2(m_constantPool, nameAndTypeIndex);
821 5282 : if (!m_methodrefInfos.insert(
822 10564 : std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
823 : {
824 : OSL_ASSERT(false);
825 : }
826 5282 : return index;
827 : }
828 :
829 489 : sal_uInt16 ClassFile::addInterfaceMethodrefInfo(
830 : rtl::OString const & type, rtl::OString const & name,
831 : rtl::OString const & descriptor)
832 : {
833 489 : sal_uInt16 classIndex = addClassInfo(type);
834 489 : sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
835 : sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
836 489 : | nameAndTypeIndex;
837 : std::map< sal_uInt32, sal_uInt16 >::iterator i(
838 489 : m_interfaceMethodrefInfos.find(key));
839 489 : if (i != m_interfaceMethodrefInfos.end()) {
840 68 : return i->second;
841 : }
842 421 : sal_uInt16 index = nextConstantPoolIndex(1);
843 421 : appendU1(m_constantPool, 11);
844 421 : appendU2(m_constantPool, classIndex);
845 421 : appendU2(m_constantPool, nameAndTypeIndex);
846 421 : if (!m_interfaceMethodrefInfos.insert(
847 842 : std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
848 : {
849 : OSL_ASSERT(false);
850 : }
851 421 : return index;
852 : }
853 :
854 21157 : sal_uInt16 ClassFile::addNameAndTypeInfo(
855 : rtl::OString const & name, rtl::OString const & descriptor)
856 : {
857 21157 : sal_uInt16 nameIndex = addUtf8Info(name);
858 21157 : sal_uInt16 descriptorIndex = addUtf8Info(descriptor);
859 : sal_uInt32 key = (static_cast< sal_uInt32 >(nameIndex) << 16)
860 21157 : | descriptorIndex;
861 : std::map< sal_uInt32, sal_uInt16 >::iterator i(
862 21157 : m_nameAndTypeInfos.find(key));
863 21157 : if (i != m_nameAndTypeInfos.end()) {
864 10459 : return i->second;
865 : }
866 10698 : sal_uInt16 index = nextConstantPoolIndex(1);
867 10698 : appendU1(m_constantPool, 12);
868 10698 : appendU2(m_constantPool, nameIndex);
869 10698 : appendU2(m_constantPool, descriptorIndex);
870 10698 : if (!m_nameAndTypeInfos.insert(
871 21396 : std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
872 : {
873 : OSL_ASSERT(false);
874 : }
875 10698 : return index;
876 : }
877 :
878 20905 : void ClassFile::appendSignatureAttribute(
879 : std::vector< unsigned char > & stream, rtl::OString const & signature)
880 : {
881 20905 : if (!signature.isEmpty()) {
882 : appendU2(
883 : stream,
884 50 : addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature"))));
885 50 : appendU4(stream, 2);
886 50 : appendU2(stream, addUtf8Info(signature));
887 : }
888 20905 : }
889 :
890 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|