/*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.objectfile;
import java.io.CharConversionException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import com.oracle.objectfile.io.OutputAssembler;
import com.oracle.objectfile.io.Utf8;
Representation of a string section that complies to the usual format (plain list of \0-terminated
strings). This includes DWARF debug_str sections, ELF strtabs/shstrtabs, etc.. Note that since
this class can be used to implement ELF string sections, Mach-O string sections, DWARF string
sections, etc., it does not implement a particular Section superclass. Instead, various different
section classes (ELFSectionHeaderStringSection, ...) use it via composition.
/**
* Representation of a string section that complies to the usual format (plain list of \0-terminated
* strings). This includes DWARF debug_str sections, ELF strtabs/shstrtabs, etc.. Note that since
* this class can be used to implement ELF string sections, Mach-O string sections, DWARF string
* sections, etc., it does not implement a particular Section superclass. Instead, various different
* section classes (ELFSectionHeaderStringSection, ...) use it via composition.
*/
public class StringTable {
protected NavigableMap<Integer, String> stringMap = new TreeMap<>();
private Map<String, Integer> stringToIndexMap = new HashMap<>();
private int totalSize;
public StringTable() {
}
public StringTable(byte[] bytes) {
this(ByteBuffer.wrap(bytes));
}
public StringTable(ByteBuffer buffer) {
read(buffer);
}
public void read(ByteBuffer buffer) {
try {
// FIXME: this is wrong if suffix encoding is used (?)
while (buffer.position() < buffer.limit()) {
final int index = buffer.position();
String s = Utf8.utf8ToString(true, buffer);
if (stringMap.containsKey(index)) {
throw new IllegalStateException("offset cannot be re-used");
}
stringMap.put(index, s);
stringToIndexMap.put(s, index);
}
totalSize = buffer.position();
} catch (CharConversionException e) {
throw new RuntimeException(e);
}
}
Add a string to the table (if it is not already present) and return its index. Use this
during from-scratch construction of the string table only!
/**
* Add a string to the table (if it is not already present) and return its index. Use this
* during from-scratch construction of the string table only!
*/
public long add(String s) {
Integer index = stringToIndexMap.get(s);
if (index != null) {
return index;
}
int newIndex = totalSize;
stringMap.put(newIndex, s);
totalSize += Utf8.utf8Length(s) + 1 /* zero termination */;
return newIndex;
}
public int indexFor(String s) {
Integer index = stringToIndexMap.get(s);
if (index == null) {
return -1;
}
return index;
}
public String get(String s) {
return stringMap.get(indexFor(s));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("str\nindex string\n==========================================================================\n");
for (Integer idx : stringMap.keySet()) {
sb.append(String.format("%5d %s\n", idx, stringMap.get(idx)));
}
return sb.toString();
}
public void write(OutputAssembler out) {
ByteBuffer blob = ByteBuffer.allocate(totalSize);
for (Integer index : stringMap.keySet()) {
assert blob.position() == index;
String s = stringMap.get(index);
Utf8.substringToUtf8(blob, s, 0, s.length(), true);
}
out.writeBlob(blob.array());
}
}