201 } else { 202 throw new IllegalArgumentException("Unknown type: " + type); 203 } 204 } while (parser.skipToNextStartSection()); 205 206 if (parser.event() != END_FILE) 207 throw new IOException("Expected END_FILE"); 208 } finally { 209 close(); 210 } 211 } 212 213 public byte[] getModuleInfoBytes() { 214 return moduleInfoBytes.clone(); 215 } 216 217 public byte[] getHash() { 218 return fileHeader.getHash(); 219 } 220 221 public List<byte[]> getCalculatedHashes() { 222 List<byte[]> hashes = new ArrayList<>(); 223 hashes.add(parser.getHeaderHash()); 224 for (Entry<SectionType,byte[]> entry : parser.getHashes().entrySet()) { 225 if (entry.getKey() != SIGNATURE) 226 hashes.add(entry.getValue()); 227 } 228 hashes.add(getHash()); 229 230 return hashes; 231 } 232 233 public boolean hasSignature() { 234 return moduleSignatureBytes != null; 235 } 236 237 public SignatureType getSignatureType() { 238 return moduleSignatureType; 239 } 240 540 private static short readHashLength(DataInputStream in) throws IOException { 541 final short hashLength = in.readShort(); 542 ensureNonNegativity(hashLength, "hashLength"); 543 544 return hashLength; 545 } 546 547 private static byte[] readHashBytes(DataInputStream in, short hashLength) 548 throws IOException 549 { 550 final byte[] hash = new byte[hashLength]; 551 in.readFully(hash); 552 553 return hash; 554 } 555 556 private static byte[] readHash(DataInputStream in) throws IOException { 557 return readHashBytes(in, readHashLength(in)); 558 } 559 560 private static byte[] readFileHash(DigestInputStream dis) 561 throws IOException 562 { 563 DataInputStream in = new DataInputStream(dis); 564 565 final short hashLength = readHashLength(in); 566 567 // Turn digest computation off before reading the file hash 568 dis.on(false); 569 byte[] hash = readHashBytes(in, hashLength); 570 // Turn digest computation on again afterwards. 571 dis.on(true); 572 573 return hash; 574 } 575 576 /** 577 * <p> A module-file header </p> 578 */ 579 public final static class ModuleFileHeader { 580 public static final int LENGTH_WITHOUT_HASH = 30; 581 public static final int LENGTH = 582 LENGTH_WITHOUT_HASH + HashType.SHA256.length(); 583 584 // Fields are specified as unsigned. Treat signed values as bugs. 585 private final int magic; // MAGIC 586 private final FileConstants.Type type; // Type.MODULE_FILE 587 private final short major; // ModuleFile.MAJOR_VERSION 588 private final short minor; // ModuleFile.MINOR_VERSION 589 private final long csize; // Size of rest of file, compressed 590 private final long usize; // Space required for uncompressed contents 591 // (upper private final ound; need not be exact) 592 private final HashType hashType; // One of ModuleFile.HashType 593 // (applies final o all hashes in this file) 594 private final byte[] hash; // Hash of entire file (except this hash 595 // and the Signature section, if present) 596 597 public HashType getHashType() { 598 return hashType; 599 } 600 601 public byte[] getHash() { 602 return hash.clone(); 603 } 604 605 private byte[] getHashNoClone() { 606 return hash; 607 } 608 609 public long getCSize() { 610 return csize; 611 } 612 613 public long getUSize() { 614 return usize; 615 } 616 617 public ModuleFileHeader(long csize, long usize, 618 HashType hashType, byte[] hash) { 619 ensureNonNegativity(csize, "csize"); 620 ensureNonNegativity(usize, "usize"); 621 622 magic = FileConstants.MAGIC; 623 type = FileConstants.Type.MODULE_FILE; 624 major = MAJOR_VERSION; 625 minor = MINOR_VERSION; 626 627 this.csize = csize; 628 this.usize = usize; 629 this.hashType = hashType; 630 this.hash = hash.clone(); 631 } 632 633 public void write(final DataOutput out) throws IOException { 634 out.writeInt(magic); 635 out.writeShort(type.value()); 636 out.writeShort(major); 637 out.writeShort(minor); 638 out.writeLong(csize); 639 out.writeLong(usize); 640 out.writeShort(hashType.value()); 641 writeHash(out, hash); 642 } 643 644 public static ModuleFileHeader read(final DigestInputStream dis) 645 throws IOException 646 { 647 DataInputStream in = new DataInputStream(dis); 648 649 final int magic = in.readInt(); 650 ensureMatch(magic, FileConstants.MAGIC, 651 "FileConstants.MAGIC"); 652 653 final short type = in.readShort(); 654 ensureMatch(type, FileConstants.Type.MODULE_FILE.value(), 655 "Type.MODULE_FILE"); 656 657 final short major = in.readShort(); 658 ensureMatch(major, MAJOR_VERSION, 659 "ModuleFile.MAJOR_VERSION"); 660 661 final short minor = in.readShort(); 662 ensureMatch(minor, MINOR_VERSION, 663 "ModuleFile.MINOR_VERSION"); 664 665 final long csize = in.readLong(); 666 final long usize = in.readLong(); 667 final short hashTypeValue = in.readShort(); 668 HashType hashType = null; 669 try { 670 hashType = HashType.valueOf(hashTypeValue); 671 } catch (IllegalArgumentException x) { 672 throw new IOException("Invalid hash type: " + hashTypeValue); 673 } 674 final byte[] hash = readFileHash(dis); 675 676 return new ModuleFileHeader(csize, usize, hashType, hash); 677 } 678 679 @Override 680 public String toString() { 681 return "MODULE{csize=" + csize + 682 ", hash=" + hashHexString(hash) + "}"; 683 } 684 } 685 686 /** 687 * <p> A module-file section header </p> 688 */ 689 public final static class SectionHeader { 690 public static final int LENGTH_WITHOUT_HASH = 12; 691 public static final int LENGTH = 692 LENGTH_WITHOUT_HASH + HashType.SHA256.length(); 693 694 // Fields are specified as unsigned. Treat signed values as bugs. 695 private final SectionType type; 696 private final Compressor compressor; | 201 } else { 202 throw new IllegalArgumentException("Unknown type: " + type); 203 } 204 } while (parser.skipToNextStartSection()); 205 206 if (parser.event() != END_FILE) 207 throw new IOException("Expected END_FILE"); 208 } finally { 209 close(); 210 } 211 } 212 213 public byte[] getModuleInfoBytes() { 214 return moduleInfoBytes.clone(); 215 } 216 217 public byte[] getHash() { 218 return fileHeader.getHash(); 219 } 220 221 public ModuleArchitecture getArchitecture() { 222 return fileHeader.getArchitecture(); 223 } 224 225 public List<byte[]> getCalculatedHashes() { 226 List<byte[]> hashes = new ArrayList<>(); 227 hashes.add(parser.getHeaderHash()); 228 for (Entry<SectionType,byte[]> entry : parser.getHashes().entrySet()) { 229 if (entry.getKey() != SIGNATURE) 230 hashes.add(entry.getValue()); 231 } 232 hashes.add(getHash()); 233 234 return hashes; 235 } 236 237 public boolean hasSignature() { 238 return moduleSignatureBytes != null; 239 } 240 241 public SignatureType getSignatureType() { 242 return moduleSignatureType; 243 } 244 544 private static short readHashLength(DataInputStream in) throws IOException { 545 final short hashLength = in.readShort(); 546 ensureNonNegativity(hashLength, "hashLength"); 547 548 return hashLength; 549 } 550 551 private static byte[] readHashBytes(DataInputStream in, short hashLength) 552 throws IOException 553 { 554 final byte[] hash = new byte[hashLength]; 555 in.readFully(hash); 556 557 return hash; 558 } 559 560 private static byte[] readHash(DataInputStream in) throws IOException { 561 return readHashBytes(in, readHashLength(in)); 562 } 563 564 private static byte[] readFileHash(InputStream in) 565 throws IOException 566 { 567 boolean digestStream = in instanceof DigestInputStream ? true : false; 568 DataInputStream din = new DataInputStream(in); 569 570 final short hashLength = readHashLength(din); 571 572 // Turn digest computation off before reading the file hash 573 if (digestStream) 574 ((DigestInputStream)in).on(false); 575 byte[] hash = readHashBytes(din, hashLength); 576 // Turn digest computation on again afterwards. 577 if (digestStream) 578 ((DigestInputStream)in).on(true); 579 580 return hash; 581 } 582 583 /** 584 * <p> A module-file header </p> 585 */ 586 public final static class ModuleFileHeader { 587 private static final int LENGTH_WITHOUT_VARIABLE_FIELDS = 34; 588 589 // Fields are specified as unsigned. Treat signed values as bugs. 590 private final int magic; // MAGIC 591 private final FileConstants.Type type; // Type.MODULE_FILE 592 private final short major; // ModuleFile.MAJOR_VERSION 593 private final short minor; // ModuleFile.MINOR_VERSION 594 private final long csize; // Size of rest of file, compressed 595 private final long usize; // Space required for uncompressed contents 596 // (upper private final ound; need not be exact) 597 private final HashType hashType; // One of ModuleFile.HashType 598 // (applies final o all hashes in this file) 599 private final byte[] hash; // Hash of entire file (except this hash 600 // and the Signature section, if present) 601 private final ModuleArchitecture modArch;// os/arch, Java-modified UTF-8 pair 602 603 private final int length; 604 605 public HashType getHashType() { 606 return hashType; 607 } 608 609 public byte[] getHash() { 610 return hash.clone(); 611 } 612 613 private byte[] getHashNoClone() { 614 return hash; 615 } 616 617 public long getCSize() { 618 return csize; 619 } 620 621 public long getUSize() { 622 return usize; 623 } 624 625 public ModuleArchitecture getArchitecture() { 626 return modArch; 627 } 628 629 public int getLength() { 630 return length; 631 } 632 633 private ModuleFileHeader(long csize, long usize, HashType hashType, 634 byte[] hash, ModuleArchitecture modArch) { 635 ensureNonNegativity(csize, "csize"); 636 ensureNonNegativity(usize, "usize"); 637 638 magic = FileConstants.MAGIC; 639 type = FileConstants.Type.MODULE_FILE; 640 major = MAJOR_VERSION; 641 minor = MINOR_VERSION; 642 643 this.csize = csize; 644 this.usize = usize; 645 this.hashType = hashType; 646 this.hash = hash.clone(); 647 this.modArch = modArch; 648 try { 649 length = LENGTH_WITHOUT_VARIABLE_FIELDS 650 + hash.length 651 + modArch.os().getBytes("UTF-8").length 652 + modArch.arch().getBytes("UTF-8").length; 653 } catch (UnsupportedEncodingException x) { 654 throw new InternalError(x); 655 } 656 } 657 658 public static Builder newBuilder() { 659 return new Builder(); 660 } 661 662 public static class Builder { 663 private long csize; 664 private long usize; 665 private ModuleArchitecture architecture = ModuleArchitecture.ANY; 666 private HashType hashType; 667 private byte[] hash; 668 669 private Builder() {} 670 671 public Builder setHashType(HashType hashType) { 672 this.hashType = hashType; 673 return this; 674 } 675 676 public Builder setHash(byte[] hash) { 677 this.hash = hash.clone(); 678 return this; 679 } 680 681 public Builder setCSize(long csize) { 682 this.csize = csize; 683 return this; 684 } 685 686 public Builder setUSize(long usize) { 687 this.usize = usize; 688 return this; 689 } 690 691 public Builder setArchitecture(ModuleArchitecture architecture) { 692 this.architecture = architecture; 693 return this; 694 } 695 696 public ModuleFileHeader build() { 697 ensureNonNegativity(csize, "csize"); 698 ensureNonNegativity(usize, "usize"); 699 return new ModuleFileHeader(csize, usize, hashType, hash, 700 architecture); 701 } 702 } 703 704 public void write(final DataOutput out) throws IOException { 705 out.writeInt(magic); 706 out.writeShort(type.value()); 707 out.writeShort(major); 708 out.writeShort(minor); 709 out.writeLong(csize); 710 out.writeLong(usize); 711 out.writeShort(hashType.value()); 712 writeHash(out, hash); 713 out.writeUTF(modArch.os()); 714 out.writeUTF(modArch.arch()); 715 } 716 717 public static ModuleFileHeader read(final InputStream in) 718 throws IOException 719 { 720 DataInputStream din = new DataInputStream(in); 721 722 final int magic = din.readInt(); 723 ensureMatch(magic, FileConstants.MAGIC, 724 "FileConstants.MAGIC"); 725 726 final short type = din.readShort(); 727 ensureMatch(type, FileConstants.Type.MODULE_FILE.value(), 728 "Type.MODULE_FILE"); 729 730 final short major = din.readShort(); 731 ensureMatch(major, MAJOR_VERSION, 732 "ModuleFile.MAJOR_VERSION"); 733 734 final short minor = din.readShort(); 735 ensureMatch(minor, MINOR_VERSION, 736 "ModuleFile.MINOR_VERSION"); 737 738 final long csize = din.readLong(); 739 final long usize = din.readLong(); 740 741 final short hashTypeValue = din.readShort(); 742 HashType hashType = null; 743 try { 744 hashType = HashType.valueOf(hashTypeValue); 745 } catch (IllegalArgumentException x) { 746 throw new IOException("Invalid hash type: " + hashTypeValue); 747 } 748 final byte[] hash = readFileHash(in); 749 750 final String os = din.readUTF(); 751 final String arch = din.readUTF(); 752 final ModuleArchitecture architecture = ModuleArchitecture.create(os, arch); 753 754 return new ModuleFileHeader(csize, usize, hashType, hash, architecture); 755 } 756 757 @Override 758 public String toString() { 759 return "MODULE{csize=" + csize + 760 ", hash=" + hashHexString(hash) + "}"; 761 } 762 } 763 764 /** 765 * <p> A module-file section header </p> 766 */ 767 public final static class SectionHeader { 768 public static final int LENGTH_WITHOUT_HASH = 12; 769 public static final int LENGTH = 770 LENGTH_WITHOUT_HASH + HashType.SHA256.length(); 771 772 // Fields are specified as unsigned. Treat signed values as bugs. 773 private final SectionType type; 774 private final Compressor compressor; |