Skip to content

Commit 7b07ebe

Browse files
committed
moved logreader classes to each its own file
added support for reading unicode files (UTF-8 and UTF16)
1 parent 634c439 commit 7b07ebe

16 files changed

+622
-105
lines changed

DebugView++/MainFrame.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,16 @@ void CMainFrame::HandleDroppedFile(const std::wstring& file)
436436
m_logSources.AddProcessReader(L"cmd.exe", wstringbuilder() << L"/Q /C \"" << file << "\"");
437437
}
438438
else
439-
m_logSources.AddDBLogReader(file);
439+
{
440+
if (IsBinaryFileType(IdentifyFile(Str(file))))
441+
{
442+
m_logSources.AddBinaryFileReader(file);
443+
}
444+
else
445+
{
446+
m_logSources.AddDBLogReader(file);
447+
}
448+
}
440449
}
441450

442451
void CMainFrame::OnDropFiles(HDROP hDropInfo)

DebugView++/version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
#define VERSION 1,4,0,6
2-
#define VERSION_STR "1.4.0.6"
1+
#define VERSION 1,4,0,14
2+
#define VERSION_STR "1.4.0.14"

DebugView++Lib/BinaryFileReader.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// (C) Copyright Gert-Jan de Vos and Jan Wilmans 2013.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at
4+
// http://www.boost.org/LICENSE_1_0.txt)
5+
6+
// Repository at: https://github.com/djeedjay/DebugViewPP/
7+
8+
#include "stdafx.h"
9+
#include <boost/filesystem.hpp>
10+
#include "DebugView++Lib/FileIO.h"
11+
#include "DebugView++Lib/BinaryFileReader.h"
12+
#include "DebugView++Lib/LineBuffer.h"
13+
#include "DebugView++Lib/Line.h"
14+
15+
#include <locale>
16+
#include <codecvt>
17+
18+
namespace fusion {
19+
namespace debugviewpp {
20+
21+
BinaryFileReader::BinaryFileReader(Timer& timer, ILineBuffer& linebuffer, FileType::type filetype, const std::wstring& filename) :
22+
LogSource(timer, SourceType::File, linebuffer),
23+
m_end(true),
24+
m_filename(Str(filename).str()),
25+
m_fileType(filetype),
26+
m_name(Str(boost::filesystem::wpath(filename).filename().string()).str()),
27+
m_handle(FindFirstChangeNotification(boost::filesystem::wpath(m_filename).parent_path().wstring().c_str(), false, FILE_NOTIFY_CHANGE_SIZE)), //todo: maybe using FILE_NOTIFY_CHANGE_LAST_WRITE could have benefits, not sure what though.
28+
m_wifstream(m_filename, std::ios::binary),
29+
m_filenameOnly(boost::filesystem::wpath(m_filename).filename().string()),
30+
m_initialized(false)
31+
{
32+
switch (filetype)
33+
{
34+
case FileType::UTF16LE:
35+
m_wifstream.imbue(std::locale(m_wifstream.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::codecvt_mode(std::little_endian | std::consume_header)>));
36+
break;
37+
case FileType::UTF16BE:
38+
m_wifstream.imbue(std::locale(m_wifstream.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
39+
break;
40+
case FileType::UTF8:
41+
m_wifstream.imbue(std::locale(m_wifstream.getloc(), new std::codecvt_utf8<wchar_t>));
42+
break;
43+
default:
44+
assert(!"This BinaryFileReader filetype was not implemented!");
45+
break;
46+
47+
}
48+
SetDescription(filename);
49+
}
50+
51+
BinaryFileReader::~BinaryFileReader()
52+
{
53+
}
54+
55+
void BinaryFileReader::Initialize()
56+
{
57+
if (m_initialized)
58+
{
59+
return;
60+
}
61+
m_initialized = true;
62+
63+
if (m_wifstream.is_open())
64+
{
65+
ReadUntilEof();
66+
m_end = false;
67+
}
68+
}
69+
70+
bool BinaryFileReader::AtEnd() const
71+
{
72+
return m_end;
73+
}
74+
75+
HANDLE BinaryFileReader::GetHandle() const
76+
{
77+
return m_handle.get();
78+
}
79+
80+
void BinaryFileReader::Notify()
81+
{
82+
ReadUntilEof();
83+
FindNextChangeNotification(m_handle.get());
84+
}
85+
86+
void BinaryFileReader::ReadUntilEof()
87+
{
88+
std::wstring line;
89+
while (std::getline(m_wifstream, line))
90+
AddLine(Str(line));
91+
92+
if (m_wifstream.eof())
93+
{
94+
m_wifstream.clear(); // clear EOF condition
95+
96+
// resync to end of file, even if the file shrunk
97+
auto lastReadPosition = m_wifstream.tellg();
98+
m_wifstream.seekg(0, m_wifstream.end);
99+
auto length = m_wifstream.tellg();
100+
if (length > lastReadPosition)
101+
m_wifstream.seekg(lastReadPosition);
102+
else if (length != lastReadPosition)
103+
Add(stringbuilder() << "file shrank, resynced at offset " << length);
104+
}
105+
else
106+
{
107+
// Some error other then EOF occured
108+
Add("Stopped tailing " + m_filename);
109+
m_end = true;
110+
}
111+
}
112+
113+
void BinaryFileReader::AddLine(const std::string& line)
114+
{
115+
Add(line.c_str());
116+
}
117+
118+
void BinaryFileReader::PreProcess(Line& line) const
119+
{
120+
line.processName = m_filenameOnly;
121+
}
122+
123+
// todo: Reading support for more filetypes, maybe not, who logs in unicode anyway?
124+
// see #107
125+
// posepone until we have a valid usecase
126+
// ANSI/ASCII
127+
// UTF-8
128+
// UTF-16
129+
// UTF-8 NO BOM ?
130+
// UTF-16 NO BOM ?
131+
// UTF-16 Big Endian
132+
// UTF-16 Big Endian NO BOM?
133+
// Unicode ASCII escaped.
134+
135+
// http://stackoverflow.com/questions/10504044/correctly-reading-a-utf-16-text-file-into-a-string-without-external-libraries
136+
137+
// check a utf-16 file will always contain an even-amount of bytes?
138+
// std::wifstream ifs(m_filename, std::ios::binary);
139+
// fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
140+
// for(wchar_t c; fin.get(c); ) std::cout << std::showbase << std::hex << c << '\n';
141+
142+
} // namespace debugviewpp
143+
} // namespace fusion

DebugView++Lib/DBLogReader.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// (C) Copyright Gert-Jan de Vos and Jan Wilmans 2013.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at
4+
// http://www.boost.org/LICENSE_1_0.txt)
5+
6+
// Repository at: https://github.com/djeedjay/DebugViewPP/
7+
8+
#include "stdafx.h"
9+
#include <boost/filesystem.hpp>
10+
#include "DebugView++Lib/FileIO.h"
11+
#include "DebugView++Lib/DBLogReader.h"
12+
#include "DebugView++Lib/LineBuffer.h"
13+
#include "DebugView++Lib/Line.h"
14+
15+
namespace fusion {
16+
namespace debugviewpp {
17+
18+
DBLogReader::DBLogReader(Timer& timer, ILineBuffer& linebuffer, FileType::type filetype, const std::wstring& filename) :
19+
FileReader(timer, linebuffer, filetype, filename),
20+
m_linenumber(0)
21+
{
22+
}
23+
24+
double GetDifference(FILETIME ft1, FILETIME ft2)
25+
{
26+
return (*((ULONGLONG*)&ft2) - *((ULONGLONG*)&ft1))/10000000.0;
27+
}
28+
29+
// used to create a relative time from the systemtime when only systemtime is stored in Sysinternals DbgView files.
30+
// the reverse (creating system-time from relative times) makes no sense.
31+
void DBLogReader::GetRelativeTime(Line& line)
32+
{
33+
if (line.time != 0.0) // if relative time is already filled in do nothing
34+
return;
35+
36+
if (m_linenumber == 1)
37+
{
38+
m_firstFiletime = line.systemTime;
39+
return;
40+
}
41+
42+
line.time = GetDifference(m_firstFiletime, line.systemTime);
43+
}
44+
45+
void DBLogReader::AddLine(const std::string& data)
46+
{
47+
++m_linenumber;
48+
Line line;
49+
switch (m_fileType)
50+
{
51+
case FileType::Unknown:
52+
case FileType::AsciiText:
53+
return FileReader::AddLine(data);
54+
case FileType::Sysinternals:
55+
ReadSysInternalsLogFileMessage(data, line, m_converter);
56+
GetRelativeTime(line);
57+
break;
58+
case FileType::DebugViewPP1:
59+
case FileType::DebugViewPP2:
60+
if (m_linenumber == 1) // ignore the header line
61+
{
62+
return;
63+
}
64+
ReadLogFileMessage(data, line);
65+
break;
66+
default:
67+
assert(false);
68+
}
69+
70+
Add(line.time, line.systemTime, line.pid, line.processName.c_str(), TabsToSpaces(line.message).c_str()); // workaround for issue #173
71+
}
72+
73+
void DBLogReader::PreProcess(Line& line) const
74+
{
75+
// intentionally empty (will negate the default behavior)
76+
}
77+
78+
} // namespace debugviewpp
79+
} // namespace fusion

DebugView++Lib/DebugView++Lib.vcxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,10 @@
133133
</Link>
134134
</ItemDefinitionGroup>
135135
<ItemGroup>
136+
<ClInclude Include="..\include\DebugView++Lib\BinaryFileReader.h" />
136137
<ClInclude Include="..\include\DebugView++Lib\Colors.h" />
137138
<ClInclude Include="..\include\DebugView++Lib\Conversions.h" />
139+
<ClInclude Include="..\include\DebugView++Lib\DBLogReader.h" />
138140
<ClInclude Include="..\include\DebugView++Lib\DBWinBuffer.h" />
139141
<ClInclude Include="..\include\DebugView++Lib\DBWinReader.h" />
140142
<ClInclude Include="..\include\DebugView++Lib\DBWinWriter.h" />
@@ -167,8 +169,10 @@
167169
<ClInclude Include="targetver.h" />
168170
</ItemGroup>
169171
<ItemGroup>
172+
<ClCompile Include="BinaryFileReader.cpp" />
170173
<ClCompile Include="Colors.cpp" />
171174
<ClCompile Include="Conversions.cpp" />
175+
<ClCompile Include="DBLogReader.cpp" />
172176
<ClCompile Include="DBWinBuffer.cpp" />
173177
<ClCompile Include="DBWinReader.cpp" />
174178
<ClCompile Include="DBWinWriter.cpp" />

DebugView++Lib/DebugView++Lib.vcxproj.filters

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@
107107
<ClInclude Include="..\include\DebugView++Lib\Conversions.h">
108108
<Filter>Header Files</Filter>
109109
</ClInclude>
110+
<ClInclude Include="..\include\DebugView++Lib\BinaryFileReader.h">
111+
<Filter>Header Files</Filter>
112+
</ClInclude>
113+
<ClInclude Include="..\include\DebugView++Lib\DBLogReader.h">
114+
<Filter>Header Files</Filter>
115+
</ClInclude>
110116
</ItemGroup>
111117
<ItemGroup>
112118
<ClCompile Include="stdafx.cpp">
@@ -199,5 +205,11 @@
199205
<ClCompile Include="Conversions.cpp">
200206
<Filter>Source Files</Filter>
201207
</ClCompile>
208+
<ClCompile Include="DBLogReader.cpp">
209+
<Filter>Source Files</Filter>
210+
</ClCompile>
211+
<ClCompile Include="BinaryFileReader.cpp">
212+
<Filter>Source Files</Filter>
213+
</ClCompile>
202214
</ItemGroup>
203215
</Project>

DebugView++Lib/FileIO.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ std::string FileTypeToString(FileType::type value)
9696
return "Sysinternals Debugview Logfile";
9797
case FileType::AsciiText:
9898
return "Ascii text file";
99+
case FileType::UTF8:
100+
return "Unicode UTF-8";
101+
case FileType::UTF16BE:
102+
return "Unicode UTF16BE";
103+
case FileType::UTF16LE:
104+
return "Unicode UTF16LE";
99105
default:
100106
break;
101107
}
@@ -104,6 +110,25 @@ std::string FileTypeToString(FileType::type value)
104110

105111
FileType::type IdentifyFile(std::string filename)
106112
{
113+
{
114+
// Encoding detection is very complex, see #107
115+
std::ifstream fs(filename, std::ios::binary);
116+
std::vector<unsigned char> buffer(3);
117+
fs.read((char*)buffer.data(), buffer.size());
118+
if (buffer[0] == 0xfe && buffer[1] == 0xff)
119+
{
120+
return FileType::UTF16BE;
121+
}
122+
if (buffer[0] == 0xff && buffer[1] == 0xfe)
123+
{
124+
return FileType::UTF16LE;
125+
}
126+
if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
127+
{
128+
return FileType::UTF8;
129+
}
130+
}
131+
107132
std::ifstream is(filename, std::ios::in);
108133
std::string line;
109134
if (!std::getline(is, line))
@@ -145,6 +170,23 @@ FileType::type IdentifyFile(std::string filename)
145170
return FileType::AsciiText;
146171
}
147172

173+
bool IsBinaryFileType(FileType::type filetype)
174+
{
175+
switch (filetype)
176+
{
177+
case FileType::UTF16BE:
178+
return true;
179+
case FileType::UTF16LE:
180+
return true;
181+
case FileType::UTF8:
182+
return true;
183+
default:
184+
// do nothing
185+
break;
186+
}
187+
return false;
188+
}
189+
148190
// read localtime in format "HH:mm:ss.ms"
149191
bool ReadLocalTimeMs(const std::string& text, FILETIME& ft)
150192
{

0 commit comments

Comments
 (0)