Quake II RTX doxygen  1.0 dev
download.c File Reference
#include "client.h"
#include "format/md2.h"
#include "format/sp2.h"

Go to the source code of this file.

Macros

#define CL_DOWNLOAD_IGNORES   "download-ignores.txt"
 
#define check_file(path, type)   check_file_len(path, strlen(path), type)
 

Enumerations

enum  precache_t { PRECACHE_MODELS, PRECACHE_OTHER, PRECACHE_MAP, PRECACHE_FINAL }
 

Functions

qerror_t CL_QueueDownload (const char *path, dltype_t type)
 
qboolean CL_IgnoreDownload (const char *path)
 
void CL_FinishDownload (dlqueue_t *q)
 
void CL_CleanupDownloads (void)
 
void CL_LoadDownloadIgnores (void)
 
static qboolean start_udp_download (dlqueue_t *q)
 
void CL_StartNextDownload (void)
 
static void finish_udp_download (const char *msg)
 
static int write_udp_download (byte *data, int size)
 
static int inflate_udp_download (byte *data, int inlen, int outlen)
 
void CL_HandleDownload (byte *data, int size, int percent, int compressed)
 
qboolean CL_CheckDownloadExtension (const char *ext)
 
static qerror_t check_file_len (const char *path, size_t len, dltype_t type)
 
static void check_skins (const char *name)
 
static void check_player (const char *name)
 
static qboolean downloads_pending (dltype_t type)
 
void CL_RequestNextDownload (void)
 
void CL_ResetPrecacheCheck (void)
 
static void CL_Download_f (void)
 
void CL_InitDownloads (void)
 

Variables

static precache_t precache_check
 
static int precache_sexed_sounds [MAX_SOUNDS]
 
static int precache_sexed_total
 

Macro Definition Documentation

◆ check_file

#define check_file (   path,
  type 
)    check_file_len(path, strlen(path), type)

Definition at line 570 of file download.c.

◆ CL_DOWNLOAD_IGNORES

#define CL_DOWNLOAD_IGNORES   "download-ignores.txt"

Definition at line 27 of file download.c.

Enumeration Type Documentation

◆ precache_t

enum precache_t
Enumerator
PRECACHE_MODELS 
PRECACHE_OTHER 
PRECACHE_MAP 
PRECACHE_FINAL 

Definition at line 29 of file download.c.

Function Documentation

◆ check_file_len()

static qerror_t check_file_len ( const char *  path,
size_t  len,
dltype_t  type 
)
static

Definition at line 510 of file download.c.

511 {
512  char buffer[MAX_QPATH], *ext;
513  qerror_t ret;
514  int valid;
515 
516  // check for oversize path
517  if (len >= MAX_QPATH)
518  return Q_ERR_NAMETOOLONG;
519 
520  // normalize path
521  len = FS_NormalizePath(buffer, path);
522 
523  // check for empty path
524  if (len == 0)
525  return Q_ERR_NAMETOOSHORT;
526 
527  valid = FS_ValidatePath(buffer);
528 
529  // check path
530  if (valid == PATH_INVALID
531  || !Q_ispath(buffer[0])
532  || !Q_ispath(buffer[len - 1])
533  || strstr(buffer, "..")
534  || !strchr(buffer, '/')) {
535  // some of these checks are too conservative or even redundant
536  // once we have normalized the path, however they have to stay for
537  // compatibility reasons with older servers (some would even ban us
538  // for sending .. for example)
539  return Q_ERR_INVALID_PATH;
540  }
541 
542  // check extension
543  ext = COM_FileExtension(buffer);
544  if (*ext != '.' || !CL_CheckDownloadExtension(ext + 1))
545  return Q_ERR_INVALID_PATH;
546 
547  if (FS_FileExists(buffer))
548  // it exists, no need to download
549  return Q_ERR_EXIST;
550 
551  if (valid == PATH_MIXED_CASE)
552  // convert to lower case to make download server happy
553  Q_strlwr(buffer);
554 
555  if (CL_IgnoreDownload(buffer))
556  return Q_ERR_PERM;
557 
558  ret = HTTP_QueueDownload(buffer, type);
559  if (ret != Q_ERR_NOSYS)
560  return ret;
561 
562  // queue and start legacy UDP download
563  ret = CL_QueueDownload(buffer, type);
564  if (ret == Q_ERR_SUCCESS)
566 
567  return ret;
568 }

Referenced by check_player(), and CL_RequestNextDownload().

◆ check_player()

static void check_player ( const char *  name)
static

Definition at line 666 of file download.c.

