lucasgautheron

auto downloader

Sep 2nd, 2011
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 40.92 KB | None | 0 0
  1. Index: config/pcksources.cfg
  2. ===================================================================
  3. --- config/pcksources.cfg   (revision 0)
  4. +++ config/pcksources.cfg   (revision 0)
  5. @@ -0,0 +1,3 @@
  6. +// list of package source servers (only add servers you trust!)
  7. +
  8. +addpckserver http://de582.ispfr.net/cube
  9. Index: config/scontext.cfg
  10. ===================================================================
  11. --- config/scontext.cfg (revision 6612)
  12. +++ config/scontext.cfg (working copy)
  13. @@ -6,15 +6,19 @@
  14.  context_cfg    = 1 // known scripts
  15.  context_prompt = 2 // command prompt
  16.  context_mapcfg = 3 // map configs, we don't trust them
  17. +context_mdlcfg = 4 // mdl configs, same
  18.  
  19.  // set allowed commands for the map config context
  20.  mapcfgidents = [ loadnotexture loadsky mapmodelreset mapmodel texturereset texture fog fogcolour mapsoundreset mapsound watercolour shadowyaw ]
  21. +mdlcfgidents = [ md2anim md2emit md2tag md3anim md3emit md3link md3load md3skin mdlalphatest mdlcachelimit mdlcullface mdlscale mdlshadowdist mdltrans mdltranslucent mdlvertexlight]
  22.  loop i (listlen $mapcfgidents) [ scriptcontext $context_mapcfg (at $mapcfgidents $i) ]
  23. +loop i (listlen $mdlcfgidents) [ scriptcontext $context_mdlcfg (at $mdlcfgidents $i) ]
  24.  
  25.  // isolate the map config context
  26.  // this disables access from this context to identifiers located in other contexts
  27.  // also it removes all aliases created in this context once the running context changes
  28.  isolatecontext $context_mapcfg
  29. +isolatecontext $context_mdlcfg
  30.  
  31.  // secure this configuration for the rest of the game
  32.  sealcontexts
  33. \ No newline at end of file
  34. Index: source/src/audiomanager.cpp
  35. ===================================================================
  36. --- source/src/audiomanager.cpp (revision 6613)
  37. +++ source/src/audiomanager.cpp (working copy)
  38. @@ -220,19 +220,19 @@
  39.      return -1;
  40.  }
  41.  
  42. -void audiomanager::preloadmapsound(entity &e)
  43. +void audiomanager::preloadmapsound(entity &e, bool trydl)
  44.  {
  45.      if(e.type!=SOUND || !mapsounds.inrange(e.attr1)) return;
  46.      sbuffer *buf = mapsounds[e.attr1].buf;
  47. -    if(!buf->load()) conoutf("\f3failed to load sample %s", buf->name);
  48. +    if(!buf->load(trydl) && !trydl) conoutf("\f3failed to load sample %s", buf->name);
  49.  }
  50.  
  51. -void audiomanager::preloadmapsounds()
  52. +void audiomanager::preloadmapsounds(bool trydl)
  53.  {
  54.      loopv(ents)
  55.      {
  56.          entity &e = ents[i];
  57. -        if(e.type==SOUND) preloadmapsound(e);
  58. +        if(e.type==SOUND) preloadmapsound(e, trydl);
  59.      }
  60.  }
  61.  
  62. Index: source/src/client.cpp
  63. ===================================================================
  64. --- source/src/client.cpp   (revision 6613)
  65. +++ source/src/client.cpp   (working copy)
  66. @@ -215,7 +215,7 @@
  67.      }
  68.  #endif
  69.      if(!onlyclean) localconnect();
  70. -    
  71. +
  72.      if(identexists("onDisconnect")) execute("onDisconnect");
  73.  }
  74.  
  75. @@ -739,12 +739,22 @@
  76.      conoutf(_("sending map %s to server..."), mapname);
  77.  }
  78.  
  79. -void getmap()
  80. +void getmap(char *name)
  81.  {
  82. -    conoutf(_("requesting map from server..."));
  83. -    packetbuf p(10, ENET_PACKET_FLAG_RELIABLE);
  84. -    putint(p, SV_RECVMAP);
  85. -    sendpackettoserv(2, p.finalize());
  86. +    if(!name || name[0] == '\0')
  87. +    {
  88. +        conoutf(_("requesting map from server..."));
  89. +        packetbuf p(10, ENET_PACKET_FLAG_RELIABLE);
  90. +        putint(p, SV_RECVMAP);
  91. +        sendpackettoserv(2, p.finalize());
  92. +    }
  93. +    else
  94. +    {
  95. +        defformatstring(package)("packages/maps/%s.cgz", name);
  96. +        requirepackage(PCK_MAP, package);
  97. +        if(downloadpackages()) conoutf("map %s installed successfully", name);
  98. +        else conoutf("\f3map download failed.");
  99. +    }
  100.  }
  101.  
  102.  void deleteservermap(char *mapname)
  103. @@ -805,7 +815,7 @@
  104.  }
  105.  
  106.  COMMAND(sendmap, ARG_1STR);
  107. -COMMAND(getmap, ARG_NONE);
  108. +COMMAND(getmap, ARG_1STR);
  109.  COMMAND(deleteservermap, ARG_1STR);
  110.  COMMAND(resetsecuremaps, ARG_NONE);
  111.  COMMAND(securemap, ARG_1STR);
  112. @@ -813,3 +823,172 @@
  113.  COMMAND(listdemos, ARG_NONE);
  114.  COMMANDN(setmr, setminutesremaining, ARG_1INT);
  115.  COMMANDN(rewind, rewinddemo, ARG_1INT);
  116. +
  117. +// packages auto - downloader
  118. +
  119. +// arrays
  120. +vector<pckserver *> pckservers;
  121. +hashtable<const char *, package *> pendingpackages;
  122. +
  123. +// cubescript
  124. +
  125. +void resetpckservers()
  126. +{
  127. +    pckservers.deletecontents();
  128. +}
  129. +
  130. +void addpckserver(char *addr)
  131. +{
  132. +    pckserver *srcserver = new pckserver();
  133. +    srcserver->addr = newstring(addr);
  134. +    srcserver->pending = true;
  135. +    pckservers.add(srcserver);
  136. +}
  137. +
  138. +COMMAND(resetpckservers, ARG_NONE);
  139. +COMMAND(addpckserver, ARG_1STR);
  140. +
  141. +// cURL / Network
  142. +
  143. +bool havecurl = false, canceldownloads = false;
  144. +
  145. +void setupcurl()
  146. +{
  147. +    if(curl_global_init(CURL_GLOBAL_NOTHING)) conoutf("\f3could not init cURL, content downloads not available");
  148. +    else
  149. +    {
  150. +        havecurl = true;
  151. +        execfile("config/pcksources.cfg");
  152. +    }
  153. +}
  154. +
  155. +static size_t write_callback(void *ptr, size_t size, size_t nmemb, FILE *stream)
  156. +{
  157. +    return fwrite(ptr, size, nmemb, stream);
  158. +}
  159. +
  160. +int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
  161. +{
  162. +    package *pck = (package *)clientp;
  163. +    loadingscreen("downloading...\n%s %.0f/%.0f KB (%.1f%%)\n(ESC to cancel)", pck->name, dlnow/double(1000.0), dltotal/double(1000.0), dltotal == 0 ? 0 : (dlnow/dltotal * double(100.0)));
  164. +    if(interceptkey(SDLK_ESCAPE))
  165. +    {
  166. +        canceldownloads = true;
  167. +        loadingscreen();
  168. +        return 1;
  169. +    }
  170. +    return 0;
  171. +}
  172. +
  173. +int processdonwload(package *pck)
  174. +{
  175. +    FILE *fp = NULL;
  176. +
  177. +    if(!pck->pending)
  178. +    {
  179. +        switch(pck->type)
  180. +        {
  181. +            case PCK_TEXTURE: case PCK_AUDIO:
  182. +            {
  183. +                preparedir(pck->name);
  184. +                // with textures/sounds, the image/audio file itself is sent. Just need to copy it from the temporary file
  185. +                if(!copyfile(path("config/tmp", true), pck->name)) conoutf("\f3failed to install %s", pck->name);
  186. +                break;
  187. +            }
  188. +
  189. +            case PCK_MAP: case PCK_MAPMODEL:
  190. +            {
  191. +                const char *p = path("config/tmp", true);
  192. +                addzip(p, pck->name, NULL, true, pck->type);
  193. +                break;
  194. +            }
  195. +
  196. +            case PCK_SKYBOX:
  197. +            {
  198. +                const char *p = path("config/tmp", true);
  199. +                char *fname = newstring(pck->name), *ls = strrchr(fname, '/');
  200. +                if(ls) *ls = '\0';
  201. +                addzip(p, fname, NULL, true, pck->type);
  202. +                break;
  203. +            }
  204. +
  205. +            default:
  206. +                conoutf("could not install package %s", pck->name);
  207. +                break;
  208. +        }
  209. +    }
  210. +    return 0;
  211. +}
  212. +
  213. +// download a package
  214. +double dlpackage(package *pck)
  215. +{
  216. +    if(!pck || !pck->source) return false;
  217. +    FILE *outfile = fopen(path("config/tmp", true), "wb");
  218. +    string req;
  219. +    sprintf(req, "%s/%s%s", pck->source->addr, pck->name, (pck->type==PCK_MAP || pck->type==PCK_MAPMODEL || pck->type==PCK_SKYBOX) ? ".zip" : "");
  220. +    conoutf("downloading %s from %s ...", pck->name, pck->source->addr);
  221. +
  222. +    int result, httpresult = 0;
  223. +    double dlsize;
  224. +    pck->curl = curl_easy_init();
  225. +    curl_easy_setopt(pck->curl, CURLOPT_URL, req);
  226. +    curl_easy_setopt(pck->curl, CURLOPT_WRITEFUNCTION, write_callback);
  227. +    curl_easy_setopt(pck->curl, CURLOPT_WRITEDATA, outfile);
  228. +    curl_easy_setopt(pck->curl, CURLOPT_NOPROGRESS, 0);
  229. +    curl_easy_setopt(pck->curl, CURLOPT_PROGRESSFUNCTION, progress_callback);
  230. +    curl_easy_setopt(pck->curl, CURLOPT_PROGRESSDATA, pck);
  231. +    curl_easy_setopt(pck->curl, CURLOPT_CONNECTTIMEOUT, 10);     // generous timeout for Bukz ;)
  232. +    result = curl_easy_perform(pck->curl);
  233. +    curl_easy_getinfo(pck->curl, CURLINFO_RESPONSE_CODE, &httpresult);
  234. +    curl_easy_getinfo(pck->curl, CURLINFO_SIZE_DOWNLOAD, &dlsize);
  235. +    curl_easy_cleanup(pck->curl);
  236. +    pck->curl = NULL;
  237. +    fclose(outfile);
  238. +
  239. +    pck->pending = false;
  240. +    if(result == CURLE_OPERATION_TIMEDOUT) pck->source->responsive = false;     // mark source unresponsive (might want to add more here)
  241. +    if(!result && httpresult == 200) processdonwload(pck);
  242. +    else if(result == CURLE_ABORTED_BY_CALLBACK) conoutf("\f3download cancelled");
  243. +    else conoutf("\f2request for %s failed (cURL %d, HTTP %d)", req, result, httpresult);
  244. +    return (!result && httpresult == 200) ? dlsize : 0;
  245. +}
  246. +
  247. +int downloadpackages()
  248. +{
  249. +    double total = 0;
  250. +    enumerate(pendingpackages, package *, pck,
  251. +    {
  252. +        total += dlpackage(pck);
  253. +        pendingpackages.remove(pck->name);
  254. +        delete pck;
  255. +    });
  256. +    return (int)total;
  257. +}
  258. +
  259. +bool requirepackage(int type, const char *path)
  260. +{
  261. +    if(!havecurl || canceldownloads || type < 0 || type >= PCK_NUM || pendingpackages.access(path)) return false;
  262. +
  263. +    package *pck = new package;
  264. +    pck->name = unixpath(newstring(path));
  265. +    pck->type = type;
  266. +    loopv(pckservers) if(pckservers[i]->responsive) pck->source = pckservers[i];
  267. +    if(!pck->source) { conoutf("\f3no responsive source server found, can't download"); return false; }
  268. +    pck->pending = true;
  269. +
  270. +    pendingpackages.access(pck->name, pck);
  271. +
  272. +    return true;
  273. +}
  274. +
  275. +
  276. +void writepcksourcecfg()
  277. +{
  278. +    stream *f = openfile(path("config/pcksources.cfg", true), "w");
  279. +    if(!f) return;
  280. +    f->printf("// list of package source servers (only add servers you trust!)\n");
  281. +    loopv(pckservers) f->printf("\naddpckserver %s", pckservers[i]->addr);
  282. +    f->printf("\n");
  283. +    delete f;
  284. +}
  285. Index: source/src/clientgame.cpp
  286. ===================================================================
  287. --- source/src/clientgame.cpp   (revision 6613)
  288. +++ source/src/clientgame.cpp   (working copy)
  289. @@ -1205,8 +1205,11 @@
  290.  }
  291.  COMMAND(showmapstats, ARG_NONE);
  292.  
  293. +extern bool canceldownloads;
  294. +
  295.  void startmap(const char *name, bool reset)   // called just after a map load
  296.  {
  297. +    canceldownloads = false;
  298.      copystring(clientmap, name);
  299.      sendmapidenttoserver = true;
  300.      // Added by Rick
  301. Index: source/src/command.h
  302. ===================================================================
  303. --- source/src/command.h    (revision 6613)
  304. +++ source/src/command.h    (working copy)
  305. @@ -87,7 +87,7 @@
  306.      ARG_VARI
  307.  };
  308.  
  309. -enum { IEXC_CORE = 0, IEXC_CFG, IEXC_PROMPT, IEXC_MAPCFG, IEXC_NUM }; // script execution context
  310. +enum { IEXC_CORE = 0, IEXC_CFG, IEXC_PROMPT, IEXC_MAPCFG, IEXC_MDLCFG, IEXC_NUM }; // script execution context
  311.  
  312.  // nasty macros for registering script functions, abuses globals to avoid excessive infrastructure
  313.  #define COMMANDN(name, fun, nargs) static bool __dummy_##fun = addcommand(#name, (void (*)())fun, nargs)
  314. Index: source/src/entity.h
  315. ===================================================================
  316. --- source/src/entity.h (revision 6613)
  317. +++ source/src/entity.h (working copy)
  318. @@ -622,3 +622,24 @@
  319.  
  320.      return killmessages[gib?1:0][gun];
  321.  }
  322. +
  323. +struct pckserver
  324. +{
  325. +    char *addr;
  326. +    bool pending, responsive;
  327. +
  328. +    pckserver() : addr(NULL), pending(false), responsive(true) {}
  329. +};
  330. +
  331. +enum { PCK_TEXTURE, PCK_SKYBOX, PCK_MAPMODEL, PCK_AUDIO, PCK_MAP, PCK_NUM };
  332. +
  333. +struct package
  334. +{
  335. +    char *name;
  336. +    int type;
  337. +    bool pending;
  338. +    pckserver *source;
  339. +    CURL *curl;
  340. +
  341. +    package() : name(NULL), type(-1), pending(false), source(NULL), curl(NULL) {}
  342. +};
  343. Index: source/src/main.cpp
  344. ===================================================================
  345. --- source/src/main.cpp (revision 6613)
  346. +++ source/src/main.cpp (working copy)
  347. @@ -35,6 +35,7 @@
  348.      writeinitcfg();
  349.      writeservercfg();
  350.      writekillmsgcfg();
  351. +    writepcksourcecfg();
  352.      if(resetcfg) deletecfg();
  353.      else writecfg();
  354.      cleanup(NULL);
  355. @@ -1110,6 +1111,9 @@
  356.      notexture = noworldtexture = textureload("packages/misc/notexture.jpg");
  357.      if(!notexture) fatal("could not find core textures (hint: run AssaultCube from the parent of the bin directory)");
  358.  
  359. +    nomodel = loadmodel("misc/gib01", -1);      //FIXME: need actual placeholder model
  360. +    if(!notexture) fatal("could not find core models");
  361. +
  362.      initlog("console");
  363.      persistidents = false;
  364.      // Main font file, all other font files execute from here.
  365. @@ -1188,6 +1192,9 @@
  366.      initing = NOT_INITING;
  367.      uniformtexres = !hirestextures;
  368.  
  369. +    initlog("curl");
  370. +    setupcurl();
  371. +
  372.      initlog("models");
  373.      preload_playermodels();
  374.      preload_hudguns();
  375. Index: source/src/openal.cpp
  376. ===================================================================
  377. --- source/src/openal.cpp   (revision 6613)
  378. +++ source/src/openal.cpp   (working copy)
  379. @@ -254,7 +254,7 @@
  380.      unload();
  381.  }
  382.  
  383. -bool sbuffer::load()
  384. +bool sbuffer::load(bool trydl)
  385.  {
  386.      if(!name) return false;
  387.      if(id) return true;
  388. @@ -264,79 +264,94 @@
  389.      {
  390.          const char *exts[] = { "", ".wav", ".ogg" };
  391.          string filepath;
  392. -        loopi(sizeof(exts)/sizeof(exts[0]))
  393. +        loopk(2)
  394.          {
  395. -            formatstring(filepath)("packages/audio/%s%s", name, exts[i]);
  396. -            stream *f = openfile(path(filepath), "rb");
  397. -            if(!f) continue;
  398. -
  399. -            size_t len = strlen(filepath);
  400. -            if(len >= 4 && !strcasecmp(filepath + len - 4, ".ogg"))
  401. +            loopi(sizeof(exts)/sizeof(exts[0]))
  402.              {
  403. -                OggVorbis_File oggfile;
  404. -                if(!ov_open_callbacks(f, &oggfile, NULL, 0, oggcallbacks))
  405. +                formatstring(filepath)("packages/audio/%s%s", name, exts[i]);
  406. +                stream *f = openfile(path(filepath), "rb");
  407. +                if(!f && k>0 && trydl) // only try donwloading after trying all extensions
  408.                  {
  409. -                    vorbis_info *info = ov_info(&oggfile, -1);
  410. +                    requirepackage(PCK_AUDIO, filepath);
  411. +                    bool skip = false;
  412. +                    loopj(sizeof(exts)/sizeof(exts[0])) if(strstr(name, exts[j])) skip = true;  // don't try extensions if name already has a known extension
  413. +                    if(skip) break;
  414. +                    continue;
  415. +                }
  416. +                if(!f) continue;
  417.  
  418. -                    const size_t BUFSIZE = 32*1024;
  419. -                    vector<char> buf;
  420. -                    int bitstream;
  421. -                    long bytes;
  422. +                size_t len = strlen(filepath);
  423. +                if(len >= 4 && !strcasecmp(filepath + len - 4, ".ogg"))
  424. +                {
  425. +                    OggVorbis_File oggfile;
  426. +                    if(!ov_open_callbacks(f, &oggfile, NULL, 0, oggcallbacks))
  427. +                    {
  428. +                        vorbis_info *info = ov_info(&oggfile, -1);
  429.  
  430. -                    do
  431. +                        const size_t BUFSIZE = 32*1024;
  432. +                        vector<char> buf;
  433. +                        int bitstream;
  434. +                        long bytes;
  435. +
  436. +                        do
  437. +                        {
  438. +                            char buffer[BUFSIZE];
  439. +                            bytes = ov_read(&oggfile, buffer, BUFSIZE, isbigendian(), 2, 1, &bitstream);
  440. +                            loopi(bytes) buf.add(buffer[i]);
  441. +                        } while(bytes > 0);
  442. +
  443. +                        alBufferData(id, info->channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, buf.getbuf(), buf.length(), info->rate);
  444. +                        ov_clear(&oggfile);
  445. +                    }
  446. +                    else
  447.                      {
  448. -                        char buffer[BUFSIZE];
  449. -                        bytes = ov_read(&oggfile, buffer, BUFSIZE, isbigendian(), 2, 1, &bitstream);
  450. -                        loopi(bytes) buf.add(buffer[i]);
  451. -                    } while(bytes > 0);
  452. -
  453. -                    alBufferData(id, info->channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, buf.getbuf(), buf.length(), info->rate);
  454. -                    ov_clear(&oggfile);
  455. +                        delete f;
  456. +                        continue;
  457. +                    }
  458.                  }
  459.                  else
  460.                  {
  461. +                    SDL_AudioSpec wavspec;
  462. +                    uint32_t wavlen;
  463. +                    uint8_t *wavbuf;
  464. +
  465. +                    if(!SDL_LoadWAV_RW(f->rwops(), 1, &wavspec, &wavbuf, &wavlen))
  466. +                    {
  467. +                        SDL_ClearError();
  468. +                        continue;
  469. +                    }
  470. +
  471. +                    ALenum format;
  472. +                    switch(wavspec.format) // map wav header to openal format
  473. +                    {
  474. +                        case AUDIO_U8:
  475. +                        case AUDIO_S8:
  476. +                            format = wavspec.channels==2 ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8;
  477. +                            break;
  478. +                        case AUDIO_U16:
  479. +                        case AUDIO_S16:
  480. +                            format = wavspec.channels==2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
  481. +                            break;
  482. +                        default:
  483. +                            SDL_FreeWAV(wavbuf);
  484. +                            delete f;
  485. +                            unload();
  486. +                            return false;
  487. +                    }
  488. +
  489. +                    alBufferData(id, format, wavbuf, wavlen, wavspec.freq);
  490. +                    SDL_FreeWAV(wavbuf);
  491.                      delete f;
  492. -                    continue;
  493. -                }
  494. -            }
  495. -            else
  496. -            {
  497. -                SDL_AudioSpec wavspec;
  498. -                uint32_t wavlen;
  499. -                uint8_t *wavbuf;
  500.  
  501. -                if(!SDL_LoadWAV_RW(f->rwops(), 1, &wavspec, &wavbuf, &wavlen))
  502. -                {
  503. -                    SDL_ClearError();
  504. -                    continue;
  505. -                }
  506. -
  507. -                ALenum format;
  508. -                switch(wavspec.format) // map wav header to openal format
  509. -                {
  510. -                    case AUDIO_U8:
  511. -                    case AUDIO_S8:
  512. -                        format = wavspec.channels==2 ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8;
  513. -                        break;
  514. -                    case AUDIO_U16:
  515. -                    case AUDIO_S16:
  516. -                        format = wavspec.channels==2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
  517. -                        break;
  518. -                    default:
  519. -                        SDL_FreeWAV(wavbuf);
  520. -                        delete f;
  521. +                    if(ALERR)
  522. +                    {
  523.                          unload();
  524.                          return false;
  525. +                    };
  526.                  }
  527.  
  528. -                alBufferData(id, format, wavbuf, wavlen, wavspec.freq);
  529. -                SDL_FreeWAV(wavbuf);
  530. -                delete f;
  531. -
  532. -                if(ALERR) break;
  533. +                return true;
  534.              }
  535. -
  536. -            return true;
  537.          }
  538.      }
  539.      unload(); // loading failed
  540. Index: source/src/platform.h
  541. ===================================================================
  542. --- source/src/platform.h   (revision 6613)
  543. +++ source/src/platform.h   (working copy)
  544. @@ -71,3 +71,8 @@
  545.  
  546.      #include <setjmp.h>
  547.  #endif
  548. +
  549. +#ifndef CURL_STATICLIB
  550. +#define CURL_STATICLIB
  551. +#endif
  552. +#include "curl/curl.h"
  553. Index: source/src/protos.h
  554. ===================================================================
  555. --- source/src/protos.h (revision 6613)
  556. +++ source/src/protos.h (working copy)
  557. @@ -291,20 +291,26 @@
  558.  extern SDL_Surface *creatergbasurface(int width, int height);
  559.  extern SDL_Surface *forcergbsurface(SDL_Surface *os);
  560.  extern SDL_Surface *forcergbasurface(SDL_Surface *os);
  561. -extern Texture *textureload(const char *name, int clamp = 0, bool mipmap = true, bool canreduce = false, float scale = 1.0f);
  562. -extern Texture *lookuptexture(int tex, Texture *failtex = notexture);
  563. +extern Texture *textureload(const char *name, int clamp = 0, bool mipmap = true, bool canreduce = false, float scale = 1.0f, bool trydl = false);
  564. +extern Texture *lookuptexture(int tex, Texture *failtex = notexture, bool trydl = false);
  565.  extern bool reloadtexture(Texture &t);
  566.  extern bool reloadtexture(const char *name);
  567.  extern void reloadtextures();
  568.  Texture *createtexturefromsurface(const char *name, SDL_Surface *s);
  569.  extern void blitsurface(SDL_Surface *dst, SDL_Surface *src, int x, int y);
  570. +void loadsky(char *basename, bool reload);
  571.  
  572. -static inline Texture *lookupworldtexture(int tex)
  573. -{ return lookuptexture(tex, noworldtexture); }
  574. +static inline Texture *lookupworldtexture(int tex, bool trydl = true)
  575. +{ return lookuptexture(tex, noworldtexture, trydl); }
  576.  
  577.  extern float skyfloor;
  578.  extern void draw_envbox(int fogdist);
  579.  
  580. +extern void setupcurl();
  581. +extern bool requirepackage(int type, const char *path);
  582. +extern int downloadpackages();
  583. +extern void writepcksourcecfg();
  584. +
  585.  extern int maxtmus;
  586.  extern void inittmus();
  587.  extern void resettmu(int n);
  588. @@ -346,7 +352,7 @@
  589.  extern void neterr(const char *s);
  590.  extern int getclientnum();
  591.  extern void changeteam(int team, bool respawn = true); // deprecated?
  592. -extern void getmap();
  593. +extern void getmap(char *name = NULL);
  594.  extern void newteam(char *name);
  595.  extern bool securemapcheck(const char *map, bool msg = true);
  596.  extern void sendintro();
  597. @@ -655,11 +661,12 @@
  598.  extern mapmodelinfo &getmminfo(int i);
  599.  extern int findanim(const char *name);
  600.  extern void loadskin(const char *dir, const char *altdir, Texture *&skin);
  601. -extern model *loadmodel(const char *name, int i = -1);
  602. +extern model *nomodel;
  603. +extern model *loadmodel(const char *name, int i = -1, bool trydl = false);
  604.  extern void preload_playermodels();
  605.  extern void preload_entmodels();
  606.  extern void preload_hudguns();
  607. -extern void preload_mapmodels();
  608. +extern void preload_mapmodels(bool trydl = false);
  609.  extern void renderclients();
  610.  extern void renderclient(playerent *d);
  611.  extern void renderclient(playerent *d, const char *mdlname, const char *vwepname, int tex = 0);
  612. Index: source/src/rendermodel.cpp
  613. ===================================================================
  614. --- source/src/rendermodel.cpp  (revision 6613)
  615. +++ source/src/rendermodel.cpp  (working copy)
  616. @@ -87,6 +87,7 @@
  617.      mmi.rad = atoi(rad);
  618.      mmi.h = atoi(h);
  619.      mmi.zoff = atoi(zoff);
  620. +    mmi.m = NULL;
  621.      formatstring(mmi.name)("mapmodels/%s", name);
  622.  }
  623.  
  624. @@ -102,7 +103,9 @@
  625.  
  626.  hashtable<const char *, model *> mdllookup;
  627.  
  628. -model *loadmodel(const char *name, int i)
  629. +model *nomodel = NULL;
  630. +
  631. +model *loadmodel(const char *name, int i, bool trydl)
  632.  {
  633.      if(!name)
  634.      {
  635. @@ -116,6 +119,7 @@
  636.      if(mm) m = *mm;
  637.      else
  638.      {
  639. +        pushscontext(IEXC_MDLCFG);
  640.          m = new md2(name);
  641.          loadingmodel = m;
  642.          if(!m->load())
  643. @@ -127,9 +131,20 @@
  644.              {
  645.                  delete m;
  646.                  loadingmodel = NULL;
  647. -                return NULL;
  648. +                if(trydl)
  649. +                {
  650. +                    defformatstring(dl)("packages/models/%s", name);
  651. +                    requirepackage(PCK_MAPMODEL, dl);
  652. +                }
  653. +                else
  654. +                {
  655. +                    mdllookup.access(newstring(name), nomodel);
  656. +                    conoutf("\f3failed to load model %s", name);
  657. +                }
  658.              }
  659.          }
  660. +        popscontext();
  661. +        if(!loadingmodel) return NULL;
  662.          loadingmodel = NULL;
  663.          mdllookup.access(m->name(), m);
  664.      }
  665. @@ -511,14 +526,14 @@
  666.      }
  667.  }
  668.  
  669. -void preload_mapmodels()
  670. +void preload_mapmodels(bool trydl)
  671.  {
  672.      loopv(ents)
  673.      {
  674.          entity &e = ents[i];
  675.          if(e.type!=MAPMODEL || !mapmodels.inrange(e.attr2)) continue;
  676. -        if(!loadmodel(NULL, e.attr2)) continue;
  677. -        if(e.attr4) lookuptexture(e.attr4);
  678. +        loadmodel(NULL, e.attr2, trydl);
  679. +        if(e.attr4) lookuptexture(e.attr4, notexture, trydl);
  680.      }
  681.  }
  682.  
  683. Index: source/src/sound.h
  684. ===================================================================
  685. --- source/src/sound.h  (revision 6613)
  686. +++ source/src/sound.h  (working copy)
  687. @@ -160,7 +160,7 @@
  688.      sbuffer();
  689.      ~sbuffer();
  690.  
  691. -    bool load();
  692. +    bool load(bool trydl = false);
  693.      void unload();
  694.  };
  695.  
  696. @@ -388,8 +388,8 @@
  697.  
  698.      // init & setup
  699.      void initsound();
  700. -    void preloadmapsound(entity &e);
  701. -    void preloadmapsounds();
  702. +    void preloadmapsound(entity &e, bool trydl = false);
  703. +    void preloadmapsounds(bool trydl = false);
  704.      void applymapsoundchanges();
  705.  
  706.      // configuration
  707. Index: source/src/stream.cpp
  708. ===================================================================
  709. --- source/src/stream.cpp   (revision 6613)
  710. +++ source/src/stream.cpp   (working copy)
  711. @@ -74,6 +74,12 @@
  712.      return s;
  713.  }
  714.  
  715. +char *unixpath(char *s)
  716. +{
  717. +    for(char *t = s; (t = strchr(t, '\\')); *t++ = '/');
  718. +    return s;
  719. +}
  720. +
  721.  char *path(const char *s, bool copy)
  722.  {
  723.      static string tmp;
  724. @@ -304,6 +310,38 @@
  725.      return !remove(path);
  726.  }
  727.  
  728. +bool copyfile(const char *source, const char *destination)
  729. +{
  730. +    FILE *from = fopen(source, "rb");
  731. +    FILE *dest = fopen(destination, "wb");
  732. +
  733. +    if(!from || !dest) return false;
  734. +    size_t len;
  735. +    uchar buf[1024];
  736. +    while((len = fread(&buf, sizeof(uchar), 1024, from)))
  737. +    {
  738. +        fwrite(&buf, sizeof(uchar), len, dest);
  739. +    }
  740. +    fclose(from);
  741. +    fclose(dest);
  742. +    return true;
  743. +}
  744. +
  745. +bool preparedir(const char *destination)
  746. +{
  747. +    string dir;
  748. +    copystring(dir, parentdir(destination));
  749. +    vector<char *> dirs;
  750. +    while(!fileexists(dir, "r"))
  751. +    {
  752. +        dirs.add(newstring(dir));
  753. +        copystring(dir, parentdir(dir));
  754. +    }
  755. +    
  756. +    loopvrev(dirs) if(!createdir(dirs[i])) return false;
  757. +    return true;
  758. +}
  759. +
  760.  #ifndef STANDALONE
  761.  static int rwopsseek(SDL_RWops *rw, int offset, int whence)
  762.  {
  763. Index: source/src/texture.cpp
  764. ===================================================================
  765. --- source/src/texture.cpp  (revision 6613)
  766. +++ source/src/texture.cpp  (working copy)
  767. @@ -354,7 +354,7 @@
  768.  VARFP(hirestextures, 0, 1, 1, initwarning("texture resolution", INIT_LOAD));
  769.  bool uniformtexres = !hirestextures;
  770.  
  771. -GLuint loadsurface(const char *texname, int &xs, int &ys, int &bpp, int clamp = 0, bool mipmap = true, bool canreduce = false, float scale = 1.0f)
  772. +GLuint loadsurface(const char *texname, int &xs, int &ys, int &bpp, int clamp = 0, bool mipmap = true, bool canreduce = false, float scale = 1.0f, bool trydl = false)
  773.  {
  774.      const char *file = texname;
  775.      if(texname[0]=='<')
  776. @@ -377,6 +377,11 @@
  777.          delete z;
  778.      }
  779.      if(!s) s = IMG_Load(findfile(file, "rb"));
  780. +    if(!s && trydl)
  781. +    {
  782. +        requirepackage(PCK_TEXTURE, file);
  783. +        return 0;
  784. +    }
  785.      if(!s) { if(!silent_texture_load) conoutf("couldn't load texture %s", texname); return 0; }
  786.      s = fixsurfaceformat(s);
  787.      Uint8 x = 0;
  788. @@ -420,7 +425,7 @@
  789.  // each texture slot can have multiple texture frames, of which currently only the first is used
  790.  // additional frames can be used for various shaders
  791.  
  792. -Texture *textureload(const char *name, int clamp, bool mipmap, bool canreduce, float scale)
  793. +Texture *textureload(const char *name, int clamp, bool mipmap, bool canreduce, float scale, bool trydl)
  794.  {
  795.      string pname;
  796.      copystring(pname, name);
  797. @@ -428,7 +433,7 @@
  798.      Texture *t = textures.access(pname);
  799.      if(t) return t;
  800.      int xs, ys, bpp;
  801. -    GLuint id = loadsurface(pname, xs, ys, bpp, clamp, mipmap, canreduce, scale);
  802. +    GLuint id = loadsurface(pname, xs, ys, bpp, clamp, mipmap, canreduce, scale, trydl);
  803.      if(!id) return notexture;
  804.      char *key = newstring(pname);
  805.      t = &textures[key];
  806. @@ -498,7 +503,7 @@
  807.  COMMAND(texturereset, ARG_NONE);
  808.  COMMAND(texture, ARG_2STR);
  809.  
  810. -Texture *lookuptexture(int tex, Texture *failtex)
  811. +Texture *lookuptexture(int tex, Texture *failtex, bool trydl)
  812.  {
  813.      Texture *t = failtex;
  814.      if(slots.inrange(tex))
  815. @@ -507,7 +512,7 @@
  816.          if(!s.loaded)
  817.          {
  818.              defformatstring(pname)("packages/textures/%s", s.name);
  819. -            s.tex = textureload(pname, 0, true, true, s.scale);
  820. +            s.tex = textureload(pname, 0, true, true, s.scale, trydl);
  821.              if(s.tex==notexture) s.tex = failtex;
  822.              s.loaded = true;
  823.          }
  824. @@ -547,19 +552,27 @@
  825.  }
  826.  
  827.  Texture *sky[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
  828. +static string skybox;
  829.  
  830. -void loadsky(char *basename)
  831. +void loadsky(char *basename, bool reload)
  832.  {
  833.      const char *side[] = { "lf", "rt", "ft", "bk", "dn", "up" };
  834. +    if(reload) basename = skybox;
  835. +    else copystring(skybox, basename);
  836.      loopi(6)
  837.      {
  838.          defformatstring(name)("packages/%s_%s.jpg", basename, side[i]);
  839.          sky[i] = textureload(name, 3);
  840. -        if(!sky[i]) conoutf("could not load sky texture: %s", name);
  841. +        if(sky[i] == notexture && !reload)
  842. +        {
  843. +            defformatstring(dl)("packages/%s", basename);
  844. +            requirepackage(PCK_SKYBOX, dl);
  845. +            break;
  846. +        }
  847.      }
  848.  }
  849.  
  850. -COMMAND(loadsky, ARG_1STR);
  851. +ICOMMANDF(loadsky, ARG_1STR, (char *name) { loadsky(name, false); return 0; });
  852.  
  853.  void loadnotexture(char *c)
  854.  {
  855. Index: source/src/tools.h
  856. ===================================================================
  857. --- source/src/tools.h  (revision 6613)
  858. +++ source/src/tools.h  (working copy)
  859. @@ -882,6 +882,7 @@
  860.  extern const char *numtime();
  861.  extern char *path(char *s);
  862.  extern char *path(const char *s, bool copy);
  863. +extern char *unixpath(char *s);
  864.  extern const char *behindpath(const char *s);
  865.  extern const char *parentdir(const char *directory);
  866.  extern bool fileexists(const char *path, const char *mode);
  867. @@ -901,6 +902,10 @@
  868.  extern int listfiles(const char *dir, const char *ext, vector<char *> &files);
  869.  extern int listzipfiles(const char *dir, const char *ext, vector<char *> &files);
  870.  extern bool delfile(const char *path);
  871. +extern bool copyfile(const char *source, const char *destination);
  872. +extern bool preparedir(const char *destination);
  873. +extern bool addzip(const char *name, const char *mount = NULL, const char *strip = NULL, bool extract = false, int type = -1);
  874. +extern bool removezip(const char *name);
  875.  extern struct mapstats *loadmapstats(const char *filename, bool getlayout);
  876.  extern bool cmpb(void *b, int n, enet_uint32 c);
  877.  extern bool cmpf(char *fn, enet_uint32 c);
  878. Index: source/src/worldio.cpp
  879. ===================================================================
  880. --- source/src/worldio.cpp  (revision 6613)
  881. +++ source/src/worldio.cpp  (working copy)
  882. @@ -685,17 +685,44 @@
  883.      popscontext();
  884.  
  885.      c2skeepalive();
  886. +
  887.      watch.start();
  888. +    loopi(256) if(texuse[i]) lookupworldtexture(i, true);
  889. +    int texloadtime = watch.stop();
  890. +
  891. +    c2skeepalive();
  892. +
  893. +    watch.start();
  894. +    preload_mapmodels(true);
  895. +    int mdlloadtime = watch.stop();
  896. +
  897. +    c2skeepalive();
  898. +
  899. +    watch.start();
  900. +    audiomgr.preloadmapsounds(true);
  901. +    int audioloadtime = watch.stop();
  902. +
  903. +    c2skeepalive();
  904. +
  905. +    watch.start();
  906. +    int downloaded = downloadpackages();
  907. +    if(downloaded > 0) printf("downloaded content (%d KB in %d seconds)\n", downloaded/1000, watch.stop()/1000);
  908. +
  909. +    c2skeepalive();
  910. +
  911. +
  912. +    loadsky(NULL, true);
  913. +    watch.start();
  914.      loopi(256) if(texuse[i]) lookupworldtexture(i);
  915. -    printf("loaded textures (%d milliseconds)\n", watch.stop());
  916. +    printf("loaded textures (%d milliseconds)\n", texloadtime+watch.stop());
  917.      c2skeepalive();
  918.      watch.start();
  919.      preload_mapmodels();
  920. -    printf("loaded mapmodels (%d milliseconds)\n", watch.stop());
  921. +    printf("loaded mapmodels (%d milliseconds)\n", mdlloadtime+watch.stop());
  922.      c2skeepalive();
  923.      watch.start();
  924.      audiomgr.preloadmapsounds();
  925. -    printf("loaded mapsounds (%d milliseconds)\n", watch.stop());
  926. +    printf("loaded mapsounds (%d milliseconds)\n", audioloadtime+watch.stop());
  927.      c2skeepalive();
  928.  
  929.      defformatstring(startmillis)("%d", millis_());
  930. @@ -840,6 +867,12 @@
  931.      delete f;
  932.  }
  933.  
  934. +// get all dependencies for the current map
  935. +void curmapdeps()
  936. +{
  937. +
  938. +}
  939. +
  940.  COMMAND(listmapdependencies, ARG_1STR);
  941.  
  942.  void listmapdependencies_all(int sure)
  943. Index: source/src/zip.cpp
  944. ===================================================================
  945. --- source/src/zip.cpp  (revision 6613)
  946. +++ source/src/zip.cpp  (working copy)
  947. @@ -22,7 +22,7 @@
  948.  {
  949.      uint signature;
  950.      ushort version, needversion, flags, compression, modtime, moddate;
  951. -    uint crc32, compressedsize, uncompressedsize;
  952. +    uint crc32, compressedsize, uncompressedsize;
  953.      ushort namelength, extralength, commentlength, disknumber, internalattribs;
  954.      uint externalattribs, offset;
  955.  };
  956. @@ -43,9 +43,9 @@
  957.      zipfile() : name(NULL), header(0), offset(~0U), size(0), compressedsize(0)
  958.      {
  959.      }
  960. -    ~zipfile()
  961. -    {
  962. -        DELETEA(name);
  963. +    ~zipfile()
  964. +    {
  965. +        DELETEA(name);
  966.      }
  967.  };
  968.  
  969. @@ -57,9 +57,10 @@
  970.      FILE *data;
  971.      hashtable<const char *, zipfile> files;
  972.      int openfiles;
  973. +    int type;
  974.      zipstream *owner;
  975.  
  976. -    ziparchive() : name(NULL), data(NULL), files(512), openfiles(0), owner(NULL)
  977. +    ziparchive() : name(NULL), data(NULL), files(512), openfiles(0), owner(NULL), type(-1)
  978.      {
  979.      }
  980.      ~ziparchive()
  981. @@ -85,9 +86,9 @@
  982.          if(next + carry < ZIP_DIRECTORY_SIZE || fseek(f, offset, SEEK_SET) < 0 || (int)fread(buf, 1, next, f) != next) return false;
  983.          len = next + carry;
  984.          uchar *search = &buf[next-1];
  985. -        for(; search >= buf; search--) if(*(uint *)search == signature) break;
  986. +        for(; search >= buf; search--) if(*(uint *)search == signature) break;
  987.          if(search >= buf) { src = search; break; }
  988. -    }        
  989. +    }
  990.  
  991.      if(&buf[len] - src < ZIP_DIRECTORY_SIZE) return false;
  992.  
  993. @@ -149,7 +150,7 @@
  994.          pname[namelen] = '\0';
  995.          path(pname);
  996.          char *name = newstring(pname);
  997. -    
  998. +
  999.          zipfile &f = files.add();
  1000.          f.name = name;
  1001.          f.header = hdr.offset;
  1002. @@ -206,18 +207,36 @@
  1003.      return true;
  1004.  }
  1005.  
  1006. -static void mountzip(ziparchive &arch, vector<zipfile> &files, const char *mountdir, const char *stripdir)
  1007. +bool extractzipfile(ziparchive *a, zipfile *f, const char *name);
  1008. +
  1009. +bool fitspackage(char *filename, int type)
  1010.  {
  1011. +    char *extension = strrchr(filename, '.');
  1012. +    ++extension;
  1013. +    switch(type)
  1014. +    {
  1015. +        case PCK_MAPMODEL:  return !strcmp(extension, "md2") || !strcmp(extension, "md3")
  1016. +                               || !strcmp(extension, "cfg") || !strcmp(extension, "txt")
  1017. +                               || !strcmp(extension, "jpg");
  1018. +        case PCK_MAP:       return !strcmp(extension, "cgz") || !strcmp(extension, "cfg");
  1019. +        case PCK_SKYBOX:    return !strcmp(extension, "jpg");
  1020. +        default:            return true;
  1021. +    }
  1022. +}
  1023. +
  1024. +static void mountzip(ziparchive &arch, vector<zipfile> &files, const char *mountdir, const char *stripdir, bool extract)
  1025. +{
  1026.      string packagesdir = "packages/";
  1027.      path(packagesdir);
  1028.      int striplen = stripdir ? (int)strlen(stripdir) : 0;
  1029. +    if(arch.type == PCK_MAP) mountdir = "packages/maps/";
  1030.      if(!mountdir && !stripdir) loopv(files)
  1031.      {
  1032.          zipfile &f = files[i];
  1033.          const char *foundpackages = strstr(f.name, packagesdir);
  1034.          if(foundpackages)
  1035.          {
  1036. -            if(foundpackages > f.name)
  1037. +            if(foundpackages > f.name)
  1038.              {
  1039.                  stripdir = f.name;
  1040.                  striplen = foundpackages - f.name;
  1041. @@ -239,7 +258,8 @@
  1042.                  if(!mountdir) mountdir = "packages/maps/";
  1043.                  break;
  1044.              }
  1045. -        }    
  1046. +            mountdir = "packages/maps/";
  1047. +        }
  1048.      }
  1049.      string mdir = "", fname;
  1050.      if(mountdir)
  1051. @@ -256,26 +276,32 @@
  1052.          zipfile &mf = arch.files[mname];
  1053.          mf = f;
  1054.          mf.name = mname;
  1055. +
  1056. +        if(extract)
  1057. +        {
  1058. +            if(fitspackage(fname, arch.type)) extractzipfile(&arch, &f, fname);
  1059. +            else conoutf("\f3could not extract \"%s\" : file extension not supported", fname);
  1060. +        }
  1061.      }
  1062.  }
  1063.  
  1064. -bool addzip(const char *name, const char *mount = NULL, const char *strip = NULL)
  1065. +bool addzip(const char *name, const char *mount, const char *strip, bool extract, int type)
  1066.  {
  1067.      string pname;
  1068.      copystring(pname, name);
  1069.      path(pname);
  1070. -    int plen = (int)strlen(pname);
  1071. -    if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");
  1072. +    /*int plen = (int)strlen(pname);
  1073. +    if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");*/
  1074.  
  1075. -    ziparchive *exists = findzip(pname);
  1076. -    if(exists)
  1077. +    /*ziparchive *exists = findzip(pname);
  1078. +    if(exists)
  1079.      {
  1080.          conoutf("already added zip %s", pname);
  1081.          return true;
  1082. -    }
  1083. -
  1084. +    }*/
  1085. +
  1086.      FILE *f = fopen(findfile(pname, "rb"), "rb");
  1087. -    if(!f)
  1088. +    if(!f)
  1089.      {
  1090.          conoutf("could not open file %s", pname);
  1091.          return false;
  1092. @@ -288,24 +314,24 @@
  1093.          fclose(f);
  1094.          return false;
  1095.      }
  1096. -    
  1097. +
  1098.      ziparchive *arch = new ziparchive;
  1099.      arch->name = newstring(pname);
  1100.      arch->data = f;
  1101. -    mountzip(*arch, files, mount, strip);
  1102. -    archives.add(arch);
  1103. +    arch->type = type;
  1104. +    mountzip(*arch, files, mount, strip, extract);
  1105. +    if(!extract) archives.add(arch);
  1106. +    else delete arch;
  1107. +    return true;
  1108. +}
  1109.  
  1110. -    conoutf("added zip %s", pname);
  1111. -    return true;
  1112. -}
  1113. -    
  1114.  bool removezip(const char *name)
  1115.  {
  1116.      string pname;
  1117.      copystring(pname, name);
  1118.      path(pname);
  1119. -    int plen = (int)strlen(pname);
  1120. -    if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");
  1121. +    /*int plen = (int)strlen(pname);
  1122. +    if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");*/
  1123.      ziparchive *exists = findzip(pname);
  1124.      if(!exists)
  1125.      {
  1126. @@ -317,8 +343,8 @@
  1127.          conoutf("zip %s has open files", pname);
  1128.          return false;
  1129.      }
  1130. -    conoutf("removed zip %s", exists->name);
  1131. -    archives.removeobj(exists);
  1132. +    //conoutf("removed zip %s", exists->name);
  1133. +    archives.removeobj(exists);
  1134.      delete exists;
  1135.      return true;
  1136.  }
  1137. @@ -416,11 +442,11 @@
  1138.          {
  1139.              switch(whence)
  1140.              {
  1141. -                case SEEK_END: pos += info->offset + info->size; break;
  1142. +                case SEEK_END: pos += info->offset + info->size; break;
  1143.                  case SEEK_CUR: pos += reading; break;
  1144.                  case SEEK_SET: pos += info->offset; break;
  1145.                  default: return false;
  1146. -            }
  1147. +            }
  1148.              pos = clamp(pos, long(info->offset), long(info->offset + info->size));
  1149.              arch->owner = NULL;
  1150.              if(fseek(arch->data, pos, SEEK_SET) < 0) return false;
  1151. @@ -429,10 +455,10 @@
  1152.              ended = false;
  1153.              return true;
  1154.          }
  1155. -
  1156. +
  1157.          switch(whence)
  1158.          {
  1159. -            case SEEK_END: pos += info->size; break;
  1160. +            case SEEK_END: pos += info->size; break;
  1161.              case SEEK_CUR: pos += zfile.total_out; break;
  1162.              case SEEK_SET: break;
  1163.              default: return false;
  1164. @@ -443,7 +469,7 @@
  1165.              reading = info->offset + info->compressedsize;
  1166.              zfile.next_in += zfile.avail_in;
  1167.              zfile.avail_in = 0;
  1168. -            zfile.total_in = info->compressedsize;
  1169. +            zfile.total_in = info->compressedsize;
  1170.              arch->owner = NULL;
  1171.              ended = false;
  1172.              return true;
  1173. @@ -451,7 +477,7 @@
  1174.  
  1175.          if(pos < 0) return false;
  1176.          if(pos >= (long)zfile.total_out) pos -= zfile.total_out;
  1177. -        else
  1178. +        else
  1179.          {
  1180.              if(zfile.next_in && zfile.total_in <= uint(zfile.next_in - buf))
  1181.              {
  1182. @@ -491,7 +517,7 @@
  1183.                  if(fseek(arch->data, reading, SEEK_SET) < 0) { stopreading(); return 0; }
  1184.                  arch->owner = this;
  1185.              }
  1186. -              
  1187. +
  1188.              int n = (int)fread(buf, 1, min(len, int(info->size + info->offset - reading)), arch->data);
  1189.              reading += n;
  1190.              if(n < len) ended = true;
  1191. @@ -504,7 +530,7 @@
  1192.          {
  1193.              if(!zfile.avail_in) readbuf(BUFSIZE);
  1194.              int err = inflate(&zfile, Z_NO_FLUSH);
  1195. -            if(err != Z_OK)
  1196. +            if(err != Z_OK)
  1197.              {
  1198.                  if(err == Z_STREAM_END) ended = true;
  1199.                  else
  1200. @@ -514,13 +540,33 @@
  1201.  #endif
  1202.                      stopreading();
  1203.                  }
  1204. -                break;
  1205. +                break;
  1206.              }
  1207.          }
  1208.          return len - zfile.avail_out;
  1209.      }
  1210.  };
  1211.  
  1212. +bool extractzipfile(ziparchive *a, zipfile *f, const char *name)
  1213. +{
  1214. +    zipstream *s = new zipstream;
  1215. +    FILE *target;
  1216. +    defformatstring(fname)("%s", findfile(name, "wb"));
  1217. +    preparedir(fname);
  1218. +    bool error = false;
  1219. +    if(s->open(a, f) && (target = fopen(fname, "wb")))
  1220. +    {
  1221. +        size_t len;
  1222. +        uchar copybuf[1024];
  1223. +        while((len = s->read(copybuf, 1024))) fwrite(copybuf, 1, len, target);
  1224. +    }
  1225. +    else error = true;
  1226. +    if(error) conoutf("failed to extract zip file %s from archive %s", fname, a->name);
  1227. +    if(target) fclose(target);
  1228. +    delete s;
  1229. +    return !error;
  1230. +}
  1231. +
  1232.  stream *openzipfile(const char *name, const char *mode)
  1233.  {
  1234.      for(; *mode; mode++) if(*mode=='w' || *mode=='a') return NULL;
Add Comment
Please, Sign In to add comment