25
25
import java .io .OutputStream ;
26
26
import java .util .HashSet ;
27
27
import java .util .zip .GZIPOutputStream ;
28
+ import java .util .zip .ZipEntry ;
28
29
import java .util .zip .ZipException ;
29
30
import java .util .zip .ZipInputStream ;
30
31
@@ -117,6 +118,11 @@ public class TinkerZipOutputStream extends FilterOutputStream implements ZipCons
117
118
* to the start of the current entry header is greater than 0xFFFFFFFF.
118
119
*/
119
120
private boolean currentEntryNeedsZip64 ;
121
+
122
+ private final int alignBytes ;
123
+
124
+ private int padding = 0 ;
125
+
120
126
/**
121
127
* Constructs a new {@code ZipOutputStream} that writes a zip file to the given
122
128
* {@code OutputStream}.
@@ -130,8 +136,13 @@ public TinkerZipOutputStream(OutputStream os) {
130
136
* @hide for testing only.
131
137
*/
132
138
public TinkerZipOutputStream (OutputStream os , boolean forceZip64 ) {
139
+ this (os , forceZip64 , 4 );
140
+ }
141
+
142
+ public TinkerZipOutputStream (OutputStream os , boolean forceZip64 , int alignBytes ) {
133
143
super (os );
134
144
this .forceZip64 = forceZip64 ;
145
+ this .alignBytes = alignBytes ;
135
146
}
136
147
137
148
/**
@@ -328,7 +339,8 @@ public void closeEntry() throws IOException {
328
339
if (currentEntry .extra != null ) {
329
340
cDir .write (currentEntry .extra );
330
341
}
331
- offset += curOffset ;
342
+ offset += curOffset + padding ;
343
+ padding = 0 ;
332
344
if (entryCommentBytes .length > 0 ) {
333
345
cDir .write (entryCommentBytes );
334
346
entryCommentBytes = BYTE ;
@@ -390,7 +402,7 @@ public void finish() throws IOException {
390
402
writeIntAsUint16 (cDir , entries .size ()); // Number of entries
391
403
writeIntAsUint16 (cDir , entries .size ()); // Number of entries
392
404
writeLongAsUint32 (cDir , cdirEntriesSize ); // Size of central dir
393
- writeLongAsUint32 (cDir , offset ); // Offset of central dir
405
+ writeLongAsUint32 (cDir , offset + padding ); // Offset of central dir
394
406
}
395
407
writeIntAsUint16 (cDir , commentBytes .length );
396
408
if (commentBytes .length > 0 ) {
@@ -401,6 +413,22 @@ public void finish() throws IOException {
401
413
cDir = null ;
402
414
}
403
415
416
+ private int getPaddingByteCount (TinkerZipEntry entry , long entryFileOffset ) {
417
+ if (entry .getMethod () != ZipEntry .STORED || alignBytes == 0 ) {
418
+ return 0 ;
419
+ }
420
+ return (int ) ((alignBytes - (entryFileOffset % alignBytes )) % alignBytes );
421
+ }
422
+
423
+ private void makePaddingToStream (OutputStream os , long padding ) throws IOException {
424
+ if (padding <= 0 ) {
425
+ return ;
426
+ }
427
+ while (padding -- > 0 ) {
428
+ os .write (0 );
429
+ }
430
+ }
431
+
404
432
/**
405
433
* Writes entry information to the underlying stream. Data associated with
406
434
* the entry can then be written using {@code write()}. After data is
@@ -502,19 +530,23 @@ public void putNextEntry(TinkerZipEntry ze) throws IOException {
502
530
writeLongAsUint32 (out , 0 );
503
531
writeLongAsUint32 (out , 0 );
504
532
}
505
- writeIntAsUint16 (out , nameBytes .length );
533
+ final int nameLength = nameBytes .length ;
534
+ writeIntAsUint16 (out , nameLength );
535
+ final long currDataOffset = offset + LOCHDR + nameLength + (currentEntry .getExtra () != null ? currentEntry .getExtra ().length : 0 );
536
+ padding = getPaddingByteCount (currentEntry , currDataOffset );
506
537
/*if (currentEntryNeedsZip64) {
507
538
Zip64.insertZip64ExtendedInfoToExtras(currentEntry);
508
539
}*/
509
540
if (currentEntry .extra != null ) {
510
- writeIntAsUint16 (out , currentEntry .extra .length );
541
+ writeIntAsUint16 (out , currentEntry .extra .length + padding );
511
542
} else {
512
- writeIntAsUint16 (out , 0 );
543
+ writeIntAsUint16 (out , padding );
513
544
}
514
545
out .write (nameBytes );
515
546
if (currentEntry .extra != null ) {
516
547
out .write (currentEntry .extra );
517
548
}
549
+ makePaddingToStream (out , padding );
518
550
}
519
551
520
552
/**
0 commit comments