667 {
668  char fn[MAX_QPATH], model[MAX_QPATH], skin[MAX_QPATH], *p;
669  size_t len;
670  int i, j;
671 
672  CL_ParsePlayerSkin(NULL, model, skin, name);
673 
674  // model
675  len = Q_concat(fn, sizeof(fn), "players/", model, "/tris.md2", NULL);
676  check_file_len(fn, len, DL_OTHER);
677 
678  // weapon models
679  for (i = 0; i < cl.numWeaponModels; i++) {
680  len = Q_concat(fn, sizeof(fn), "players/", model, "/", cl.weaponModels[i], NULL);
681  check_file_len(fn, len, DL_OTHER);
682  }
683 
684  // default weapon skin
685  len = Q_concat(fn, sizeof(fn), "players/", model, "/weapon.pcx", NULL);
686  check_file_len(fn, len, DL_OTHER);
687 
688  // skin
689  len = Q_concat(fn, sizeof(fn), "players/", model, "/", skin, ".pcx", NULL);
690  check_file_len(fn, len, DL_OTHER);
691 
692  // skin_i
693  len = Q_concat(fn, sizeof(fn), "players/", model, "/", skin, "_i.pcx", NULL);
694  check_file_len(fn, len, DL_OTHER);
695 
696  // sexed sounds
697  for (i = 0; i < precache_sexed_total; i++) {
698  j = precache_sexed_sounds[i];
699  p = cl.configstrings[CS_SOUNDS + j];
700 
701  if (*p == '*') {
702  len = Q_concat(fn, sizeof(fn), "players/", model, "/", p + 1, NULL);
703  check_file_len(fn, len, DL_OTHER);
704  }
705  }
706 }

Referenced by CL_RequestNextDownload().

◆ check_skins()

static void check_skins ( const char *  name)
static

Definition at line 573 of file download.c.

574 {
575  size_t i, num_skins, ofs_skins, end_skins;
576  byte *model;
577  size_t len;
578  dmd2header_t *md2header;
579  dsp2header_t *sp2header;
580  char *md2skin;
581  dsp2frame_t *sp2frame;
582  uint32_t ident;
583  char fn[MAX_QPATH];
584 
585  len = FS_LoadFile(name, (void **)&model);
586  if (!model) {
587  // couldn't load it
588  return;
589  }
590 
591  if (len < sizeof(ident)) {
592  // file too small
593  goto done;
594  }
595 
596  // check ident
597  ident = LittleLong(*(uint32_t *)model);
598  switch (ident) {
599  case MD2_IDENT:
600  // alias model
601  md2header = (dmd2header_t *)model;
602  if (len < sizeof(*md2header) ||
603  LittleLong(md2header->ident) != MD2_IDENT ||
604  LittleLong(md2header->version) != MD2_VERSION) {
605  // not an alias model
606  goto done;
607  }
608 
609  num_skins = LittleLong(md2header->num_skins);
610  ofs_skins = LittleLong(md2header->ofs_skins);
611  end_skins = ofs_skins + num_skins * MD2_MAX_SKINNAME;
612  if (num_skins > MD2_MAX_SKINS || end_skins < ofs_skins || end_skins > len) {
613  // bad alias model
614  goto done;
615  }
616 
617  md2skin = (char *)model + ofs_skins;
618  for (i = 0; i < num_skins; i++) {
619  if (!Q_memccpy(fn, md2skin, 0, sizeof(fn))) {
620  // bad alias model
621  goto done;
622  }
623  check_file(fn, DL_OTHER);
624  md2skin += MD2_MAX_SKINNAME;
625  }
626  break;
627 
628  case SP2_IDENT:
629  // sprite model
630  sp2header = (dsp2header_t *)model;
631  if (len < sizeof(*sp2header) ||
632  LittleLong(sp2header->ident) != SP2_IDENT ||
633  LittleLong(sp2header->version) != SP2_VERSION) {
634  // not a sprite model
635  goto done;
636  }
637 
638  num_skins = LittleLong(sp2header->numframes);
639  ofs_skins = sizeof(*sp2header);
640  end_skins = ofs_skins + num_skins * sizeof(dsp2frame_t);
641  if (num_skins > SP2_MAX_FRAMES || end_skins < ofs_skins || end_skins > len) {
642  // bad sprite model
643  goto done;
644  }
645 
646  sp2frame = (dsp2frame_t *)(model + ofs_skins);
647  for (i = 0; i < num_skins; i++) {
648  if (!Q_memccpy(fn, sp2frame->name, 0, sizeof(fn))) {
649  // bad sprite model
650  goto done;
651  }
652  check_file(fn, DL_OTHER);
653  sp2frame++;
654  }
655  break;
656 
657  default:
658  // unknown file format
659  goto done;
660  }
661 
662 done:
663  FS_FreeFile(model);
664 }

Referenced by CL_RequestNextDownload().

