Skip to content

Commit

Permalink
Merge pull request #25 from cameron314/master
Browse files Browse the repository at this point in the history
Use UTF-8 to decode strings everywhere (and fixed locale-dependent unit tests)
  • Loading branch information
konrad-kruczynski committed Mar 11, 2015
2 parents a616318 + 7c4e0b4 commit 1ae7119
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 52 deletions.
2 changes: 1 addition & 1 deletion ELFSharp/ELF/Sections/NoteData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ internal NoteData(Class elfClass, long sectionOffset, Func<EndianBinaryReader> r
var fields = Math.DivRem(nameSize, FieldSize, out remainder);
var alignedNameSize = FieldSize * (remainder > 0 ? fields + 1 : fields);
var name = reader.ReadBytesOrThrow(alignedNameSize);
Name = Encoding.ASCII.GetString(name, 0, nameSize - 1); // minus one to omit terminating NUL
Name = Encoding.UTF8.GetString(name, 0, nameSize - 1); // minus one to omit terminating NUL
Description = reader.ReadBytesOrThrow((int)descriptionSize - 1);
}
reader = null;
Expand Down
110 changes: 60 additions & 50 deletions ELFSharp/ELF/Sections/StringTable.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using MiscUtil.IO;

namespace ELFSharp.ELF.Sections
Expand All @@ -9,71 +10,80 @@ public sealed class StringTable<T> : Section<T>, IStringTable where T : struct
{
internal StringTable(SectionHeader header, Func<EndianBinaryReader> readerSource) : base(header, readerSource)
{
stringsByIdx = new Dictionary<long, string>();
ReadStrings();
stringCache = new Dictionary<long, string>();
stringCache.Add(0, string.Empty);

stringBlob = ReadStringData();
}

public IEnumerable<string> Strings
{
get
{
return stringsByIdx.Values;
{
if (!cachePopulated)
PrepopulateCache();
return stringCache.Values;
}
}

public string this[long index]
{
get
{
if(stringsByIdx.ContainsKey(index))
{
string result;
if (stringCache.TryGetValue(index, out result))
{
return stringsByIdx[index];
return result;
}
HandleUnexpectedIndex(index);
return this[index];
return HandleUnexpectedIndex(index);
}
}

private void HandleUnexpectedIndex(long index)
{
if(index >= Header.Size)
{
throw new ArgumentOutOfRangeException("index");
}
var previousIndex = index;
while (!stringsByIdx.ContainsKey(previousIndex))
{
previousIndex--;
}
stringsByIdx.Add(index, stringsByIdx[previousIndex].Substring(Convert.ToInt32(index - previousIndex)));
private string HandleUnexpectedIndex(long index)
{
var stringStart = (int)index;
for (int i = stringStart; i < stringBlob.Length; ++i)
{
if (stringBlob[i] == 0)
{
var str = Encoding.UTF8.GetString(stringBlob, stringStart, i - stringStart);
stringCache.Add(stringStart, str);
return str;
}
}
throw new IndexOutOfRangeException();
}

private void ReadStrings()
private void PrepopulateCache()
{
cachePopulated = true;

var stringStart = 1;
for (int i = 1; i < stringBlob.Length; ++i)
{
if (stringBlob[i] == 0)
{
if (!stringCache.ContainsKey(stringStart))
{
stringCache.Add(stringStart, Encoding.UTF8.GetString(stringBlob, stringStart, i - stringStart));
}
stringStart = i + 1;
}
}
}

private byte[] ReadStringData()
{
using (var reader = ObtainReader())
{
reader.ReadByte(); // NULL char
stringsByIdx.Add(0, string.Empty);
// TODO: make buffered reader or sth better
var currentIdx = 1L;
var lastKey = 1L;
var builder = new StringBuilder();
while (currentIdx < Header.Size)
{
currentIdx += 1;
var character = reader.ReadByte();
if (character == 0)
{
stringsByIdx.Add(lastKey, builder.ToString());
builder = new StringBuilder();
lastKey = currentIdx;
continue;
}
builder.Append((char) character);
}
}
}

private readonly Dictionary<long, string> stringsByIdx;
{
var blob = reader.ReadBytes((int)Header.Size);
Debug.Assert(blob.Length == 0 || (blob[0] == 0 && blob[blob.Length - 1] == 0), "First and last bytes must be the null character (except for empty string tables)");
return blob;
}
}

private readonly Dictionary<long, string> stringCache;
private readonly byte[] stringBlob;
private bool cachePopulated;
}
}
}
2 changes: 1 addition & 1 deletion ELFSharp/UImage/UImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal UImage(string fileName)
Type = (ImageType)reader.ReadByte();
Compression = (CompressionType)reader.ReadByte();
var nameAsBytes = reader.ReadBytes(32);
Name = Encoding.ASCII.GetString(nameAsBytes.Reverse().SkipWhile(x => x == 0).Reverse().ToArray());
Name = Encoding.UTF8.GetString(nameAsBytes.Reverse().SkipWhile(x => x == 0).Reverse().ToArray());
image = reader.ReadBytes((int)Size);
}
}
Expand Down

0 comments on commit 1ae7119

Please sign in to comment.