2 // filethread.cpp - File discovery thread
5 // (C) 2010 Underground Software
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- -------------------------------------------------------------
11 // JLH 01/28/2010 Created this file
12 // JLH 02/16/2010 Moved RomIdentifier stuff to its own file
13 // JLH 03/02/2010 Added .ZIP file fishing
14 // JLH 06/28/2011 Cleanup in the file parsing/fishing code, to make it easier
15 // to follow the flow of the logic
18 #include "filethread.h"
27 #define VERBOSE_LOGGING
29 FileThread::FileThread(QObject * parent/*= 0*/): QThread(parent), abort(false)
33 FileThread::~FileThread()
43 void FileThread::Go(bool allowUnknown/*= false*/)
45 allowUnknownSoftware = allowUnknown;
46 QMutexLocker locker(&mutex);
51 Our strategy here is like so:
52 Look at the files in the directory pointed to by ROMPath.
53 For each file in the directory, take the CRC32 of it and compare it to the CRC
54 in the romList[]. If there's a match, put it in a list and note it's index value
55 in romList for future reference.
57 When constructing the list, use the index to pull up an image of the cart and
58 put that in the list. User picks from a graphical image of the cart.
60 Ideally, the label will go into the archive along with the ROM image, but that's
62 Maybe box art, screenshots will go as well...
63 The future is NOW! :-)
67 // Here's the thread's actual execution path...
69 void FileThread::run(void)
71 QDir romDir(vjs.ROMPath);
72 QFileInfoList list = romDir.entryInfoList();
74 for(int i=0; i<list.size(); i++)
77 #ifdef VERBOSE_LOGGING
79 printf("FileThread: Aborting!!!\n");
82 #ifdef VERBOSE_LOGGING
86 HandleFile(list.at(i));
91 // This handles file identification and ZIP extraction.
93 void FileThread::HandleFile(QFileInfo fileInfo)
95 bool haveZIPFile = (fileInfo.suffix().compare("zip", Qt::CaseInsensitive) == 0
97 uint32_t fileSize = 0;
98 uint8 * buffer = NULL;
102 // ZIP files are special: They contain more than just the software now... ;-)
103 // So now we fish around inside them to pull out the stuff we want.
104 // Probably also need more stringent error checking as well... :-O
105 fileSize = GetFileFromZIP(fileInfo.filePath().toAscii(), FT_SOFTWARE, buffer);
112 QFile file(fileInfo.filePath());
114 if (!file.open(QIODevice::ReadOnly))
117 fileSize = fileInfo.size();
122 buffer = new uint8[fileSize];
123 file.read((char *)buffer, fileSize);
127 // Try to divine the file type by size & header
128 int fileType = ParseFileType(buffer[0], buffer[1], fileSize);
130 // Check for Alpine ROM w/Universal Header
131 bool foundUniversalHeader = HasUniversalHeader(buffer, fileSize);
134 //printf("FileThread: About to calc checksum on file with size %u... (buffer=%08X)\n", size, buffer);
135 if (foundUniversalHeader)
136 crc = crc32_calcCheckSum(buffer + 8192, fileSize - 8192);
138 crc = crc32_calcCheckSum(buffer, fileSize);
140 uint32 index = FindCRCIndexInFileList(crc);
142 if ((index != 0xFFFFFFFF) && (romList[index].flags & FF_BIOS))
143 HandleBIOSFile(buffer, crc);
147 // Here we filter out files *not* in the DB (if configured that way) and
149 if (index == 0xFFFFFFFF)
151 // If we allow unknown software, we pass the (-1) index on, otherwise...
152 if (!allowUnknownSoftware)
153 return; // CRC wasn't found, so bail...
155 else if (romList[index].flags & FF_BIOS)
158 //Here's a little problem. When we create the image here and pass it off to FilePicker,
159 //we can clobber this image before we have a chance to copy it out in the FilePicker function
160 //because we can be back here before FilePicker can respond.
161 // So now we create the image on the heap, problem solved. :-)
164 // See if we can fish out a label. :-)
167 uint32 size = GetFileFromZIP(fileInfo.filePath().toAscii(), FT_LABEL, buffer);
168 //printf("FT: Label size = %u bytes.\n", size);
173 bool successful = label.loadFromData(buffer, size);
175 *img = label.scaled(365, 168, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
176 //printf("FT: Label %s: %ux%u.\n", (successful ? "succeeded" : "did not succeed"), img->width(), img->height());
179 //printf("FileThread: Attempted to load image. Size: %u x %u...\n", img.width(), img.height());
182 // emit FoundAFile2(index, fileInfo.canonicalFilePath(), img, fileSize);
183 emit FoundAFile3(index, fileInfo.canonicalFilePath(), img, fileSize, foundUniversalHeader, fileType, crc);
187 // Handle checking/copying BIOS files into Jaguar core memory
189 void FileThread::HandleBIOSFile(uint8 * buffer, uint32 crc)
192 { 0x55A0669C, "[BIOS] Atari Jaguar Developer CD (World)", FF_BIOS },
193 { 0x687068D5, "[BIOS] Atari Jaguar CD (World)", FF_BIOS },
194 { 0x8D15DBC6, "[BIOS] Atari Jaguar Stubulator '94 (World)", FF_BIOS },
195 { 0xE60277BB, "[BIOS] Atari Jaguar Stubulator '93 (World)", FF_BIOS },
196 { 0xFB731AAA, "[BIOS] Atari Jaguar (World)", FF_BIOS },
198 uint8 jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
199 uint8 jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM (256K)
200 uint8 jaguarDevBootROM1[0x040000]; // 68K CPU Stubulator 1 ROM--uses only half of this!
201 uint8 jaguarDevBootROM2[0x040000]; // 68K CPU Stubulator 2 ROM--uses only half of this!
202 uint8 jaguarDevCDBootROM[0x040000]; // 68K CPU Dev CD BIOS ROM (256K)
204 enum { BIOS_NORMAL=0x01, BIOS_CD=0x02, BIOS_STUB1=0x04, BIOS_STUB2=0x08, BIOS_DEV_CD=0x10 };
205 extern int biosAvailable;
207 if (crc == 0xFB731AAA && !(biosAvailable & BIOS_NORMAL))
209 memcpy(jaguarBootROM, buffer, 0x20000);
210 biosAvailable |= BIOS_NORMAL;
212 else if (crc == 0x687068D5 && !(biosAvailable & BIOS_CD))
214 memcpy(jaguarCDBootROM, buffer, 0x40000);
215 biosAvailable |= BIOS_CD;
217 else if (crc == 0x8D15DBC6 && !(biosAvailable & BIOS_STUB1))
219 memcpy(jaguarDevBootROM1, buffer, 0x20000);
220 biosAvailable |= BIOS_STUB1;
222 else if (crc == 0xE60277BB && !(biosAvailable & BIOS_STUB2))
224 memcpy(jaguarDevBootROM2, buffer, 0x20000);
225 biosAvailable |= BIOS_STUB2;
227 else if (crc == 0x55A0669C && !(biosAvailable & BIOS_DEV_CD))
229 memcpy(jaguarDevCDBootROM, buffer, 0x40000);
230 biosAvailable |= BIOS_DEV_CD;
235 // Find a CRC in the ROM list (simple brute force algorithm).
236 // If it's there, return the index, otherwise return $FFFFFFFF
238 uint32 FileThread::FindCRCIndexInFileList(uint32 crc)
240 // Instead of a simple brute-force search, we should probably do a binary
241 // partition search instead, since the CRCs are sorted numerically.
242 #warning "!!! Should do binary partition search here !!!"
243 for(int i=0; romList[i].crc32!=0xFFFFFFFF; i++)
245 if (romList[i].crc32 == crc)