◆ CL_CheckDownloadExtension()

qboolean CL_CheckDownloadExtension ( const char *  ext)

Definition at line 494 of file download.c.

495 {
496  static const char allowed[][4] = {
497  "pcx", "wal", "wav", "md2", "sp2", "tga", "png",
498  "jpg", "bsp", "ent", "txt", "dm2", "loc", "md3"
499  };
500  int i;
501 
502  for (i = 0; i < q_countof(allowed); i++)
503  if (!Q_stricmp(ext, allowed[i]))
504  return qtrue;
505 
506  return qfalse;
507 }

Referenced by check_and_queue_download(), and check_file_len().

◆ CL_CleanupDownloads()

void CL_CleanupDownloads ( void  )

Definition at line 136 of file download.c.

137 {
138  dlqueue_t *q, *n;
139 
141 
142  FOR_EACH_DLQ_SAFE(q, n) {
143  Z_Free(q);
144  }
145 
146  List_Init(&cls.download.queue);
147  cls.download.pending = 0;
148 
149  cls.download.current = NULL;
150  cls.download.percent = 0;
151  cls.download.position = 0;
152 
153  if (cls.download.file) {
155  cls.download.file = 0;
156  }
157 
158  cls.download.temp[0] = 0;
159 
160 #if USE_ZLIB
161  inflateEnd(&cls.download.z);
162 #endif
163 }

Referenced by CL_Disconnect().

◆ CL_Download_f()

static void CL_Download_f ( void  )
static

Definition at line 909 of file download.c.

910 {
911  char *path;
912  qerror_t ret;
913 
914  if (cls.state < ca_connected) {
915  Com_Printf("Must be connected to a server.\n");
916  return;
917  }
918 
919  if (allow_download->integer == -1) {
920  Com_Printf("Downloads are permanently disabled.\n");
921  return;
922  }
923 
924  if (Cmd_Argc() != 2) {
925  Com_Printf("Usage: download <filename>\n");
926  return;
927  }
928 
929  path = Cmd_Argv(1);
930 
931  ret = check_file(path, DL_OTHER);
932  if (ret) {
933  Com_Printf("Couldn't download %s: %s\n", path, Q_ErrorString(ret));
934  }
935 }

Referenced by CL_InitDownloads().

◆ CL_FinishDownload()

void CL_FinishDownload ( dlqueue_t q)

Definition at line 115 of file download.c.

116 {
117  if (q->state == DL_DONE) {
118  Com_Error(ERR_DROP, "%s: already done", __func__);
119  }
120  if (!cls.download.pending) {
121  Com_Error(ERR_DROP, "%s: bad pending count", __func__);
122  }
123 
124  q->state = DL_DONE;
125  cls.download.pending--;
126  Com_DPrintf("%s: %s [%d]\n", __func__, q->path, cls.download.pending);
127 }

Referenced by abort_downloads(), finish_download(), finish_udp_download(), rescan_queue(), start_download(), and start_udp_download().

◆ CL_HandleDownload()

void CL_HandleDownload ( byte *  data,
int  size,
int  percent,
int  compressed 
)

Definition at line 424 of file download.c.

