Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
DataLoader.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: nGenEx.lib
6  FILE: DataLoader.cpp
7  AUTHOR: John DiCamillo
8 
9 */
10 
11 #include "MemDebug.h"
12 #include "DataLoader.h"
13 #include "Archive.h"
14 #include "Color.h"
15 #include "D3DXImage.h"
16 #include "Bitmap.h"
17 #include "Bmp.h"
18 #include "PCX.h"
19 #include "Sound.h"
20 #include "Resource.h"
21 #include "Video.h"
22 #include "Wave.h"
23 
24 // +------------------------------------------------------------------+
25 
26 static DataLoader* def_loader = 0;
27 DataLoader* DataLoader::loader = 0;
28 
29 static List<DataArchive> archives;
30 
31 // +--------------------------------------------------------------------+
32 
34 : datapath(""), video(0), use_file_system(true), enable_media(true)
35 { }
36 
37 // +--------------------------------------------------------------------+
38 
39 void
41 {
42  video = v;
43 }
44 
45 // +--------------------------------------------------------------------+
46 
47 void
49 {
50  def_loader = new(__FILE__,__LINE__) DataLoader;
51  loader = def_loader;
52 
53  archives.destroy();
54 }
55 
56 void
58 {
59  archives.destroy();
61 
62  delete def_loader;
63  def_loader = 0;
64  loader = 0;
65 }
66 
67 void
69 {
70  Close();
71 }
72 
73 // +--------------------------------------------------------------------+
74 
75 void
77 {
78  use_file_system = use;
79 }
80 
81 void
83 {
84  enable_media = enable;
85 }
86 
87 // +--------------------------------------------------------------------+
88 
89 int
90 DataLoader::EnableDatafile(const char* name)
91 {
92  int status = DATAFILE_NOTEXIST;
93 
94  FILE* f;
95  fopen_s(&f, name, "rb");
96 
97  if (f) {
98  ::fclose(f);
99 
100  DataArchive* a = new(__FILE__,__LINE__) DataArchive(name);
101 
102  if (a && a->NumFiles() >= 1) {
103  status = DATAFILE_OK;
104 
105  bool found = false;
106  ListIter<DataArchive> iter = archives;
107  while (++iter && !found) {
108  DataArchive* archive = iter.value();
109  if (!strcmp(archive->Name(), name)) {
110  found = true;
111  }
112  }
113 
114  if (!found)
115  archives.append(a);
116  }
117  else {
118  Print(" WARNING: invalid data file '%s'\n", name);
119  status = DATAFILE_INVALID;
120 
121  delete a;
122  }
123 
124  loader = this;
125  }
126  else {
127  Print(" WARNING: could not open datafile '%s'\n", name);
128  status = DATAFILE_NOTEXIST;
129  }
130 
131  return status;
132 }
133 
134 int
136 {
137  ListIter<DataArchive> iter = archives;
138  while (++iter) {
139  DataArchive* a = iter.value();
140  if (!strcmp(a->Name(), name)) {
141  delete iter.removeItem();
142  return DATAFILE_OK;
143  }
144  }
145 
146  return DATAFILE_NOTEXIST;
147 }
148 
149 // +--------------------------------------------------------------------+
150 
151 void
152 DataLoader::SetDataPath(const char* path)
153 {
154  if (path)
155  datapath = path;
156  else
157  datapath = "";
158 }
159 
160 // +--------------------------------------------------------------------+
161 
162 bool
163 DataLoader::FindFile(const char* name)
164 {
165  // assemble file name:
166  char filename[1024];
167  strcpy_s(filename, datapath);
168  strcat_s(filename, name);
169 
170  // first check current directory:
171  if (use_file_system) {
172  FILE* f;
173  ::fopen_s(&f, filename, "rb");
174 
175  if (f) {
176  ::fclose(f);
177  return true;
178  }
179  }
180 
181  // then check datafiles, from last to first:
182  int narchives = archives.size();
183  for (int i = 0; i < narchives; i++) {
184  DataArchive* a = archives[narchives-1-i];
185  if (a->FindEntry(filename) > -1) {
186  return true;
187  }
188  }
189 
190  return false;
191 }
192 
193 // +--------------------------------------------------------------------+
194 
195 int
196 DataLoader::ListFiles(const char* filter, List<Text>& list, bool recurse)
197 {
198  list.destroy();
199 
200  ListFileSystem(filter, list, datapath, recurse);
201 
202  // then check datafile(s):
203  int narchives = archives.size();
204  for (int i = 0; i < narchives; i++) {
205  DataArchive* a = archives[narchives-1-i];
206  ListArchiveFiles(a->Name(), filter, list);
207  }
208 
209  return list.size();
210 }
211 
212 int
213 DataLoader::ListArchiveFiles(const char* archive_name, const char* filter, List<Text> &list)
214 {
215  int pathlen = datapath.length();
216  DataArchive* a = 0;
217 
218  if (archive_name) {
219  int narchives = archives.size();
220  for (int i = 0; i < narchives && !a; i++) {
221  a = archives[narchives-1-i];
222 
223  if (_stricmp(a->Name(), archive_name))
224  a = 0;
225  }
226  }
227 
228  if (!a) {
229  ListFileSystem(filter, list, datapath, true);
230  return list.size();
231  }
232 
233  if (!strcmp(filter, "*.*")) {
234  int count = a->NumFiles();
235  for (int n = 0; n < count; n++) {
236  DataEntry* entry = a->GetFile(n);
237  Text entry_name = entry->name;
238  entry_name.setSensitive(false);
239 
240  if (entry_name.contains(datapath)) {
241  Text fname = entry_name(pathlen, 1000);
242 
243  if (!list.contains(&fname))
244  list.append(new Text(fname));
245  }
246  }
247  }
248  else {
249  char data_filter[256];
250  ZeroMemory(data_filter, 256);
251 
252  const char* pf = filter;
253  char* pdf = data_filter;
254 
255  while (*pf) {
256  if (*pf != '*')
257  *pdf++ = *pf;
258  pf++;
259  }
260 
261  int count = a->NumFiles();
262  for (int n = 0; n < count; n++) {
263  DataEntry* entry = a->GetFile(n);
264  Text entry_name = entry->name;
265  entry_name.setSensitive(false);
266 
267  if (entry_name.contains(datapath) && entry_name.contains(data_filter)) {
268  Text fname = entry_name(pathlen, 1000);
269 
270  if (!list.contains(&fname))
271  list.append(new Text(fname));
272  }
273  }
274  }
275 
276  return list.size();
277 }
278 
279 // +--------------------------------------------------------------------+
280 
281 void
282 DataLoader::ListFileSystem(const char* filter, List<Text>& list, Text base_path, bool recurse)
283 {
284  if (use_file_system) {
285  char data_filter[256];
286  ZeroMemory(data_filter, 256);
287 
288  const char* pf = filter;
289  char* pdf = data_filter;
290 
291  while (*pf) {
292  if (*pf != '*')
293  *pdf++ = *pf;
294  pf++;
295  }
296 
297  int pathlen = base_path.length();
298 
299  // assemble win32 find filter:
300  char win32_filter[1024];
301  strcpy_s(win32_filter, datapath);
302 
303  if (recurse)
304  strcat_s(win32_filter, "*.*");
305  else
306  strcat_s(win32_filter, filter);
307 
308  // first check current directory:
309  WIN32_FIND_DATA data;
310  HANDLE hFind = FindFirstFile(win32_filter, &data);
311 
312  if (hFind != INVALID_HANDLE_VALUE) {
313  do {
314  if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
315  if (recurse && data.cFileName[0] != '.') {
316  Text old_datapath = datapath;
317 
318  Text newpath = datapath;
319  newpath += data.cFileName;
320  newpath += "/";
321  datapath = newpath;
322 
323  ListFileSystem(filter, list, base_path, recurse);
324 
325  datapath = old_datapath;
326  }
327  }
328  else {
329  if (!strcmp(filter, "*.*") || strstr(data.cFileName, data_filter)) {
330  Text full_name = datapath;
331  full_name += data.cFileName;
332 
333  list.append(new Text(full_name(pathlen, 1000)));
334  }
335  }
336  }
337  while (FindNextFile(hFind, &data));
338  }
339  }
340 }
341 
342 // +--------------------------------------------------------------------+
343 
344 int
345 DataLoader::LoadBuffer(const char* name, BYTE*& buf, bool null_terminate, bool optional)
346 {
347  buf = 0;
348 
349  // assemble file name:
350  char filename[1024];
351  strcpy_s(filename, datapath);
352  strcat_s(filename, name);
353 
354  if (use_file_system) {
355  // first check current directory:
356  FILE* f;
357  ::fopen_s(&f, filename, "rb");
358 
359  if (f) {
360  ::fseek(f, 0, SEEK_END);
361  int len = ftell(f);
362  ::fseek(f, 0, SEEK_SET);
363 
364  if (null_terminate) {
365  buf = new(__FILE__,__LINE__) BYTE[len+1];
366  if (buf)
367  buf[len] = 0;
368  }
369 
370  else {
371  buf = new(__FILE__,__LINE__) BYTE[len];
372  }
373 
374  if (buf)
375  ::fread(buf, len, 1, f);
376 
377  ::fclose(f);
378 
379  return len;
380  }
381  }
382 
383  // then check datafile(s):
384  int narchives = archives.size();
385 
386  // vox files are usually in their own archive,
387  // so check there first
388  if (narchives > 1 && strstr(filename, "Vox")) {
389  for (int i = 0; i < narchives; i++) {
390  DataArchive* a = archives[narchives-1-i];
391  if (strstr(a->Name(), "vox")) {
392  int index = a->FindEntry(filename);
393  if (index > -1)
394  return a->ExpandEntry(index, buf, null_terminate);
395  }
396  }
397  }
398 
399  for (int i = 0; i < narchives; i++) {
400  DataArchive* a = archives[narchives-1-i];
401  int index = a->FindEntry(filename);
402  if (index > -1)
403  return a->ExpandEntry(index, buf, null_terminate);
404  }
405 
406  if (!optional)
407  Print("WARNING - DataLoader could not load buffer '%s'\n", filename);
408  return 0;
409 }
410 
411 // +--------------------------------------------------------------------+
412 
413 int
414 DataLoader::LoadPartialFile(const char* name, BYTE*& buf, int max_load, bool optional)
415 {
416  buf = 0;
417 
418  // assemble file name:
419  char filename[1024];
420  strcpy_s(filename, datapath);
421  strcat_s(filename, name);
422 
423  // first check current directory:
424  FILE* f;
425  ::fopen_s(&f, filename, "rb");
426 
427  if (f) {
428  ::fseek(f, 0, SEEK_END);
429  int len = ftell(f);
430  ::fseek(f, 0, SEEK_SET);
431 
432  if (len > max_load) {
433  len = max_load;
434  }
435 
436  buf = new(__FILE__,__LINE__) BYTE[len];
437 
438  if (buf)
439  ::fread(buf, len, 1, f);
440 
441  ::fclose(f);
442 
443  return len;
444  }
445 
446  if (!optional)
447  Print("WARNING - DataLoader could not load partial file '%s'\n", filename);
448  return 0;
449 }
450 
451 int
452 DataLoader::fread(void* buffer, size_t size, size_t count, BYTE*& stream)
453 {
454  CopyMemory(buffer, stream, size*count);
455  stream += size*count;
456 
457  return size*count;
458 }
459 
460 // +--------------------------------------------------------------------+
461 
462 void
464 {
465  delete [] buf;
466  buf = 0;
467 }
468 
469 // +--------------------------------------------------------------------+
470 
471 int
472 DataLoader::CacheBitmap(const char* name, Bitmap*& bitmap, int type, bool optional)
473 {
474  int result = 0;
475 
476  // search cache:
477  bitmap = Bitmap::CheckCache(name);
478  if (bitmap) return 1;
479 
480  // not in cache yet:
481  bitmap = new(__FILE__,__LINE__) Bitmap;
482 
483  if (bitmap)
484  result = LoadBitmap(name, *bitmap, type, optional);
485 
486  if (result && bitmap)
487  Bitmap::AddToCache(bitmap);
488 
489  return result;
490 }
491 
492 // +--------------------------------------------------------------------+
493 
494 int
495 DataLoader::LoadBitmap(const char* name, Bitmap& bitmap, int type, bool optional)
496 {
497  if (!enable_media)
498  return 0;
499 
500  int result = LoadIndexed(name, bitmap, type);
501 
502  // check for a matching high color bitmap:
503  if (result == 1) {
504  int hi_result = LoadHiColor(name, bitmap, type);
505 
506  if (hi_result == 2)
507  result = 3;
508  }
509 
510  bitmap.SetFilename(name);
511 
512  if (!result && !optional)
513  Print("WARNING - DataLoader could not load bitmap '%s%s'\n", datapath.data(), name);
514 
515  return result;
516 }
517 
518 // +--------------------------------------------------------------------+
519 
520 int
521 DataLoader::LoadTexture(const char* name, Bitmap*& bitmap, int type, bool preload_cache, bool optional)
522 {
523  if (!enable_media)
524  return 0;
525 
526  int result = 0;
527 
528  // assemble file name:
529  char filename[256];
530  strcpy_s(filename, datapath);
531  strcat_s(filename, name);
532 
533  // search cache:
534  bitmap = Bitmap::CheckCache(filename);
535  if (bitmap) return 1;
536 
537  // not in cache yet:
538  bitmap = new(__FILE__,__LINE__) Bitmap;
539 
540  if (bitmap) {
541  result = LoadHiColor(name, *bitmap, type);
542 
543  if (!result) {
544  result = LoadIndexed(name, *bitmap, type);
545  }
546 
547  bitmap->SetFilename(filename);
548 
549  if (result) {
550  bitmap->MakeTexture();
551  Bitmap::AddToCache(bitmap);
552  }
553  else {
554  delete bitmap;
555  bitmap = 0;
556 
557  if (!optional)
558  Print("WARNING - DataLoader could not load texture '%s%s'\n", datapath.data(), name);
559  }
560  }
561  else if (!optional) {
562  Print("WARNING - DataLoader could not allocate texture '%s%s'\n", datapath.data(), name);
563  }
564 
565  return result;
566 }
567 
568 // +--------------------------------------------------------------------+
569 
570 int
571 DataLoader::LoadIndexed(const char* name, Bitmap& bitmap, int type)
572 {
573  if (!enable_media)
574  return 0;
575 
576  int result = 0;
577  PcxImage pcx;
578  D3DXImage d3dx;
579  bool pcx_file = strstr(name, ".pcx") || strstr(name, ".PCX");
580 
581  // assemble file name:
582  char filename[256];
583  strcpy_s(filename, datapath);
584  strcat_s(filename, name);
585 
586  // first try to load from current directory:
587  bool loaded = false;
588 
589  if (use_file_system) {
590  if (pcx_file)
591  loaded = pcx.Load(filename) == PCX_OK;
592 
593  else
594  loaded = d3dx.Load(filename);
595  }
596 
597  if (!loaded) {
598  // then check datafile:
599  int len = 0;
600  BYTE* tmp_buf = 0;
601 
602  int narchives = archives.size();
603  for (int i = 0; i < narchives; i++) {
604  DataArchive* a = archives[narchives-1-i];
605  int index = a->FindEntry(filename);
606  if (index > -1) {
607  len = a->ExpandEntry(index, tmp_buf);
608 
609  if (pcx_file)
610  pcx.LoadBuffer(tmp_buf, len);
611 
612  else
613  d3dx.LoadBuffer(tmp_buf, len);
614 
615  ReleaseBuffer(tmp_buf);
616  break;
617  }
618  }
619  }
620 
621  // now copy the image into the bitmap:
622  if (pcx_file) {
623  if (pcx.bitmap) {
624  bitmap.CopyImage(pcx.width, pcx.height, pcx.bitmap, type);
625  result = 1;
626  }
627 
628  else if (pcx.himap) {
629  bitmap.CopyHighColorImage(pcx.width, pcx.height, pcx.himap, type);
630  result = 2;
631  }
632 
633  if (result == 2)
634  LoadAlpha(name, bitmap, type);
635  }
636 
637  else {
638  if (d3dx.image) {
639  bitmap.CopyHighColorImage(d3dx.width, d3dx.height, d3dx.image, type);
640  result = 2;
641  }
642 
643  if (result == 2) {
644  LoadAlpha(name, bitmap, type);
645  }
646  }
647 
648  return result;
649 }
650 
651 int
652 DataLoader::LoadHiColor(const char* name, Bitmap& bitmap, int type)
653 {
654  if (!enable_media)
655  return 0;
656 
657  int result = 0;
658  PcxImage pcx;
659  D3DXImage d3dx;
660  bool pcx_file = strstr(name, ".pcx") || strstr(name, ".PCX");
661  bool bmp_file = strstr(name, ".bmp") || strstr(name, ".BMP");
662  bool png_file = strstr(name, ".png") || strstr(name, ".PNG");
663 
664  // check for a matching high color bitmap:
665  char filename[256];
666  char name2[256];
667  strcpy_s(name2, name);
668 
669  char* dot = strrchr(name2, '.');
670  if (dot && pcx_file)
671  strcpy(dot, "+.pcx");
672  else if (dot && bmp_file)
673  strcpy(dot, "+.bmp");
674  else if (dot && png_file)
675  strcpy(dot, "+.png");
676  else
677  return result;
678 
679  strcpy_s(filename, datapath);
680  strcat_s(filename, name2);
681 
682  // first try to load from current directory:
683  bool loaded = false;
684 
685  if (use_file_system) {
686  if (pcx_file)
687  loaded = pcx.Load(filename) == PCX_OK;
688 
689  else
690  loaded = d3dx.Load(filename);
691  }
692 
693  if (!loaded) {
694  // then check datafile:
695  int len = 0;
696  BYTE* tmp_buf = 0;
697 
698  int narchives = archives.size();
699  for (int i = 0; i < narchives; i++) {
700  DataArchive* a = archives[narchives-1-i];
701  int index = a->FindEntry(filename);
702  if (index > -1) {
703  len = a->ExpandEntry(index, tmp_buf);
704 
705  if (pcx_file)
706  pcx.LoadBuffer(tmp_buf, len);
707  else
708  d3dx.LoadBuffer(tmp_buf, len);
709 
710  ReleaseBuffer(tmp_buf);
711  break;
712  }
713  }
714  }
715 
716  // now copy the image into the bitmap:
717  if (pcx_file && pcx.himap) {
718  bitmap.CopyHighColorImage(pcx.width, pcx.height, pcx.himap, type);
719  result = 2;
720  }
721 
722  else if (d3dx.image) {
723  bitmap.CopyHighColorImage(d3dx.width, d3dx.height, d3dx.image, type);
724  result = 2;
725  }
726 
727  if (result == 2)
728  LoadAlpha(name, bitmap, type);
729 
730  return result;
731 }
732 
733 int
734 DataLoader::LoadAlpha(const char* name, Bitmap& bitmap, int type)
735 {
736  if (!enable_media)
737  return 0;
738 
739  PcxImage pcx;
740  D3DXImage d3dx;
741  bool pcx_file = strstr(name, ".pcx") || strstr(name, ".PCX");
742  bool bmp_file = strstr(name, ".bmp") || strstr(name, ".BMP");
743  bool png_file = strstr(name, ".png") || strstr(name, ".PNG");
744  bool tga_file = strstr(name, ".tga") || strstr(name, ".TGA");
745 
746  // check for an associated alpha-only (grayscale) bitmap:
747  char filename[256];
748  char name2[256];
749  strcpy_s(name2, name);
750  char* dot = strrchr(name2, '.');
751  if (dot && pcx_file)
752  strcpy(dot, "@.pcx");
753  else if (dot && bmp_file)
754  strcpy(dot, "@.bmp");
755  else if (dot && png_file)
756  strcpy(dot, "@.png");
757  else if (dot && tga_file)
758  strcpy(dot, "@.tga");
759  else
760  return 0;
761 
762  strcpy_s(filename, datapath);
763  strcat_s(filename, name2);
764 
765  // first try to load from current directory:
766  bool loaded = false;
767 
768  if (use_file_system) {
769  if (pcx_file)
770  loaded = pcx.Load(filename) == PCX_OK;
771 
772  else
773  loaded = d3dx.Load(filename);
774  }
775 
776  if (!loaded) {
777  // then check datafile:
778  int len = 0;
779  BYTE* tmp_buf = 0;
780 
781  int narchives = archives.size();
782  for (int i = 0; i < narchives; i++) {
783  DataArchive* a = archives[narchives-1-i];
784  int index = a->FindEntry(filename);
785  if (index > -1) {
786  len = a->ExpandEntry(index, tmp_buf);
787 
788  if (pcx_file)
789  pcx.LoadBuffer(tmp_buf, len);
790  else
791  d3dx.LoadBuffer(tmp_buf, len);
792 
793  ReleaseBuffer(tmp_buf);
794  break;
795  }
796  }
797  }
798 
799  // now copy the alpha values into the bitmap:
800  if (pcx_file && pcx.bitmap) {
801  bitmap.CopyAlphaImage(pcx.width, pcx.height, pcx.bitmap);
802  }
803  else if (pcx_file && pcx.himap) {
804  bitmap.CopyAlphaRedChannel(pcx.width, pcx.height, pcx.himap);
805  }
806  else if (d3dx.image) {
807  bitmap.CopyAlphaRedChannel(d3dx.width, d3dx.height, d3dx.image);
808  }
809 
810  return 0;
811 }
812 
813 // +--------------------------------------------------------------------+
814 
815 int
816 DataLoader::LoadSound(const char* name, Sound*& snd, DWORD flags, bool optional)
817 {
818  if (!enable_media)
819  return 0;
820 
821  if (strstr(name, ".ogg"))
822  return LoadStream(name, snd, optional);
823 
824  int result = 0;
825 
826  WAVE_HEADER head;
827  WAVE_FMT fmt;
828  WAVE_FACT fact;
829  WAVE_DATA data;
830  WAVEFORMATEX wfex;
831  LPBYTE wave;
832 
833  LPBYTE buf;
834  LPBYTE p;
835  int len;
836 
837  ZeroMemory(&head, sizeof(head));
838  ZeroMemory(&fmt, sizeof(fmt));
839  ZeroMemory(&fact, sizeof(fact));
840  ZeroMemory(&data, sizeof(data));
841 
842  len = LoadBuffer(name, buf, false, optional);
843 
844  if (len > sizeof(head)) {
845  CopyMemory(&head, buf, sizeof(head));
846 
847  if (head.RIFF == MAKEFOURCC('R', 'I', 'F', 'F') &&
848  head.WAVE == MAKEFOURCC('W', 'A', 'V', 'E')) {
849 
850  p = buf + sizeof(WAVE_HEADER);
851 
852  do {
853  DWORD chunk_id = *((LPDWORD) p);
854 
855  switch (chunk_id) {
856  case MAKEFOURCC('f', 'm', 't', ' '):
857  CopyMemory(&fmt, p, sizeof(fmt));
858  p += fmt.chunk_size + 8;
859  break;
860 
861  case MAKEFOURCC('f', 'a', 'c', 't'):
862  CopyMemory(&fact, p, sizeof(fact));
863  p += fact.chunk_size + 8;
864  break;
865 
866  case MAKEFOURCC('s', 'm', 'p', 'l'):
867  CopyMemory(&fact, p, sizeof(fact));
868  p += fact.chunk_size + 8;
869  break;
870 
871  case MAKEFOURCC('d', 'a', 't', 'a'):
872  CopyMemory(&data, p, sizeof(data));
873  p += 8;
874  break;
875 
876  default:
877  ReleaseBuffer(buf);
878  return result;
879  }
880  }
881  while (data.chunk_size == 0);
882 
883  wfex.wFormatTag = fmt.wFormatTag;
884  wfex.nChannels = fmt.nChannels;
885  wfex.nSamplesPerSec = fmt.nSamplesPerSec;
886  wfex.nAvgBytesPerSec = fmt.nAvgBytesPerSec;
887  wfex.nBlockAlign = fmt.nBlockAlign;
888  wfex.wBitsPerSample = fmt.wBitsPerSample;
889  wfex.cbSize = 0;
890  wave = p;
891 
892  snd = Sound::Create(flags, &wfex, data.chunk_size, wave);
893 
894  if (snd)
895  result = data.chunk_size;
896  }
897  }
898 
899  ReleaseBuffer(buf);
900  return result;
901 }
902 
903 int
904 DataLoader::LoadStream(const char* name, Sound*& snd, bool optional)
905 {
906  if (!enable_media)
907  return 0;
908 
909  if (!name)
910  return 0;
911 
912  int namelen = strlen(name);
913 
914  if (namelen < 5)
915  return 0;
916 
917  if ((name[namelen-3] == 'o' || name[namelen-3] == 'O') &&
918  (name[namelen-2] == 'g' || name[namelen-2] == 'G') &&
919  (name[namelen-1] == 'g' || name[namelen-1] == 'G')) {
920 
921  return LoadOggStream(name, snd);
922  }
923 
924  int result = 0;
925 
926  WAVE_HEADER head;
927  WAVE_FMT fmt;
928  WAVE_FACT fact;
929  WAVE_DATA data;
930  WAVEFORMATEX wfex;
931 
932  LPBYTE buf;
933  LPBYTE p;
934  int len;
935 
936  ZeroMemory(&head, sizeof(head));
937  ZeroMemory(&fmt, sizeof(fmt));
938  ZeroMemory(&fact, sizeof(fact));
939  ZeroMemory(&data, sizeof(data));
940 
941  len = LoadPartialFile(name, buf, 4096, optional);
942 
943  if (len > sizeof(head)) {
944  CopyMemory(&head, buf, sizeof(head));
945 
946  if (head.RIFF == MAKEFOURCC('R', 'I', 'F', 'F') &&
947  head.WAVE == MAKEFOURCC('W', 'A', 'V', 'E')) {
948 
949  p = buf + sizeof(WAVE_HEADER);
950 
951  do {
952  DWORD chunk_id = *((LPDWORD) p);
953 
954  switch (chunk_id) {
955  case MAKEFOURCC('f', 'm', 't', ' '):
956  CopyMemory(&fmt, p, sizeof(fmt));
957  p += fmt.chunk_size + 8;
958  break;
959 
960  case MAKEFOURCC('f', 'a', 'c', 't'):
961  CopyMemory(&fact, p, sizeof(fact));
962  p += fact.chunk_size + 8;
963  break;
964 
965  case MAKEFOURCC('s', 'm', 'p', 'l'):
966  CopyMemory(&fact, p, sizeof(fact));
967  p += fact.chunk_size + 8;
968  break;
969 
970  case MAKEFOURCC('d', 'a', 't', 'a'):
971  CopyMemory(&data, p, sizeof(data));
972  p += 8;
973  break;
974 
975  default:
976  ReleaseBuffer(buf);
977  return result;
978  }
979  }
980  while (data.chunk_size == 0);
981 
982  wfex.wFormatTag = fmt.wFormatTag;
983  wfex.nChannels = fmt.nChannels;
984  wfex.nSamplesPerSec = fmt.nSamplesPerSec;
985  wfex.nAvgBytesPerSec = fmt.nAvgBytesPerSec;
986  wfex.nBlockAlign = fmt.nBlockAlign;
987  wfex.wBitsPerSample = fmt.wBitsPerSample;
988  wfex.cbSize = 0;
989 
990  snd = Sound::Create(Sound::STREAMED, &wfex);
991 
992  if (snd) {
993  // assemble file name:
994  char filename[1024];
995  strcpy_s(filename, datapath);
996  strcat_s(filename, name);
997 
998  snd->StreamFile(filename, p - buf);
999 
1000  result = data.chunk_size;
1001  }
1002  }
1003  }
1004 
1005  ReleaseBuffer(buf);
1006  return result;
1007 }
1008 
1009 int
1010 DataLoader::LoadOggStream(const char* name, Sound*& snd)
1011 {
1012  if (!enable_media)
1013  return 0;
1014 
1015  snd = Sound::CreateOggStream(name);
1016 
1017  return snd != 0;
1018 }