001/**
002 * Copyright 2012 Emmanuel Bourg
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package net.jsign.pe;
018
019import java.nio.charset.StandardCharsets;
020import java.util.List;
021
022/**
023 * Section of an executable file.
024 * 
025 * @author Emmanuel Bourg
026 * @since 1.0
027 */
028public class Section {
029    
030    private final PEFile peFile;
031    private final int baseOffset;
032
033    Section(PEFile peFile, int baseOffset) {
034        this.peFile = peFile;
035        this.baseOffset = baseOffset;
036    }
037
038    /**
039     * An 8-byte, null-padded UTF-8 encoded string. If the string is exactly
040     * 8 characters long, there is no terminating null. For longer names, this
041     * field contains a slash (/) that is followed by an ASCII representation
042     * of a decimal number that is an offset into the string table. Executable
043     * images do not use a string table and do not support section names longer
044     * than 8 characters. Long names in object files are truncated if they are
045     * emitted to an executable file.
046     * 
047     * @return the name of the section
048     */
049    public String getName() {
050        byte[] buffer = new byte[8];
051        peFile.read(buffer, baseOffset, 0);
052        String name = new String(buffer, StandardCharsets.UTF_8);
053        if (name.indexOf(0) != -1) {
054            name = name.substring(0, name.indexOf(0));
055        }
056        
057        return name;
058    }
059
060    /**
061     * The total size of the section when loaded into memory. If this value is 
062     * greater than SizeOfRawData, the section is zero-padded. This field is 
063     * valid only for executable images and should be set to zero for object files.
064     * 
065     * @return the virtual size
066     */
067    public long getVirtualSize() {
068        return peFile.readDWord(baseOffset, 8);
069    }
070
071    /**
072     * For executable images, the address of the first byte of the section
073     * relative to the image base when the section is loaded into memory.
074     * For object files, this field is the address of the first byte before
075     * relocation is applied; for simplicity, compilers should set this to zero.
076     * Otherwise, it is an arbitrary value that is subtracted from offsets
077     * during relocation.
078     * 
079     * @return the section address relative to the image base address
080     */
081    public long getVirtualAddress() {
082        return peFile.readDWord(baseOffset, 12);
083    }
084
085    /**
086     * The size of the section (for object files) or the size of the initialized
087     * data on disk (for image files). For executable images, this must be a
088     * multiple of FileAlignment from the optional header. If this is less than
089     * VirtualSize, the remainder of the section is zero-filled. Because the
090     * SizeOfRawData field is rounded but the VirtualSize field is not, it is
091     * possible for SizeOfRawData to be greater than VirtualSize as well. When
092     * a section contains only uninitialized data, this field should be zero.
093     * 
094     * @return the size of the section
095     */
096    public long getSizeOfRawData() {
097        return peFile.readDWord(baseOffset, 16);
098    }
099
100    /**
101     * The file pointer to the first page of the section within the COFF file.
102     * For executable images, this must be a multiple of FileAlignment from the
103     * optional header. For object files, the value should be aligned on a 4 byte
104     * boundary for best performance. When a section contains only uninitialized
105     * data, this field should be zero.
106     * 
107     * @return the file pointer to the first page
108     */
109    public long getPointerToRawData() {
110        return peFile.readDWord(baseOffset, 20);
111    }
112
113    /**
114     * The file pointer to the beginning of relocation entries for the section.
115     * This is set to zero for executable images or if there are no relocations.
116     * 
117     * @return the file pointer to the beginning of relocation entries
118     */
119    public long getPointerToRelocations() {
120        return peFile.readDWord(baseOffset, 24);
121    }
122
123    /**
124     * The file pointer to the beginning of line-number entries for the section.
125     * This is set to zero if there are no COFF line numbers. This value should 
126     * be zero for an image because COFF debugging information is deprecated.
127     * 
128     * @return the file pointer to the beginning of line-number entries
129     */
130    public long getPointerToLineNumbers() {
131        return peFile.readDWord(baseOffset, 28);
132    }
133
134    /**
135     * The number of relocation entries for the section. This is set to zero
136     * for executable images.
137     * 
138     * @return the number of relocation entries
139     */
140    public int getNumberOfRelocations() {
141        return peFile.readWord(baseOffset, 32);
142    }
143
144    /**
145     * The number of line-number entries for the section. This value should
146     * be zero for an image because COFF debugging information is deprecated.
147     * 
148     * @return the number of line-number entries
149     */
150    public int getNumberOfLineNumbers() {
151        return peFile.readWord(baseOffset, 34);
152    }
153
154    /**
155     * The flags that describe the characteristics of the section.
156     * 
157     * @return the characteristics flags
158     */
159    public List<SectionFlag> getCharacteristics() {
160        return SectionFlag.getFlags((int) peFile.readDWord(baseOffset, 36));
161    }
162}