425 {
427  qerror_t ret;
428 
429  if (!q) {
430  Com_Error(ERR_DROP, "%s: no download requested", __func__);
431  }
432 
433  if (size == -1) {
434  if (!percent) {
435  finish_udp_download("FAIL");
436  } else {
437  finish_udp_download("STOP");
438  }
439  return;
440  }
441 
442  // open the file if not opened yet
443  if (!cls.download.file) {
444  ret = FS_FOpenFile(cls.download.temp, &cls.download.file, FS_MODE_WRITE);
445  if (!cls.download.file) {
446  Com_EPrintf("[UDP] Couldn't open %s for writing: %s\n",
448  finish_udp_download(NULL);
449  return;
450  }
451  }
452 
453  if (compressed) {
454  if (inflate_udp_download(data, size, compressed))
455  return;
456  } else {
457  if (write_udp_download(data, size))
458  return;
459  }
460 
461  if (percent != 100) {
462  // request next block
463  // change display routines by zoid
464  cls.download.percent = percent;
465  cls.download.position += size;
466 
467  CL_ClientCommand("nextdl");
468  } else {
469  // close the file before renaming
471  cls.download.file = 0;
472 
473  // rename the temp file to its final name
474  ret = FS_RenameFile(cls.download.temp, q->path);
475  if (ret) {
476  Com_EPrintf("[UDP] Couldn't rename %s to %s: %s\n",
477  cls.download.temp, q->path, Q_ErrorString(ret));
478  finish_udp_download(NULL);
479  } else {
480  finish_udp_download("DONE");
481  }
482  }
483 }

Referenced by CL_ParseDownload().

◆ CL_IgnoreDownload()

qboolean CL_IgnoreDownload ( const char *  path)

Definition at line 95 of file download.c.

96 {
97  string_entry_t *entry;
98 
99  for (entry = cls.download.ignores; entry; entry = entry->next) {
100  if (Com_WildCmp(entry->string, path)) {
101  return qtrue;
102  }
103  }
104 
105  return qfalse;
106 }

Referenced by check_and_queue_download(), and check_file_len().

◆ CL_InitDownloads()

void CL_InitDownloads ( void  )

Definition at line 937 of file download.c.

938 {
939  Cmd_AddCommand("download", CL_Download_f);
940 
941  List_Init(&cls.download.queue);
942 }

Referenced by CL_InitLocal().

◆ CL_LoadDownloadIgnores()

void CL_LoadDownloadIgnores ( void  )

Definition at line 173 of file download.c.

174 {
175  string_entry_t *entry, *next;
176  char *raw, *data, *p;
177  int count, line;
178  ssize_t len;
179 
180  // free previous entries
181  for (entry = cls.download.ignores; entry; entry = next) {
182  next = entry->next;
183  Z_Free(entry);
184  }
185 
186  cls.download.ignores = NULL;
187 
188  // load new list
189  len = FS_LoadFile(CL_DOWNLOAD_IGNORES, (void **)&raw);
190  if (!raw) {
191  if (len != Q_ERR_NOENT)
192  Com_EPrintf("Couldn't load %s: %s\n",
194  return;
195  }
196 
197  count = 0;
198  line = 1;
199  data = raw;
200 
201  while (*data) {
202  p = strchr(data, '\n');
203  if (p) {
204  if (p > data && *(p - 1) == '\r')
205  *(p - 1) = 0;
206  *p = 0;
207  }
208 
209  // ignore empty lines and comments
210  if (*data && *data != '#' && *data != '/') {
211  len = strlen(data);
212  if (len < MAX_QPATH) {
213  entry = Z_Malloc(sizeof(*entry) + len);
214  memcpy(entry->string, data, len + 1);
215  entry->next = cls.download.ignores;
216  cls.download.ignores = entry;
217  count++;
218  } else {
219  Com_WPrintf("Oversize filter on line %d in %s\n",
220  line, CL_DOWNLOAD_IGNORES);
221  }
222  }
223 
224  if (!p)
225  break;
226 
227  data = p + 1;
228  line++;
229  }
230 
231  Com_DPrintf("Loaded %d filters from %s\n", count, CL_DOWNLOAD_IGNORES);
232 
233  FS_FreeFile(raw);
234 }

Referenced by CL_Init(), and CL_RestartFilesystem().

◆ CL_QueueDownload()

qerror_t CL_QueueDownload ( const char *  path,
dltype_t  type 
)

Definition at line 49 of file download.c.

50 {
51  dlqueue_t *q;
52  size_t len;
53 
54  FOR_EACH_DLQ(q) {
55  // avoid sending duplicate requests
56  if (!FS_pathcmp(path, q->path)) {
57  Com_DPrintf("%s: %s [DUP]\n", __func__, path);
58  return Q_ERR_EXIST;
59  }
60  }
61 
62  len = strlen(path);
63  if (len >= MAX_QPATH) {
64  Com_Error(ERR_DROP, "%s: oversize quake path", __func__);
65  }
66 
67  q = Z_Malloc(sizeof(*q) + len);
68  memcpy(q->path, path, len + 1);
69  q->type = type;
70  q->state = DL_PENDING;
71 
72 #if USE_CURL
73  // paks get bumped to the top and HTTP switches to single downloading.
74  // this prevents someone on 28k dialup trying to do both the main .pak
75  // and referenced configstrings data at once.
76  if (type == DL_PAK)
77  List_Insert(&cls.download.queue, &q->entry);
78  else
79 #endif
80  List_Append(&cls.download.queue, &q->entry);
81 
83  Com_DPrintf("%s: %s [%d]\n", __func__, path, cls.download.pending);
84  return Q_ERR_SUCCESS;
85 }

Referenced by check_and_queue_download(), check_file_len(), and HTTP_QueueDownload().

◆ CL_RequestNextDownload()

void CL_RequestNextDownload ( void  )

Definition at line 735 of file download.c.

736 {
737  char fn[MAX_QPATH], *name;
738  size_t len;
739  int i;
740 
741  if (cls.state != ca_connected && cls.state != ca_loading)
742  return;
743 
744  if (allow_download->integer <= 0 || NET_IsLocalAddress(&cls.serverAddress)) {
745  if (precache_check <= PRECACHE_MAP) {
747  }
748 
749  CL_Begin();
750  return;
751  }
752 
753  switch (precache_check) {
754  case PRECACHE_MODELS:
755  // confirm map
756  if (allow_download_maps->integer)
757  check_file(cl.configstrings[CS_MODELS + 1], DL_MAP);
758 
759  // checking for models
760  if (allow_download_models->integer) {
761  for (i = 2; i < MAX_MODELS; i++) {
762  name = cl.configstrings[CS_MODELS + i];
763  if (!name[0]) {
764  break;
765  }
766  if (name[0] == '*' || name[0] == '#') {
767  continue;
768  }
769  check_file(name, DL_MODEL);
770  }
771  }
772 
774  // fall through
775 
776  case PRECACHE_OTHER:
777  if (allow_download_models->integer) {
779  // pending downloads (models), let's wait here before we can check skins.
780  Com_DPrintf("%s: waiting for models...\n", __func__);
781  return;
782  }
783 
784  for (i = 2; i < MAX_MODELS; i++) {
785  name = cl.configstrings[CS_MODELS + i];
786  if (!name[0]) {
787  break;
788  }
789  if (name[0] == '*' || name[0] == '#') {
790  continue;
791  }
792  check_skins(name);
793  }
794  }
795 
796  if (allow_download_sounds->integer) {
797  for (i = 1; i < MAX_SOUNDS; i++) {
798  name = cl.configstrings[CS_SOUNDS + i];
799  if (!name[0]) {
800  break;
801  }
802  if (name[0] == '*') {
803  continue;
804  }
805  if (name[0] == '#') {
806  len = Q_strlcpy(fn, name + 1, sizeof(fn));
807  } else {
808  len = Q_concat(fn, sizeof(fn), "sound/", name, NULL);
809  }
810  check_file_len(fn, len, DL_OTHER);
811  }
812  }
813 
814  if (allow_download_pics->integer) {
815  for (i = 1; i < MAX_IMAGES; i++) {
816  name = cl.configstrings[CS_IMAGES + i];
817  if (!name[0]) {
818  break;
819  }
820  if (name[0] == '/' || name[0] == '\\') {
821  len = Q_strlcpy(fn, name + 1, sizeof(fn));
822  } else {
823  len = Q_concat(fn, sizeof(fn), "pics/", name, ".pcx", NULL);
824  }
825  check_file_len(fn, len, DL_OTHER);
826  }
827  }
828 
829  if (allow_download_players->integer) {
830  // find sexed sounds
832  for (i = 1; i < MAX_SOUNDS; i++) {
833  if (cl.configstrings[CS_SOUNDS + i][0] == '*') {
835  }
836  }
837 
838  for (i = 0; i < MAX_CLIENTS; i++) {
839  name = cl.configstrings[CS_PLAYERSKINS + i];
840  if (!name[0]) {
841  continue;
842  }
843  check_player(name);
844  }
845  }
846 
847  if (allow_download_textures->integer) {
848  static const char env_suf[6][3] = {
849  "rt", "bk", "lf", "ft", "up", "dn"
850  };
851 
852  for (i = 0; i < 6; i++) {
853  len = Q_concat(fn, sizeof(fn), "env/", cl.configstrings[CS_SKY], env_suf[i], ".tga", NULL);
854  check_file_len(fn, len, DL_OTHER);
855  }
856  }
857 
859  // fall through
860 
861  case PRECACHE_MAP:
862  if (downloads_pending(DL_MAP)) {
863  // map might still be downloading?
864  Com_DPrintf("%s: waiting for map...\n", __func__);
865  return;
866  }
867 
868  // load the map file before checking textures
870 
871  if (allow_download_textures->integer) {
872  for (i = 0; i < cl.bsp->numtexinfo; i++) {
873  len = Q_concat(fn, sizeof(fn), "textures/", cl.bsp->texinfo[i].name, ".wal", NULL);
874  check_file_len(fn, len, DL_OTHER);
875  }
876  }
877 
879  // fall through
880 
881  case PRECACHE_FINAL:
883  // pending downloads (possibly textures), let's wait here.
884  Com_DPrintf("%s: waiting for others...\n", __func__);
885  return;
886  }
887 
888  // all done, tell server we are ready
889  CL_Begin();
890  break;
891 
892  default:
893  Com_Error(ERR_DROP, "%s: bad precache_check\n", __func__);
894  }
895 }

