]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/gui/filethread.cpp
Merging qt-experimental into trunk.
[virtualjaguar] / src / gui / filethread.cpp
index 3d53f92b8dd4a02b85a08e7673e224a0d85a6a56..28d7389cb3156fe68e49c09019a86b275f09cb13 100644 (file)
@@ -9,87 +9,42 @@
 // Who  When        What
 // ---  ----------  -------------------------------------------------------------
 // JLH  01/28/2010  Created this file
+// JLH  02/16/2010  Moved RomIdentifier stuff to its own file
+// JLH  03/02/2010  Added .ZIP file fishing
+// JLH  06/28/2011  Cleanup in the file parsing/fishing code, to make it easier
+//                  to follow the flow of the logic
 //
 
 #include "filethread.h"
 
+#include <QtGui>
 #include "crc32.h"
+#include "file.h"
+#include "filedb.h"
 #include "settings.h"
-#include "types.h"
 
-struct RomIdentifier
+#define VERBOSE_LOGGING
+
+FileThread::FileThread(QObject * parent/*= 0*/): QThread(parent), abort(false)
+{
+}
+
+FileThread::~FileThread()
+{
+       mutex.lock();
+       abort = true;
+       condition.wakeOne();
+       mutex.unlock();
+
+       wait();
+}
+
+void FileThread::Go(bool allowUnknown/*= false*/)
 {
-       const uint32 crc32;
-       const char name[128];
-       const char file[128];
-};
-
-RomIdentifier romList[] = {
-       { 0x0509C85E, "Raiden (World)", "" },
-       { 0x08F15576, "Iron Soldier (World) (v1.04)", "" },
-       { 0x0957A072, "Kasumi Ninja (World)", "" },
-       { 0x0AC83D77, "NBA Jam T.E. (World)", "" },
-       { 0x0EC5369D, "Evolution - Dino Dudes (World)", "" },
-       { 0x0F6A1C2C, "Ultra Vortek (World)", "" },
-       { 0x14915F20, "White Men Can't Jump (World)", "" },
-       { 0x1660F070, "Power Drive Rally (World)", "" },
-       { 0x1E451446, "Trevor McFur in the Crescent Galaxy (World)", "" },
-       { 0x27594C6A, "Defender 2000 (World)", "" },
-       { 0x2E17D5DA, "Bubsy in Fractured Furry Tales (World)", "" },
-       { 0x348E6449, "Double Dragon V - The Shadow Falls (World)", "" },
-       { 0x3615AF6A, "Fever Pitch Soccer (World) (En,Fr,De,Es,It)", "" },
-       { 0x38A130ED, "Troy Aikman NFL Football (World)", "" },
-       { 0x3C044941, "Skyhammer (World)", "" },
-       { 0x42A13EC5, "Soccer Kid (World)", "" },
-       { 0x47EBC158, "Theme Park (World)", "" },
-       { 0x4899628F, "Hover Strike (World)", "" },
-       { 0x53DF6440, "Space War 2000 (World)", "" },
-       { 0x55A0669C, "[BIOS] Atari Jaguar Developer CD (World)", "" },
-       { 0x58272540, "Syndicate (World)", "" },
-       { 0x5A101212, "Sensible Soccer - International Edition (World)", "" },
-       { 0x5B6BB205, "Ruiner Pinball (World)", "" },
-       { 0x5CFF14AB, "Pinball Fantasies (World)", "" },
-       { 0x5E2CDBC0, "Doom (World)", "" },
-       { 0x61C7EEC0, "Zero 5 (World)", "" },
-       { 0x67F9AB3A, "Battle Sphere Gold (World)", "" },
-       { 0x687068D5, "[BIOS] Atari Jaguar CD (World)", "" },
-       { 0x6B2B95AD, "Tempest 2000 (World)", "" },
-       { 0x6EB774EB, "Worms (World)", "" },
-       { 0x6F8B2547, "Super Burnout (World)", "" },
-       { 0x817A2273, "Pitfall - The Mayan Adventure (World)", "" },
-       { 0x8975F48B, "Zool 2 (World)", "" },
-       { 0x8D15DBC6, "[BIOS] Atari Jaguar Stubulator '94 (World)", "" },
-       { 0x8FEA5AB0, "Dragon - The Bruce Lee Story (World)", "" },
-       { 0x97EB4651, "I-War (World)", "" },
-       { 0xA27823D8, "Ultra Vortek (World) (v0.94) (Beta)", "" },
-       { 0xA56D0798, "Protector - Special Edition (World)", "" },
-       { 0xA9F8A00E, "Rayman (World)", "" },
-       { 0xB14C4753, "Fight for Life (World)", "" },
-       { 0xBCB1A4BF, "Brutal Sports Football (World)", "" },
-       { 0xBDA405C6, "Cannon Fodder (World)", "" },
-       { 0xBDE67498, "Cybermorph (World) (Rev 1)", "" },
-       { 0xC5562581, "Zoop! (World)", "" },
-       { 0xC654681B, "Total Carnage (World)", "" },
-       { 0xC6C7BA62, "Fight for Life (World) (Alt)", "" },
-       { 0xC9608717, "Val d'Isere Skiing and Snowboarding (World)", "" },
-       { 0xCBFD822A, "Air Cars (World)", "" },
-       { 0xCD5BF827, "Attack of the Mutant Penguins (World)", "" },
-       { 0xD6C19E34, "Iron Soldier 2 (World)", "" },
-       { 0xDA9C4162, "Missile Command 3D (World)", "" },
-       { 0xDC187F82, "Alien vs Predator (World)", "" },
-       { 0xDE55DCC7, "Flashback - The Quest for Identity (World) (En,Fr)", "" },
-       { 0xE28756DE, "Atari Karts (World)", "" },
-       { 0xE60277BB, "[BIOS] Atari Jaguar Stubulator '93 (World)", "" },
-       { 0xE91BD644, "Wolfenstein 3D (World)", "" },
-       { 0xEC22F572, "SuperCross 3D (World)", "" },
-       { 0xECF854E7, "Cybermorph (World) (Rev 2)", "" },
-       { 0xEEE8D61D, "Club Drive (World)", "" },
-       { 0xF0360DB3, "Hyper Force (World)", "" },
-       { 0xFA7775AE, "Checkered Flag (World)", "" },
-       { 0xFAE31DD0, "Flip Out! (World)", "" },
-       { 0xFB731AAA, "[BIOS] Atari Jaguar (World)", "" },
-       { 0xFFFFFFFF, "***END***", "" }
-};
+       allowUnknownSoftware = allowUnknown;
+       QMutexLocker locker(&mutex);
+       start();
+}
 
 /*
 Our strategy here is like so:
@@ -104,71 +59,139 @@ put that in the list. User picks from a graphical image of the cart.
 Ideally, the label will go into the archive along with the ROM image, but that's
 for the future...
 Maybe box art, screenshots will go as well...
+The future is NOW! :-)
 */
 
