Instancefy currently loaded ROM
[lsnes.git] / src / core / filedownload.cpp
blob6f92cc6e24c13f6e5846d2179aa2bf274bd8a145
1 #include "core/filedownload.hpp"
2 #include "core/moviedata.hpp"
3 #include "interface/romtype.hpp"
4 #include "library/string.hpp"
5 #include "library/zip.hpp"
7 #include <fstream>
9 namespace
11 void file_download_thread_trampoline(file_download* d, loaded_rom* rom)
13 d->_do_async(*rom);
16 class file_download_handler : public http_request::output_handler
18 public:
19 file_download_handler(const std::string& filename)
21 fp.open(filename, std::ios::binary);
22 tsize = 0;
24 ~file_download_handler()
27 void header(const std::string& name, const std::string& content)
29 //Ignore headers.
31 void write(const char* source, size_t srcsize)
33 fp.write(source, srcsize);
34 tsize += srcsize;
36 private:
37 std::ofstream fp;
38 size_t tsize;
42 file_download::file_download()
44 finished = false;
45 req.ohandler = NULL;
48 file_download::~file_download()
50 if(req.ohandler) delete req.ohandler;
53 void file_download::cancel()
55 req.cancel();
56 errormsg = "Canceled";
57 finished = true;
60 void file_download::do_async(loaded_rom& rom)
62 tempname = get_temp_file();
63 req.ihandler = NULL;
64 req.ohandler = new file_download_handler(tempname);
65 req.verb = "GET";
66 req.url = url;
67 try {
68 req.lauch_async();
69 (new threads::thread(file_download_thread_trampoline, this, &rom))->detach();
70 } catch(std::exception& e) {
71 req.cancel();
72 threads::alock h(m);
73 errormsg = e.what();
74 finished = true;
75 cond.notify_all();
79 std::string file_download::statusmsg()
81 int64_t dn, dt, un, ut;
82 if(finished)
83 return (stringfmt() << "Downloading finished").str();
84 req.get_xfer_status(dn, dt, un, ut);
85 if(dn == 0)
86 return "Connecting...";
87 else if(dt == 0)
88 return (stringfmt() << "Downloading (" << dn << "/<unknown>)").str();
89 else if(dn < dt)
90 return (stringfmt() << "Downloading (" << (100 * dn / dt) << "%)").str();
91 else
92 return (stringfmt() << "Downloading finished").str();
95 void file_download::_do_async(loaded_rom& rom)
97 while(!req.finished) {
98 threads::alock h(req.m);
99 req.finished_cond.wait(h);
100 if(!req.finished)
101 continue;
102 if(req.errormsg != "") {
103 remove(tempname.c_str());
104 threads::alock h(m);
105 errormsg = req.errormsg;
106 finished = true;
107 cond.notify_all();
108 return;
111 delete req.ohandler;
112 req.ohandler = NULL;
113 if(req.http_code > 299) {
114 threads::alock h(m);
115 errormsg = (stringfmt() << "Got HTTP error " << req.http_code).str();
116 finished = true;
117 cond.notify_all();
119 //Okay, we got the file.
120 std::istream* s = NULL;
121 try {
122 zip::reader r(tempname);
123 unsigned count = 0;
124 for(auto i : r) {
125 count++;
127 if(count == 1) {
128 std::istream& s = r[*r.begin()];
129 std::ofstream out(tempname2 = get_temp_file(), std::ios::binary);
130 while(s) {
131 char buf[4096];
132 s.read(buf, sizeof(buf));
133 out.write(buf, s.gcount());
135 delete &s;
136 } else {
137 tempname2 = tempname;
139 } catch(...) {
140 if(s) delete s;
141 tempname2 = tempname;
143 if(tempname != tempname2) remove(tempname.c_str());
144 try {
145 core_type* gametype = NULL;
146 if(!rom.rtype->isnull())
147 gametype = rom.rtype;
148 else {
149 moviefile::brief_info info(tempname2);
150 auto sysregs = core_sysregion::find_matching(info.sysregion);
151 for(auto i : sysregs)
152 if(i->get_type().get_core_identifier() == info.corename)
153 gametype = &i->get_type();
154 if(!gametype)
155 for(auto i : sysregs)
156 gametype = &i->get_type();
158 auto mv = moviefile::memref(target_slot);
159 moviefile::memref(target_slot) = new moviefile(tempname2, *gametype);
160 delete mv;
161 remove(tempname2.c_str());
162 } catch(std::exception& e) {
163 remove(tempname2.c_str());
164 threads::alock h(m);
165 errormsg = e.what();
166 finished = true;
167 cond.notify_all();
168 return;
170 //We are done!
171 threads::alock h(m);
172 finished = true;
173 cond.notify_all();
176 urirewrite::rewriter lsnes_uri_rewrite;