Referenced by abort_downloads(), CL_Precache_f(), finish_download(), finish_udp_download(), and start_download().

◆ CL_ResetPrecacheCheck()

void CL_ResetPrecacheCheck ( void  )

Definition at line 897 of file download.c.

898 {
900 }

Referenced by CL_Precache_f().

◆ CL_StartNextDownload()

void CL_StartNextDownload ( void  )

Definition at line 294 of file download.c.

295 {
296  dlqueue_t *q;
297 
299  return;
300  }
301 
302  FOR_EACH_DLQ(q) {
303  if (q->state == DL_PENDING) {
304  if (start_udp_download(q)) {
305  break;
306  }
307  }
308  }
309 }

Referenced by abort_downloads(), check_file_len(), and finish_udp_download().

◆ downloads_pending()

static qboolean downloads_pending ( dltype_t  type)
static

Definition at line 709 of file download.c.

710 {
711  dlqueue_t *q;
712 
713  // DL_OTHER just checks for any download
714  if (type == DL_OTHER) {
715  return !!cls.download.pending;
716  }
717 
718  // see if there are pending downloads of the given type
719  FOR_EACH_DLQ(q) {
720  if (q->state != DL_DONE && q->type == type) {
721  return qtrue;
722  }
723  }
724 
725  return qfalse;
726 }

