CDFILE.CPP (34803B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /* $Header: /CounterStrike/CDFILE.CPP 1 3/03/97 10:24a Joe_bostic $ */ 17 /*********************************************************************************************** 18 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Westwood Library * 22 * * 23 * File Name : CDFILE.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : October 18, 1994 * 28 * * 29 * Last Update : September 22, 1995 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * CDFileClass::Clear_Search_Drives -- Removes all record of a search path. * 34 * CDFileClass::Open -- Opens the file object -- with path search. * 35 * CDFileClass::Open -- Opens the file wherever it can be found. * 36 * CDFileClass::Set_Name -- Performs a multiple directory scan to set the filename. * 37 * CDFileClass::Set_Search_Drives -- Sets a list of search paths for file access. * 38 * Is_Disk_Inserted -- Checks to see if a disk is inserted in specified drive. * 39 * harderr_handler -- Handles hard DOS errors. * 40 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 41 42 43 #include "cdfile.h" 44 #include <stdio.h> 45 #include <string.h> 46 47 #ifndef WIN32 48 #include <wwstd.h> 49 #include <playcd.h> 50 #endif 51 52 /* 53 ** Pointer to the first search path record. 54 */ 55 CDFileClass::SearchDriveType * CDFileClass::First = 0; 56 57 int CDFileClass::CurrentCDDrive = 0; 58 int CDFileClass::LastCDDrive = 0; 59 char CDFileClass::RawPath[512] = {0}; 60 61 CDFileClass::CDFileClass(char const *filename) : 62 IsDisabled(false) 63 { 64 CDFileClass::Set_Name(filename); 65 // memset (RawPath, 0, sizeof(RawPath)); 66 } 67 68 69 CDFileClass::CDFileClass(void) : 70 IsDisabled(false) 71 { 72 } 73 extern int Get_CD_Index (int cd_drive, int timeout); 74 75 /*********************************************************************************************** 76 * harderr_handler -- Handles hard DOS errors. * 77 * * 78 * This routine will handle the low level DOS error trapper. Instead of displaying the * 79 * typical "Abort, Retry, Ignore" message, it simply returns with the failure code. The * 80 * cause of the error will fail. The likely case would be with disk I/O. * 81 * * 82 * INPUT: * 83 * * 84 * OUTPUT: Return the failure code. * 85 * * 86 * WARNINGS: Do no processing in this routine that could possibly generate another * 87 * hard error condition. * 88 * * 89 * HISTORY: * 90 * 09/22/1995 JLB : Created. * 91 *=============================================================================================*/ 92 #ifdef WIN32 93 int harderr_handler(unsigned int , unsigned int , unsigned int *) 94 #else 95 int harderr_handler(unsigned int , unsigned int , unsigned int __far *) 96 #endif 97 { 98 return(0); // _HARDERR_FAIL); 99 } 100 101 102 /*********************************************************************************************** 103 * Is_Disk_Inserted -- Checks to see if a disk is inserted in specified drive. * 104 * * 105 * This routine will examine the drive specified to see if there is a disk inserted. It * 106 * can be used for floppy drives as well as for the CD-ROM. * 107 * * 108 * INPUT: disk -- The drive number to examine. 0=A, 1=B, etc. * 109 * * 110 * OUTPUT: bool; Is a disk inserted into the specified drive? * 111 * * 112 * WARNINGS: none * 113 * * 114 * HISTORY: * 115 * 09/20/1995 JLB : Created. * 116 *=============================================================================================*/ 117 int cdecl Is_Disk_Inserted(int disk) 118 { 119 #ifndef OBSOLETE 120 disk; 121 return true; 122 #if (0) 123 struct find_t fb; 124 char scan[] = "?:\\*.*"; 125 126 #ifndef WIN32 127 _harderr(harderr_handler); // BG: Install hard error handler 128 #endif 129 130 scan[0] = (char)('A' + disk); 131 return(_dos_findfirst(scan, _A_SUBDIR, &fb) == 0); 132 #endif 133 #else 134 struct { 135 struct { 136 char Length; 137 char Unit; 138 char Function; 139 char Status; 140 char Reserved[8]; 141 } ReqHdr; 142 char MediaDescriptor; // Media descriptor byte from BPB. 143 void *Transfer; // Pointer to transfer address block. 144 short Length; // Number of bytes to transfer. 145 short Sector; // Starting sector number. 146 void *Volume; // Pointer to requested volume. 147 } IOCTLI; 148 char status[5]; 149 150 memset(IOCTLI, 0, sizeof(IOCTLI)); 151 IOCTLI.ReqHdr.Length = 26; 152 IOCTLI.ReqHdr.Unit = 0; // First CD-ROM controlled by this driver. 153 //IOCTLI.ReqHdr.Unit = 11; // Hard coded for K: 154 IOCTLI.ReqHdr.Function = 3; // IOCTL read 155 IOCTLI.Transfer = &status[0]; 156 IOCTLI.Length = sizeof(status); 157 status[0] = 6; // Fetch device status code. 158 _AX = 0x440D; 159 _CX = 0x0003; 160 geninterrupt(0x21); 161 return(!(_AX & (1<<11))); 162 #endif 163 } 164 165 166 /*********************************************************************************************** 167 * CDFileClass::Open -- Opens the file object -- with path search. * 168 * * 169 * This will open the file object, but since the file object could have been constructed * 170 * with a pathname, this routine will try to find the file first. For files opened for * 171 * writing, then use the existing filename without performing a path search. * 172 * * 173 * INPUT: rights -- The access rights to use when opening the file * 174 * * 175 * OUTPUT: bool; Was the open successful? * 176 * * 177 * WARNINGS: none * 178 * * 179 * HISTORY: * 180 * 10/18/1994 JLB : Created. * 181 *=============================================================================================*/ 182 int CDFileClass::Open(int rights) 183 { 184 return(BufferIOFileClass::Open(rights)); 185 } 186 /*********************************************************************************************** 187 * CDFC::Refresh_Search_Drives -- Updates the search path when a CD changes or is added * 188 * * 189 * * 190 * * 191 * INPUT: Nothing * 192 * * 193 * OUTPUT: Nothing * 194 * * 195 * WARNINGS: None * 196 * * 197 * HISTORY: * 198 * 5/22/96 9:01AM ST : Created * 199 *=============================================================================================*/ 200 void CDFileClass::Refresh_Search_Drives (void) 201 { 202 Clear_Search_Drives(); 203 Set_Search_Drives(RawPath); 204 } 205 206 #if 0 207 /*********************************************************************************************** 208 * CDFileClass::Set_Search_Drives -- Sets a list of search paths for file access. * 209 * * 210 * This routine sets up a list of search paths to use when accessing files. The path list * 211 * is scanned if the file could not be found in the current directory. This is the primary * 212 * method of supporting CD-ROM drives, but is also useful for scanning network and other * 213 * directories. The pathlist as passed to this routine is of the same format as the path * 214 * list used by DOS -- paths are separated by semicolons and need not end in an antivirgule.* 215 * * 216 * If a path entry begins with "?:" then the question mark will be replaced with the first * 217 * CD-ROM drive letter available. If there is no CD-ROM driver detected, then this path * 218 * entry will be ignored. By using this feature, you can always pass the CD-ROM path * 219 * specification to this routine and it will not break if the CD-ROM is not loaded (as in * 220 * the case during development). * 221 * * 222 * Here is an example path specification: * 223 * * 224 * Set_Search_Drives("DATA;?:\DATA;F:\PROJECT\DATA"); * 225 * * 226 * In this example, the current directory will be searched first, followed by a the * 227 * subdirectory "DATA" located off of the current directory. If not found, then the CD-ROM * 228 * will be searched in a directory called "\DATA". If not found or the CD-ROM is not * 229 * present, then it will look to the hard coded path of "F:\PROJECTS\DATA" (maybe a * 230 * network?). If all of these searches fail, the file system will default to the current * 231 * directory and let the normal file error system take over. * 232 * * 233 * INPUT: pathlist -- Pointer to string of path specifications (separated by semicolons) * 234 * that will be used to search for files. * 235 * * 236 * OUTPUT: none * 237 * * 238 * WARNINGS: none * 239 * * 240 * HISTORY: * 241 * 10/18/1994 JLB : Created. * 242 *=============================================================================================*/ 243 int CDFileClass::Set_Search_Drives(char * pathlist) 244 { 245 int found = false; 246 int empty = false; 247 248 /* 249 ** If there is no pathlist to add, then just return. 250 */ 251 if (!pathlist) return(0); 252 253 char const * ptr = strtok(pathlist, ";"); 254 while (ptr) { 255 char path[PATH_MAX]; // Working path buffer. 256 SearchDriveType *srch; // Working pointer to path object. 257 258 /* 259 ** Fixup the path to be legal. Legal is defined as all that is necessary to 260 ** create a pathname is to append the actual filename submitted to the 261 ** file system. This means that it must have either a trailing ':' or '\' 262 ** character. 263 */ 264 strcpy(path, ptr); 265 switch (path[strlen(path)-1]) { 266 case ':': 267 case '\\': 268 break; 269 270 default: 271 strcat(path, "\\"); 272 break; 273 } 274 275 /* 276 ** If there is a drive letter specified, and this drive letter is '?', then it should 277 ** be substituted with the CD-ROM drive letter. In the case of no CD-ROM attached, then 278 ** merely ignore this path entry. 279 */ 280 if (strncmp(path, "?:", 2) == 0) { 281 #ifndef WIN32 282 GetCDClass temp; 283 int cd = temp.GetCDDrive(); 284 #else 285 int cd = 10; 286 #endif 287 found = cd; 288 empty = !Is_Disk_Inserted(cd); 289 if (!found || empty) goto nextpath; 290 path[0] = (char)('A' + cd); 291 } 292 293 /* 294 ** Allocate a record structure. 295 */ 296 srch = new SearchDriveType; 297 if (srch) { 298 found = true; 299 300 /* 301 ** Attach the path to this structure. 302 */ 303 srch->Path = strdup(path); 304 srch->Next = NULL; 305 306 /* 307 ** Attach this path record to the end of the path chain. 308 */ 309 if (!First) { 310 First = srch; 311 } else { 312 SearchDriveType * chain = First; 313 314 while (chain->Next) { 315 chain = (SearchDriveType *)chain->Next; 316 } 317 chain->Next = srch; 318 } 319 } 320 321 /* 322 ** Find the next path string and resubmit. 323 */ 324 nextpath: 325 ptr = strtok(NULL, ";"); 326 } 327 if (!found) return(1); 328 if (empty) return(2); 329 return(0); 330 } 331 #endif 332 333 334 /*********************************************************************************************** 335 * CDFileClass::Set_Search_Drives -- Sets a list of search paths for file access. * 336 * * 337 * This routine sets up a list of search paths to use when accessing files. The path list * 338 * is scanned if the file could not be found in the current directory. This is the primary * 339 * method of supporting CD-ROM drives, but is also useful for scanning network and other * 340 * directories. The pathlist as passed to this routine is of the same format as the path * 341 * list used by DOS -- paths are separated by semicolons and need not end in an antivirgule.* 342 * * 343 * If a path entry begins with "?:" then the question mark will be replaced with the first * 344 * CD-ROM drive letter available. If there is no CD-ROM driver detected, then this path * 345 * entry will be ignored. By using this feature, you can always pass the CD-ROM path * 346 * specification to this routine and it will not break if the CD-ROM is not loaded (as in * 347 * the case during development). * 348 * * 349 * Here is an example path specification: * 350 * * 351 * Set_Search_Drives("DATA;?:\DATA;F:\PROJECT\DATA"); * 352 * * 353 * In this example, the current directory will be searched first, followed by a the * 354 * subdirectory "DATA" located off of the current directory. If not found, then the CD-ROM * 355 * will be searched in a directory called "\DATA". If not found or the CD-ROM is not * 356 * present, then it will look to the hard coded path of "F:\PROJECTS\DATA" (maybe a * 357 * network?). If all of these searches fail, the file system will default to the current * 358 * directory and let the normal file error system take over. * 359 * * 360 * INPUT: pathlist -- Pointer to string of path specifications (separated by semicolons) * 361 * that will be used to search for files. * 362 * * 363 * OUTPUT: none * 364 * * 365 * WARNINGS: none * 366 * * 367 * HISTORY: * 368 * 10/18/1994 JLB : Created. * 369 * 05/21/1996 ST : Modified to recognise multiple CD drives * 370 *=============================================================================================*/ 371 int CDFileClass::Set_Search_Drives(char * pathlist) 372 { 373 int found = FALSE; 374 int empty = FALSE; 375 376 /* 377 ** If there is no pathlist to add, then just return. 378 */ 379 if (!pathlist) return(0); 380 381 /* 382 ** Save the path as it was passed in so we can parse it again later. 383 ** Check for the case where RawPath was passed in. 384 */ 385 if (pathlist != RawPath) { 386 strcat (RawPath, ";"); 387 strcat (RawPath, pathlist); 388 } 389 390 char const * ptr = strtok(pathlist, ";"); 391 while (ptr != NULL) { 392 if (strlen(ptr) > 0) { 393 394 char path[MAX_PATH]; // Working path buffer. 395 396 /* 397 ** Fixup the path to be legal. Legal is defined as all that is necessary to 398 ** create a pathname is to append the actual filename submitted to the 399 ** file system. This means that it must have either a trailing ':' or '\' 400 ** character. 401 */ 402 strcpy(path, ptr); 403 switch (path[strlen(path)-1]) { 404 case ':': 405 case '\\': 406 break; 407 408 default: 409 strcat(path, "\\"); 410 break; 411 } 412 413 /* 414 ** If there is a drive letter specified, and this drive letter is '?', then it should 415 ** be substituted with the CD-ROM drive letter. In the case of no CD-ROM attached, then 416 ** merely ignore this path entry. 417 ** Adds an extra entry for each CD drive in the system that has a C&C disc inserted. 418 ** ST - 5/21/96 4:40PM 419 */ 420 if (strncmp(path, "?:", 2) == 0) { 421 if (CurrentCDDrive) { 422 found = true; 423 424 /* 425 ** If the drive has a C&C CD in it then add it to the path 426 */ 427 if (Get_CD_Index(CurrentCDDrive, 2*60) >= 0) { 428 path[0] = (char)(CurrentCDDrive + 'A'); 429 Add_Search_Drive(path); 430 } 431 } 432 433 /* 434 ** Find the next path string and resubmit. 435 */ 436 ptr = strtok(NULL, ";"); 437 continue; 438 } 439 440 found = true; 441 Add_Search_Drive(path); 442 } 443 444 /* 445 ** Find the next path string and resubmit. 446 */ 447 ptr = strtok(NULL, ";"); 448 } 449 if (!found) return(1); 450 if (empty) return(2); 451 return(0); 452 } 453 454 455 /*********************************************************************************************** 456 * CDFC::Add_Search_Drive -- Add a new path to the search path list * 457 * * 458 * * 459 * * 460 * INPUT: path * 461 * * 462 * OUTPUT: Nothing * 463 * * 464 * WARNINGS: None * 465 * * 466 * HISTORY: * 467 * 5/22/96 10:12AM ST : Created * 468 *=============================================================================================*/ 469 void CDFileClass::Add_Search_Drive(char *path) 470 { 471 SearchDriveType *srch; // Working pointer to path object. 472 /* 473 ** Allocate a record structure. 474 */ 475 srch = new SearchDriveType; 476 477 /* 478 ** Attach the path to this structure. 479 */ 480 srch->Path = strdup(path); 481 srch->Next = NULL; 482 483 /* 484 ** Attach this path record to the end of the path chain. 485 */ 486 if (!First) { 487 First = srch; 488 } else { 489 SearchDriveType * chain = First; 490 491 while (chain->Next) { 492 chain = (SearchDriveType *)chain->Next; 493 } 494 chain->Next = srch; 495 } 496 } 497 498 499 /*********************************************************************************************** 500 * CDFC::Set_CD_Drive -- sets the current CD drive letter * 501 * * 502 * * 503 * * 504 * INPUT: Nothing * 505 * * 506 * OUTPUT: Nothing * 507 * * 508 * WARNINGS: None * 509 * * 510 * HISTORY: * 511 * 5/22/96 9:39AM ST : Created * 512 *=============================================================================================*/ 513 void CDFileClass::Set_CD_Drive (int drive) 514 { 515 LastCDDrive = CurrentCDDrive; 516 CurrentCDDrive = drive; 517 } 518 519 520 /*********************************************************************************************** 521 * CDFileClass::Clear_Search_Drives -- Removes all record of a search path. * 522 * * 523 * Use this routine to clear out any previous path(s) set with Set_Search_Drives() * 524 * function. * 525 * * 526 * INPUT: none * 527 * * 528 * OUTPUT: none * 529 * * 530 * WARNINGS: none * 531 * * 532 * HISTORY: * 533 * 10/18/1994 JLB : Created. * 534 *=============================================================================================*/ 535 void CDFileClass::Clear_Search_Drives(void) 536 { 537 SearchDriveType * chain; // Working pointer to path chain. 538 539 chain = First; 540 while (chain) { 541 SearchDriveType *next; 542 543 next = (SearchDriveType *)chain->Next; 544 if (chain->Path) { 545 free((char *)chain->Path); 546 } 547 delete chain; 548 549 chain = next; 550 } 551 First = 0; 552 } 553 554 555 /*********************************************************************************************** 556 * CDFileClass::Set_Name -- Performs a multiple directory scan to set the filename. * 557 * * 558 * This routine will scan all the directories specified in the path list and if the file * 559 * was found in one of the directories, it will set the filename to a composite of the * 560 * correct directory and the filename. It is used to allow path searching when searching * 561 * for files. Typical use is to support CD-ROM drives. This routine examines the current * 562 * directory first before scanning through the path list. If after scanning the entire * 563 * path list, the file still could not be found, then the file object's name is set with * 564 * just the raw filename as passed to this routine. * 565 * * 566 * INPUT: filename -- Pointer to the filename to set as the name of this file object. * 567 * * 568 * OUTPUT: Returns a pointer to the final and complete filename of this file object. This * 569 * may have a path attached to the file. * 570 * * 571 * WARNINGS: none * 572 * * 573 * HISTORY: * 574 * 10/18/1994 JLB : Created. * 575 *=============================================================================================*/ 576 char const * CDFileClass::Set_Name(char const *filename) 577 { 578 /* 579 ** Try to find the file in the current directory first. If it can be found, then 580 ** just return with the normal file name setting process. Do the same if there is 581 ** no multi-drive search path. 582 */ 583 BufferIOFileClass::Set_Name(filename); 584 if (IsDisabled || !First || BufferIOFileClass::Is_Available()) return(File_Name()); 585 586 /* 587 ** Attempt to find the file first. Check the current directory. If not found there, then 588 ** search all the path specifications available. If it still can't be found, then just 589 ** fall into the normal raw file filename setting system. 590 */ 591 SearchDriveType * srch = First; 592 593 while (srch) { 594 char path[_MAX_PATH]; 595 596 /* 597 ** Build a pathname to search for. 598 */ 599 strcpy(path, srch->Path); 600 strcat(path, filename); 601 602 /* 603 ** Check to see if the file could be found. The low level Is_Available logic will 604 ** prompt if necessary when the CD-ROM drive has been removed. In all other cases, 605 ** it will return false and the search process will continue. 606 */ 607 BufferIOFileClass::Set_Name(path); 608 if (BufferIOFileClass::Is_Available()) { 609 return(File_Name()); 610 } 611 612 /* 613 ** It wasn't found, so try the next path entry. 614 */ 615 srch = (SearchDriveType *)srch->Next; 616 } 617 618 /* 619 ** At this point, all path searching has failed. Just set the file name to the 620 ** plain text passed to this routine and be done with it. 621 */ 622 BufferIOFileClass::Set_Name(filename); 623 return(File_Name()); 624 } 625 626 627 /*********************************************************************************************** 628 * CDFileClass::Open -- Opens the file wherever it can be found. * 629 * * 630 * This routine is similar to the RawFileClass open except that if the file is being * 631 * opened only for READ access, it will search all specified directories looking for the * 632 * file. If after a complete search the file still couldn't be found, then it is opened * 633 * using the normal BufferIOFileClass system -- resulting in normal error procedures. * 634 * * 635 * INPUT: filename -- Pointer to the override filename to supply for this file object. It * 636 * would be the base filename (sans any directory specification). * 637 * * 638 * rights -- The access rights to use when opening the file. * 639 * * 640 * OUTPUT: bool; Was the file opened successfully? If so then the filename may be different * 641 * than requested. The location of the file can be determined by examining the * 642 * filename of this file object. The filename will contain the complete * 643 * pathname used to open the file. * 644 * * 645 * WARNINGS: none * 646 * * 647 * HISTORY: * 648 * 10/18/1994 JLB : Created. * 649 *=============================================================================================*/ 650 int CDFileClass::Open(char const *filename, int rights) 651 { 652 CDFileClass::Close(); 653 654 /* 655 ** Verify that there is a filename associated with this file object. If not, then this is a 656 ** big error condition. 657 */ 658 if (!filename) { 659 Error(ENOENT, false); 660 } 661 662 /* 663 ** If writing is requested, then multiple drive searching is not performed. 664 */ 665 if (IsDisabled || rights == WRITE) { 666 667 BufferIOFileClass::Set_Name( filename ); 668 return( BufferIOFileClass::Open( rights ) ); 669 } 670 671 /* 672 ** Perform normal multiple drive searching for the filename and open 673 ** using the normal procedure. 674 */ 675 Set_Name(filename); 676 return(BufferIOFileClass::Open(rights)); 677 } 678 679 680 const char *CDFileClass::Get_Search_Path(int index) 681 { 682 if (First == NULL) { 683 return NULL; 684 } 685 686 SearchDriveType *sd = First; 687 688 for (int i = 0; i <= index; i++) { // We want to loop once, even if index==0 689 690 if (i == index) { 691 return sd->Path; 692 } 693 694 sd = (SearchDriveType *)sd->Next; 695 if (sd == NULL) { 696 return NULL; 697 } 698 } 699 700 return NULL; 701 } 702 703 704 705 #ifdef NEVER 706 /* 707 ** Get the drive letters if the CD's online */ 708 */ 709 WORD cdecl GetCDDrive(VOID) 710 { 711 _ES = FP_SEG(&cdDrive[0]); 712 _BX = FP_OFF(&cdDrive[0]); 713 _AX = 0x150d; 714 geninterrupt(0x2F); 715 return((WORD)(*cdDrive)); 716 } 717 #endif 718 719 #if 0 720 int Get_CD_Drive(void) 721 { 722 #ifdef WIN32 723 return(10); 724 #else 725 726 #ifdef NEVER 727 for (int index = 0; index < 26; index++) { 728 union REGS regs; 729 730 regs.w.ax = 0x150B; 731 regs.w.bx = 0; 732 regs.w.cx = index; 733 int386(0x2F, ®s, ®s); 734 if (regs.w.bx == 0xADAD) { 735 return(index); 736 } 737 } 738 return(0); 739 #else 740 GetCDClass temp; 741 return(temp.GetCDDrive()); 742 #endif 743 #endif 744 } 745 746 #endif