Lua: Fix type confusion between signed and unsigned
[lsnes.git] / src / core / filedownload.cpp
blob5316d58e62aa1aaf5563ace8f8a56157e4b7c5d4
1 #include "core/filedownload.hpp"
2 #include "core/moviedata.hpp"
3 #include "core/rom.hpp"
4 #include "interface/romtype.hpp"
5 #include "library/string.hpp"
6 #include "library/zip.hpp"
8 #include <fstream>
10 namespace
12 void file_download_thread_trampoline(file_download* d, loaded_rom* rom)
14 d->_do_async(*rom);
17 class file_download_handler : public http_request::output_handler
19 public:
20 file_download_handler(const std::string& filename)
22 fp.open(filename, std::ios::binary);
23 tsize = 0;
25 ~file_download_handler()
28 void header(const std::string& name, const std::string& content)
30 //Ignore headers.
32 void write(const char* source, size_t srcsize)
34 fp.write(source, srcsize);
35 tsize += srcsize;
37 private:
38 std::ofstream fp;
39 size_t tsize;
43 file_download::file_download()
45 finished = false;
46 req.ohandler = NULL;
49 file_download::~file_download()
51 if(req.ohandler) delete req.ohandler;
54 void file_download::cancel()
56 req.cancel();
57 errormsg = "Canceled";
58 finished = true;
61 void file_download::do_async(loaded_rom& rom)
63 tempname = get_temp_file();
64 req.ihandler = NULL;
65 req.ohandler = new file_download_handler(tempname);
66 req.verb = "GET";
67 req.url = url;
68 try {
69 req.lauch_async();
70 (new threads::thread(file_download_thread_trampoline, this, &rom))->detach();
71 } catch(std::exception& e) {
72 req.cancel();
73 threads::alock h(m);
74 errormsg = e.what();
75 finished = true;
76 cond.notify_all();
80 std::string file_download::statusmsg()
82 int64_t dn, dt, un, ut;
83 if(finished)
84 return (stringfmt() << "Downloading finished").str();
85 req.get_xfer_status(dn, dt, un, ut);
86 if(dn == 0)
87 return "Connecting...";
88 else if(dt == 0)
89 return (stringfmt() << "Downloading (" << dn << "/<unknown>)").str();
90 else if(dn < dt)
91 return (stringfmt() << "Downloading (" << (100 * dn / dt) << "%)").str();
92 else
93 return (stringfmt() << "Downloading finished").str();
96 void file_download::_do_async(loaded_rom& rom)
98 while(!req.finished) {
99 threads::alock h(req.m);
100 req.finished_cond.wait(h);
101 if(!req.finished)
102 continue;
103 if(req.errormsg != "") {
104 remove(tempname.c_str());
105 threads::alock h(m);
106 errormsg = req.errormsg;
107 finished = true;
108 cond.notify_all();
109 return;
112 delete req.ohandler;
113 req.ohandler = NULL;
114 if(req.http_code > 299) {
115 threads::alock h(m);
116 errormsg = (stringfmt() << "Got HTTP error " << req.http_code).str();
117 finished = true;
118 cond.notify_all();
120 //Okay, we got the file.
121 std::istream* s = NULL;
122 try {
123 zip::reader r(tempname);
124 unsigned count = 0;
125 for(auto i : r) {
126 count++;
128 if(count == 1) {
129 std::istream& s = r[*r.begin()];
130 std::ofstream out(tempname2 = get_temp_file(), std::ios::binary);
131 while(s) {
132 char buf[4096];
133 s.read(buf, sizeof(buf));
134 out.write(buf, s.gcount());
136 delete &s;
137 } else {
138 tempname2 = tempname;
140 } catch(...) {
141 if(s) delete s;
142 tempname2 = tempname;
144 if(tempname != tempname2) remove(tempname.c_str());
145 try {
146 core_type* gametype = NULL;
147 if(!rom.isnull())
148 gametype = &rom.get_internal_rom_type();
149 else {
150 moviefile::brief_info info(tempname2);
151 auto sysregs = core_sysregion::find_matching(info.sysregion);
152 for(auto i : sysregs)
153 if(i->get_type().get_core_identifier() == info.corename)
154 gametype = &i->get_type();
155 if(!gametype)
156 for(auto i : sysregs)
157 gametype = &i->get_type();
159 auto mv = moviefile::memref(target_slot);
160 moviefile::memref(target_slot) = new moviefile(tempname2, *gametype);
161 delete mv;
162 remove(tempname2.c_str());
163 } catch(std::exception& e) {
164 remove(tempname2.c_str());
165 threads::alock h(m);
166 errormsg = e.what();
167 finished = true;
168 cond.notify_all();
169 return;
171 //We are done!
172 threads::alock h(m);
173 finished = true;
174 cond.notify_all();
177 urirewrite::rewriter lsnes_uri_rewrite;