-FileThread::FileThread(QObject * parent/*= 0*/): QThread(parent), listWidget(NULL), abort(false)
+//
+// Here's the thread's actual execution path...
+//
+void FileThread::run(void)
 {
-}
+       QDir romDir(vjs.ROMPath);
+       QFileInfoList list = romDir.entryInfoList();
 
-FileThread::~FileThread()
+       for(int i=0; i<list.size(); i++)
+       {
+               if (abort)
+#ifdef VERBOSE_LOGGING
 {
-       mutex.lock();
-       abort = true;
-       condition.wakeOne();
-       mutex.unlock();
-
-       wait();
+printf("FileThread: Aborting!!!\n");
+#endif
+                       return;
+#ifdef VERBOSE_LOGGING
 }
+#endif
 
-FileThread::Go(QListWidget * lw)
-{
-       QMutexLocker locker(&mutex);
-       this->listWidget = lw;
-       start();
+               HandleFile(list.at(i));
+       }
 }
 
-void FileThread::run(void)
+//
+// This handles file identification and ZIP extraction.
+//
+void FileThread::HandleFile(QFileInfo fileInfo)
 {
-//     mutex.lock();
-//     if (abort)
-//             return;
-//     mutex.unlock();
+       bool haveZIPFile = (fileInfo.suffix().compare("zip", Qt::CaseInsensitive) == 0
+               ? true : false);
+       uint32_t fileSize = 0;
+       uint8 * buffer = NULL;
 
-       QDir romDir(vjs.ROMPath);
-       QFileInfoList list = romDir.entryInfoList();
+       if (haveZIPFile)
+       {
+               // ZIP files are special: They contain more than just the software now... ;-)
+               // So now we fish around inside them to pull out the stuff we want.
+               // Probably also need more stringent error checking as well... :-O
+               fileSize = GetFileFromZIP(fileInfo.filePath().toAscii(), FT_SOFTWARE, buffer);
 
-       for(int i=0; i<list.size(); i++)
+               if (fileSize == 0)
+                       return;
+       }
+       else
        {
-               if (abort)
+               QFile file(fileInfo.filePath());
+
+               if (!file.open(QIODevice::ReadOnly))
                        return;
 
-               QFileInfo fileInfo = list.at(i);
-//         std::cout << qPrintable(QString("%1 %2").arg(fileInfo.size(), 10)
-//                                                 .arg(fileInfo.fileName()));
-//         std::cout << std::endl;
-               QFile file(romDir.filePath(fileInfo.fileName()));
-               uint8 * buffer = new uint8[fileInfo.size()];
+               fileSize = fileInfo.size();
+
+               if (fileSize == 0)
+                       return;
+
+               buffer = new uint8[fileSize];
+               file.read((char *)buffer, fileSize);
+               file.close();
+       }
+
+       // Try to divine the file type by size & header
+       int fileType = ParseFileType(buffer[0], buffer[1], fileSize);
 
-               if (file.open(QIODevice::ReadOnly))
+       // Check for Alpine ROM w/Universal Header
+       bool foundUniversalHeader = HasUniversalHeader(buffer, fileSize);
+       uint32 crc;
+
+//printf("FileThread: About to calc checksum on file with size %u... (buffer=%08X)\n", size, buffer);
+       if (foundUniversalHeader)
+               crc = crc32_calcCheckSum(buffer + 8192, fileSize - 8192);
+       else
+               crc = crc32_calcCheckSum(buffer, fileSize);
+
+       uint32 index = FindCRCIndexInFileList(crc);
+       delete[] buffer;
+
+       // Here we filter out files *not* in the DB (if configured that way) and
+       // BIOS files.
+       if (index == 0xFFFFFFFF)
+       {
+               // If we allow unknown software, we pass the (-1) index on, otherwise...
+               if (!allowUnknownSoftware)
+                       return;                                                         // CRC wasn't found, so bail...
+       }
+       else if (romList[index].flags & FF_BIOS)
+               return;
+
+//Here's a little problem. When we create the image here and pass it off to FilePicker,
+//we can clobber this image before we have a chance to copy it out in the FilePicker function
+//because we can be back here before FilePicker can respond.
+// So now we create the image on the heap, problem solved. :-)
+       QImage * img = NULL;
+
+       // See if we can fish out a label. :-)
+       if (haveZIPFile)
+       {
+               uint32 size = GetFileFromZIP(fileInfo.filePath().toAscii(), FT_LABEL, buffer);
+//printf("FT: Label size = %u bytes.\n", size);
+
+               if (size > 0)
                {
-                       file.read((char *)buffer, fileInfo.size());
-                       uint32 crc = crc32_calcCheckSum(buffer, fileInfo.size());
-                       file.close();
-//printf("FilePickerWindow: File crc == %08X...\n", crc);
-
-                       for(int j=0; romList[j].crc32 != 0xFFFFFFFF; j++)
-                       {
-                               if (romList[j].crc32 == crc)
-                               {
-printf("FilePickerWindow: Found match [%s]...\n", romList[j].name);
-                                       new QListWidgetItem(QIcon(":/res/generic.png"), romList[j].name, listWidget);
-                                       break;
-                               }
-                       }
+                       QImage label;
+                       bool successful = label.loadFromData(buffer, size);
+                       img = new QImage;
+                       *img = label.scaled(365, 168, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+//printf("FT: Label %s: %ux%u.\n", (successful ? "succeeded" : "did not succeed"), img->width(), img->height());
+                       delete[] buffer;
                }
-
-               delete[] buffer;
+//printf("FileThread: Attempted to load image. Size: %u x %u...\n", img.width(), img.height());
        }
 
+//     emit FoundAFile2(index, fileInfo.canonicalFilePath(), img, fileSize);
+       emit FoundAFile3(index, fileInfo.canonicalFilePath(), img, fileSize, foundUniversalHeader, fileType, crc);
 }
 
+//
+// Find a CRC in the ROM list (simple brute force algorithm).
+// If it's there, return the index, otherwise return $FFFFFFFF
+//
+uint32 FileThread::FindCRCIndexInFileList(uint32 crc)
+{
+       // Instead of a simple brute-force search, we should probably do a binary
+       // partition search instead, since the CRCs are sorted numerically.
+#warning "!!! Should do binary partition search here !!!"
+       for(int i=0; romList[i].crc32!=0xFFFFFFFF; i++)
+       {
+               if (romList[i].crc32 == crc)
+                       return i;
+       }
+
+       return 0xFFFFFFFF;
+}