WXReader.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. using SQLite;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows;
  10. using System.Windows.Documents;
  11. using System.Windows.Interop;
  12. using WechatPCMsgBakTool.Helpers;
  13. using WechatPCMsgBakTool.Model;
  14. namespace WechatPCMsgBakTool
  15. {
  16. public class WXReader
  17. {
  18. private DBInfo DecDBInfo;
  19. private Dictionary<string, SQLiteConnection> DBInfo = new Dictionary<string, SQLiteConnection>();
  20. public WXReader(DBInfo? info = null) {
  21. if (info == null)
  22. DecDBInfo = WechatDBHelper.GetDBInfo();
  23. else
  24. DecDBInfo = info;
  25. string[] dbFileList = Directory.GetFiles(Path.Combine(DecDBInfo.UserPath, "DecDB"));
  26. foreach (var item in dbFileList)
  27. {
  28. FileInfo fileInfo = new FileInfo(item);
  29. if (fileInfo.Extension != ".db")
  30. continue;
  31. SQLiteConnection con = new SQLiteConnection(item);
  32. string dbName = fileInfo.Name.Split('.')[0];
  33. DBInfo.Add(dbName, con);
  34. }
  35. }
  36. public List<WXSession>? GetWXSessions(string? name = null)
  37. {
  38. SQLiteConnection con = DBInfo["MicroMsg"];
  39. if (con == null)
  40. return null;
  41. string query = "select * from session";
  42. if(name != null)
  43. {
  44. query = "select * from session where strUsrName = ?";
  45. return con.Query<WXSession>(query, name);
  46. }
  47. return con.Query<WXSession>(query);
  48. }
  49. public List<WXContact>? GetUser(string? name = null)
  50. {
  51. SQLiteConnection con = DBInfo["MicroMsg"];
  52. if (con == null)
  53. return null;
  54. string query = "select * from contact";
  55. if (name != null)
  56. {
  57. query = "select * from contact where username = ? or alias = ?";
  58. return con.Query<WXContact>(query, name, name);
  59. }
  60. return con.Query<WXContact>(query);
  61. }
  62. public WXSessionAttachInfo? GetWXMsgAtc(WXMsg msg)
  63. {
  64. SQLiteConnection con = DBInfo["MultiSearchChatMsg"];
  65. if (con == null)
  66. return null;
  67. string query = "select * from SessionAttachInfo where msgId = ? order by attachsize desc";
  68. List<WXSessionAttachInfo> list = con.Query<WXSessionAttachInfo>(query, msg.MsgSvrID);
  69. if (list.Count != 0)
  70. return list[0];
  71. else
  72. return null;
  73. }
  74. public List<WXMsg> GetMsgs(string uid)
  75. {
  76. List<WXMsg> tmp = new List<WXMsg>();
  77. for(int i = 0; i <= DecDBInfo.MaxMsgDBCount; i++)
  78. {
  79. SQLiteConnection con = DBInfo["MSG" + i.ToString()];
  80. if (con == null)
  81. continue;
  82. string query = "select * from MSG where StrTalker=?";
  83. List<WXMsg> wXMsgs = con.Query<WXMsg>(query, uid);
  84. foreach(WXMsg w in wXMsgs)
  85. {
  86. tmp.Add(w);
  87. }
  88. }
  89. return tmp;
  90. }
  91. public WXMediaMsg? GetVoiceMsg(string msgid)
  92. {
  93. for (int i = 0; i <= DecDBInfo.MaxMediaDBCount; i++)
  94. {
  95. SQLiteConnection con = DBInfo["MediaMSG" + i.ToString()];
  96. if (con == null)
  97. continue;
  98. string query = "select * from Media where Reserved0=?";
  99. List<WXMediaMsg> wXMsgs = con.Query<WXMediaMsg>(query, msgid);
  100. if(wXMsgs.Count != 0)
  101. return wXMsgs[0];
  102. }
  103. return null;
  104. }
  105. public string? GetVideo(WXMsg msg)
  106. {
  107. WXSessionAttachInfo? attachInfo = GetWXMsgAtc(msg);
  108. if (attachInfo == null)
  109. return null;
  110. string resBasePath = Path.Combine(DecDBInfo.ResPath, attachInfo.attachPath);
  111. if (!File.Exists(resBasePath))
  112. return null;
  113. string videoPath = Path.Combine(DecDBInfo.UserPath, msg.StrTalker, "Video");
  114. if (!Directory.Exists(videoPath))
  115. Directory.CreateDirectory(videoPath);
  116. FileInfo fileInfo = new FileInfo(resBasePath);
  117. string savePath = Path.Combine(videoPath, fileInfo.Name);
  118. if(!File.Exists(savePath))
  119. File.Copy(resBasePath, savePath, false);
  120. savePath = savePath.Replace(DecDBInfo.UserPath + "\\", "");
  121. return savePath;
  122. }
  123. public string? GetVoice(WXMsg msg) {
  124. string tmp = Path.Combine(DecDBInfo.UserPath, msg.StrTalker, "tmp");
  125. if (!Directory.Exists(tmp))
  126. {
  127. Directory.CreateDirectory(tmp);
  128. }
  129. WXMediaMsg? voiceMsg = GetVoiceMsg(msg.MsgSvrID);
  130. if(voiceMsg != null)
  131. {
  132. if (voiceMsg.Buf == null)
  133. return null;
  134. string voicePath = Path.Combine(DecDBInfo.UserPath, msg.StrTalker, "Voice");
  135. if (!Directory.Exists(voicePath))
  136. Directory.CreateDirectory(voicePath);
  137. // 从DB取音频文件到临时目录
  138. string tmp_file_path = Path.Combine(tmp, voiceMsg.Key + ".arm");
  139. using (FileStream stream = new FileStream(tmp_file_path,FileMode.OpenOrCreate))
  140. {
  141. stream.Write(voiceMsg.Buf, 0, voiceMsg.Buf.Length);
  142. }
  143. // 调用silk_v3_decoder解码成pcm
  144. string tmp_pcm_file_path = Path.Combine(tmp, voiceMsg.Key + ".pcm");
  145. // 调用ffmpeg转换成mp3
  146. string mp3_file_path = Path.Combine(voicePath, voiceMsg.Key + ".mp3");
  147. ToolsHelper.DecodeVoice(tmp_file_path, tmp_pcm_file_path, mp3_file_path);
  148. mp3_file_path = mp3_file_path.Replace(DecDBInfo.UserPath + "\\", "");
  149. return mp3_file_path;
  150. }
  151. return null;
  152. }
  153. public string GetSavePath(WXSession session)
  154. {
  155. string savePath = Path.Combine(DecDBInfo.UserPath, session.UserName + ".html");
  156. return savePath;
  157. }
  158. public string? GetImage(WXMsg msg)
  159. {
  160. WXSessionAttachInfo? attachInfo = GetWXMsgAtc(msg);
  161. if (attachInfo == null)
  162. return null;
  163. string resBasePath = Path.Combine(DecDBInfo.ResPath, attachInfo.attachPath);
  164. //部分attachpath可能会附加md5校验,这里做处理
  165. int index = attachInfo.attachPath.IndexOf(".dat");
  166. if (attachInfo.attachPath.Length - index > 10)
  167. {
  168. resBasePath = resBasePath.Substring(0, resBasePath.Length - 32);
  169. }
  170. if (!File.Exists(resBasePath))
  171. return null;
  172. string imgPath = Path.Combine(DecDBInfo.UserPath, msg.StrTalker, "Image");
  173. if (!Directory.Exists(imgPath))
  174. Directory.CreateDirectory(imgPath);
  175. string img = DecImage(resBasePath, imgPath);
  176. img = img.Replace(DecDBInfo.UserPath + "\\", "");
  177. return img;
  178. }
  179. private string DecImage(string source,string toPath)
  180. {
  181. //读取数据
  182. byte[] fileBytes = File.ReadAllBytes(source);
  183. //算差异转换
  184. byte key = getImgKey(fileBytes);
  185. fileBytes = ConvertData(fileBytes, key);
  186. //取文件类型
  187. string type = CheckFileType(fileBytes);
  188. //
  189. FileInfo fileInfo = new FileInfo(source);
  190. string fileName = fileInfo.Name.Substring(0, fileInfo.Name.Length - 4);
  191. string saveFilePath = Path.Combine(toPath, fileName + type);
  192. using (FileStream fileStream = File.OpenWrite(saveFilePath))
  193. {
  194. fileStream.Write(fileBytes, 0, fileBytes.Length);
  195. fileStream.Flush();
  196. }
  197. return saveFilePath;
  198. }
  199. private string CheckFileType(byte[] data)
  200. {
  201. switch (data[0])
  202. {
  203. case 0XFF: //byte[] jpg = new byte[] { 0xFF, 0xD8, 0xFF };
  204. {
  205. if (data[1] == 0xD8 && data[2] == 0xFF)
  206. {
  207. return ".jpg";
  208. }
  209. break;
  210. }
  211. case 0x89: //byte[] png = new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
  212. {
  213. if (data[1] == 0x50 && data[2] == 0x4E && data[7] == 0x0A)
  214. {
  215. return ".png";
  216. }
  217. break;
  218. }
  219. case 0x42: //byte[] bmp = new byte[] { 0x42, 0x4D };
  220. {
  221. if (data[1] == 0X4D)
  222. {
  223. return ".bmp";
  224. }
  225. break;
  226. }
  227. case 0x47: //byte[] gif = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39(0x37), 0x61 };
  228. {
  229. if (data[1] == 0x49 && data[2] == 0x46 && data[3] == 0x38 && data[5] == 0x61)
  230. {
  231. return ".gif";
  232. }
  233. break;
  234. }
  235. case 0x49: // byte[] tif = new byte[] { 0x49, 0x49, 0x2A, 0x00 };
  236. {
  237. if (data[1] == 0x49 && data[2] == 0x2A && data[3] == 0x00)
  238. {
  239. return ".tif";
  240. }
  241. break;
  242. }
  243. case 0x4D: //byte[] tif = new byte[] { 0x4D, 0x4D, 0x2A, 0x00 };
  244. {
  245. if (data[1] == 0x4D && data[2] == 0x2A && data[3] == 0x00)
  246. {
  247. return ".tif";
  248. }
  249. break;
  250. }
  251. }
  252. return ".dat";
  253. }
  254. private byte getImgKey(byte[] fileRaw)
  255. {
  256. byte[] raw = new byte[8];
  257. for (int i = 0; i < 8; i++)
  258. {
  259. raw[i] = fileRaw[i];
  260. }
  261. for (byte key = 0x01; key < 0xFF; key++)
  262. {
  263. byte[] buf = new byte[8];
  264. raw.CopyTo(buf, 0);
  265. if (CheckFileType(ConvertData(buf, key)) != ".dat")
  266. {
  267. return key;
  268. }
  269. }
  270. return 0x00;
  271. }
  272. private byte[] ConvertData(byte[] data, byte key)
  273. {
  274. for (int i = 0; i < data.Length; i++)
  275. {
  276. data[i] ^= key;
  277. }
  278. return data;
  279. }
  280. }
  281. }