ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/IEC.cpp
(Generate patch)

Comparing Frodo4/Src/IEC.cpp (file contents):
Revision 1.2 by cebix, 2003-07-01T17:51:17Z vs.
Revision 1.9 by cebix, 2005-06-27T19:55:48Z

# Line 1 | Line 1
1   /*
2   *  IEC.cpp - IEC bus routines, 1541 emulation (DOS level)
3   *
4 < *  Frodo (C) 1994-1997,2002-2003 Christian Bauer
4 > *  Frodo (C) 1994-1997,2002-2005 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 49 | Line 49
49   #include "1541t64.h"
50   #include "Prefs.h"
51   #include "Display.h"
52 + #include "main.h"
53 +
54 +
55 + // IEC command codes
56 + enum {
57 +        CMD_DATA = 0x60,        // Data transfer
58 +        CMD_CLOSE = 0xe0,       // Close channel
59 +        CMD_OPEN = 0xf0         // Open channel
60 + };
61 +
62 + // IEC ATN codes
63 + enum {
64 +        ATN_LISTEN = 0x20,
65 +        ATN_UNLISTEN = 0x30,
66 +        ATN_TALK = 0x40,
67 +        ATN_UNTALK = 0x50
68 + };
69  
70  
71   /*
72   *  Constructor: Initialize variables
73   */
74  
75 + Drive *IEC::create_drive(const char *path)
76 + {
77 +        if (IsDirectory(path)) {
78 +                // Mount host directory
79 +                return new FSDrive(this, path);
80 +        } else {
81 +                // Not a directory, check for mountable file type
82 +                int type;
83 +                if (IsMountableFile(path, type)) {
84 +                        if (type == FILE_IMAGE) {
85 +                                // Mount disk image
86 +                                return new ImageDrive(this, path);
87 +                        } else {
88 +                                // Mount archive type file
89 +                                return new ArchDrive(this, path);
90 +                        }
91 +                } else {
92 +                        // Unknown file type
93 +                        // print error?
94 +                }
95 +        }
96 + }
97 +
98   IEC::IEC(C64Display *display) : the_display(display)
99   {
100          int i;
# Line 63 | Line 103 | IEC::IEC(C64Display *display) : the_disp
103          for (i=0; i<4; i++)
104                  drive[i] = NULL;        // Important because UpdateLEDs is called from the drive constructors (via set_error)
105  
106 <        if (!ThePrefs.Emul1541Proc)
107 <                for (i=0; i<4; i++) {
108 <                        if (ThePrefs.DriveType[i] == DRVTYPE_DIR)
109 <                                drive[i] = new FSDrive(this, ThePrefs.DrivePath[i]);
70 <                        else if (ThePrefs.DriveType[i] == DRVTYPE_D64)
71 <                                drive[i] = new D64Drive(this, ThePrefs.DrivePath[i]);
72 <                        else
73 <                                drive[i] = new T64Drive(this, ThePrefs.DrivePath[i]);
74 <                }
106 >        if (!ThePrefs.Emul1541Proc) {
107 >                for (i=0; i<4; i++)
108 >                        drive[i] = create_drive(ThePrefs.DrivePath[i]);
109 >        }
110  
111          listener_active = talker_active = false;
112          listening = false;
# Line 112 | Line 147 | void IEC::Reset(void)
147   void IEC::NewPrefs(Prefs *prefs)
148   {
149          // Delete and recreate all changed drives
150 <        for (int i=0; i<4; i++)
151 <                if ((ThePrefs.DriveType[i] != prefs->DriveType[i]) || strcmp(ThePrefs.DrivePath[i], prefs->DrivePath[i]) || ThePrefs.Emul1541Proc != prefs->Emul1541Proc) {
150 >        for (int i=0; i<4; i++) {
151 >                if (strcmp(ThePrefs.DrivePath[i], prefs->DrivePath[i]) || ThePrefs.Emul1541Proc != prefs->Emul1541Proc) {
152                          delete drive[i];
153                          drive[i] = NULL;        // Important because UpdateLEDs is called from drive constructors (via set_error())
154 <                        if (!prefs->Emul1541Proc) {
155 <                                if (prefs->DriveType[i] == DRVTYPE_DIR)
121 <                                        drive[i] = new FSDrive(this, prefs->DrivePath[i]);
122 <                                else if (prefs->DriveType[i] == DRVTYPE_D64)
123 <                                        drive[i] = new D64Drive(this, prefs->DrivePath[i]);
124 <                                else
125 <                                        drive[i] = new T64Drive(this, prefs->DrivePath[i]);
126 <                        }
154 >                        if (!prefs->Emul1541Proc)
155 >                                drive[i] = create_drive(prefs->DrivePath[i]);
156                  }
157 +        }
158  
159          UpdateLEDs();
160   }
# Line 210 | Line 240 | uint8 IEC::OutSec(uint8 byte)
240   *  Read one byte
241   */
242  
243 < uint8 IEC::In(uint8 *byte)
243 > uint8 IEC::In(uint8 &byte)
244   {
245          if (talker_active && (received_cmd == CMD_DATA))
246                  return data_in(byte);
247  
248 <        *byte = 0;
248 >        byte = 0;
249          return ST_TIMEOUT;
250   }
251  
# Line 367 | Line 397 | uint8 IEC::open_out(uint8 byte, bool eoi
397                  *name_ptr = 0;                          // End string
398                  listener->LED = DRVLED_ON;      // Turn on drive LED
399                  UpdateLEDs();
400 <                return listener->Open(sec_addr, name_buf);
400 >                return listener->Open(sec_addr, name_buf, name_len);
401          }
402  
403          return ST_OK;
# Line 388 | Line 418 | uint8 IEC::data_out(uint8 byte, bool eoi
418   *  Read byte from channel
419   */
420  
421 < uint8 IEC::data_in(uint8 *byte)
421 > uint8 IEC::data_in(uint8 &byte)
422   {
423          return talker->Read(sec_addr, byte);
424   }
# Line 412 | Line 442 | Drive::Drive(IEC *iec)
442   */
443  
444   // 1541 error messages
445 < char *Errors_1541[] = {
446 <        "00, OK,00,00\r",
447 <        "25,WRITE ERROR,00,00\r",
448 <        "26,WRITE PROTECT ON,00,00\r",
449 <        "30,SYNTAX ERROR,00,00\r",
450 <        "33,SYNTAX ERROR,00,00\r",
451 <        "60,WRITE FILE OPEN,00,00\r",
452 <        "61,FILE NOT OPEN,00,00\r",
453 <        "62,FILE NOT FOUND,00,00\r",
454 <        "67,ILLEGAL TRACK OR SECTOR,00,00\r",
455 <        "70,NO CHANNEL,00,00\r",
456 <        "73,CBM DOS V2.6 1541,00,00\r",
457 <        "74,DRIVE NOT READY,00,00\r"
445 > static const char *Errors_1541[] = {
446 >        "00, OK,%02d,%02d\x0d",
447 >        "01, FILES SCRATCHED,%02d,%02d\x0d",
448 >        "03, UNIMPLEMENTED,%02d,%02d\x0d",
449 >        "20, READ ERROR,%02d,%02d\x0d",
450 >        "21, READ ERROR,%02d,%02d\x0d",
451 >        "22, READ ERROR,%02d,%02d\x0d",
452 >        "23, READ ERROR,%02d,%02d\x0d",
453 >        "24, READ ERROR,%02d,%02d\x0d",
454 >        "25, WRITE ERROR,%02d,%02d\x0d",
455 >        "26, WRITE PROTECT ON,%02d,%02d\x0d",
456 >        "27, READ ERROR,%02d,%02d\x0d",
457 >        "28, WRITE ERROR,%02d,%02d\x0d",
458 >        "29, DISK ID MISMATCH,%02d,%02d\x0d",
459 >        "30, SYNTAX ERROR,%02d,%02d\x0d",
460 >        "31, SYNTAX ERROR,%02d,%02d\x0d",
461 >        "32, SYNTAX ERROR,%02d,%02d\x0d",
462 >        "33, SYNTAX ERROR,%02d,%02d\x0d",
463 >        "34, SYNTAX ERROR,%02d,%02d\x0d",
464 >        "60, WRITE FILE OPEN,%02d,%02d\x0d",
465 >        "61, FILE NOT OPEN,%02d,%02d\x0d",
466 >        "62, FILE NOT FOUND,%02d,%02d\x0d",
467 >        "63, FILE EXISTS,%02d,%02d\x0d",
468 >        "64, FILE TYPE MISMATCH,%02d,%02d\x0d",
469 >        "65, NO BLOCK,%02d,%02d\x0d",
470 >        "66, ILLEGAL TRACK OR SECTOR,%02d,%02d\x0d",
471 >        "70, NO CHANNEL,%02d,%02d\x0d",
472 >        "71, DIR ERROR,%02d,%02d\x0d",
473 >        "72, DISK FULL,%02d,%02d\x0d",
474 >        "73, CBM DOS V2.6 1541,%02d,%02d\x0d",
475 >        "74, DRIVE NOT READY,%02d,%02d\x0d"
476   };
477  
478 < void Drive::set_error(int error)
478 > void Drive::set_error(int error, int track, int sector)
479   {
480 <        error_ptr = Errors_1541[error];
481 <        error_len = strlen(error_ptr);
480 >        // Write error message to buffer
481 >        sprintf(error_buf, Errors_1541[error], track, sector);
482 >        error_ptr = error_buf;
483 >        error_len = strlen(error_buf);
484 >        current_error = error;
485  
486          // Set drive condition
487 <        if (error != ERR_OK)
487 >        if (error != ERR_OK && error != ERR_SCRATCHED)
488                  if (error == ERR_STARTUP)
489                          LED = DRVLED_OFF;
490                  else
# Line 442 | Line 493 | void Drive::set_error(int error)
493                  LED = DRVLED_OFF;
494          the_iec->UpdateLEDs();
495   }
496 +
497 +
498 + /*
499 + *  Parse file name, determine access mode and file type
500 + */
501 +
502 + void Drive::parse_file_name(const uint8 *src, int src_len, uint8 *dest, int &dest_len, int &mode, int &type, int &rec_len, bool convert_charset)
503 + {
504 +        // If the string contains a ':', the file name starts after that
505 +        const uint8 *p = (const uint8 *)memchr(src, ':', src_len);
506 +        if (p) {
507 +                p++;
508 +                src_len -= p - src;
509 +        } else
510 +                p = src;
511 +
512 +        // Transfer file name upto ','
513 +        dest_len = 0;
514 +        uint8 *q = dest;
515 +        while (*p != ',' && src_len-- > 0) {
516 +                if (convert_charset)
517 +                        *q++ = petscii2ascii(*p++);
518 +                else
519 +                        *q++ = *p++;
520 +                dest_len++;
521 +        }
522 +        *q++ = 0;
523 +
524 +        // Strip trailing CRs
525 +        while (dest_len > 0 && dest[dest_len - 1] == 0x0d)
526 +                dest[--dest_len] = 0;
527 +
528 +        // Look for mode and type parameters separated by ','
529 +        p++; src_len--;
530 +        while (src_len > 0) {
531 +                switch (*p) {
532 +                        case 'D':
533 +                                type = FTYPE_DEL;
534 +                                break;
535 +                        case 'S':
536 +                                type = FTYPE_SEQ;
537 +                                break;
538 +                        case 'P':
539 +                                type = FTYPE_PRG;
540 +                                break;
541 +                        case 'U':
542 +                                type = FTYPE_USR;
543 +                                break;
544 +                        case 'L':
545 +                                type = FTYPE_REL;
546 +                                while (*p != ',' && src_len-- > 0) p++;
547 +                                p++; src_len--;
548 +                                rec_len = *p++; src_len--;
549 +                                if (src_len < 0)
550 +                                        rec_len = 0;
551 +                                break;
552 +                        case 'R':
553 +                                mode = FMODE_READ;
554 +                                break;
555 +                        case 'W':
556 +                                mode = FMODE_WRITE;
557 +                                break;
558 +                        case 'A':
559 +                                mode = FMODE_APPEND;
560 +                                break;
561 +                        case 'M':
562 +                                mode = FMODE_M;
563 +                                break;
564 +                }
565 +
566 +                // Skip to ','
567 +                while (*p != ',' && src_len-- > 0) p++;
568 +                p++; src_len--;
569 +        }
570 + }
571 +
572 +
573 + /*
574 + *  Execute DOS command (parse command and call appropriate routine)
575 + */
576 +
577 + static void parse_block_cmd_args(const uint8 *p, int &arg1, int &arg2, int &arg3, int &arg4)
578 + {
579 +        arg1 = arg2 = arg3 = arg4 = 0;
580 +
581 +        while (*p == ' ' || *p == 0x1d || *p == ',') p++;
582 +        while (*p >= '0' && *p < '@')
583 +                arg1 = arg1 * 10 + (*p++ & 0x0f);
584 +
585 +        while (*p == ' ' || *p == 0x1d || *p == ',') p++;
586 +        while (*p >= '0' && *p < '@')
587 +                arg2 = arg2 * 10 + (*p++ & 0x0f);
588 +
589 +        while (*p == ' ' || *p == 0x1d || *p == ',') p++;
590 +        while (*p >= '0' && *p < '@')
591 +                arg3 = arg3 * 10 + (*p++ & 0x0f);
592 +
593 +        while (*p == ' ' || *p == 0x1d || *p == ',') p++;
594 +        while (*p >= '0' && *p < '@')
595 +                arg4 = arg4 * 10 + (*p++ & 0x0f);
596 + }
597 +
598 + void Drive::execute_cmd(const uint8 *cmd, int cmd_len)
599 + {
600 +        // Strip trailing CRs
601 +        while (cmd_len > 0 && cmd[cmd_len - 1] == 0x0d)
602 +                cmd_len--;
603 +
604 +        // Find token delimiters
605 +        const uint8 *colon = (const uint8 *)memchr(cmd, ':', cmd_len);
606 +        const uint8 *equal = colon ? (const uint8 *)memchr(colon, '=', cmd_len - (colon - cmd)) : NULL;
607 +        const uint8 *comma = (const uint8 *)memchr(cmd, ',', cmd_len);
608 +        const uint8 *minus = (const uint8 *)memchr(cmd, '-', cmd_len);
609 +
610 +        // Parse command name
611 +        set_error(ERR_OK);
612 +        switch (cmd[0]) {
613 +                case 'B':       // Block/buffer
614 +                        if (!minus)
615 +                                set_error(ERR_SYNTAX31);
616 +                        else {
617 +                                // Parse arguments (up to 4 decimal numbers separated by
618 +                                // space, cursor right or comma)
619 +                                const uint8 *p = colon ? colon + 1 : cmd + 3;
620 +                                int arg1, arg2, arg3, arg4;
621 +                                parse_block_cmd_args(p, arg1, arg2, arg3, arg4);
622 +
623 +                                // Switch on command
624 +                                switch (minus[1]) {
625 +                                        case 'R':
626 +                                                block_read_cmd(arg1, arg3, arg4);
627 +                                                break;
628 +                                        case 'W':
629 +                                                block_write_cmd(arg1, arg3, arg4);
630 +                                                break;
631 +                                        case 'E':
632 +                                                block_execute_cmd(arg1, arg3, arg4);
633 +                                                break;
634 +                                        case 'A':
635 +                                                block_allocate_cmd(arg2, arg3);
636 +                                                break;
637 +                                        case 'F':
638 +                                                block_free_cmd(arg2, arg3);
639 +                                                break;
640 +                                        case 'P':
641 +                                                buffer_pointer_cmd(arg1, arg2);
642 +                                                break;
643 +                                        default:
644 +                                                set_error(ERR_SYNTAX31);
645 +                                                break;
646 +                                }
647 +                        }
648 +                        break;
649 +
650 +                case 'M':       // Memory
651 +                        if (cmd[1] != '-')
652 +                                set_error(ERR_SYNTAX31);
653 +                        else {
654 +                                // Read parameters
655 +                                uint16 adr = uint8(cmd[3]) | (uint8(cmd[4]) << 8);
656 +                                uint8 len = uint8(cmd[5]);
657 +
658 +                                // Switch on command
659 +                                switch (cmd[2]) {
660 +                                        case 'R':
661 +                                                mem_read_cmd(adr, (cmd_len < 6) ? 1 : len);
662 +                                                break;
663 +                                        case 'W':
664 +                                                mem_write_cmd(adr, len, (uint8 *)cmd + 6);
665 +                                                break;
666 +                                        case 'E':
667 +                                                mem_execute_cmd(adr);
668 +                                                break;
669 +                                        default:
670 +                                                set_error(ERR_SYNTAX31);
671 +                                                break;
672 +                                }
673 +                        }
674 +                        break;
675 +
676 +                case 'C':       // Copy
677 +                        if (!colon)
678 +                                set_error(ERR_SYNTAX31);
679 +                        else if (!equal || memchr(cmd, '*', cmd_len) || memchr(cmd, '?', cmd_len) || (comma && comma < equal))
680 +                                set_error(ERR_SYNTAX30);
681 +                        else
682 +                                copy_cmd(colon + 1, equal - colon - 1, equal + 1, cmd_len - (equal + 1 - cmd));
683 +                        break;
684 +
685 +                case 'R':       // Rename
686 +                        if (!colon)
687 +                                set_error(ERR_SYNTAX34);
688 +                        else if (!equal || comma || memchr(cmd, '*', cmd_len) || memchr(cmd, '?', cmd_len))
689 +                                set_error(ERR_SYNTAX30);
690 +                        else
691 +                                rename_cmd(colon + 1, equal - colon - 1, equal + 1, cmd_len - (equal + 1 - cmd));
692 +                        break;
693 +
694 +                case 'S':       // Scratch
695 +                        if (!colon)
696 +                                set_error(ERR_SYNTAX34);
697 +                        else
698 +                                scratch_cmd(colon + 1, cmd_len - (colon + 1 - cmd));
699 +                        break;
700 +
701 +                case 'P':       // Position
702 +                        position_cmd(cmd + 1, cmd_len - 1);
703 +                        break;
704 +
705 +                case 'I':       // Initialize
706 +                        initialize_cmd();
707 +                        break;
708 +
709 +                case 'N':       // New (format)
710 +                        if (!colon)
711 +                                set_error(ERR_SYNTAX34);
712 +                        else
713 +                                new_cmd(colon + 1, comma ? (comma - colon - 1) : cmd_len - (colon + 1 - cmd), comma);
714 +                        break;
715 +
716 +                case 'V':       // Validate
717 +                        validate_cmd();
718 +                        break;
719 +
720 +                case 'U':       // User
721 +                        if (cmd[1] == '0')
722 +                                break;
723 +                        switch (cmd[1] & 0x0f) {
724 +                                case 1: {       // U1/UA: Read block
725 +                                        const uint8 *p = colon ? colon + 1 : cmd + 2;
726 +                                        int arg1, arg2, arg3, arg4;
727 +                                        parse_block_cmd_args(p, arg1, arg2, arg3, arg4);
728 +                                        block_read_cmd(arg1, arg3, arg4, true);
729 +                                        break;
730 +                                }
731 +                                case 2: {       // U2/UB: Write block
732 +                                        const uint8 *p = colon ? colon + 1 : cmd + 2;
733 +                                        int arg1, arg2, arg3, arg4;
734 +                                        parse_block_cmd_args(p, arg1, arg2, arg3, arg4);
735 +                                        block_write_cmd(arg1, arg3, arg4, true);
736 +                                        break;
737 +                                }
738 +                                case 9:         // U9/UI: C64/VC20 mode switch
739 +                                        if (cmd[2] != '+' && cmd[2] != '-')
740 +                                                Reset();
741 +                                        break;
742 +                                case 10:        // U:/UJ: Reset
743 +                                        Reset();
744 +                                        break;
745 +                                default:
746 +                                        set_error(ERR_UNIMPLEMENTED);
747 +                                        break;
748 +                        }
749 +                        break;
750 +
751 +                default:
752 +                        set_error(ERR_SYNTAX31);
753 +                        break;
754 +        }
755 + }
756 +
757 + // BLOCK-READ:channel,0,track,sector
758 + void Drive::block_read_cmd(int channel, int track, int sector, bool user_cmd)
759 + {
760 +        set_error(ERR_UNIMPLEMENTED);
761 + }
762 +
763 + // BLOCK-WRITE:channel,0,track,sector
764 + void Drive::block_write_cmd(int channel, int track, int sector, bool user_cmd)
765 + {
766 +        set_error(ERR_UNIMPLEMENTED);
767 + }
768 +
769 + // BLOCK-EXECUTE:channel,0,track,sector
770 + void Drive::block_execute_cmd(int channel, int track, int sector)
771 + {
772 +        set_error(ERR_UNIMPLEMENTED);
773 + }
774 +
775 + // BLOCK-ALLOCATE:0,track,sector
776 + void Drive::block_allocate_cmd(int track, int sector)
777 + {
778 +        set_error(ERR_UNIMPLEMENTED);
779 + }
780 +
781 + // BLOCK-FREE:0,track,sector
782 + void Drive::block_free_cmd(int track, int sector)
783 + {
784 +        set_error(ERR_UNIMPLEMENTED);
785 + }
786 +
787 + // BUFFER-POINTER:channel,pos
788 + void Drive::buffer_pointer_cmd(int channel, int pos)
789 + {
790 +        set_error(ERR_UNIMPLEMENTED);
791 + }
792 +
793 + // M-R<adr low><adr high>[<number>]
794 + void Drive::mem_read_cmd(uint16 adr, uint8 len)
795 + {
796 +        unsupp_cmd();
797 +        error_ptr = error_buf;
798 +        error_buf[0] = 0;
799 +        error_len = 0;
800 +        set_error(ERR_OK);
801 + }
802 +
803 + // M-W<adr low><adr high><number><data...>
804 + void Drive::mem_write_cmd(uint16 adr, uint8 len, uint8 *p)
805 + {
806 +        set_error(ERR_UNIMPLEMENTED);
807 + }
808 +
809 + // M-E<adr low><adr high>
810 + void Drive::mem_execute_cmd(uint16 adr)
811 + {
812 +        set_error(ERR_UNIMPLEMENTED);
813 + }
814 +
815 + //   COPY:new=file1,file2,...
816 + //        ^   ^
817 + // new_file   old_files
818 + void Drive::copy_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_files, int old_files_len)
819 + {
820 +        set_error(ERR_UNIMPLEMENTED);
821 + }
822 +
823 + // RENAME:new=old
824 + //        ^   ^
825 + // new_file   old_file
826 + void Drive::rename_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_file, int old_file_len)
827 + {
828 +        set_error(ERR_UNIMPLEMENTED);
829 + }
830 +
831 + // SCRATCH:file1,file2,...
832 + //         ^
833 + //         files
834 + void Drive::scratch_cmd(const uint8 *files, int files_len)
835 + {
836 +        set_error(ERR_UNIMPLEMENTED);
837 + }
838 +
839 + // P<channel><record low><record high><byte>
840 + //  ^
841 + //  cmd
842 + void Drive::position_cmd(const uint8 *cmd, int cmd_len)
843 + {
844 +        set_error(ERR_UNIMPLEMENTED);
845 + }
846 +
847 + // INITIALIZE
848 + void Drive::initialize_cmd(void)
849 + {
850 +        set_error(ERR_UNIMPLEMENTED);
851 + }
852 +
853 + // NEW:name,id
854 + //     ^   ^
855 + //  name   comma (or NULL)
856 + void Drive::new_cmd(const uint8 *name, int name_len, const uint8 *comma)
857 + {
858 +        set_error(ERR_UNIMPLEMENTED);
859 + }
860 +
861 + // VALIDATE
862 + void Drive::validate_cmd(void)
863 + {
864 +        set_error(ERR_UNIMPLEMENTED);
865 + }
866 +
867 +
868 + /*
869 + *  Notice user of unsupported drive command
870 + */
871 +
872 + void Drive::unsupp_cmd(void)
873 + {
874 + }
875 +
876 +
877 + /*
878 + *  Convert PETSCII<->ASCII
879 + */
880 +
881 + uint8 ascii2petscii(char c)
882 + {
883 +        if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
884 +                return c ^ 0x20;
885 +        return c;
886 + }
887 +
888 + void ascii2petscii(uint8 *dest, const char *src, int n)
889 + {
890 +        while (n-- && (*dest++ = ascii2petscii(*src++))) ;
891 + }
892 +
893 + char petscii2ascii(uint8 c)
894 + {
895 +        if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
896 +                return c ^ 0x20;
897 +        if ((c >= 0xc1) && (c <= 0xda))
898 +                return c ^ 0x80;
899 +        return c;
900 + }
901 +
902 + void petscii2ascii(char *dest, const uint8 *src, int n)
903 + {
904 +        while (n-- && (*dest++ = petscii2ascii(*src++))) ;
905 + }
906 +
907 +
908 + /*
909 + *  Check whether file is a mountable disk image or archive file, return type
910 + */
911 +
912 + bool IsMountableFile(const char *path, int &type)
913 + {
914 +        // Read header and determine file size
915 +        uint8 header[64];
916 +        memset(header, 0, sizeof(header));
917 +        FILE *f = fopen(path, "rb");
918 +        if (f == NULL)
919 +                return false;
920 +        fseek(f, 0, SEEK_END);
921 +        long size = ftell(f);
922 +        fseek(f, 0, SEEK_SET);
923 +        fread(header, 1, sizeof(header), f);
924 +        fclose(f);
925 +
926 +        if (IsImageFile(path, header, size)) {
927 +                type = FILE_IMAGE;
928 +                return true;
929 +        } else if (IsArchFile(path, header, size)) {
930 +                type = FILE_ARCH;
931 +                return true;
932 +        } else
933 +                return false;
934 + }
935 +
936 +
937 + /*
938 + *  Read directory of mountable disk image or archive file into c64_dir_entry vector,
939 + *  returns false on error
940 + */
941 +
942 + bool ReadDirectory(const char *path, int type, vector<c64_dir_entry> &vec)
943 + {
944 +        vec.clear();
945 +        switch (type) {
946 +                case FILE_IMAGE:
947 +                        return ReadImageDirectory(path, vec);
948 +                case FILE_ARCH:
949 +                        return ReadArchDirectory(path, vec);
950 +                default:
951 +                        return false;
952 +        }
953 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines