ScummVM API documentation
prodos.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef COMMON_PRODOS_H
23 #define COMMON_PRODOS_H
24 
25 #include "common/memstream.h"
26 #include "common/file.h"
27 #include "common/debug.h"
28 #include "common/error.h"
29 
30 /* Quick note about ProDOS:
31  * This disk code handles inactive, seedling, sapling, tree, and subdirectory files.
32  * It does *not* handle sparse files at the moment. If a sparse file exists, it may not
33  * be read correctly. It also does not do anything with Pascal files, but those should not
34  * matter for game engines anyway.
35  */
36 
37 namespace Common {
38 
39 // These values define for ProDOS how to read the file entry, and also whether it's a keyblock (if it is a directory header, it's the keyblock of that directory)
40 enum FileType : char {
41  kFileTypeDead = 0,
42  kFileTypeSeed = 1,
43  kFileTypeSapling = 2,
44  kFileTypeTree = 3,
45  kFileTypePascal = 4,
46  kFileTypeSubDir = 0x0D,
47  kFileTypeSubHead = 0x0E,
48  kFileTypeVolHead = 0x0F
49 };
50 
51 /* File extensions for all the ProDOS supported file types
52  * NOTE: ProDOS user defined files are F1-F8. If they are ever required,
53  * they can be added to this enum.
54  */
55 enum FileExt {
56  kFileExtNull = 0,
57  kFileExtBad = 1,
58  kFileExtTxt = 4,
59  kFileExtBin = 6,
60  kFileExtGfx = 8,
61  kFileExtDir = 0xF,
62  kFileExtDB = 0x19,
63  kFileExtWord = 0x1A,
64  kFileExtSpread = 0x1B,
65  kFileExtSTART = 0xB3,
66  kFileExtPascal = 0xEF,
67  kFileExtPDCI = 0xF0,
68  kFileExtPDRes = 0xF9,
69  kFileExtIBProg = 0xFA,
70  kFileExtIBVar = 0xFB,
71  kFileExtAPSProg = 0xFC,
72  kFileExtAPSVar = 0xFD,
73  kFileExtEDASM = 0xFE,
74  kFileExtSYS = 0xFF
75 };
76 
77 /* A ProDOS file simply contains meta data about the file and the ability to
78  * find and put together the data blocks that make up the file contents.
79  * This implements Common::ArchiveMember so that it can be used directly in
80  * the Archive methods in ProDOSDisk.
81  */
82 
84 public:
85  ProDOSFile(char name[16], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk);
86  ~ProDOSFile() {}; // File does not need a destructor, because the file it reads from is a pointer to Disk, and Disk has a destructor
87 
88  // -- These are the Common::ArchiveMember related functions --
89  Common::String getName() const override; // Returns _name
90  Common::Path getPathInArchive() const override; // Returns _name
91  Common::String getFileName() const override; // Returns _name
92  Common::SeekableReadStream *createReadStream() const override; // This is what the archive needs to create a file
93  Common::SeekableReadStream *createReadStreamForAltStream(Common::AltStreamType altStreamType) const override;
94  void getDataBlock(byte *memOffset, int offset, int size) const; // Gets data up to the size of a single data block (512 bytes)
95  int parseIndexBlock(byte *memOffset, int blockNum, int cSize) const; // Uses getDataBlock() on every pointer in the index file, adding them to byte * memory block
96 
97  // For debugging purposes, just prints the metadata
98  void printInfo();
99 
100 private:
101  char _name[16];
102  uint8 _type; // As defined by enum FileType
103  uint16 _blockPtr; // Block index in volume of index block or data
104  uint16 _totalBlocks;
105  uint32 _eof; // End Of File, used generally as size (exception being sparse files)
106  Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object
107 };
108 
109 /* This class defines the entire disk volume. Upon using the open() method,
110  * it will parse the volume and add them to a hashmap where the file path
111  * returns a file object. This implements Common::Archive to allow regular
112  * file operations to work with it.
113  */
114 
115 class ProDOSDisk : public Common::Archive {
116 public:
117  static const int kBlockSize = 512; // A ProDOS block is always 512 bytes (should this be an enum?)
118 
119  ProDOSDisk(const Common::Path &filename);
120  ~ProDOSDisk(); // Frees the memory used in the dictionary and the volume bitmap
121 
122  // Called from the constructor, it parses the volume and fills the hashmap with files
123  bool open(const Common::Path &filename);
124 
125  // These are the Common::Archive related methods
126  bool hasFile(const Common::Path &path) const override;
127  int listMembers(Common::ArchiveMemberList &list) const override;
128  const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
129  Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
130 
131 private:
132  byte _loader1[kBlockSize]; // There's not much reason for these to be needed, but I included them just in case
133  byte _loader2[kBlockSize];
134  Common::String _name; // Name of volume
135  Common::File _disk; // The volume file itself
136  int _volBlocks; // Total blocks in volume
137  byte *_volBitmap; // This can determine if the volume is corrupt as it contains a bit for every block, where 0 = unused, 1 = used
138  Common::HashMap<Common::String, Common::SharedPtr<ProDOSFile>> _files; // Hashmap of files in the volume, where key=Path, Value=ProDOSFile
139 
140  struct Date {
141  uint8 _day;
142  uint8 _month;
143  uint8 _year;
144  };
145 
146  struct Time {
147  uint8 _hour;
148  uint8 _minute;
149  };
150 
151  struct VolHeader {
152  uint8 _type; // Not really important for a volume header, as this will always be F
153  uint8 _nameLen;
154  char _name[16];
155  byte _reserved[8]; // Extra space reserved for possible future uses, not important
156  Date _date;
157  Time _time;
158  uint8 _ver;
159  uint8 _minVer; // Should pretty much always be 0 as far as I know
160  uint8 _access; // If this ends up useful, there should be an enum for the access values
161  uint8 _entryLen; // Always 27 in ProDOS 1.0
162  uint8 _entriesPerBlock; // Always 0D in ProDOS 1.0
163  uint16 _fileCount; // Number of files across all data blocks in this directory
164  uint16 _bitmapPtr; // Block pointer to the keyblock of the bitmap for the entire volume
165  uint16 _volBlocks; // Blocks in entire volume
166  };
167 
168  struct DirHeader {
169  uint8 _type;
170  uint8 _nameLen;
171  char _name[16];
172  byte _reserved[8];
173  Date _date;
174  Time _time;
175  uint8 _ver;
176  uint8 _minVer;
177  uint8 _access;
178  uint8 _entryLen;
179  uint8 _entriesPerBlock;
180  uint16 _fileCount;
181  uint16 _parentBlockPtr; // These values allow ProDOS to navigate back out of a directory, but they aren't really needed by the class to navigate
182  uint8 _parentEntryIndex; // Index in the current directory
183  uint8 _parentEntryLen; // This is always 27 in ProDOS 1.0
184  };
185 
186  struct FileEntry {
187  uint8 _type; // 0 = inactive, 1-3 = file, 4 = pascal area, 14 = subdirectory, 15 = volume directory
188  uint8 _nameLen;
189  char _name[16];
190  uint8 _ext; // File extension, uses the enum FileExt
191  uint16 _blockPtr; // Block pointer to data for seedling, index block for sapling, or master block for tree
192  uint16 _totalBlocks; // Really important to remember this is the total *including* the index block
193  uint32 _eof; // This is a long (3 bytes, read low to high) value representing the total readable data in a file (unless it's a sparse file, be careful!)
194  Date _date;
195  Time _time;
196  uint8 _ver;
197  uint8 _minVer;
198  uint8 _access;
199  uint16 _varUse;
200  Date _modDate;
201  Time _modTime;
202  uint16 _dirHeadPtr; // Pointer to the key block of the directory that contains this file entry
203  };
204 
205  void getDate(Date *d, uint16 date); // Decompresses the date into a struct
206  void getTime(Time *t, uint16 time); // Decompresses the time into a struct
207  void getHeader(DirHeader *h); // Adds the main header values to the struct
208  void getDirectoryHeader(DirHeader *h); // Uses getHeader and then fills in the values for the parent directory
209  void getVolumeHeader(VolHeader *dir); // Uses getHeader and then fills in the volume related information (there is no parent directory to this one)
210  void getFileEntry(FileEntry *f); // Adds all of the file entry information to the struct
211  void searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path); // Recursively searches all files within a directory, by calling itself for subdirectories
212  void getVolumeBitmap(VolHeader *h); // Puts together the volume bitmap
213 };
214 
215 
216 } // Namespace Common
217 
218 #endif
Common::SeekableReadStream * createReadStream() const override
Definition: str.h:59
Definition: prodos.h:115
Common::Path getPathInArchive() const override
Definition: prodos.h:83
Definition: list.h:44
Common::String getName() const override
Definition: path.h:52
Definition: stream.h:745
Definition: archive.h:141
Common::SeekableReadStream * createReadStreamForAltStream(Common::AltStreamType altStreamType) const override
Definition: hashmap.h:85
Definition: file.h:47
Definition: archive.h:68
Definition: algorithm.h:29
Common::String getFileName() const override