]> Shamusworld >> Repos - virtualjaguar/blob - src/gui/filethread.cpp
Removed some cruft and nonstandard int/uint types, added M series BIOS.
[virtualjaguar] / src / gui / filethread.cpp
1 //
2 // filethread.cpp - File discovery thread
3 //
4 // by James Hammons
5 // (C) 2010 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // Who  When        What
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
16 //
17
18 #include "filethread.h"
19
20 #include <QtGui>
21 #include "crc32.h"
22 #include "file.h"
23 #include "filedb.h"
24 //#include "memory.h"
25 #include "settings.h"
26
27 #define VERBOSE_LOGGING
28
29 FileThread::FileThread(QObject * parent/*= 0*/): QThread(parent), abort(false)
30 {
31 }
32
33 FileThread::~FileThread()
34 {
35         mutex.lock();
36         abort = true;
37         condition.wakeOne();
38         mutex.unlock();
39
40         wait();
41 }
42
43 void FileThread::Go(bool allowUnknown/*= false*/)
44 {
45         allowUnknownSoftware = allowUnknown;
46         QMutexLocker locker(&mutex);
47         start();
48 }
49
50 /*
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.
56
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.
59
60 Ideally, the label will go into the archive along with the ROM image, but that's
61 for the future...
62 Maybe box art, screenshots will go as well...
63 The future is NOW! :-)
64 */
65
66 //
67 // Here's the thread's actual execution path...
68 //
69 void FileThread::run(void)
70 {
71         QDir romDir(vjs.ROMPath);
72         QFileInfoList list = romDir.entryInfoList();
73
74         for(int i=0; i<list.size(); i++)
75         {
76                 if (abort)
77 #ifdef VERBOSE_LOGGING
78 {
79 printf("FileThread: Aborting!!!\n");
80 #endif
81                         return;
82 #ifdef VERBOSE_LOGGING
83 }
84 #endif
85
86                 HandleFile(list.at(i));
87         }
88 }
89
90 //
91 // This handles file identification and ZIP extraction.
92 //
93 void FileThread::HandleFile(QFileInfo fileInfo)
94 {
95         // Really, need to come up with some kind of cacheing scheme here, so we don't
96         // fish through these files every time we run VJ :-P
97 #warning "!!! Need to come up with some kind of cacheing scheme here !!!"
98         bool haveZIPFile = (fileInfo.suffix().compare("zip", Qt::CaseInsensitive) == 0
99                 ? true : false);
100         uint32_t fileSize = 0;
101         uint8_t * buffer = NULL;
102
103         if (haveZIPFile)
104         {
105                 // ZIP files are special: They contain more than just the software now... ;-)
106                 // So now we fish around inside them to pull out the stuff we want.
107                 // Probably also need more stringent error checking as well... :-O
108                 fileSize = GetFileFromZIP(fileInfo.filePath().toAscii(), FT_SOFTWARE, buffer);
109
110                 if (fileSize == 0)
111                         return;
112         }
113         else
114         {
115                 QFile file(fileInfo.filePath());
116
117                 if (!file.open(QIODevice::ReadOnly))
118                         return;
119
120                 fileSize = fileInfo.size();
121
122                 if (fileSize == 0)
123                         return;
124
125                 buffer = new uint8_t[fileSize];
126                 file.read((char *)buffer, fileSize);
127                 file.close();
128         }
129
130         // Try to divine the file type by size & header
131         int fileType = ParseFileType(buffer, fileSize);
132
133         // Check for Alpine ROM w/Universal Header
134         bool foundUniversalHeader = HasUniversalHeader(buffer, fileSize);
135         uint32_t crc;
136
137 //printf("FileThread: About to calc checksum on file with size %u... (buffer=%08X)\n", size, buffer);
138         if (foundUniversalHeader)
139                 crc = crc32_calcCheckSum(buffer + 8192, fileSize - 8192);
140         else
141                 crc = crc32_calcCheckSum(buffer, fileSize);
142
143         uint32_t index = FindCRCIndexInFileList(crc);
144         delete[] buffer;
145
146         // Here we filter out files that are *not* in the DB and of unknown type,
147         // and BIOS files. If desired, this can be overriden with a config option.
148         if ((index == 0xFFFFFFFF) && (fileType == JST_NONE))
149         {
150                 // If we allow unknown software, we pass the (-1) index on, otherwise...
151                 if (!allowUnknownSoftware)
152                         return;                                                         // CRC wasn't found, so bail...
153         }
154         else if ((index != 0xFFFFFFFF) && romList[index].flags & FF_BIOS)
155                 return;
156
157 //Here's a little problem. When we create the image here and pass it off to FilePicker,
158 //we can clobber this image before we have a chance to copy it out in the FilePicker function
159 //because we can be back here before FilePicker can respond.
160 // So now we create the image on the heap, problem solved. :-)
161         QImage * img = NULL;
162
163         // See if we can fish out a label. :-)
164         if (haveZIPFile)
165         {
166                 uint32_t size = GetFileFromZIP(fileInfo.filePath().toAscii(), FT_LABEL, buffer);
167 //printf("FT: Label size = %u bytes.\n", size);
168
169                 if (size > 0)
170                 {
171                         QImage label;
172                         bool successful = label.loadFromData(buffer, size);
173                         img = new QImage;
174                         *img = label.scaled(365, 168, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
175 //printf("FT: Label %s: %ux%u.\n", (successful ? "succeeded" : "did not succeed"), img->width(), img->height());
176                         delete[] buffer;
177                 }
178 //printf("FileThread: Attempted to load image. Size: %u x %u...\n", img.width(), img.height());
179         }
180
181 //      emit FoundAFile2(index, fileInfo.canonicalFilePath(), img, fileSize);
182         emit FoundAFile3(index, fileInfo.canonicalFilePath(), img, fileSize, foundUniversalHeader, fileType, crc);
183 }
184
185 //
186 // Find a CRC in the ROM list (simple brute force algorithm).
187 // If it's there, return the index, otherwise return $FFFFFFFF
188 //
189 uint32_t FileThread::FindCRCIndexInFileList(uint32_t crc)
190 {
191         // Instead of a simple brute-force search, we should probably do a binary
192         // partition search instead, since the CRCs are sorted numerically.
193 #warning "!!! Should do binary partition search here !!!"
194         for(int i=0; romList[i].crc32!=0xFFFFFFFF; i++)
195         {
196                 if (romList[i].crc32 == crc)
197                         return i;
198         }
199
200         return 0xFFFFFFFF;
201 }