forked from rutice/NicoJK
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathImportLogUtil.cpp
183 lines (176 loc) · 4.89 KB
/
ImportLogUtil.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include "ToolsCommon.h"
#include <memory>
#include <regex>
#include "ImportLogUtil.h"
namespace
{
// ローカル形式をタイムシフトする
bool TxtToLocalFormat(LPCTSTR srcPath, const std::function<FILE *(unsigned int &)> &onChatTag)
{
FILE *fp;
size_t len = _tcslen(srcPath);
if (len >= 5 && !ComparePath(&srcPath[len - 4], TEXT(".txt")) && srcPath[len - 5] != TEXT('/') &&
#ifdef _WIN32
srcPath[len - 5] != TEXT('\\') && !_tfopen_s(&fp, srcPath, TEXT("rN"))
#else
!!(fp = fopen(srcPath, "r"))
#endif
) {
std::unique_ptr<FILE, fclose_deleter> fpSrc(fp);
const std::regex re("<chat(?= )[^>]*? date=\"(\\d+)\"[^]*\n");
std::cmatch m;
char buf[8192];
bool bFound = false;
while (fgets(buf, sizeof(buf), fpSrc.get())) {
if (std::regex_match(buf, m, re)) {
// chatタグが1行以上見つかれば成功
bFound = true;
unsigned int tm = strtoul(m[1].first, nullptr, 10);
fp = onChatTag(tm);
if (fp) {
fwrite(buf, 1, m[1].first - buf, fp);
fprintf(fp, "%u", tm);
fwrite(m[1].second, 1, m[0].second - m[1].second - (*(m[0].second - 2) == '\r' ? 2 : 1), fp);
// 必ずCRLF
fputs("\r\n", fp);
}
}
}
return bFound;
}
return false;
}
void WriteChatTag(FILE *fp, const std::cmatch &m, unsigned int tm)
{
fwrite(m[0].first, 1, m[1].first - m[0].first, fp);
fprintf(fp, "%u", tm);
const char *p = m[1].second;
size_t len = 0;
while (p + len < m[0].second) {
// 改行文字は数値文字参照に置換
if (p[len] == '\n' || p[len] == '\r') {
fwrite(p, 1, len, fp);
fprintf(fp, "&#%d;", p[len]);
p += len + 1;
len = 0;
} else {
++len;
}
}
fwrite(p, 1, len, fp);
// 必ずCRLF
fputs("\r\n", fp);
}
// JikkyoRec.jklをローカル形式に変換する
bool JklToLocalFormat(LPCTSTR srcPath, const std::function<FILE *(unsigned int &)> &onChatTag)
{
FILE *fp;
size_t len = _tcslen(srcPath);
if (len >= 5 && !ComparePath(&srcPath[len - 4], TEXT(".jkl")) && srcPath[len - 5] != TEXT('/') &&
#ifdef _WIN32
srcPath[len - 5] != TEXT('\\') && !_tfopen_s(&fp, srcPath, TEXT("rbN"))
#else
!!(fp = fopen(srcPath, "r"))
#endif
) {
std::unique_ptr<FILE, fclose_deleter> fpSrc(fp);
char buf[8192];
if (fread(buf, 1, 10, fpSrc.get()) == 10 && !memcmp(buf, "<JikkyoRec", 10)) {
// 空行まで読み飛ばす
int c;
for (int d = '\0'; (c = fgetc(fpSrc.get())) != EOF && !(d=='\n' && (c=='\n' || c=='\r')); d = c);
const std::regex re("<chat(?= )[^>]*? date=\"(\\d+)\"[^]*?(?:/>|</chat>)");
std::cmatch m;
size_t bufLen = 0;
while ((c = fgetc(fpSrc.get())) != EOF) {
if (bufLen >= sizeof(buf)) {
bufLen = 0;
continue;
}
buf[bufLen++] = static_cast<char>(c);
if (c == '\0') {
if (std::regex_search(buf, m, re)) {
unsigned int tm = strtoul(m[1].first, nullptr, 10);
fp = onChatTag(tm);
if (fp) {
WriteChatTag(fp, m, tm);
}
}
bufLen = 0;
}
}
return true;
}
}
return false;
}
// ニコニコ実況コメントビューア.xmlをローカル形式に変換する
bool XmlToLocalFormat(LPCTSTR srcPath, const std::function<FILE *(unsigned int &)> &onChatTag)
{
FILE *fp;
size_t len = _tcslen(srcPath);
if (len >= 5 && !ComparePath(&srcPath[len - 4], TEXT(".xml")) && srcPath[len - 5] != TEXT('/') &&
#ifdef _WIN32
srcPath[len - 5] != TEXT('\\') && !_tfopen_s(&fp, srcPath, TEXT("rN"))
#else
!!(fp = fopen(srcPath, "r"))
#endif
) {
std::unique_ptr<FILE, fclose_deleter> fpSrc(fp);
char buf[8192];
if (fgets(buf, sizeof(buf), fpSrc.get()) && strstr(buf, "<?xml")) {
const std::regex re("<chat(?= )[^>]*? date=\"(\\d+)\"[^]*?(?:/>|</chat>)");
std::cmatch m;
size_t bufLen = 0;
while (fgets(buf + bufLen, static_cast<int>(sizeof(buf) - bufLen), fpSrc.get())) {
bufLen += strlen(buf + bufLen);
if (bufLen >= sizeof(buf) - 1) {
bufLen = 0;
continue;
}
if (std::regex_search(buf, m, re)) {
unsigned int tm = strtoul(m[1].first, nullptr, 10);
fp = onChatTag(tm);
if (fp) {
WriteChatTag(fp, m, tm);
}
bufLen = 0;
}
}
return true;
}
}
return false;
}
}
bool ImportLogfile(LPCTSTR srcPath, const std::function<FILE *(unsigned int &)> &onChatTag)
{
return JklToLocalFormat(srcPath, onChatTag) ||
XmlToLocalFormat(srcPath, onChatTag) ||
TxtToLocalFormat(srcPath, onChatTag);
}
bool ImportLogfile(LPCTSTR srcPath, LPCTSTR destPath, unsigned int tmNew)
{
std::unique_ptr<FILE, fclose_deleter> fpDest;
unsigned int tmOld = 0;
bool bFirst = true;
bool bRet = ImportLogfile(srcPath, [=, &fpDest, &tmOld, &bFirst](unsigned int &tm) -> FILE * {
if (bFirst) {
#ifdef _WIN32
FILE *fp;
if (!_tfopen_s(&fp, destPath, TEXT("wbN"))) {
fpDest.reset(fp);
}
#else
fpDest.reset(fopen(destPath, "w"));
#endif
tmOld = tm;
bFirst = false;
}
if (tmNew != 0) {
tm = tm - tmOld + tmNew;
}
return fpDest.get();
});
return bRet && fpDest;
}