Commit | Line | Data |
---|---|---|
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 | ||
30 | FileThread::FileThread(QObject * parent/*= 0*/): QThread(parent), abort(false) | |
31 | { | |
32 | } | |
33 | ||
34 | FileThread::~FileThread() | |
35 | { | |
36 | mutex.lock(); | |
37 | abort = true; | |
38 | condition.wakeOne(); | |
39 | mutex.unlock(); | |
40 | ||
41 | wait(); | |
42 | } | |
43 | ||
44 | void FileThread::Go(bool allowUnknown/*= false*/) | |
45 | { | |
46 | allowUnknownSoftware = allowUnknown; | |
47 | QMutexLocker locker(&mutex); | |
48 | start(); | |
49 | } | |
50 | ||
51 | /* | |
52 | Our strategy here is like so: | |
53 | Look at the files in the directory pointed to by ROMPath. | |
54 | For each file in the directory, take the CRC32 of it and compare it to the CRC | |
55 | in the romList[]. If there's a match, put it in a list and note it's index value | |
56 | in romList for future reference. | |
57 | ||
58 | When constructing the list, use the index to pull up an image of the cart and | |
59 | put that in the list. User picks from a graphical image of the cart. | |
60 | ||
61 | Ideally, the label will go into the archive along with the ROM image, but that's | |
62 | for the future... | |
63 | Maybe box art, screenshots will go as well... | |
64 | The future is NOW! :-) | |
65 | */ | |
66 | ||
67 | // | |
68 | // Here's the thread's actual execution path... | |
69 | // | |
70 | void 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 | { | |
80 | printf("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 | // | |
94 | void 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 | // | |
194 | uint32_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 | } |