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.macho;
  27 
  28 import com.oracle.ipack.util.Util;
  29 import java.io.DataInput;
  30 import java.io.DataOutput;
  31 import java.io.IOException;
  32 import java.util.ArrayList;
  33 
  34 public final class MachoHeader {
  35     private ArrayList<MachoCommand> commands;
  36 
  37     private int magic;
  38     private int cpuType;
  39     private int cpuSubType;
  40     private int fileType;
  41     private int flags;
  42 
  43     public MachoHeader() {
  44         commands = new ArrayList<MachoCommand>();
  45     }
  46 
  47     public MachoCommand findCommand(final int commandId) {
  48         for (final MachoCommand command: commands) {
  49             if (command.getId() == commandId) {
  50                 return command;
  51             }
  52         }
  53 
  54         return null;
  55     }
  56 
  57     public SegmentCommand findSegment(final String segmentName) {
  58         for (final MachoCommand command: commands) {
  59             if (command.getId() == MachoCommand.LC_SEGMENT) {
  60                 final SegmentCommand segmentCommand = (SegmentCommand) command;
  61                 if (segmentName.equals(segmentCommand.getSegmentName())) {
  62                     return segmentCommand;
  63                 }
  64             }
  65         }
  66 
  67         return null;
  68     }
  69 
  70     public void addCommand(final MachoCommand command) {
  71         commands.add(command);
  72     }
  73 
  74     public static MachoHeader read(final DataInput dataInput)
  75             throws IOException {
  76         final MachoHeader header = new MachoHeader();
  77         header.readImpl(dataInput);
  78         return header;
  79     }
  80 
  81     public int getSize() {
  82         int size = 7 * 4;
  83         for (final MachoCommand command: commands) {
  84             size += command.getSize();
  85         }
  86 
  87         return size;
  88     }
  89 
  90     public int getMagic() {
  91         return magic;
  92     }
  93 
  94     public void setMagic(final int magic) {
  95         this.magic = magic;
  96     }
  97 
  98     public int getCpuType() {
  99         return cpuType;
 100     }
 101 
 102     public void setCpuType(final int cpuType) {
 103         this.cpuType = cpuType;
 104     }
 105 
 106     public int getCpuSubType() {
 107         return cpuSubType;
 108     }
 109 
 110     public void setCpuSubType(final int cpuSubType) {
 111         this.cpuSubType = cpuSubType;
 112     }
 113 
 114     public int getFileType() {
 115         return fileType;
 116     }
 117 
 118     public void setFileType(final int fileType) {
 119         this.fileType = fileType;
 120     }
 121 
 122     public int getFlags() {
 123         return flags;
 124     }
 125 
 126     public void setFlags(final int flags) {
 127         this.flags = flags;
 128     }
 129 
 130     public void write(final DataOutput dataOutput) throws IOException {
 131         dataOutput.writeInt(magic);
 132         dataOutput.writeInt(cpuType);
 133         dataOutput.writeInt(cpuSubType);
 134         dataOutput.writeInt(fileType);
 135         dataOutput.writeInt(commands.size());
 136         dataOutput.writeInt(getSizeOfCommands());
 137         dataOutput.writeInt(flags);
 138 
 139         for (final MachoCommand command: commands) {
 140             command.write(dataOutput);
 141         }
 142     }
 143 
 144     private void readImpl(final DataInput dataInput) throws IOException {
 145         magic = dataInput.readInt();
 146         cpuType = dataInput.readInt();
 147         cpuSubType = dataInput.readInt();
 148         fileType = dataInput.readInt();
 149         final int numberOfCommands = dataInput.readInt();
 150         final int sizeOfCommands = dataInput.readInt();
 151         flags = dataInput.readInt();
 152 
 153         int sizeOfReadCommands = 0;
 154         commands.clear();
 155         commands.ensureCapacity(numberOfCommands);
 156         for (int i = 0; i < numberOfCommands; ++i) {
 157             final MachoCommand command = MachoCommand.read(dataInput);
 158             commands.add(command);
 159             sizeOfReadCommands += command.getSize();
 160         }
 161 
 162         if (sizeOfCommands != sizeOfReadCommands) {
 163             throw new IOException("Failed to decode commands");
 164         }
 165     }
 166 
 167     private int getSizeOfCommands() {
 168         int sizeOfCommands = 0;
 169         for (final MachoCommand command: commands) {
 170             sizeOfCommands += command.getSize();
 171         }
 172 
 173         return sizeOfCommands;
 174     }
 175 
 176     @Override
 177     public String toString() {
 178         return "Header { magic: 0x" + Util.hex32(magic)
 179                          + ", cpuType: " + cpuType
 180                          + ", cpuSubType: " + cpuSubType
 181                          + ", fileType: " + fileType
 182                          + ", flags: 0x" + Util.hex32(flags)
 183                          + ", commands: " + commands + " }";
 184     }
 185 }