/*******************************************************************************
* Copyright (c) 2006, 2010 Nokia and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nokia - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.utils.coff;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.ISymbolReader;
import org.eclipse.core.runtime.IProgressMonitor;
public class CodeViewReader implements ISymbolReader {
private RandomAccessFile file;
private int cvData;
private boolean isLe;
private List<String> fileList;
private String[] files = null;
private boolean parsed = false;
public CodeViewReader(RandomAccessFile accessFile, int dataOffset, boolean littleEndian) {
file = accessFile;
cvData = dataOffset;
isLe = littleEndian;
fileList = new ArrayList<String>();
}
public String[] getSourceFiles() {
if (!parsed) {
try {
parse();
} catch (IOException e) {
}
parsed = true;
files = new String[fileList.size()];
for (int i = 0; i < fileList.size(); i++) {
files[i] = fileList.get(i);
}
}
return files;
}
private int getInt(int value) {
if (isLe) {
int tmp = 0;
for (int i = 0; i < 4; i++) {
tmp <<= 8;
tmp |= value & 0xFF;
value >>= 8;
}
return tmp;
} else {
return value;
}
}
private short getShort(short value) {
if (isLe) {
short tmp = value;
tmp &= 0xFF;
tmp <<= 8;
tmp |= (value >> 8) & 0xFF;
return tmp;
} else {
return value;
}
}
private void parse() throws IOException {
if (cvData <= 0)
return;
// seek to the start of the CodeView data
file.seek(cvData);
// skip the next four bytes - signature "NB11"
file.skipBytes(4);
// get the offset to the subsection directory
int subsectionDirOffset = getInt(file.readInt());
// seek to the start of the subsection directory
file.seek(cvData + subsectionDirOffset);
// skip the header length (2) and directory entry length (2)
file.skipBytes(4);
// loop through the directories looking for source files
int directoryCount = getInt(file.readInt());
// skip the rest of the header
file.skipBytes(8);
// save the file offset to the base of the directories
long directoryOffset = file.getFilePointer();
for (int i = 0; i < directoryCount; i++) {
// seek to the next directory
file.seek(directoryOffset + i*12);
// get the type of the subsection. we only care about source modules
short subsectionType = getShort(file.readShort());
if (0x127 == subsectionType) {
// skip the module index
file.skipBytes(2);
// get the offset from the base address
int subsectionOffset = getInt(file.readInt());
// seek to the start of the source module section
file.seek(cvData + subsectionOffset);
// get the number of source files
short fileCount = getShort(file.readShort());
// skip the number of segments
file.skipBytes(2);
// save the file offset to the array of base offsets
long arrayOffset = file.getFilePointer();
// loop through the files and add them to our list
for (int j = 0; j < fileCount; j++) {
// seek to the correct array entry
file.seek(arrayOffset + j*4);
// get the offset to the first entry and seek to it
int offset = getInt(file.readInt());
file.seek(cvData + subsectionOffset + offset);
// get the number of segments
short segments = getShort(file.readShort());
// now skip to the name length
file.skipBytes(2 + segments*4 + segments*8);
int nameLength = file.readUnsignedByte();
// now extract the filename and add it to our list
// if it's not already there
byte[] nameBuffer = new byte[nameLength];
file.readFully(nameBuffer);
String name = new String(nameBuffer);
if (!fileList.contains(name))
fileList.add(name);
}
}
}
}
/**
* @since 5.2
*/
public String[] getSourceFiles(IProgressMonitor monitor) {
return getSourceFiles();
}
}