Referenced by CL_RequestNextDownload().

◆ finish_udp_download()

static void finish_udp_download ( const char *  msg)
static

Definition at line 311 of file download.c.

312 {
314 
315  // finished with current path
317 
318  cls.download.current = NULL;
319  cls.download.percent = 0;
320  cls.download.position = 0;
321 
322  if (cls.download.file) {
324  cls.download.file = 0;
325  }
326 
327  cls.download.temp[0] = 0;
328 
329 #if USE_ZLIB
330  inflateReset(&cls.download.z);
331 #endif
332 
333  if (msg) {
334  Com_Printf("[UDP] %s [%s] [%d remaining file%s]\n",
335  q->path, msg, cls.download.pending,
336  cls.download.pending == 1 ? "" : "s");
337  }
338 
339  // get another file if needed
342 }

Referenced by CL_HandleDownload(), inflate_udp_download(), and write_udp_download().

◆ inflate_udp_download()

static int inflate_udp_download ( byte *  data,
int  inlen,
int  outlen 
)
static

Definition at line 361 of file download.c.

362 {
363 #if USE_ZLIB
364 
365 #define CHUNK 0x10000
366 
367  z_streamp z = &cls.download.z;
368  byte buffer[CHUNK];
369  int ret;
370 
371  // initialize stream if not done yet
372  if (z->state == NULL && inflateInit2(z, -MAX_WBITS) != Z_OK)
373  Com_Error(ERR_FATAL, "%s: inflateInit2() failed", __func__);
374 
375  z->next_in = data;
376  z->avail_in = inlen;
377 
378  // run inflate() until output buffer not full
379  do {
380  z->next_out = buffer;
381  z->avail_out = CHUNK;
382 
383  ret = inflate(z, Z_SYNC_FLUSH);
384  if (ret != Z_OK && ret != Z_STREAM_END) {
385  Com_EPrintf("[UDP] inflate() failed: %s\n", z->msg);
386  finish_udp_download(NULL);
387  return -1;
388  }
389 
390  Com_DDPrintf("%s: %u --> %u [%d]\n",
391  __func__,
392  inlen - z->avail_in,
393  CHUNK - z->avail_out,
394  ret);
395 
396  if (write_udp_download(buffer, CHUNK - z->avail_out))
397  return -1;
398  } while (z->avail_out == 0);
399 
400  // check uncompressed length if known
401  if (outlen > 0 && outlen != z->total_out)
402  Com_WPrintf("[UDP] Decompressed length mismatch: %d != %lu\n", outlen, z->total_out);
403 
404  // prepare for the next stream if done
405  if (ret == Z_STREAM_END)
406  inflateReset(z);
407 
408  return 0;
409 #else
410  // should never happen
411  Com_Error(ERR_DROP, "Compressed server packet received, "
412  "but no zlib support linked in.");
413  return 0;
414 #endif
415 }

Referenced by CL_HandleDownload().

◆ start_udp_download()

static qboolean start_udp_download ( dlqueue_t q)
static

Definition at line 236 of file download.c.

