Lines 30-35
Link Here
|
30 |
import org.aspectj.bridge.IMessage; |
30 |
import org.aspectj.bridge.IMessage; |
31 |
import org.aspectj.weaver.bcel.BcelTypeMunger; |
31 |
import org.aspectj.weaver.bcel.BcelTypeMunger; |
32 |
|
32 |
|
|
|
33 |
import java.io.ByteArrayInputStream; // ajh02: added |
34 |
import java.io.ByteArrayOutputStream; // ajh02: added |
33 |
|
35 |
|
34 |
/** |
36 |
/** |
35 |
* WeaverStateInfo represents how a type was processed. It is used by the weaver to determine how a type |
37 |
* WeaverStateInfo represents how a type was processed. It is used by the weaver to determine how a type |
Lines 60-65
Link Here
|
60 |
private static boolean reweavableDefault = false; |
62 |
private static boolean reweavableDefault = false; |
61 |
private static boolean reweavableCompressedModeDefault = false; |
63 |
private static boolean reweavableCompressedModeDefault = false; |
62 |
|
64 |
|
|
|
65 |
private static byte key[] = { // ajh02: added |
66 |
// could be longer if it's not going in the file written to disk |
67 |
// (which I'm pretty sure it doesn't have to) |
68 |
-51, 34, 105, 56, -34, 65, 45, 78 |
69 |
}; |
70 |
private boolean unwovenClassFileDataIsDiff; // ajh02: added |
71 |
|
63 |
public WeaverStateInfo() { |
72 |
public WeaverStateInfo() { |
64 |
this(new ArrayList(), false,reweavableDefault,reweavableCompressedModeDefault); |
73 |
this(new ArrayList(), false,reweavableDefault,reweavableCompressedModeDefault); |
65 |
} |
74 |
} |
Lines 71-76
Link Here
|
71 |
this.reweavableCompressedMode = reweavableCompressedMode; |
80 |
this.reweavableCompressedMode = reweavableCompressedMode; |
72 |
this.aspectsAffectingType= new HashSet(); |
81 |
this.aspectsAffectingType= new HashSet(); |
73 |
this.unwovenClassFile = null; |
82 |
this.unwovenClassFile = null; |
|
|
83 |
unwovenClassFileDataIsDiff = false; // ajh02: line added |
74 |
} |
84 |
} |
75 |
|
85 |
|
76 |
public static void setReweavableModeDefaults(boolean mode, boolean compress) { |
86 |
public static void setReweavableModeDefaults(boolean mode, boolean compress) { |
Lines 85-90
Link Here
|
85 |
private static final byte REWEAVABLE_COMPRESSION_BIT = 1<<5; |
95 |
private static final byte REWEAVABLE_COMPRESSION_BIT = 1<<5; |
86 |
|
96 |
|
87 |
public static final WeaverStateInfo read(VersionedDataInputStream s, ISourceContext context) throws IOException { |
97 |
public static final WeaverStateInfo read(VersionedDataInputStream s, ISourceContext context) throws IOException { |
|
|
98 |
System.err.println("read called"); |
88 |
byte b = s.readByte(); |
99 |
byte b = s.readByte(); |
89 |
|
100 |
|
90 |
boolean isReweavable = ((b&REWEAVABLE_BIT)!=0); |
101 |
boolean isReweavable = ((b&REWEAVABLE_BIT)!=0); |
Lines 130-137
Link Here
|
130 |
} |
141 |
} |
131 |
|
142 |
|
132 |
public void write(DataOutputStream s) throws IOException { |
143 |
public void write(DataOutputStream s) throws IOException { |
|
|
144 |
System.err.println("write called"); |
133 |
if (oldStyle) throw new RuntimeException("shouldn't be writing this"); |
145 |
if (oldStyle) throw new RuntimeException("shouldn't be writing this"); |
134 |
|
146 |
|
|
|
147 |
if (reweavable && reweavableCompressedMode){ |
148 |
s.write(key); // ajh02: 3 lines added |
149 |
} |
150 |
|
135 |
byte weaverStateInfoKind = EXTENDED; |
151 |
byte weaverStateInfoKind = EXTENDED; |
136 |
if (reweavable) weaverStateInfoKind |= REWEAVABLE_BIT; |
152 |
if (reweavable) weaverStateInfoKind |= REWEAVABLE_BIT; |
137 |
if (reweavableCompressedMode) weaverStateInfoKind |= REWEAVABLE_COMPRESSION_BIT; |
153 |
if (reweavableCompressedMode) weaverStateInfoKind |= REWEAVABLE_COMPRESSION_BIT; |
Lines 176-185
Link Here
|
176 |
public boolean isOldStyle() { |
192 |
public boolean isOldStyle() { |
177 |
return oldStyle; |
193 |
return oldStyle; |
178 |
} |
194 |
} |
179 |
|
195 |
|
180 |
public byte[] getUnwovenClassFileData() { |
196 |
public byte[] getUnwovenClassFileData(byte wovenClassFile[]) { |
181 |
return unwovenClassFile; |
197 |
// ajh02: method added |
182 |
} |
198 |
System.err.println("getUnwovenClassFileData called"); |
|
|
199 |
if(!unwovenClassFileDataIsDiff){ |
200 |
return unwovenClassFile; |
201 |
} else { |
202 |
|
203 |
// to apply the diff we use a version of wovenClassFile |
204 |
// up to but not including the length of the WeaverStateInfo... |
205 |
// BUT actually it shouldn't matter if we give it a bit too much! |
206 |
// so we can actually just give it the whole wovenClassFile here!!!!! :D |
207 |
// so we don't need to do any horrible fiddling or serializing keys |
208 |
// to find where the length of the weaverStateInfo was serialized :) |
209 |
// DUDE! sweet! |
210 |
|
211 |
unwovenClassFile = applyDiff(wovenClassFile, unwovenClassFile); |
212 |
unwovenClassFileDataIsDiff = false; |
213 |
|
214 |
// int endOfKey = findEndOfKey(wovenClassFile); |
215 |
// int positionOfnewLength = endOfKey - key.length - 9; |
216 |
// int newLength = readInt(wovenClassFile, positionOfnewLength); |
217 |
// int oldLength = readInt(wovenClassFile, positionOfnewLength + 5); |
218 |
// byte oldLengthAndB[] = { |
219 |
// wovenClassFile[positionOfnewLength + 5], wovenClassFile[positionOfnewLength + 6], wovenClassFile[positionOfnewLength + 7], wovenClassFile[positionOfnewLength + 8], wovenClassFile[positionOfnewLength + 4] |
220 |
// }; |
221 |
// byte withoutZippedDiff[] = deleteInArray(wovenClassFile, positionOfnewLength + 8 + oldLength, positionOfnewLength + 4 + newLength); |
222 |
// withoutZippedDiff = deleteInArray(withoutZippedDiff, positionOfnewLength, positionOfnewLength + 9); |
223 |
// withoutZippedDiff = insertArray(oldLengthAndB, withoutZippedDiff, positionOfnewLength); |
224 |
// unwovenClassFile = applyDiff(withoutZippedDiff, unwovenClassFile); |
225 |
// unwovenClassFileDataIsDiff = false; |
226 |
return unwovenClassFile; |
227 |
} |
228 |
} |
183 |
|
229 |
|
184 |
public void setUnwovenClassFileData(byte[] data) { |
230 |
public void setUnwovenClassFileData(byte[] data) { |
185 |
unwovenClassFile = data; |
231 |
unwovenClassFile = data; |
Lines 205-214
Link Here
|
205 |
} |
251 |
} |
206 |
|
252 |
|
207 |
|
253 |
|
208 |
//// |
|
|
209 |
|
254 |
|
|
|
255 |
// ajh02: a load of methods in this class should be made non-static on their wsi's, shouldn't they |
256 |
// because it's just silly making it static then always giving it a wsi that can't be null anyway |
210 |
private static void readAnyReweavableData(WeaverStateInfo wsi,DataInputStream s) throws IOException { |
257 |
private static void readAnyReweavableData(WeaverStateInfo wsi,DataInputStream s) throws IOException { |
211 |
|
|
|
212 |
if (wsi.isReweavable()) { |
258 |
if (wsi.isReweavable()) { |
213 |
// Load list of aspects that need to exist in the world for reweaving to be 'legal' |
259 |
// Load list of aspects that need to exist in the world for reweaving to be 'legal' |
214 |
int numberAspectsAffectingType = s.readShort(); |
260 |
int numberAspectsAffectingType = s.readShort(); |
Lines 224-254
Link Here
|
224 |
if (bytesread!=unwovenClassFileSize) |
270 |
if (bytesread!=unwovenClassFileSize) |
225 |
throw new IOException("ERROR whilst reading reweavable data, expected "+ |
271 |
throw new IOException("ERROR whilst reading reweavable data, expected "+ |
226 |
unwovenClassFileSize+" bytes, only found "+bytesread); |
272 |
unwovenClassFileSize+" bytes, only found "+bytesread); |
|
|
273 |
wsi.unwovenClassFileDataIsDiff = false; |
227 |
} else { |
274 |
} else { |
228 |
// Decompress it |
275 |
// Decompress it |
|
|
276 |
// classData = new byte[unwovenClassFileSize]; |
277 |
// |
278 |
// ZipInputStream zis = new ZipInputStream(s); |
279 |
// ZipEntry zen = zis.getNextEntry(); |
280 |
// int current = 0; |
281 |
// int bytesToGo=unwovenClassFileSize; |
282 |
// while (bytesToGo>0) { |
283 |
// int amount = zis.read(classData,current,bytesToGo); |
284 |
// current+=amount; |
285 |
// bytesToGo-=amount; |
286 |
// } |
287 |
// zis.closeEntry(); |
288 |
// if (bytesToGo!=0) |
289 |
// throw new IOException("ERROR whilst reading compressed reweavable data, expected "+ |
290 |
// unwovenClassFileSize+" bytes, only found "+current); |
291 |
|
229 |
classData = new byte[unwovenClassFileSize]; |
292 |
classData = new byte[unwovenClassFileSize]; |
230 |
|
293 |
int bytesread = s.read(classData); |
231 |
ZipInputStream zis = new ZipInputStream(s); |
294 |
if (bytesread!=unwovenClassFileSize) |
232 |
ZipEntry zen = zis.getNextEntry(); |
295 |
throw new IOException("ERROR whilst reading reweavable data, expected "+ |
233 |
int current = 0; |
296 |
unwovenClassFileSize+" bytes, only found "+bytesread); |
234 |
int bytesToGo=unwovenClassFileSize; |
297 |
// but remember it's a diff of the unwoven classFile! |
235 |
while (bytesToGo>0) { |
298 |
wsi.unwovenClassFileDataIsDiff = true; |
236 |
int amount = zis.read(classData,current,bytesToGo); |
|
|
237 |
current+=amount; |
238 |
bytesToGo-=amount; |
239 |
} |
240 |
zis.closeEntry(); |
241 |
if (bytesToGo!=0) |
242 |
throw new IOException("ERROR whilst reading compressed reweavable data, expected "+ |
243 |
unwovenClassFileSize+" bytes, only found "+current); |
244 |
} |
299 |
} |
245 |
wsi.setUnwovenClassFileData(classData); |
300 |
wsi.setUnwovenClassFileData(classData); |
246 |
} |
301 |
} |
247 |
} |
302 |
} |
248 |
|
303 |
|
|
|
304 |
public byte[] insertAnyReweavableData(byte wovenClassFile[]) { |
305 |
// now that we have the whole wovenClassFile, |
306 |
//we can make the diff with it and write it over where we previously left the |
307 |
// key stub |
308 |
System.err.println("insertAnyReweavableData called"); |
309 |
//return wovenClassFile; |
310 |
|
311 |
if (isReweavable() && reweavableCompressedMode){ |
312 |
ByteArrayOutputStream arrayStream = new ByteArrayOutputStream(); |
313 |
DataOutputStream s = new DataOutputStream(arrayStream); |
314 |
|
315 |
int endOfKey = findEndOfKey(wovenClassFile); |
316 |
int startOfKey = endOfKey - key.length; |
317 |
int oldLengthLocation = startOfKey -4; |
318 |
int oldLength = readInt(wovenClassFile, oldLengthLocation); |
319 |
wovenClassFile = deleteInArray(wovenClassFile,startOfKey,endOfKey); // remove the key |
320 |
|
321 |
byte [] wovenClassFileToDiffWith = new byte [oldLengthLocation]; |
322 |
System.arraycopy(wovenClassFile,0,wovenClassFileToDiffWith,0,oldLengthLocation); |
323 |
|
324 |
// to make the diff we use a version of wovenClassFile |
325 |
// up to but not including the length of the WeaverStateInfo |
326 |
|
327 |
byte [] diff = generateDiff(wovenClassFileToDiffWith, unwovenClassFile); |
328 |
try { // add the length of the diff to the front of the diff |
329 |
s.writeInt(diff.length); |
330 |
s.write(diff); |
331 |
} catch(IOException e){} |
332 |
diff = arrayStream.toByteArray(); |
333 |
// we have to swap the oldLength for the new one, |
334 |
// and add the diff (can use the oldLength to work out where it goes :) |
335 |
|
336 |
int newLength = oldLength - key.length + diff.length; |
337 |
byte newLengthBytes[] = serializeInt(newLength); |
338 |
|
339 |
// swap in the serialized newLength for the oldOne: |
340 |
wovenClassFile[oldLengthLocation] = newLengthBytes[0]; |
341 |
wovenClassFile[oldLengthLocation + 1] = newLengthBytes[1]; |
342 |
wovenClassFile[oldLengthLocation + 2] = newLengthBytes[2]; |
343 |
wovenClassFile[oldLengthLocation + 3] = newLengthBytes[3]; |
344 |
|
345 |
// add the diff |
346 |
wovenClassFile = insertArray(diff, wovenClassFile, oldLengthLocation + 4 + oldLength - key.length); |
347 |
|
348 |
|
349 |
} |
350 |
return wovenClassFile; |
351 |
|
352 |
// ajh02: method added |
353 |
// ByteArrayOutputStream arrayStream = new ByteArrayOutputStream(); |
354 |
// DataOutputStream s = new DataOutputStream(arrayStream); |
355 |
// if(isReweavable()){ |
356 |
// try { |
357 |
// if(!reweavableCompressedMode) { |
358 |
// s.writeInt(unwovenClassFile.length); |
359 |
// s.write(unwovenClassFile); |
360 |
// } else { |
361 |
// byte diff[] = generateDiff(wovenClassFile, unwovenClassFile); |
362 |
// s.writeInt(diff.length); |
363 |
// s.write(diff); |
364 |
// } |
365 |
// } |
366 |
// catch(IOException e) { |
367 |
// // ajh02: hmm do something here? |
368 |
// // can this ever happen? |
369 |
// } |
370 |
// byte zippedDiff[] = arrayStream.toByteArray(); |
371 |
// int endOfKey = findEndOfKey(wovenClassFile); |
372 |
// int oldLengthLocation = endOfKey - key.length - 5; |
373 |
// int oldLength = readInt(wovenClassFile, oldLengthLocation); |
374 |
// int newLength = oldLength + 4 + zippedDiff.length; |
375 |
// ByteArrayOutputStream bos = new ByteArrayOutputStream(4); |
376 |
// DataOutputStream dos = new DataOutputStream(bos); |
377 |
// try { |
378 |
// dos.writeInt(newLength); |
379 |
// } |
380 |
// catch(IOException e) { |
381 |
// } |
382 |
// byte newLengthBytes[] = bos.toByteArray(); |
383 |
// byte oldLengthBytes[] = { |
384 |
// wovenClassFile[oldLengthLocation], wovenClassFile[oldLengthLocation + 1], wovenClassFile[oldLengthLocation + 2], wovenClassFile[oldLengthLocation + 3] |
385 |
// }; |
386 |
// wovenClassFile[oldLengthLocation] = newLengthBytes[0]; |
387 |
// wovenClassFile[oldLengthLocation + 1] = newLengthBytes[1]; |
388 |
// wovenClassFile[oldLengthLocation + 2] = newLengthBytes[2]; |
389 |
// wovenClassFile[oldLengthLocation + 3] = newLengthBytes[3]; |
390 |
// wovenClassFile = insertArray(oldLengthBytes, wovenClassFile, oldLengthLocation + 5); |
391 |
// return insertArray(zippedDiff, wovenClassFile, oldLengthLocation + 8 + oldLength); |
392 |
// } else { |
393 |
// return wovenClassFile; |
394 |
// } |
395 |
} |
396 |
|
397 |
private static final int findEndOfKey(byte lookIn[]){ |
398 |
// looks through the classfile backwards (as the attributes are all near the end) |
399 |
for(int i = lookIn.length - 1; i > 0; i--) |
400 |
if(endOfKeyHere(lookIn, i)){ |
401 |
return i + 1; |
402 |
} |
403 |
throw new RuntimeException("key not found in wovenClassFile"); |
404 |
} |
405 |
private static final boolean endOfKeyHere(byte lookIn[], int i){ |
406 |
for(int j = 0; j < key.length; j++) |
407 |
if(key[key.length - 1 - j] != lookIn[i - j]){ |
408 |
return false; |
409 |
} |
410 |
return true; |
411 |
} |
412 |
private static final byte[] insertArray(byte toInsert[], byte original[], int offset){ |
413 |
byte result[] = new byte[original.length + toInsert.length]; |
414 |
System.arraycopy(original, 0, result, 0, offset); |
415 |
System.arraycopy(toInsert, 0, result, offset, toInsert.length); |
416 |
System.arraycopy(original, offset, result, offset + toInsert.length, original.length - offset); |
417 |
return result; |
418 |
} |
419 |
private static final int readInt(byte [] a, int offset){ |
420 |
ByteArrayInputStream b = new ByteArrayInputStream(a, offset, 4); |
421 |
DataInputStream d = new DataInputStream(b); |
422 |
int length = -1; |
423 |
try{ |
424 |
length = d.readInt(); |
425 |
} |
426 |
catch(IOException e) { |
427 |
// ajh02: can this ever happen? |
428 |
} |
429 |
return length; |
430 |
} |
431 |
private static final int readUnsignedShort(byte a[], int offset){ |
432 |
ByteArrayInputStream b = new ByteArrayInputStream(a, offset, 4); |
433 |
DataInputStream d = new DataInputStream(b); |
434 |
int length = -1; |
435 |
try{ |
436 |
length = d.readUnsignedShort(); |
437 |
} |
438 |
catch(IOException e) { |
439 |
// ajh02: can this ever happen? |
440 |
} |
441 |
return length; |
442 |
} |
443 |
private static final byte[] deleteInArray(byte a[], int start, int end){ |
444 |
int lengthToDelete = end - start; |
445 |
byte result[] = new byte[a.length - lengthToDelete]; // make a new array |
446 |
System.arraycopy(a, 0, result, 0, start); // copy in the bit before the deleted bit |
447 |
System.arraycopy(a, end, result, start, a.length - end); // copy in the bit after the deleted bit |
448 |
return result; |
449 |
} |
450 |
|
451 |
// classfiles consist of: |
452 |
// 8 bytes: magic number and minor and major versions, |
453 |
// 2 bytes: its constant pool count |
454 |
// n bytes: the rest of the class file |
455 |
// |
456 |
// weaving a classfile never changes the classfile's first 8 bytes, |
457 |
// and usually there's a load of bytes 10 bytes in that weaving leaves unchanged |
458 |
// |
459 |
// so the diff consists of: |
460 |
// 2 bytes: its constant pool count |
461 |
// 4 bytes: the number of bytes the woven and unWoven class files have in common 10 bytes in |
462 |
// n bytes: the unWoven class file after the bit it has in common with the woven one |
463 |
|
464 |
byte [] applyDiff(byte [] wovenClassFile, byte [] diff){ |
465 |
|
466 |
int lengthInCommon = readInt(diff,2); |
467 |
byte [] unWovenClassFile = new byte [4 + diff.length + lengthInCommon]; |
468 |
|
469 |
// the magic number and classfile version cannot be changed by weaving |
470 |
System.arraycopy(wovenClassFile,0,unWovenClassFile,0,8); |
471 |
|
472 |
// copy across the constant pool count |
473 |
unWovenClassFile[8] = diff[0]; |
474 |
unWovenClassFile[9] = diff[1]; |
475 |
|
476 |
// copy in the stuff they have in common |
477 |
System.arraycopy(wovenClassFile,10,unWovenClassFile,10,lengthInCommon); |
478 |
|
479 |
// now copy the rest of the diff in verbatim |
480 |
System.arraycopy(diff,6,unWovenClassFile,10+lengthInCommon,diff.length-6); |
481 |
|
482 |
return unWovenClassFile; |
483 |
} |
484 |
|
485 |
byte [] generateDiff(byte [] wovenClassFile, byte [] unWovenClassFile){ |
486 |
|
487 |
// find how long the bit 10 bytes in that they have in common is |
488 |
int lookingAt = 10; |
489 |
int shorterLength |
490 |
=(wovenClassFile.length < unWovenClassFile.length)? wovenClassFile.length:unWovenClassFile.length; |
491 |
while (lookingAt < shorterLength && (wovenClassFile[lookingAt] == unWovenClassFile[lookingAt])){ |
492 |
lookingAt++; |
493 |
} |
494 |
int lengthInCommon = lookingAt - 10; |
495 |
byte [] diff = new byte [unWovenClassFile.length - 4 - lengthInCommon]; |
496 |
|
497 |
// first 2 bytes of the diff are the constant pool count |
498 |
diff[0] = unWovenClassFile[8]; |
499 |
diff[1] = unWovenClassFile[9]; |
500 |
|
501 |
// then 4 bytes saying how long they have in common after the constant pool count |
502 |
byte [] lengthInCommonBytes = serializeInt(lengthInCommon); |
503 |
diff[2] = lengthInCommonBytes[0]; |
504 |
diff[3] = lengthInCommonBytes[1]; |
505 |
diff[4] = lengthInCommonBytes[2]; |
506 |
diff[5] = lengthInCommonBytes[3]; |
507 |
|
508 |
// then we just dump the rest of the unWovenClassFile verbatim |
509 |
System.arraycopy(unWovenClassFile,10+lengthInCommon,diff,6,diff.length-6); |
510 |
|
511 |
System.err.println("unwoven class file was: " + unWovenClassFile.length); |
512 |
System.err.println("diff is: " + diff.length); |
513 |
|
514 |
return diff; |
515 |
} |
516 |
|
517 |
private byte [] serializeInt(int i){ |
518 |
ByteArrayOutputStream bos = new ByteArrayOutputStream(4); |
519 |
DataOutputStream dos = new DataOutputStream(bos); |
520 |
try { |
521 |
dos.writeInt(i); |
522 |
} catch(IOException e) {} |
523 |
return bos.toByteArray(); |
524 |
} |
525 |
|
526 |
|
249 |
|
527 |
|
250 |
|
528 |
|
251 |
private static void writeAnyReweavableData(WeaverStateInfo wsi,DataOutputStream s) throws IOException { |
529 |
private static void writeAnyReweavableData(WeaverStateInfo wsi,DataOutputStream s) throws IOException { |
|
|
530 |
System.err.println("writeAnyReweavableData called"); |
252 |
if (wsi.isReweavable()) { |
531 |
if (wsi.isReweavable()) { |
253 |
// Write out list of aspects that must exist next time we try and weave this class |
532 |
// Write out list of aspects that must exist next time we try and weave this class |
254 |
s.writeShort(wsi.aspectsAffectingType.size()); |
533 |
s.writeShort(wsi.aspectsAffectingType.size()); |
Lines 259-274
Link Here
|
259 |
} |
538 |
} |
260 |
} |
539 |
} |
261 |
byte[] data = wsi.unwovenClassFile; |
540 |
byte[] data = wsi.unwovenClassFile; |
262 |
s.writeInt(data.length); |
541 |
|
263 |
// Do we need to compress the data? |
542 |
// Do we need to compress the data? |
264 |
if (!wsi.reweavableCompressedMode) { |
543 |
if (!wsi.reweavableCompressedMode) { |
|
|
544 |
s.writeInt(data.length); |
265 |
s.write(wsi.unwovenClassFile); |
545 |
s.write(wsi.unwovenClassFile); |
266 |
} else { |
546 |
} else { |
267 |
ZipOutputStream zos = new ZipOutputStream(s); |
547 |
|
268 |
ZipEntry ze = new ZipEntry("data"); |
548 |
//s.write(key); // ajh02: line added |
269 |
zos.putNextEntry(ze); |
549 |
// put the key here as a marker for where we have to come back and |
270 |
zos.write(wsi.unwovenClassFile,0,wsi.unwovenClassFile.length); |
550 |
// fill in later |
271 |
zos.closeEntry(); |
551 |
|
|
|
552 |
|
553 |
//ZipOutputStream zos = new ZipOutputStream(s); |
554 |
//ZipEntry ze = new ZipEntry("data"); |
555 |
//zos.putNextEntry(ze); |
556 |
//zos.write(wsi.unwovenClassFile,0,wsi.unwovenClassFile.length); |
557 |
//zos.closeEntry(); |
272 |
} |
558 |
} |
273 |
} |
559 |
} |
274 |
} |
560 |
} |