写给C++开发人员,研究过程当然是曲折的,自己不懂delphi导致花了近4天才研究出来,还是要多了解其他语言,他山之石可以攻玉。
Foxmail7.0往后本地邮件数据不再是类似eml格式了,要获取数据只能自己逆向。
在软件安装路径下有用户数据文件夹,里面可以找到时间文件如C:\Foxmail 7.2\Storage\xxx@163.com\Indexes\recvdate.ind。
用UE打开后取出一封邮件的ascii信息来,如下:
00000020h: A1 C2 3F AE 00 00 00 01 00 0B 3C E0 03 55 74 60 ; ÷??.....<?Ut`
PS:这个的实际时间是 2017-05-31 15:32:12
分析一下,“A1 C2 3F AE ”是标识头,“ 00 00 00 01”是邮件编号,“00 0B 3C E0 03 55 74 60”当然就是时间信息了,但是坑来了,我一开始觉得“00 0B 3C E0 03 55 74 60”按4位分开明显是一个FILETIME的高位低位,百度一下还真的有这样的写法,于是各种组合,FileTimeToSystemTime函数结果都不对。
后面怀疑是是double类型的OLD时间,但是计算结果的年份一直不对,又没进展了。
百度得知Foxmail是用delphi开发的,直到看了delphi中TDateTime的基本知识http://blog.sina.com.cn/s/blog_56592a9f010008ku.html
才知道“在delphi里TDateTime类型本质上是Double类型的,其中整数位用于表达从1899年12月30日到现在所已经过去的天数”,也就是说“ OLD 转为 字符串日期” 中间要减去“1899年12月30日”并不是常见的1900-0-0的间隔。
上面说错了不过可以参考一下,其实并不是直接减去这么简单,是要把delphi的Double日期转为windows的Double日期,详情百度“delphi里TDateTime转FILETIME”。
简单提一下我的转法:
将d整数部分+1然后拿date里面的年-1899,小数部分自己计算。
QString qtstr = maptable->data43.toHex().toUpper();
long qtlong = qtstr.toLong(0, 16);//年月日
char chBuff[128];
sprintf(chBuff, "%d.%d", qtlong, 0);//计算方式不同不可用于计算时分秒
double d = atof(chBuff);
d += 1;//delphi里TDateTime转FILETIME 天数差1(1899-12-30 1990-0-0)
_variant_t GetMaliTime;
GetMaliTime.ChangeType(VT_DATE);
GetMaliTime = d;
_bstr_t Btime(GetMaliTime);
std::string strData = Btime;//3916/05/30 00:00:00
//处理年月日
std::string strnyr[3];
int n = 0;
for (int s = 0; s < strData.size();s++)
{
if (strData[s]=='/'){
n++;
}
else if (strData[s] == '\040'){
break;
}
else{
strnyr[n] += strData[s];
}
}
int iyear = atoi(strnyr[0].c_str());//delphi里TDateTime转FILETIME 年要-1899
iyear -= 1899;
//计算时分秒
qtstr = maptable->data44.toHex().toUpper();
qtlong = qtstr.toLong(0, 16);
DWORD haomiao = qtlong;//0x020808B3
DWORD miao = haomiao / 1000;
DWORD real_haomiao = haomiao - miao * 1000;//毫秒
DWORD fen = miao / 60;
DWORD real_miao = miao - fen * 60;//秒
DWORD shi = fen / 60;
DWORD real_fen = fen - shi * 60;//分
char chtime[32] = { 0 };
sprintf(chtime, "%04d/%02s/%02s %02d:%02d:%02d",
iyear, strnyr[1].c_str(), strnyr[2].c_str(), shi, real_fen, real_miao);