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