]> Shamusworld >> Repos - virtualjaguar/blob - src/gui/filethread.cpp
Preliminary support for alternate file types.
[virtualjaguar] / src / gui / filethread.cpp
1 //
2 // filethread.cpp - File discovery thread
3 //
4 // by James L. Hammons
5 // (C) 2010 Underground Software
6 //
7 // JLH = James L. 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 "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         bool haveZIPFile = (fileInfo.suffix().compare("zip", Qt::CaseInsensitive) == 0
95                 ? true : false);
96         uint32_t fileSize = 0;
97         uint8 * buffer = NULL;
98
99         if (haveZIPFile)
100         {
101                 // ZIP files are special: They contain more than just the software now... ;-)
102                 // So now we fish around inside them to pull out the stuff we want.
103                 // Probably also need more stringent error checking as well... :-O
104                 fileSize = GetFileFromZIP(fileInfo.filePath().toAscii(), FT_SOFTWARE, buffer);
105
106                 if (fileSize == 0)
107                         return;
108         }
109         else
110         {
111                 QFile file(fileInfo.filePath());
112
113                 if (!file.open(QIODevice::ReadOnly))
114                         return;
115
116                 fileSize = fileInfo.size();
117
118                 if (fileSize == 0)
119                         return;
120
121                 buffer = new uint8[fileSize];
122                 file.read((char *)buffer, fileSize);
123                 file.close();
124         }
125
126         // Try to divine the file type by size & header
127         int fileType = ParseFileType(buffer[0], buffer[1], fileSize);
128
129         // Check for Alpine ROM w/Universal Header
130         bool foundUniversalHeader = HasUniversalHeader(buffer, fileSize);
131         uint32 crc;
132
133 //printf("FileThread: About to calc checksum on file with size %u... (buffer=%08X)\n", size, buffer);
134         if (foundUniversalHeader)
135                 crc = crc32_calcCheckSum(buffer + 8192, fileSize - 8192);
136         else
137                 crc = crc32_calcCheckSum(buffer, fileSize);
138
139         uint32 index = FindCRCIndexInFileList(crc);
140         delete[] buffer;
141
142         // Here we filter out files *not* in the DB (if configured that way) and
143         // BIOS files.
144         if (index == 0xFFFFFFFF)
145         {
146                 // If we allow unknown software, we pass the (-1) index on, otherwise...
147                 if (!allowUnknownSoftware)
148                         return;                                                         // CRC wasn't found, so bail...
149         }
150         else if (romList[index].flags & FF_BIOS)
151                 return;
152
153 //Here's a little problem. When we create the image here and pass it off to FilePicker,
154 //we can clobber this image before we have a chance to copy it out in the FilePicker function
155 //because we can be back here before FilePicker can respond.
156 // So now we create the image on the heap, problem solved. :-)
157         QImage * img = NULL;
158
159         // See if we can fish out a label. :-)
160         if (haveZIPFile)
161         {
162                 uint32 size = GetFileFromZIP(fileInfo.filePath().toAscii(), FT_LABEL, buffer);
163 //printf("FT: Label size = %u bytes.\n", size);
164
165                 if (size > 0)
166                 {
167                         QImage label;
168                         bool successful = label.loadFromData(buffer, size);
169                         img = new QImage;
170                         *img = label.scaled(365, 168, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
171 //printf("FT: Label %s: %ux%u.\n", (successful ? "succeeded" : "did not succeed"), img->width(), img->height());
172                         delete[] buffer;
173                 }
174 //printf("FileThread: Attempted to load image. Size: %u x %u...\n", img.width(), img.height());
175         }
176
177 //      emit FoundAFile2(index, fileInfo.canonicalFilePath(), img, fileSize);
178         emit FoundAFile3(index, fileInfo.canonicalFilePath(), img, fileSize, foundUniversalHeader, fileType, crc);
179 }
180
181 //
182 // Find a CRC in the ROM list (simple brute force algorithm).
183 // If it's there, return the index, otherwise return $FFFFFFFF
184 //
185 uint32 FileThread::FindCRCIndexInFileList(uint32 crc)
186 {
187         // Instead of a simple brute-force search, we should probably do a binary
188         // partition search instead, since the CRCs are sorted numerically.
189 #warning "!!! Should do binary partition search here !!!"
190         for(int i=0; romList[i].crc32!=0xFFFFFFFF; i++)
191         {
192                 if (romList[i].crc32 == crc)
193                         return i;
194         }
195
196         return 0xFFFFFFFF;
197 }