1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.oracle.ipack.signature;
  27 
  28 import com.oracle.ipack.blobs.Blob;
  29 import java.io.DataOutput;
  30 import java.io.IOException;
  31 import java.io.UnsupportedEncodingException;
  32 
  33 public final class CodeDirectoryBlob extends Blob {
  34     private final byte[] identifierBytes;
  35 
  36     private final int numberOfSpecialSlots;
  37     private final int numberOfCodeSlots;
  38     private final byte[] specialSlots;
  39     private final byte[] codeSlots;
  40 
  41     private final int codeLimit;
  42     private final int hashSize;
  43     private final int hashType;
  44     private final int pageSize;
  45 
  46     private int flags;
  47 
  48     public CodeDirectoryBlob(final String identifier,
  49                              final int codeLimit) {
  50         this(identifier, codeLimit, 3, 4096, 20, 1);
  51     }
  52 
  53     public CodeDirectoryBlob(final String identifier,
  54                              final int codeLimit,
  55                              final int numberOfSpecialSlots,
  56                              final int pageSize,
  57                              final int hashSize,
  58                              final int hashType) {
  59         this.identifierBytes = identifierBytes(identifier);
  60 
  61         this.numberOfSpecialSlots = numberOfSpecialSlots;
  62         this.numberOfCodeSlots = (codeLimit + pageSize - 1) / pageSize;
  63 
  64         this.specialSlots = new byte[numberOfSpecialSlots * hashSize];
  65         this.codeSlots = new byte[numberOfCodeSlots * hashSize];
  66 
  67         this.codeLimit = codeLimit;
  68         this.hashSize = hashSize;
  69         this.hashType = hashType;
  70         this.pageSize = pageSize;
  71     }
  72 
  73     public int getFlags() {
  74         return flags;
  75     }
  76 
  77     public void setFlags(final int flags) {
  78         this.flags = flags;
  79     }
  80 
  81     public void setInfoPlistSlot(final byte[] hash) {
  82         setSpecialSlot(SpecialSlotConstants.CD_INFO_SLOT, hash);
  83     }
  84 
  85     public void setRequirementsSlot(final byte[] hash) {
  86         setSpecialSlot(SpecialSlotConstants.CD_REQUIREMENTS_SLOT, hash);
  87     }
  88 
  89     public void setCodeResourcesSlot(final byte[] hash) {
  90         setSpecialSlot(SpecialSlotConstants.CD_RESOURCE_DIR_SLOT, hash);
  91     }
  92 
  93     public void setSpecialSlot(final int index, final byte[] hash) {
  94         System.arraycopy(hash, 0, specialSlots,
  95                          specialSlots.length - index * hashSize,
  96                          hashSize);
  97     }
  98 
  99     public void setCodeSlot(final int index, final byte[] hash) {
 100         System.arraycopy(hash, 0, codeSlots, index * hashSize, hashSize);
 101     }
 102 
 103     @Override
 104     protected int getMagic() {
 105         return 0xfade0c02;
 106     }
 107 
 108     @Override
 109     protected int getPayloadSize() {
 110         return 4 * 10 + identifierBytes.length
 111                       + specialSlots.length
 112                       + codeSlots.length;
 113     }
 114 
 115     @Override
 116     protected void writePayload(final DataOutput dataOutput)
 117             throws IOException {
 118         final int identOffset = 8 + 4 * 10;
 119         final int hashOffset = identOffset + identifierBytes.length
 120                                            + specialSlots.length;
 121         final int pageSizeShift = 31 - Integer.numberOfLeadingZeros(pageSize);
 122 
 123         dataOutput.writeInt(0x20100); // version
 124         dataOutput.writeInt(flags);
 125         dataOutput.writeInt(hashOffset);
 126         dataOutput.writeInt(identOffset);
 127         dataOutput.writeInt(numberOfSpecialSlots);
 128         dataOutput.writeInt(numberOfCodeSlots);
 129         dataOutput.writeInt(codeLimit);
 130         dataOutput.writeByte(hashSize);
 131         dataOutput.writeByte(hashType);
 132         dataOutput.writeByte(0); // spare1
 133         dataOutput.writeByte(pageSizeShift);
 134         dataOutput.writeInt(0); // spare2
 135         dataOutput.writeInt(0); // scatterOffset
 136 
 137         dataOutput.write(identifierBytes);
 138         dataOutput.write(specialSlots);
 139         dataOutput.write(codeSlots);
 140     }
 141 
 142     private byte[] identifierBytes(final String identifier) {
 143         try {
 144             return (identifier + '\0').getBytes("UTF-8");
 145         } catch (final UnsupportedEncodingException e) {
 146             throw new IllegalStateException(e);
 147         }
 148     }
 149 }