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