DEADSOFTWARE

changed license to GPLv3 only; sorry, no trust to FSF anymore
[d2df-sdl.git] / src / game / g_res_downloader.pas
1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE ../shared/a_modes.inc}
16 unit g_res_downloader;
18 interface
20 uses sysutils, Classes, md5, g_net, g_netmsg, g_console, g_main, e_log;
22 function g_Res_SearchSameWAD(const path, filename: string; const resMd5: TMD5Digest): string;
23 function g_Res_DownloadWAD(const FileName: string): string;
25 implementation
27 uses g_language, sfs, utils, wadreader, g_game;
29 const DOWNLOAD_DIR = 'downloads';
31 procedure FindFiles(const dirName, filename: string; var files: TStringList);
32 var
33 searchResult: TSearchRec;
34 begin
35 if FindFirst(dirName+'/*', faAnyFile, searchResult) = 0 then
36 begin
37 try
38 repeat
39 if (searchResult.Attr and faDirectory) = 0 then
40 begin
41 if StrEquCI1251(searchResult.Name, filename) then
42 begin
43 files.Add(dirName+'/'+filename);
44 Exit;
45 end;
46 end
47 else if (searchResult.Name <> '.') and (searchResult.Name <> '..') then
48 FindFiles(IncludeTrailingPathDelimiter(dirName)+searchResult.Name, filename, files);
49 until FindNext(searchResult) <> 0;
50 finally
51 FindClose(searchResult);
52 end;
53 end;
54 end;
56 function CompareFileHash(const filename: string; const resMd5: TMD5Digest): Boolean;
57 var
58 gResHash: TMD5Digest;
59 fname: string;
60 begin
61 fname := findDiskWad(filename);
62 if length(fname) = 0 then begin result := false; exit; end;
63 gResHash := MD5File(fname);
64 Result := MD5Match(gResHash, resMd5);
65 end;
67 function CheckFileHash(const path, filename: string; const resMd5: TMD5Digest): Boolean;
68 var
69 fname: string;
70 begin
71 fname := findDiskWad(path+filename);
72 if length(fname) = 0 then begin result := false; exit; end;
73 Result := FileExists(fname) and CompareFileHash(fname, resMd5);
74 end;
76 function g_Res_SearchSameWAD(const path, filename: string; const resMd5: TMD5Digest): string;
77 var
78 res: string;
79 files: TStringList;
80 i: Integer;
81 begin
82 Result := '';
84 if CheckFileHash(path, filename, resMd5) then
85 begin
86 Result := path + filename;
87 Exit;
88 end;
90 files := TStringList.Create;
92 FindFiles(path, filename, files);
93 for i := 0 to files.Count - 1 do
94 begin
95 res := files.Strings[i];
96 if CompareFileHash(res, resMd5) then
97 begin
98 Result := res;
99 Break;
100 end;
101 end;
103 files.Free;
104 end;
106 function SaveWAD(const path, filename: string; const data: array of Byte): string;
107 var
108 resFile: TStream;
109 dpt: string;
110 begin
111 try
112 result := path+DOWNLOAD_DIR+'/'+filename;
113 dpt := path+DOWNLOAD_DIR;
114 if not findFileCI(dpt, true) then CreateDir(dpt);
115 resFile := createDiskFile(result);
116 resFile.WriteBuffer(data[0], Length(data));
117 resFile.Free
118 except
119 Result := '';
120 end;
121 end;
123 function g_Res_DownloadWAD(const FileName: string): string;
124 var
125 msgStream: TMemoryStream;
126 resStream: TStream;
127 mapData: TMapDataMsg;
128 i: Integer;
129 resData: TResDataMsg;
130 begin
131 SetLength(mapData.ExternalResources, 0);
132 g_Console_Add(Format(_lc[I_NET_MAP_DL], [FileName]));
133 e_WriteLog('Downloading map `' + FileName + '` from server', TMsgType.Notify);
134 g_Game_SetLoadingText(FileName + '...', 0, False);
135 MC_SEND_MapRequest();
137 msgStream := g_Net_Wait_Event(NET_MSG_MAP_RESPONSE);
138 if msgStream <> nil then
139 begin
140 mapData := MapDataFromMsgStream(msgStream);
141 msgStream.Free;
142 end else
143 mapData.FileSize := 0;
145 for i := 0 to High(mapData.ExternalResources) do
146 begin
147 if not CheckFileHash(GameDir + '/wads/',
148 mapData.ExternalResources[i].Name,
149 mapData.ExternalResources[i].md5) then
150 begin
151 g_Console_Add(Format(_lc[I_NET_WAD_DL],
152 [mapData.ExternalResources[i].Name]));
153 e_WriteLog('Downloading Wad `' + mapData.ExternalResources[i].Name +
154 '` from server', TMsgType.Notify);
155 g_Game_SetLoadingText(mapData.ExternalResources[i].Name + '...', 0, False);
156 MC_SEND_ResRequest(mapData.ExternalResources[i].Name);
158 msgStream := g_Net_Wait_Event(NET_MSG_RES_RESPONSE);
159 if msgStream = nil then
160 continue;
162 resData := ResDataFromMsgStream(msgStream);
164 resStream := createDiskFile(GameDir+'/wads/'+mapData.ExternalResources[i].Name);
165 resStream.WriteBuffer(resData.FileData[0], resData.FileSize);
167 resData.FileData := nil;
168 resStream.Free;
169 msgStream.Free;
170 end;
171 end;
173 Result := SaveWAD(MapsDir, ExtractFileName(FileName), mapData.FileData);
174 if mapData.FileSize = 0 then
175 DeleteFile(Result);
176 end;
178 end.