237 {
238  size_t len;
239  qhandle_t f;
240  ssize_t ret;
241 
242  len = strlen(q->path);
243  if (len >= MAX_QPATH) {
244  Com_Error(ERR_DROP, "%s: oversize quake path", __func__);
245  }
246 
247  // download to a temp name, and only rename
248  // to the real name when done, so if interrupted
249  // a runt file wont be left
250  memcpy(cls.download.temp, q->path, len);
251  memcpy(cls.download.temp + len, ".tmp", 5);
252 
253  // check to see if we already have a tmp for this file, if so, try to resume
254  // open the file if not opened yet
255  ret = FS_FOpenFile(cls.download.temp, &f, FS_MODE_RDWR);
256  if (ret >= 0) { // it exists
257  cls.download.file = f;
258  cls.download.position = ret;
259  // give the server an offset to start the download
260  Com_DPrintf("[UDP] Resuming %s\n", q->path);
261 #if USE_ZLIB
262  if (cls.serverProtocol == PROTOCOL_VERSION_R1Q2)
263  CL_ClientCommand(va("download \"%s\" %"PRIz" udp-zlib", q->path, ret));
264  else
265 #endif
266  CL_ClientCommand(va("download \"%s\" %"PRIz, q->path, ret));
267  } else if (ret == Q_ERR_NOENT) { // it doesn't exist
268  Com_DPrintf("[UDP] Downloading %s\n", q->path);
269 #if USE_ZLIB
270  if (cls.serverProtocol == PROTOCOL_VERSION_R1Q2)
271  CL_ClientCommand(va("download \"%s\" %"PRIz" udp-zlib", q->path, (size_t)0));
272  else
273 #endif
274  CL_ClientCommand(va("download \"%s\"", q->path));
275  } else { // error happened
276  Com_EPrintf("[UDP] Couldn't open %s for appending: %s\n",
279  return qfalse;
280  }
281 
282  q->state = DL_RUNNING;
283  cls.download.current = q;
284  return qtrue;
285 }

Referenced by CL_StartNextDownload().

◆ write_udp_download()

static int write_udp_download ( byte *  data,
int  size 
)
static

Definition at line 344 of file download.c.

345 {
346  ssize_t ret;
347 
348  ret = FS_Write(data, size, cls.download.file);
349  if (ret != size) {
350  Com_EPrintf("[UDP] Couldn't write %s: %s\n",
352  finish_udp_download(NULL);
353  return -1;
354  }
355 
356  return 0;
357 }

Referenced by CL_HandleDownload(), and inflate_udp_download().

Variable Documentation

◆ precache_check

precache_t precache_check
static

Definition at line 36 of file download.c.

Referenced by CL_RequestNextDownload(), and CL_ResetPrecacheCheck().

◆ precache_sexed_sounds

int precache_sexed_sounds[MAX_SOUNDS]
static

Definition at line 37 of file download.c.

Referenced by check_player(), and CL_RequestNextDownload().

◆ precache_sexed_total

int precache_sexed_total
static

Definition at line 38 of file download.c.

Referenced by check_player(), and CL_RequestNextDownload().

client_state_s::bsp
bsp_t * bsp
Definition: client.h:300
client_state_s::configstrings
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]
Definition: client.h:289
PRECACHE_FINAL
@ PRECACHE_FINAL
Definition: download.c:33
CL_IgnoreDownload
qboolean CL_IgnoreDownload(const char *path)
Definition: download.c:95
allow_download_players
cvar_t * allow_download_players
Definition: common.c:106
dlqueue_t
Definition: client.h:367
DL_OTHER
@ DL_OTHER
Definition: client.h:351
client_static_s::file
qhandle_t file
Definition: client.h:443
dlqueue_t::entry
list_t entry
Definition: client.h:368
FOR_EACH_DLQ_SAFE
#define FOR_EACH_DLQ_SAFE(q, n)
Definition: client.h:346
Cmd_AddCommand
void Cmd_AddCommand(const char *name, xcommand_t function)
Definition: cmd.c:1562
PRECACHE_OTHER
@ PRECACHE_OTHER
Definition: download.c:31
CL_DOWNLOAD_IGNORES
#define CL_DOWNLOAD_IGNORES
Definition: download.c:27
precache_check
static precache_t precache_check
Definition: download.c:36
client_state_s::numWeaponModels
int numWeaponModels
Definition: client.h:312
check_player
static void check_player(const char *name)
Definition: download.c:666
HTTP_CleanupDownloads
void HTTP_CleanupDownloads(void)
Definition: http.c:386
Q_ErrorString
const char * Q_ErrorString(qerror_t error)
Definition: error.c:51
DL_MAP
@ DL_MAP
Definition: client.h:352
PRECACHE_MAP
@ PRECACHE_MAP
Definition: download.c:32
client_static_s::state
connstate_t state
Definition: client.h:375
ca_connected
@ ca_connected
Definition: client.h:337
CL_FinishDownload
void CL_FinishDownload(dlqueue_t *q)
Definition: download.c:115
CL_Begin
void CL_Begin(void)
Definition: main.c:1757
ext
char ext[4]
Definition: images.c:657
client_state_s::weaponModels
char weaponModels[MAX_CLIENTWEAPONMODELS][MAX_QPATH]
Definition: client.h:311
check_skins
static void check_skins(const char *name)
Definition: download.c:573
client_static_s::ignores
string_entry_t * ignores
Definition: client.h:448
inflate_udp_download
static int inflate_udp_download(byte *data, int inlen, int outlen)
Definition: download.c:361
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
CL_RegisterBspModels
void CL_RegisterBspModels(void)
Definition: precache.c:226
FS_ValidatePath
int FS_ValidatePath(const char *s)
Definition: files.c:271
FS_FOpenFile
ssize_t FS_FOpenFile(const char *name, qhandle_t *f, unsigned mode)
Definition: files.c:1692
CL_CheckDownloadExtension
qboolean CL_CheckDownloadExtension(const char *ext)
Definition: download.c:494
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
allow_download_maps
cvar_t * allow_download_maps
Definition: common.c:109
allow_download_textures
cvar_t * allow_download_textures
Definition: common.c:110
CL_ParsePlayerSkin
void CL_ParsePlayerSkin(char *name, char *model, char *skin, const char *s)
Definition: precache.c:35
client_static_s::current
dlqueue_t * current
Definition: client.h:440
DL_MODEL
@ DL_MODEL
Definition: client.h:353
write_udp_download
static int write_udp_download(byte *data, int size)
Definition: download.c:344
downloads_pending
static qboolean downloads_pending(dltype_t type)
Definition: download.c:709
check_file_len
static qerror_t check_file_len(const char *path, size_t len, dltype_t type)
Definition: download.c:510
va
char * va(const char *format,...)
Definition: shared.c:429
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
DL_DONE
@ DL_DONE
Definition: client.h:364
client_static_s::serverProtocol
int serverProtocol
Definition: client.h:422
dlqueue_t::state
dlstate_t state
Definition: client.h:370
client_static_s::pending
int pending
Definition: client.h:439
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
client_static_s::percent
int percent
Definition: client.h:441
dlqueue_t::path
char path[1]
Definition: client.h:371
precache_sexed_total
static int precache_sexed_total
Definition: download.c:38
precache_sexed_sounds
static int precache_sexed_sounds[MAX_SOUNDS]
Definition: download.c:37
PRECACHE_MODELS
@ PRECACHE_MODELS
Definition: download.c:30
cl
client_state_t cl
Definition: main.c:99
FS_Write
ssize_t FS_Write(const void *buf, size_t len, qhandle_t f)
Definition: files.c:1643
allow_download_sounds
cvar_t * allow_download_sounds
Definition: common.c:108
HTTP_QueueDownload
qerror_t HTTP_QueueDownload(const char *path, dltype_t type)
Definition: http.c:530
cls
client_static_t cls
Definition: main.c:98
CL_RequestNextDownload
void CL_RequestNextDownload(void)
Definition: download.c:735
FOR_EACH_DLQ
#define FOR_EACH_DLQ(q)
Definition: client.h:344
DL_RUNNING
@ DL_RUNNING
Definition: client.h:363
client_static_s::queue
list_t queue
Definition: client.h:438
CL_StartNextDownload
void CL_StartNextDownload(void)
Definition: download.c:294
finish_udp_download
static void finish_udp_download(const char *msg)
Definition: download.c:311
client_static_s::download
struct client_static_s::@2 download
allow_download_pics
cvar_t * allow_download_pics
Definition: common.c:111
CL_Download_f
static void CL_Download_f(void)
Definition: download.c:909
allow_download
cvar_t * allow_download
Definition: common.c:105
DL_PENDING
@ DL_PENDING
Definition: client.h:362
msg
const char * msg
Definition: win.h:25
CL_QueueDownload
qerror_t CL_QueueDownload(const char *path, dltype_t type)
Definition: download.c:49
client_static_s::temp
char temp[MAX_QPATH+4]
Definition: client.h:444
Q_memccpy
void * Q_memccpy(void *dst, const void *src, int c, size_t size)
Definition: shared.c:895
ca_loading
@ ca_loading
Definition: client.h:338
CL_ClientCommand
void CL_ClientCommand(const char *string)
Definition: main.c:299
FS_FCloseFile
void FS_FCloseFile(qhandle_t f)
Definition: files.c:759
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
allow_download_models
cvar_t * allow_download_models
Definition: common.c:107
client_static_s::serverAddress
netadr_t serverAddress
Definition: client.h:409
check_file
#define check_file(path, type)
Definition: download.c:570
start_udp_download
static qboolean start_udp_download(dlqueue_t *q)
Definition: download.c:236
dlqueue_t::type
dltype_t type
Definition: client.h:369
COM_FileExtension
char * COM_FileExtension(const char *in)
Definition: shared.c:199
client_static_s::position
int position
Definition: client.h:442
FS_NormalizePath
size_t FS_NormalizePath(char *out, const char *in)
Definition: files.c:331
precache_t
precache_t
Definition: download.c:29