Merge remote-tracking branch

'origin/GP-2342_dev747368_cleanup_BinaryReader_string_reading--SQUASHED'
(Closes #4452)
This commit is contained in:
Ryan Kurtz
2022-09-03 01:35:09 -04:00
22 changed files with 578 additions and 296 deletions
File diff suppressed because it is too large Load Diff
@@ -15,17 +15,17 @@
*/
package ghidra.app.util.bin.format.coff;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import java.io.InputStream;
import ghidra.app.util.bin.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.Language;
import ghidra.util.*;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
@@ -73,18 +73,21 @@ public class CoffSectionHeader implements StructConverter {
}
protected void readName(BinaryReader reader) throws IOException {
byte[] nameBytes = reader.readNextByteArray(CoffConstants.SECTION_NAME_LENGTH);
if (nameBytes[0] == 0 && nameBytes[1] == 0 && nameBytes[2] == 0 && nameBytes[3] == 0) {//if 1st 4 bytes are zero, then lookup name in string table
// Name field is fixed length 8 bytes.
// Can be thought of as union { struct { int32 zeroflag; int32 nameindex; }; char[8] name; }
DataConverter dc = reader.isLittleEndian() ? LittleEndianDataConverter.INSTANCE
: BigEndianDataConverter.INSTANCE;
int nameIndex = dc.getInt(nameBytes, 4);//string table index
if (reader.peekNextInt() == 0) {
// if first 4 bytes are 0, this variant is 2 x int32's. Read 2 int32 values.
reader.readNextInt(); // skip the 0
int nameIndex = reader.readNextInt();
int stringTableIndex = _header.getSymbolTablePointer() +
(_header.getSymbolTableEntries() * CoffConstants.SYMBOL_SIZEOF);
s_name = reader.readAsciiString(stringTableIndex + nameIndex);
}
else {
s_name = (new String(nameBytes)).trim();
// Read 8 chars
// TODO: support "/string_table_offset"?
s_name = reader.readNextAsciiString(CoffConstants.SECTION_NAME_LENGTH).trim();
}
}
@@ -94,45 +94,41 @@ public class CoffArchiveMemberHeader implements StructConverter {
* consists of a series of terminated ASCII strings.
* The longnames member is the third archive member
*/
String name =
reader.readFixedLenAsciiString(headerOffset + CAMH_NAME_OFF, CAMH_NAME_LEN).trim();
String name = reader.readAsciiString(headerOffset + CAMH_NAME_OFF, CAMH_NAME_LEN).trim();
/*
* The number of seconds since 1/1/1970 UCT
*/
String dateStr =
reader.readFixedLenAsciiString(headerOffset + CAMH_DATE_OFF, CAMH_DATE_LEN).trim();
String dateStr = reader.readAsciiString(headerOffset + CAMH_DATE_OFF, CAMH_DATE_LEN).trim();
/*
* Ascii integer string or blank
*/
String userId =
reader.readFixedLenAsciiString(headerOffset + CAMH_USERID_OFF, CAMH_USERID_LEN).trim();
reader.readAsciiString(headerOffset + CAMH_USERID_OFF, CAMH_USERID_LEN).trim();
/*
* Ascii integer string or blank
*/
String groupId = reader.readFixedLenAsciiString(headerOffset + CAMH_GROUPID_OFF,
CAMH_GROUPID_LEN).trim();
String groupId =
reader.readAsciiString(headerOffset + CAMH_GROUPID_OFF, CAMH_GROUPID_LEN).trim();
/*
* Ascii integer string of ST_MODE value from the C run-time function _wstat
*/
String mode =
reader.readFixedLenAsciiString(headerOffset + CAMH_MODE_OFF, CAMH_MODE_LEN).trim();
String mode = reader.readAsciiString(headerOffset + CAMH_MODE_OFF, CAMH_MODE_LEN).trim();
/*
* Ascii integer string representing the total size of the archive member,
* not including the header. If the name is stored at the beginning of the
* payload (ie. name == "#1/nnn"), the member's effective size needs to be adjusted.
*/
String sizeStr =
reader.readFixedLenAsciiString(headerOffset + CAMH_SIZE_OFF, CAMH_SIZE_LEN).trim();
String sizeStr = reader.readAsciiString(headerOffset + CAMH_SIZE_OFF, CAMH_SIZE_LEN).trim();
/*
* Two byte Ascii string 0x60 0x0a ("'\n")
*/
String endOfHeader = reader.readFixedLenAsciiString(headerOffset + CAMH_EOH_OFF, CAMH_EOH_LEN);
String endOfHeader = reader.readAsciiString(headerOffset + CAMH_EOH_OFF, CAMH_EOH_LEN);
if (!endOfHeader.equals(CAMH_EOH_MAGIC)) {
throw new IOException("Bad EOH magic string: " + endOfHeader);
@@ -151,8 +147,7 @@ public class CoffArchiveMemberHeader implements StructConverter {
try {
int nameLen = Integer.parseInt(name.substring(3));
// name seems to be padded with trailing nulls to put payload at aligned offset
name = StringUtilities.trimTrailingNulls(
reader.readFixedLenAsciiString(payloadOffset, nameLen));
name = reader.readAsciiString(payloadOffset, nameLen);
size -= nameLen;
payloadOffset += nameLen;
} catch ( NumberFormatException nfe ) {
@@ -15,14 +15,15 @@
*/
package ghidra.app.util.bin.format.coff.archive;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* A string table that contains the full filenames of COFF archive members who's actual
* filenames can not fit in the fixed-length name
@@ -57,7 +58,7 @@ public final class LongNamesMember implements StructConverter {
reader.setPointerIndex(endOfStrings);
while (tmpOffset < endOfStrings) {
String s = reader.readTerminatedString(tmpOffset, LONGNAME_STR_TERM_CHARS);
String s = readTerminatedString(reader, tmpOffset);
tmpOffset += s.length() + 1;
++_nStrings;
lengths.add(s.length() + 1);
@@ -70,15 +71,16 @@ public final class LongNamesMember implements StructConverter {
public String getStringAtOffset(ByteProvider provider, long offset) throws IOException {
BinaryReader reader = new BinaryReader(provider, false);
return reader.readTerminatedString(_fileOffset + offset, LONGNAME_STR_TERM_CHARS);
return readTerminatedString(reader, _fileOffset + offset);
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = StructConverterUtil.parseName(LongNamesMember.class);
String uniqueName = name + "_" + _nStrings;
Structure struct = new StructureDataType(uniqueName, 0);
for (int i = 0 ; i < _nStrings ; ++i) {
struct.add(STRING, lengths.get(i), "string["+i+"]", null);
for (int i = 0; i < _nStrings; ++i) {
struct.add(STRING, lengths.get(i), "string[" + i + "]", null);
}
return struct;
}
@@ -100,4 +102,18 @@ public final class LongNamesMember implements StructConverter {
}
return nm;
}
private static String readTerminatedString(BinaryReader reader, long index) throws IOException {
StringBuilder buffer = new StringBuilder();
long len = reader.length();
while (index < len) {
char c = (char) reader.readByte(index++);
if (LONGNAME_STR_TERM_CHARS.indexOf(c) != -1) {
break;
}
buffer.append(c);
}
return buffer.toString();
}
}
@@ -139,7 +139,7 @@ public class DWARFAttributeFactory {
return DWARFBooleanAttribute.TRUE;
case DW_FORM_string:
return new DWARFStringAttribute(reader.readNextNullTerminatedAsciiString());
return new DWARFStringAttribute(reader.readNextUtf8String());
case DW_FORM_strp:
// Note: we can either read the string from the string section (via. the
// string table) here and put it in a DWARFStringAttribute and hope
@@ -15,11 +15,12 @@
*/
package ghidra.app.util.bin.format.elf;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;
import java.util.function.Consumer;
import java.io.IOException;
import java.io.RandomAccessFile;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.Writeable;
import ghidra.app.util.bin.format.elf.ElfRelocationTable.TableFormat;
@@ -1277,24 +1278,17 @@ public class ElfHeader implements StructConverter, Writeable {
}
preLinkImageBase = -1L;
try {
long ptr = reader.getPointerIndex();
long fileLength = reader.getByteProvider().length();
// not enough bytes
if (fileLength < 8) {
return -1;
}
//reader.setPointerIndex(fileLength - 8);
int readInt = reader.readInt(fileLength - 8);
String readAsciiString = reader.readAsciiString(fileLength - 4, 4);
int preLinkImageBaseInt = reader.readInt(fileLength - 8);
String preLinkMagicString = reader.readAsciiString(fileLength - 4, 4).trim();
if (reader.getPointerIndex() != ptr) {
reader.setPointerIndex(ptr);
}
if (readAsciiString.equals("PRE")) {
preLinkImageBase = (readInt) & 0xffffffffL;
if (preLinkMagicString.equals("PRE")) {
preLinkImageBase = Integer.toUnsignedLong(preLinkImageBaseInt);
}
}
catch (IOException e) {
@@ -61,7 +61,7 @@ public class ElfStringTable implements ElfFileSection {
if (stringOffset >= length) {
throw new IOException("String read beyond table bounds");
}
return reader.readAsciiString(fileOffset + stringOffset);
return reader.readUtf8String(fileOffset + stringOffset).trim();
}
catch (IOException e) {
header.logError(
@@ -128,7 +128,7 @@ public class DyldChainedImport implements StructConverter {
}
public void initString(BinaryReader reader) throws IOException {
symbolName = reader.readNextNullTerminatedAsciiString();
symbolName = reader.readNextAsciiString();
}
}
@@ -15,10 +15,11 @@
*/
package ghidra.app.util.bin.format.macho.commands;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.app.util.importer.MessageLog;
@@ -42,11 +43,10 @@ public class LinkerOptionCommand extends LoadCommand {
super(reader);
count = reader.readNextInt();
linkerOptions = new ArrayList<>(count);
long readerIndex = reader.getPointerIndex();
BinaryReader stringReader = reader.clone();
for (int i = 0; i < count; i++) {
String str = reader.readTerminatedString(readerIndex, '\0');
String str = stringReader.readNextAsciiString();
linkerOptions.add(str);
readerIndex += str.length() + 1;
}
}
@@ -63,7 +63,7 @@ public class ArchitectureDataDirectory extends DataDirectory {
Msg.info(this, "Requesting ASCII string of size "+getSize());
return false;
}
copyright = reader.readAsciiString(ptr, getSize());
copyright = reader.readAsciiString(ptr, getSize()).trim();
return true;
}
@@ -15,10 +15,11 @@
*/
package ghidra.app.util.bin.format.pe;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.pe.debug.DebugDirectoryParser;
@@ -116,18 +117,16 @@ public class SeparateDebugHeader implements OffsetValidator {
ptr += SectionHeader.IMAGE_SIZEOF_SECTION_HEADER;
}
long tmp = ptr;
BinaryReader stringReader = reader.clone(ptr);
List<String> exportedNameslist = new ArrayList<>();
while (true) {
String str = reader.readAsciiString(tmp);
if (str == null || str.length() == 0) {
String str = stringReader.readNextAsciiString();
if (str.isEmpty()) {
break;
}
tmp += str.length() + 1;
exportedNameslist.add(str);
}
exportedNames = new String[exportedNameslist.size()];
exportedNameslist.toArray(exportedNames);
exportedNames = exportedNameslist.toArray(String[]::new);
ptr += exportedNamesSize;
@@ -220,13 +220,10 @@ public class CliBlobMarshalSpec extends CliBlob {
break;
case NATIVE_TYPE_CUSTOMMARSHALER:
customMarshallerGuidOrTypeName =
reader.readTerminatedString(reader.getPointerIndex(), '\0');
customMarshallerTypeName =
reader.readTerminatedString(reader.getPointerIndex(), '\0');
if (reader.peekNextByte() > 0) {
customMarshallerCookie =
reader.readTerminatedString(reader.getPointerIndex(), '\0');
customMarshallerGuidOrTypeName = reader.readNextUtf8String();
customMarshallerTypeName = reader.readNextUtf8String();
if (reader.peekNextByte() != 0) {
customMarshallerCookie = reader.readNextUtf8String();
}
break;
@@ -267,6 +264,7 @@ public class CliBlobMarshalSpec extends CliBlob {
break;
case NATIVE_TYPE_CUSTOMMARSHALER:
// TODO: length of these UTF-8 strings isn't the same as number of characters
struct.add(UTF8, customMarshallerGuidOrTypeName.length(), "", "GUID or Type Name");
struct.add(UTF8, customMarshallerGuidOrTypeName.length(), "", "Type Name");
if (customMarshallerCookie.compareTo("") != 0) {
@@ -18,7 +18,6 @@ package ghidra.app.util.bin.format.pe.debug;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.util.Conv;
/**
* <pre>
@@ -47,7 +46,7 @@ class DataSym32_new extends DebugSymbol {
byte nameLen = reader.readByte(ptr); ptr += BinaryReader.SIZEOF_BYTE;
this.name = reader.readAsciiString(ptr, Conv.byteToInt(nameLen));
this.name = reader.readAsciiString(ptr, Byte.toUnsignedInt(nameLen));
}
int getTypeIndex() {
@@ -139,7 +139,7 @@ public class DebugCOFFSymbol implements StructConverter {
//
int shortVal = reader.readInt(index);
if (shortVal != 0) {
name = reader.readAsciiString(index, NAME_LENGTH);
name = reader.readAsciiString(index, NAME_LENGTH).trim();
index += 8;
}
else {
@@ -188,7 +188,7 @@ public class DebugCOFFSymbolAux implements StructConverter {
private String name;
private AuxFile(BinaryReader reader, int index) throws IOException {
name = reader.readAsciiString(index, DebugCOFFSymbol.IMAGE_SIZEOF_SYMBOL);
name = reader.readAsciiString(index, DebugCOFFSymbol.IMAGE_SIZEOF_SYMBOL).trim();
}
String getName() {
@@ -15,9 +15,10 @@
*/
package ghidra.app.util.bin.format.pe.debug;
import java.io.IOException;
import java.util.ArrayList;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.util.Conv;
@@ -80,8 +81,8 @@ public class OMFSrcModuleFile {
cbName = reader.readByte(index);
index += BinaryReader.SIZEOF_BYTE;
name = reader.readAsciiString(index, cbName);
index += cbName;
name = reader.readAsciiString(index, Byte.toUnsignedInt(cbName));
index += Byte.toUnsignedInt(cbName);
for (int i = 0; i < Conv.shortToInt(cSeg); ++i) {
//OMFSrcModuleLine line = new OMFSrcModuleLine(reader, index);
@@ -35,8 +35,8 @@ class S_LDATA32_NEW extends DebugSymbol{
byte nameLen = reader.readByte(ptr); ptr += BinaryReader.SIZEOF_BYTE;
this.name = reader.readAsciiString(ptr, Conv.byteToInt(nameLen));
ptr+=nameLen;
this.name = reader.readAsciiString(ptr, Byte.toUnsignedInt(nameLen));
ptr += Byte.toUnsignedInt(nameLen);
int sizeOfPadding = Conv.shortToInt(length) -
BinaryReader.SIZEOF_SHORT -
@@ -33,7 +33,8 @@ class S_OBJNAME extends DebugSymbol {
signature = reader.readInt(ptr); ptr += BinaryReader.SIZEOF_INT;
nameLen = reader.readByte(ptr); ptr += BinaryReader.SIZEOF_BYTE;
name = reader.readAsciiString(ptr, Conv.byteToInt(nameLen)); ptr += nameLen + 1;
name = reader.readAsciiString(ptr, Byte.toUnsignedInt(nameLen));
ptr += Byte.toUnsignedInt(nameLen) + 1;
int sizeOfPadding = BinaryReader.SIZEOF_SHORT+
BinaryReader.SIZEOF_INT+
@@ -15,13 +15,13 @@
*/
package ghidra.app.util.bin.format.pe.resource;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* <pre>
* typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING {
@@ -42,12 +42,9 @@ public class ResourceDirectoryString implements StructConverter {
* @param index the index where this resource string begins
*/
public ResourceDirectoryString(BinaryReader reader, int index) throws IOException {
length = reader.readShort(index);
nameString = reader.readAsciiString(index+BinaryReader.SIZEOF_SHORT);
if (nameString.length() != length) {
//todo:
throw new IllegalArgumentException("name string length != length");
}
BinaryReader stringReader = reader.clone(index);
length = stringReader.readNextShort();
nameString = stringReader.readNextAsciiString(Short.toUnsignedInt(length));
}
/**
@@ -66,6 +63,7 @@ public class ResourceDirectoryString implements StructConverter {
return nameString;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType(NAME+"_"+length, 0);
struct.add(WORD, "Length", null);
@@ -42,8 +42,9 @@ public class ResourceDirectoryStringU implements StructConverter {
* @param index the index where this resource string begins
*/
public ResourceDirectoryStringU(BinaryReader reader, int index) throws IOException {
length = reader.readShort(index);
nameString = reader.readUnicodeString(index+BinaryReader.SIZEOF_SHORT, length);
BinaryReader stringReader = reader.clone(index);
length = stringReader.readNextShort();
nameString = stringReader.readNextUnicodeString(Short.toUnsignedInt(length));
}
/**
@@ -62,6 +63,7 @@ public class ResourceDirectoryStringU implements StructConverter {
return nameString;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType(NAME+"_"+(length*2), 0);
struct.add(WORD, "Length", null);
@@ -18,8 +18,10 @@ package ghidra.app.util.bin;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.EOFException;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import ghidra.util.NumberUtil;
@@ -276,33 +278,68 @@ public class BinaryReaderTest {
// UTF-16 Unicode String
// ------------------------------------------------------------------------------------
@Test
public void testReadUnicodeString_LE() throws IOException {
public void test_ReadUnicodeString_fixedlen_LE() throws IOException {
BinaryReader br = br(true, 1, 1, 1, 'A', 0, 'B', 0, 'C', 0, 0, 0x80, 0);
assertEquals("ABC\u8000", br.readUnicodeString(3, 4));
}
@Test
public void testReadUnicodeString_BE() throws IOException {
public void test_ReadUnicodeString__fixedlen_BE() throws IOException {
BinaryReader br = br(false, 1, 1, 1, 0, 'A', 0, 'B', 0, 'C', 0x80, 0, 0);
assertEquals("ABC\u8000", br.readUnicodeString(3, 4));
}
@Test
public void testReadTerminatedUnicodeString_LE() throws IOException {
public void test_ReadUnicodeString_LE() throws IOException {
BinaryReader br = br(true, 1, 1, 1, 'A', 0, 'B', 0, 'C', 0, 0, 0x80, 0, 0);
assertEquals("ABC\u8000", br.readUnicodeString(3));
}
@Test
public void testReadTerminatedUnicodeString_BE() throws IOException {
public void test_ReadUnicodeString_BE() throws IOException {
BinaryReader br = br(false, 1, 1, 1, 0, 'A', 0, 'B', 0, 'C', 0x80, 0, 0, 0);
assertEquals("ABC\u8000", br.readUnicodeString(3));
}
@Test
public void testReadNextUnicodeString_LE() throws IOException {
public void test_ReadUnicodeString_EmptyStr() throws IOException {
BinaryReader br = br(false, 1, 1, 1, 0, 0, 0, 'B', 0, 'C', 0x80, 0, 0, 0);
assertEquals("", br.readUnicodeString(3));
}
@Test(expected = EOFException.class)
public void test_ReadUnicodeString_EofTerminated() throws IOException {
BinaryReader br = br(false, 1, 1, 1, 0, 'A', 0, 'B', 0, 'C');
br.readUnicodeString(3);
}
@Test(expected = EOFException.class)
public void test_ReadUnicodeString_Missing_Full_Terminator() throws IOException {
BinaryReader br = br(false, 0, 'A', 0, 'B', 0, 'C', 0);
br.readUnicodeString(0);
}
@Test(expected = EOFException.class)
public void test_ReadUnicodeString_AtEof() throws IOException {
BinaryReader br = br(false, 1, 1, 1, 0, 'A', 0, 'B', 0, 'C');
br.readUnicodeString(9);
}
@Test(expected = EOFException.class)
public void test_ReadUnicodeString_PastEof() throws IOException {
BinaryReader br = br(false, 1, 1, 1, 0, 'A', 0, 'B', 0, 'C');
br.readUnicodeString(10);
}
@Test
public void test_ReadNextUnicodeString_LE() throws IOException {
BinaryReader br =
br(true, 1, 1, 1, 'A', 0, 'B', 0, 'C', 0, 0, 0x80, 0, 0, /* magic flag value */ 42);
br.setPointerIndex(3);
@@ -311,7 +348,7 @@ public class BinaryReaderTest {
}
@Test
public void testReadNextUnicodeString_BE() throws IOException {
public void test_ReadNextUnicodeString_BE() throws IOException {
BinaryReader br =
br(false, 1, 1, 1, 0, 'A', 0, 'B', 0, 'C', 0x80, 0, 0, 0, /* magic flag value */ 42);
br.setPointerIndex(3);
@@ -319,4 +356,194 @@ public class BinaryReaderTest {
assertEquals(42, br.readNextUnsignedByte());
}
@Test
public void test_ReadNextUnicodeString_WithTrailingWhitespace() throws IOException {
BinaryReader br =
br(false, 1, 1, 1, 0, 'A', 0, 'B', 0, 'C', 0, ' ', 0, 0, /* magic flag value */ 42);
br.setPointerIndex(3);
assertEquals("ABC ", br.readNextUnicodeString());
assertEquals(42, br.readNextUnsignedByte());
}
@Test
public void test_ReadNextUnicodeString_Empty() throws IOException {
BinaryReader br =
br(false, 1, 1, 1, 0, 0, 0, 'B', 0, 'C', 0, 0, /* magic flag value */ 42);
br.setPointerIndex(3);
assertEquals("", br.readNextUnicodeString());
assertEquals("BC", br.readNextUnicodeString());
assertEquals(42, br.readNextUnsignedByte());
}
@Test
public void test_ReadNextUnicodeString_Fixedlen() throws IOException {
BinaryReader br =
br(false, 1, 1, 1, 0, 'A', 0, 'B', 0, 'C', 0, ' ', /* magic flag value */ 42);
br.setPointerIndex(3);
assertEquals("ABC ", br.readNextUnicodeString(4));
assertEquals(42, br.readNextUnsignedByte());
}
@Test
public void test_ReadNextUnicodeString_Fixedlen_Nullterms() throws IOException {
BinaryReader br =
br(false, 1, 1, 1, 0, 'A', 0, 'B', 0, 'C', 0, 0, 0, 0, /* magic flag value */ 42);
br.setPointerIndex(3);
assertEquals("ABC", br.readNextUnicodeString(5));
assertEquals(42, br.readNextUnsignedByte());
}
@Test
public void test_ReadNextUnicodeString_Fixedlen_Emptystr() throws IOException {
BinaryReader br =
br(false, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* magic flag value */ 42);
br.setPointerIndex(3);
assertEquals("", br.readNextUnicodeString(5));
assertEquals(42, br.readNextUnsignedByte());
}
@Test
public void test_ReadNextUnicodeString_NullTerm_AtEof() throws IOException {
BinaryReader br = br(false, 0, 'A', 0, 'B', 0, 'C', 0, 0);
assertEquals("ABC", br.readNextUnicodeString());
try {
br.readNextUnicodeString();
Assert.fail();
}
catch (IOException e) {
// good
}
}
@Test
public void test_ReadNextUnicodeString_NullTerm_ToEof() throws IOException {
BinaryReader br = br(false, 0, 'A', 0, 'B', 0, 'C');
try {
br.readNextUnicodeString();
Assert.fail();
}
catch (EOFException e) {
// good
}
}
// ------------------------------------------------------------------------------------
// 'Ascii' Strings
// ------------------------------------------------------------------------------------
@Test
public void test_ReadAsciiString_NullTerm() throws IOException {
BinaryReader br = br(true, 'A', 'B', 'C', 0, /* magic flag */ 42);
assertEquals("ABC", br.readAsciiString(0));
}
@Test(expected = EOFException.class)
public void test_ReadAsciiString_Not_Terminated() throws IOException {
BinaryReader br = br(true, 'A', 'B', 'C');
assertEquals("", br.readAsciiString(0));
}
@Test(expected = EOFException.class)
public void test_ReadAsciiString_AtEof() throws IOException {
BinaryReader br = br(true, 'A', 'B', 'C');
assertEquals("", br.readAsciiString(3));
}
@Test(expected = EOFException.class)
public void test_ReadAsciiString_PastEof() throws IOException {
BinaryReader br = br(true, 'A', 'B', 'C');
br.readAsciiString(4);
}
@Test
public void test_ReadAsciiString_NotTrimed() throws IOException {
BinaryReader br = br(true, ' ', 'A', 'B', 'C', ' ', 0, /* magic flag */ 42);
assertEquals(" ABC ", br.readAsciiString(0));
}
@Test
public void test_ReadAsciiString_tab_terminates() throws IOException {
// tests the readAsciiString() doesn't terminate on a '\t' tab char
BinaryReader br = br(true, 'A', 'B', 'C', '\t', 'D', 'E', 'F', 0, /* magic flag */ 42);
assertEquals("ABC\tDEF", br.readAsciiString(0));
}
@Test
public void test_ReadNextAsciiString() throws IOException {
BinaryReader br = br(true, ' ', 'A', 'B', 'C', ' ', 0, /* magic flag */ 42);
assertEquals(" ABC ", br.readNextAsciiString());
assertEquals(42, br.readNextUnsignedByte());
}
@Test
public void test_ReadNextAsciiString_EmtpyStr() throws IOException {
BinaryReader br = br(true, ' ', 'A', 'B', 'C', ' ', 0, /* magic flag */ 42);
br.setPointerIndex(5);
assertEquals("", br.readNextAsciiString());
assertEquals(42, br.readNextUnsignedByte());
}
@Test
public void test_ReadNextAsciiString_AtEof() throws IOException {
BinaryReader br = br(true, 'A', 'B', 'C', 0);
assertEquals("ABC", br.readNextAsciiString());
try {
br.readNextAsciiString();
Assert.fail();
}
catch (IOException e) {
// good
}
}
@Test
public void test_ReadNextAsciiString_FixedLength() throws IOException {
BinaryReader br = br(true, 'A', 'B', 'C', 'D', 'E', 'F', 0, /* magic flag */ 42);
assertEquals("ABC", br.readNextAsciiString(3));
assertEquals("DEF", br.readNextAsciiString(4));
assertEquals(42, br.readNextByte());
}
@Test
public void test_ReadNextAsciiString_FixedLength_With_whitespace() throws IOException {
BinaryReader br = br(true, 'A', 'B', ' ', '\0', 'D', 'E', 'F', 0, /* magic flag */ 42);
assertEquals("AB ", br.readNextAsciiString(4));
assertEquals("DEF", br.readNextAsciiString());
assertEquals(42, br.readNextByte());
}
@Test
public void test_ReadNextAsciiString_FixedLength_EmptyStr() throws IOException {
BinaryReader br = br(true, 0, 0, 0, 'D', 'E', 'F', 0, /* magic flag */ 42);
assertEquals("", br.readNextAsciiString(3));
assertEquals("DEF", br.readNextAsciiString());
assertEquals(42, br.readNextByte());
}
@Test(expected = EOFException.class)
public void test_ReadAsciiString_ToEof() throws IOException {
BinaryReader br = br(true, 'A', 'B', 'C');
br.readAsciiString(0);
}
@Test
public void test_ReadUtf8String() throws IOException {
// tests variable length decoding
BinaryReader br = br(true, -22, -87, -107, -61, -65, 0);
assertEquals("\uaa55\u00ff", br.readUtf8String(0));
}
@Test
public void test_ReadNextUtf8String() throws IOException {
// tests variable length decoding
BinaryReader br = br(true, -22, -87, -107, -61, -65, 0, -22, -87, -107, 0);
assertEquals("\uaa55\u00ff", br.readNextUtf8String());
assertEquals("\uaa55", br.readNextUtf8String());
}
@Test
public void test_ReadUtf8String_bad_data() throws IOException {
// tests variable length decoding
BinaryReader br = br(true, -22, -87, 'A', 0);
assertEquals("\ufffdA" /* unicode replacement char, 'A'*/, br.readUtf8String(0));
}
}
@@ -15,12 +15,13 @@
*/
package ghidra.app.util.bin;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.io.File;
import java.io.IOException;
import java.nio.file.AccessMode;
import java.util.Arrays;
import org.junit.Test;
@@ -50,7 +51,7 @@ public class FileByteProviderTest extends AbstractGenericTest {
@Test
public void testSmallRead() throws IOException {
File file1 = createTempFileForTest("file1");
FileUtilities.writeStringToFile(file1, "testing\nsecond line");
FileUtilities.writeStringToFile(file1, "testing\0second line\0");
try (FileByteProvider fbp = new FileByteProvider(file1, null, AccessMode.READ)) {
BinaryReader br = new BinaryReader(fbp, true);
assertEquals("testing", br.readAsciiString(0));