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